diff --git a/app/models/concerns/time_trackable.rb b/app/models/concerns/time_trackable.rb index 1caf47072bc551f2733de4ad50ec092f35dfab9c..0fc321c52bcfa5ebb31c9414d59b5222def8f8fd 100644 --- a/app/models/concerns/time_trackable.rb +++ b/app/models/concerns/time_trackable.rb @@ -30,8 +30,6 @@ def spend_time(options) return if @time_spent == 0 - touch if touchable? - if @time_spent == :reset reset_spent_time else @@ -59,10 +57,6 @@ def time_estimate=(val) private - def touchable? - valid? && persisted? - end - def reset_spent_time timelogs.new(time_spent: total_time_spent * -1, user: @time_spent_user) # rubocop:disable Gitlab/ModuleWithInstanceVariables end diff --git a/app/models/timelog.rb b/app/models/timelog.rb index e166cf69703a960e711b4dd908f2d1f3e110bdef..f4c5c581a11627dbf854426832b636576301bf9f 100644 --- a/app/models/timelog.rb +++ b/app/models/timelog.rb @@ -2,8 +2,8 @@ class Timelog < ActiveRecord::Base validates :time_spent, :user, presence: true validate :issuable_id_is_present - belongs_to :issue - belongs_to :merge_request + belongs_to :issue, touch: true + belongs_to :merge_request, touch: true belongs_to :user def issuable diff --git a/app/services/issuable_base_service.rb b/app/services/issuable_base_service.rb index 1f67e3ecf9dfda5dd013d28a635917a9d705dfb0..683f64e82ad89e082bfe9db5541667acd1f18c0b 100644 --- a/app/services/issuable_base_service.rb +++ b/app/services/issuable_base_service.rb @@ -183,7 +183,10 @@ def update(issuable) old_associations = associations_before_update(issuable) label_ids = process_label_ids(params, existing_label_ids: issuable.label_ids) - params[:label_ids] = label_ids if labels_changing?(issuable.label_ids, label_ids) + if labels_changing?(issuable.label_ids, label_ids) + params[:label_ids] = label_ids + issuable.touch + end if issuable.changed? || params.present? issuable.assign_attributes(params.merge(updated_by: current_user)) diff --git a/changelogs/unreleased/46478-update-updated-at-on-mr.yml b/changelogs/unreleased/46478-update-updated-at-on-mr.yml new file mode 100644 index 0000000000000000000000000000000000000000..c58b4fc8f84529df2164918a7d02dfccb43b6af6 --- /dev/null +++ b/changelogs/unreleased/46478-update-updated-at-on-mr.yml @@ -0,0 +1,5 @@ +--- +title: Updates updated_at on label changes +merge_request: 19065 +author: Jacopo Beschi @jacopo-beschi +type: fixed diff --git a/spec/factories/issues.rb b/spec/factories/issues.rb index 998080a3dd5dce2c2ea6e81bbbfcf4657e92d06e..3a35bdd25deb9fbb8addfd0dce1e91b36471f39e 100644 --- a/spec/factories/issues.rb +++ b/spec/factories/issues.rb @@ -3,6 +3,7 @@ title { generate(:title) } project author { project.creator } + updated_by { author } trait :confidential do confidential true diff --git a/spec/fixtures/api/schemas/entities/issue.json b/spec/fixtures/api/schemas/entities/issue.json index 38467b4ca20af181f25087d8b5254842ad6bc9f4..00abe73ec8aaa730088e2f31d41f5bac90ecf2d4 100644 --- a/spec/fixtures/api/schemas/entities/issue.json +++ b/spec/fixtures/api/schemas/entities/issue.json @@ -27,7 +27,7 @@ "due_date": { "type": "date" }, "confidential": { "type": "boolean" }, "discussion_locked": { "type": ["boolean", "null"] }, - "updated_by_id": { "type": ["string", "null"] }, + "updated_by_id": { "type": ["integer", "null"] }, "time_estimate": { "type": "integer" }, "total_time_spent": { "type": "integer" }, "human_time_estimate": { "type": ["integer", "null"] }, diff --git a/spec/models/concerns/issuable_spec.rb b/spec/models/concerns/issuable_spec.rb index bd6bf5b07123168a7da959ab77531f1f4d2a7524..1cfd526834c5629c205746d95711d339941af2e8 100644 --- a/spec/models/concerns/issuable_spec.rb +++ b/spec/models/concerns/issuable_spec.rb @@ -12,6 +12,7 @@ it { is_expected.to belong_to(:author) } it { is_expected.to have_many(:notes).dependent(:destroy) } it { is_expected.to have_many(:todos).dependent(:destroy) } + it { is_expected.to have_many(:labels) } context 'Notes' do let!(:note) { create(:note, noteable: issue, project: issue.project) } @@ -274,8 +275,8 @@ it 'skips coercion for not Integer values' do expect { issue.time_estimate = nil }.to change { issue.time_estimate }.to(nil) - expect { issue.time_estimate = 'invalid time' }.not_to raise_error(StandardError) - expect { issue.time_estimate = 22.33 }.not_to raise_error(StandardError) + expect { issue.time_estimate = 'invalid time' }.not_to raise_error + expect { issue.time_estimate = 22.33 }.not_to raise_error end end diff --git a/spec/models/timelog_spec.rb b/spec/models/timelog_spec.rb index 6e30798356c36c891d89b867f2b4a2f9b983b629..a0c93c531eaacbcbcea23e7b466968bcf7fc8596 100644 --- a/spec/models/timelog_spec.rb +++ b/spec/models/timelog_spec.rb @@ -5,6 +5,9 @@ let(:issue) { create(:issue) } let(:merge_request) { create(:merge_request) } + it { is_expected.to belong_to(:issue).touch(true) } + it { is_expected.to belong_to(:merge_request).touch(true) } + it { is_expected.to be_valid } it { is_expected.to validate_presence_of(:time_spent) } diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb index 3106083293fbef6dabaa5b26f4dbac57289a0a13..4181f4ebbbe894deb60a7a2411d5c8c73ee2da53 100644 --- a/spec/requests/api/issues_spec.rb +++ b/spec/requests/api/issues_spec.rb @@ -1351,19 +1351,25 @@ expect(json_response['labels']).to eq([label.title]) end - it 'removes all labels' do - put api("/projects/#{project.id}/issues/#{issue.iid}", user), labels: '' + it 'removes all labels and touches the record' do + Timecop.travel(1.minute.from_now) do + put api("/projects/#{project.id}/issues/#{issue.iid}", user), labels: '' + end expect(response).to have_gitlab_http_status(200) expect(json_response['labels']).to eq([]) + expect(json_response['updated_at']).to be > Time.now end - it 'updates labels' do - put api("/projects/#{project.id}/issues/#{issue.iid}", user), + it 'updates labels and touches the record' do + Timecop.travel(1.minute.from_now) do + put api("/projects/#{project.id}/issues/#{issue.iid}", user), labels: 'foo,bar' + end expect(response).to have_gitlab_http_status(200) expect(json_response['labels']).to include 'foo' expect(json_response['labels']).to include 'bar' + expect(json_response['updated_at']).to be > Time.now end it 'allows special label names' do diff --git a/spec/services/issues/update_service_spec.rb b/spec/services/issues/update_service_spec.rb index 23b1134b5a31cb66a205117942bfbc73d5d8b479..158541d36e30b84e900bc6646083f503ac3c5899 100644 --- a/spec/services/issues/update_service_spec.rb +++ b/spec/services/issues/update_service_spec.rb @@ -337,12 +337,18 @@ def update_issue(opts) context 'when the labels change' do before do - update_issue(label_ids: [label.id]) + Timecop.freeze(1.minute.from_now) do + update_issue(label_ids: [label.id]) + end end it 'marks todos as done' do expect(todo.reload.done?).to eq true end + + it 'updates updated_at' do + expect(issue.reload.updated_at).to be > Time.now + end end end diff --git a/spec/services/merge_requests/update_service_spec.rb b/spec/services/merge_requests/update_service_spec.rb index 5279ea6164e2c07959a86151cbb7c53abbf2030b..bd2e91f1f7a5d6989d73282c10723e293d3bc1b1 100644 --- a/spec/services/merge_requests/update_service_spec.rb +++ b/spec/services/merge_requests/update_service_spec.rb @@ -326,12 +326,18 @@ def update_merge_request(opts) context 'when the labels change' do before do - update_merge_request({ label_ids: [label.id] }) + Timecop.freeze(1.minute.from_now) do + update_merge_request({ label_ids: [label.id] }) + end end it 'marks pending todos as done' do expect(pending_todo.reload).to be_done end + + it 'updates updated_at' do + expect(merge_request.reload.updated_at).to be > Time.now + end end context 'when the assignee changes' do