Commit dd2d44cb authored by Mayra Cabrera's avatar Mayra Cabrera

Merge branch 'fix-system-notes-when-moving-issues' into 'master'

Prevent duplicate system notes when moving issues

See merge request gitlab-org/gitlab!41087
parents 579a2a87 4eaf1358
...@@ -136,7 +136,7 @@ class IssuableBaseService < BaseService ...@@ -136,7 +136,7 @@ class IssuableBaseService < BaseService
{} {}
end end
def create(issuable) def create(issuable, skip_system_notes: false)
handle_quick_actions(issuable) handle_quick_actions(issuable)
filter_params(issuable) filter_params(issuable)
...@@ -153,7 +153,7 @@ class IssuableBaseService < BaseService ...@@ -153,7 +153,7 @@ class IssuableBaseService < BaseService
end end
if issuable_saved if issuable_saved
Issuable::CommonSystemNotesService.new(project, current_user).execute(issuable, is_update: false) create_system_notes(issuable, is_update: false) unless skip_system_notes
after_create(issuable) after_create(issuable)
execute_hooks(issuable) execute_hooks(issuable)
...@@ -220,8 +220,9 @@ class IssuableBaseService < BaseService ...@@ -220,8 +220,9 @@ class IssuableBaseService < BaseService
end end
if issuable_saved if issuable_saved
Issuable::CommonSystemNotesService.new(project, current_user).execute( create_system_notes(
issuable, old_labels: old_associations[:labels], old_milestone: old_associations[:milestone]) issuable, old_labels: old_associations[:labels], old_milestone: old_associations[:milestone]
)
handle_changes(issuable, old_associations: old_associations) handle_changes(issuable, old_associations: old_associations)
...@@ -255,7 +256,7 @@ class IssuableBaseService < BaseService ...@@ -255,7 +256,7 @@ class IssuableBaseService < BaseService
before_update(issuable, skip_spam_check: true) before_update(issuable, skip_spam_check: true)
if issuable.with_transaction_returning_status { issuable.save } if issuable.with_transaction_returning_status { issuable.save }
Issuable::CommonSystemNotesService.new(project, current_user).execute(issuable, old_labels: nil) create_system_notes(issuable, old_labels: nil)
handle_task_changes(issuable) handle_task_changes(issuable)
invalidate_cache_counts(issuable, users: issuable.assignees.to_a) invalidate_cache_counts(issuable, users: issuable.assignees.to_a)
...@@ -339,6 +340,10 @@ class IssuableBaseService < BaseService ...@@ -339,6 +340,10 @@ class IssuableBaseService < BaseService
AwardEmojis::ToggleService.new(issuable, award, current_user).execute if award AwardEmojis::ToggleService.new(issuable, award, current_user).execute if award
end end
def create_system_notes(issuable, **options)
Issuable::CommonSystemNotesService.new(project, current_user).execute(issuable, **options)
end
def associations_before_update(issuable) def associations_before_update(issuable)
associations = associations =
{ {
......
...@@ -5,13 +5,13 @@ module Issues ...@@ -5,13 +5,13 @@ module Issues
include SpamCheckMethods include SpamCheckMethods
include ResolveDiscussions include ResolveDiscussions
def execute def execute(skip_system_notes: false)
@issue = BuildService.new(project, current_user, params).execute @issue = BuildService.new(project, current_user, params).execute
filter_spam_check_params filter_spam_check_params
filter_resolve_discussion_params filter_resolve_discussion_params
create(@issue) create(@issue, skip_system_notes: skip_system_notes)
end end
def before_create(issue) def before_create(issue)
......
...@@ -52,7 +52,10 @@ module Issues ...@@ -52,7 +52,10 @@ module Issues
} }
new_params = original_entity.serializable_hash.symbolize_keys.merge(new_params) new_params = original_entity.serializable_hash.symbolize_keys.merge(new_params)
CreateService.new(@target_project, @current_user, new_params).execute
# Skip creation of system notes for existing attributes of the issue. The system notes of the old
# issue are copied over so we don't want to end up with duplicate notes.
CreateService.new(@target_project, @current_user, new_params).execute(skip_system_notes: true)
end end
def mark_as_moved def mark_as_moved
......
---
title: Prevent duplicate system notes and events when an issue is moved
merge_request: 41087
author:
type: fixed
...@@ -11,7 +11,7 @@ module EE ...@@ -11,7 +11,7 @@ module EE
super super
ActiveRecord::Base.no_touching do ActiveRecord::Base.no_touching do
handle_weight_change(is_update) handle_weight_change
handle_iteration_change handle_iteration_change
if is_update if is_update
...@@ -43,13 +43,11 @@ module EE ...@@ -43,13 +43,11 @@ module EE
end end
end end
def handle_weight_change(is_update) def handle_weight_change
return unless issuable.previous_changes.include?('weight') return unless issuable.previous_changes.include?('weight')
if weight_changes_tracking_enabled? if weight_changes_tracking_enabled?
# Only create a resource event here if is_update is true to exclude the move issue operation. EE::ResourceEvents::ChangeWeightService.new([issuable], current_user, Time.current).execute
# ResourceEvents for moved issues are written within AttributesRewriter.
EE::ResourceEvents::ChangeWeightService.new([issuable], current_user, Time.current).execute if is_update
else else
::SystemNoteService.change_weight_note(issuable, issuable.project, current_user) ::SystemNoteService.change_weight_note(issuable, issuable.project, current_user)
end end
......
---
title: Create resource weight event when setting the weight during issue creation
merge_request: 41087
author:
type: fixed
...@@ -115,17 +115,13 @@ RSpec.describe Issuable::CommonSystemNotesService do ...@@ -115,17 +115,13 @@ RSpec.describe Issuable::CommonSystemNotesService do
issuable.update(weight: 5, health_status: 'at_risk') issuable.update(weight: 5, health_status: 'at_risk')
end end
it 'does not create common system notes' do
expect { subject }.not_to change { issuable.notes.count }
end
context 'when resource weight event tracking is enabled' do context 'when resource weight event tracking is enabled' do
before do before do
stub_feature_flags(track_issue_weight_change_events: true) stub_feature_flags(track_issue_weight_change_events: true)
end end
it 'does not create a resource weight event' do it 'creates a resource weight event' do
expect { subject }.not_to change { ResourceWeightEvent.count } expect { subject }.to change { ResourceWeightEvent.count }
end end
it 'does not create a system note' do it 'does not create a system note' do
......
...@@ -32,6 +32,7 @@ RSpec.describe Issues::MoveService do ...@@ -32,6 +32,7 @@ RSpec.describe Issues::MoveService do
end end
context 'resource weight events' do context 'resource weight events' do
let(:old_issue) { create(:issue, project: old_project, author: user, weight: 5) }
let!(:event1) { create(:resource_weight_event, issue: old_issue, weight: 1) } let!(:event1) { create(:resource_weight_event, issue: old_issue, weight: 1) }
let!(:event2) { create(:resource_weight_event, issue: old_issue, weight: 42) } let!(:event2) { create(:resource_weight_event, issue: old_issue, weight: 42) }
let!(:event3) { create(:resource_weight_event, issue: old_issue, weight: 5) } let!(:event3) { create(:resource_weight_event, issue: old_issue, weight: 5) }
......
...@@ -29,6 +29,8 @@ RSpec.describe Issues::CreateService do ...@@ -29,6 +29,8 @@ RSpec.describe Issues::CreateService do
end end
it 'creates the issue with the given params' do it 'creates the issue with the given params' do
expect(Issuable::CommonSystemNotesService).to receive_message_chain(:new, :execute)
expect(issue).to be_persisted expect(issue).to be_persisted
expect(issue.title).to eq('Awesome issue') expect(issue.title).to eq('Awesome issue')
expect(issue.assignees).to eq [assignee] expect(issue.assignees).to eq [assignee]
...@@ -37,6 +39,16 @@ RSpec.describe Issues::CreateService do ...@@ -37,6 +39,16 @@ RSpec.describe Issues::CreateService do
expect(issue.due_date).to eq Date.tomorrow expect(issue.due_date).to eq Date.tomorrow
end end
context 'when skip_system_notes is true' do
let(:issue) { described_class.new(project, user, opts).execute(skip_system_notes: true) }
it 'does not call Issuable::CommonSystemNotesService' do
expect(Issuable::CommonSystemNotesService).not_to receive(:new)
issue
end
end
it 'refreshes the number of open issues', :use_clean_rails_memory_store_caching do it 'refreshes the number of open issues', :use_clean_rails_memory_store_caching do
expect { issue }.to change { project.open_issues_count }.from(0).to(1) expect { issue }.to change { project.open_issues_count }.from(0).to(1)
end end
......
...@@ -101,6 +101,41 @@ RSpec.describe Issues::MoveService do ...@@ -101,6 +101,41 @@ RSpec.describe Issues::MoveService do
end end
end end
context 'issue with milestone' do
let(:milestone) { create(:milestone, group: sub_group_1) }
let(:new_project) { create(:project, namespace: sub_group_1) }
let(:old_issue) do
create(:issue, title: title, description: description, project: old_project, author: author, milestone: milestone)
end
before do
create(:resource_milestone_event, issue: old_issue, milestone: milestone, action: :add)
end
it 'does not create extra milestone events' do
new_issue = move_service.execute(old_issue, new_project)
expect(new_issue.resource_milestone_events.count).to eq(old_issue.resource_milestone_events.count)
end
end
context 'issue with due date' do
let(:old_issue) do
create(:issue, title: title, description: description, project: old_project, author: author, due_date: '2020-01-10')
end
before do
SystemNoteService.change_due_date(old_issue, old_project, author, old_issue.due_date)
end
it 'does not create extra system notes' do
new_issue = move_service.execute(old_issue, new_project)
expect(new_issue.notes.count).to eq(old_issue.notes.count)
end
end
context 'issue with assignee' do context 'issue with assignee' do
let_it_be(:assignee) { create(:user) } let_it_be(:assignee) { create(:user) }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment