From bca4457ea34fa0b86e3f607bc50df93001247e03 Mon Sep 17 00:00:00 2001 From: William George Date: Thu, 18 Oct 2018 17:36:18 +0100 Subject: [PATCH 1/8] First pass at adding the `/relate` command --- .../unreleased/6249-related-quick-action.yml | 5 +++ doc/user/project/quick_actions.md | 1 + .../ee/quick_actions/interpret_service.rb | 14 +++++++ .../issues/user_uses_quick_actions_spec.rb | 30 ++++++++++++++ .../quick_actions/interpret_service_spec.rb | 40 +++++++++++++++++++ 5 files changed, 90 insertions(+) create mode 100644 changelogs/unreleased/6249-related-quick-action.yml diff --git a/changelogs/unreleased/6249-related-quick-action.yml b/changelogs/unreleased/6249-related-quick-action.yml new file mode 100644 index 00000000000000..f9b2db52f9df71 --- /dev/null +++ b/changelogs/unreleased/6249-related-quick-action.yml @@ -0,0 +1,5 @@ +--- +title: Related quick action added +merge_request: +author: William George +type: added diff --git a/doc/user/project/quick_actions.md b/doc/user/project/quick_actions.md index 2f47cf5f95e819..a5da9d465d4855 100644 --- a/doc/user/project/quick_actions.md +++ b/doc/user/project/quick_actions.md @@ -52,6 +52,7 @@ discussions, and descriptions: | `/target_branch ` | Set target branch | | ✓ | | `/wip` | Toggle the Work In Progress status | | ✓ | | `/merge` | Merge (when pipeline succeeds) | | ✓ | +| `/relate #issue [#issue...]`| Mark issues as related | ✓ | | ## Quick actions for commit messages diff --git a/ee/app/services/ee/quick_actions/interpret_service.rb b/ee/app/services/ee/quick_actions/interpret_service.rb index 9e3b117a1a51a4..b9f83f1fee8689 100644 --- a/ee/app/services/ee/quick_actions/interpret_service.rb +++ b/ee/app/services/ee/quick_actions/interpret_service.rb @@ -77,6 +77,20 @@ def extract_epic(params) extract_references(params, :epic).first end + + desc 'Mark this issue as related to another issue' + explanation do |related_reference| + "Marks this issue related to #{related_reference}." + end + params '#issue' + condition do + issuable.is_a?(Issue) && + issuable.persisted? && + current_user.can?(:"update_#{issuable.to_ability_name}", issuable) + end + command :related do |related_param| + @updates[:issue_references] = extract_references(related_param, :issue).map(&:id) + end end end end diff --git a/spec/features/issues/user_uses_quick_actions_spec.rb b/spec/features/issues/user_uses_quick_actions_spec.rb index ccca4c1f6c8bb0..1990821af8d077 100644 --- a/spec/features/issues/user_uses_quick_actions_spec.rb +++ b/spec/features/issues/user_uses_quick_actions_spec.rb @@ -227,6 +227,36 @@ end end + describe 'mark issue as related' do + let(:issue) { create(:issue, project: project) } + let(:original_issue) { create(:issue, project: project) } + + context 'when the current user can update issues' do + it 'does not create a note, and marks the issue as releated' do + add_note("/relate ##{original_issue.to_reference}") + + expect(page).not_to have_content "/relate #{original_issue.to_reference}" + expect(page).to have_content 'Commands applied' + end + end + + context 'when the current user cannot update the issue' do + let(:guest) { create(:user) } + before do + project.add_guest(guest) + gitlab_sign_out + sign_in(guest) + visit project_issue_path(project, issue) + end + + it 'does not create a note, and does not mark the issue as a duplicate' do + add_note("/relate ##{original_issue.to_reference}") + + expect(page).not_to have_content 'Commands applied' + end + end + end + describe 'make issue confidential' do let(:issue) { create(:issue, project: project) } let(:original_issue) { create(:issue, project: project) } diff --git a/spec/services/quick_actions/interpret_service_spec.rb b/spec/services/quick_actions/interpret_service_spec.rb index 116866605fc26d..10a485cabeb1e6 100644 --- a/spec/services/quick_actions/interpret_service_spec.rb +++ b/spec/services/quick_actions/interpret_service_spec.rb @@ -1029,6 +1029,41 @@ end end + context '/relate command' do + it_behaves_like 'related command' do + let(:issue_related) { create(:issue, project: project) } + let(:content) { "/relate #{issue_related.to_reference}" } + let(:issuable) { issue } + end + + it_behaves_like 'empty command' do + let(:content) { '/relate' } + let(:issuable) { issue } + end + + context 'cross project references' do + it_behaves_like 'related command' do + let(:other_project) { create(:project, :public) } + let(:issue_related) { create(:issue, project: other_project) } + let(:content) { "/relate #{issue_related.to_reference(project)}" } + let(:issuable) { issue } + end + + it_behaves_like 'empty command' do + let(:content) { "/relate imaginary#1234" } + let(:issuable) { issue } + end + + it_behaves_like 'empty command' do + let(:other_project) { create(:project, :private) } + let(:issue_related) { create(:issue, project: other_project) } + + let(:content) { "/relate #{issue_related.to_reference(project)}" } + let(:issuable) { issue } + end + end + end + context 'when current_user cannot :admin_issue' do let(:visitor) { create(:user) } let(:issue) { create(:issue, project: project, author: visitor) } @@ -1089,6 +1124,11 @@ let(:issuable) { issue } end + it_behaves_like 'empty command' do + let(:content) { '/relate #{issue.to_reference}' } + let(:issuable) { issue } + end + it_behaves_like 'empty command' do let(:content) { '/lock' } let(:issuable) { issue } -- GitLab From 4563b9aac836f9743f1689df017e588399ab1671 Mon Sep 17 00:00:00 2001 From: William George Date: Thu, 18 Oct 2018 16:41:16 +0000 Subject: [PATCH 2/8] Update 6249-related-quick-action.yml --- changelogs/unreleased/6249-related-quick-action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelogs/unreleased/6249-related-quick-action.yml b/changelogs/unreleased/6249-related-quick-action.yml index f9b2db52f9df71..ac8aa3adc1e65b 100644 --- a/changelogs/unreleased/6249-related-quick-action.yml +++ b/changelogs/unreleased/6249-related-quick-action.yml @@ -1,5 +1,5 @@ --- title: Related quick action added -merge_request: +merge_request: 8002 author: William George type: added -- GitLab From 2ac9377943e7eeafb1fffdf23e9bcbc260b12ce1 Mon Sep 17 00:00:00 2001 From: William George Date: Fri, 19 Oct 2018 17:24:05 +0100 Subject: [PATCH 3/8] Fix command name from `related` to `relate` that was missed Update test to use another issue as you can't relate an issue to itself --- ee/app/services/ee/quick_actions/interpret_service.rb | 2 +- spec/services/quick_actions/interpret_service_spec.rb | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ee/app/services/ee/quick_actions/interpret_service.rb b/ee/app/services/ee/quick_actions/interpret_service.rb index b9f83f1fee8689..24b06f80de8bc4 100644 --- a/ee/app/services/ee/quick_actions/interpret_service.rb +++ b/ee/app/services/ee/quick_actions/interpret_service.rb @@ -88,7 +88,7 @@ def extract_epic(params) issuable.persisted? && current_user.can?(:"update_#{issuable.to_ability_name}", issuable) end - command :related do |related_param| + command :relate do |related_param| @updates[:issue_references] = extract_references(related_param, :issue).map(&:id) end end diff --git a/spec/services/quick_actions/interpret_service_spec.rb b/spec/services/quick_actions/interpret_service_spec.rb index 10a485cabeb1e6..64f3e3b18173c4 100644 --- a/spec/services/quick_actions/interpret_service_spec.rb +++ b/spec/services/quick_actions/interpret_service_spec.rb @@ -1125,7 +1125,8 @@ end it_behaves_like 'empty command' do - let(:content) { '/relate #{issue.to_reference}' } + let(:issue_related) { create(:issue, project: project) } + let(:content) { '/relate #{issue_related.to_reference}' } let(:issuable) { issue } end -- GitLab From 7276a18cff62aa1f577e3ad1a8e180aee0da291d Mon Sep 17 00:00:00 2001 From: William George Date: Fri, 19 Oct 2018 17:57:59 +0100 Subject: [PATCH 4/8] Fix ee failing check Fix missing shared command spec --- .../unreleased-ee}/6249-related-quick-action.yml | 0 spec/services/quick_actions/interpret_service_spec.rb | 9 +++++++++ 2 files changed, 9 insertions(+) rename {changelogs/unreleased => ee/changelogs/unreleased-ee}/6249-related-quick-action.yml (100%) diff --git a/changelogs/unreleased/6249-related-quick-action.yml b/ee/changelogs/unreleased-ee/6249-related-quick-action.yml similarity index 100% rename from changelogs/unreleased/6249-related-quick-action.yml rename to ee/changelogs/unreleased-ee/6249-related-quick-action.yml diff --git a/spec/services/quick_actions/interpret_service_spec.rb b/spec/services/quick_actions/interpret_service_spec.rb index 64f3e3b18173c4..42f8e715bb3732 100644 --- a/spec/services/quick_actions/interpret_service_spec.rb +++ b/spec/services/quick_actions/interpret_service_spec.rb @@ -350,6 +350,15 @@ end end + shared_examples 'related command' do + it 'fetches issue and populates issue_references if content contains /relate issue_reference' do + issue_related # populate the issue + _, updates = service.execute(content, issuable) + + expect(updates[:issue_references]).to match_array([issue_related.to_reference]) + end + end + shared_examples 'copy_metadata command' do it 'fetches issue or merge request and copies labels and milestone if content contains /copy_metadata reference' do source_issuable # populate the issue -- GitLab From 684f1c2f16b63b5dcf7081a531de9fae08b21b58 Mon Sep 17 00:00:00 2001 From: William George Date: Mon, 5 Nov 2018 00:12:39 +0000 Subject: [PATCH 5/8] Add ability to link issues? --- ee/app/services/ee/issues/update_service.rb | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/ee/app/services/ee/issues/update_service.rb b/ee/app/services/ee/issues/update_service.rb index b83a90737b6f50..a848cadfcbd1c1 100644 --- a/ee/app/services/ee/issues/update_service.rb +++ b/ee/app/services/ee/issues/update_service.rb @@ -8,6 +8,7 @@ module UpdateService override :execute def execute(issue) handle_epic(issue) + handle_relate(issue) result = super if issue.previous_changes.include?(:milestone_id) && issue.epic @@ -34,6 +35,16 @@ def handle_epic(issue) EpicIssues::DestroyService.new(link, current_user).execute end end + + def handle_relate(issue) + return unless params.key?(:issue_references) + + relate_param = params.delete(:issue_references) + + if relate_param + IssueLinks::CreateService.new(relate_param, current_user, { target_issue: issue }).execute + end + end end end end -- GitLab From f662d0fb04cd29e9b10443f599b6afd27e8c394b Mon Sep 17 00:00:00 2001 From: William George Date: Mon, 5 Nov 2018 01:12:07 +0000 Subject: [PATCH 6/8] Loop over array and create links --- ee/app/services/ee/issues/update_service.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ee/app/services/ee/issues/update_service.rb b/ee/app/services/ee/issues/update_service.rb index a848cadfcbd1c1..eb21b94bd5f865 100644 --- a/ee/app/services/ee/issues/update_service.rb +++ b/ee/app/services/ee/issues/update_service.rb @@ -42,7 +42,9 @@ def handle_relate(issue) relate_param = params.delete(:issue_references) if relate_param - IssueLinks::CreateService.new(relate_param, current_user, { target_issue: issue }).execute + relate_param.each do |issuable| + IssueLinks::CreateService.new(issuable, current_user, { target_issue: issue }).execute + end end end end -- GitLab From ae01672c3f5989fe81514e759c68f6682cc05485 Mon Sep 17 00:00:00 2001 From: William George Date: Tue, 6 Nov 2018 02:08:17 +0000 Subject: [PATCH 7/8] Update `:issue_references` to `:related_issues` https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/8002#note_114531228 Add a test accepting multiple issues to the `/relate` command https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/8002#note_114531226 Try to pass an issue object, not the ID to the create link service --- ee/app/services/ee/issues/update_service.rb | 4 ++-- .../ee/quick_actions/interpret_service.rb | 2 +- .../quick_actions/interpret_service_spec.rb | 19 +++++++++++++++++-- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/ee/app/services/ee/issues/update_service.rb b/ee/app/services/ee/issues/update_service.rb index eb21b94bd5f865..a6b70180125b6c 100644 --- a/ee/app/services/ee/issues/update_service.rb +++ b/ee/app/services/ee/issues/update_service.rb @@ -37,9 +37,9 @@ def handle_epic(issue) end def handle_relate(issue) - return unless params.key?(:issue_references) + return unless params.key?(:related_issues) - relate_param = params.delete(:issue_references) + relate_param = params.delete(:related_issues) if relate_param relate_param.each do |issuable| diff --git a/ee/app/services/ee/quick_actions/interpret_service.rb b/ee/app/services/ee/quick_actions/interpret_service.rb index 24b06f80de8bc4..ee84f33d40bcd2 100644 --- a/ee/app/services/ee/quick_actions/interpret_service.rb +++ b/ee/app/services/ee/quick_actions/interpret_service.rb @@ -89,7 +89,7 @@ def extract_epic(params) current_user.can?(:"update_#{issuable.to_ability_name}", issuable) end command :relate do |related_param| - @updates[:issue_references] = extract_references(related_param, :issue).map(&:id) + @updates[:related_issues] = extract_references(related_param, :issue) end end end diff --git a/spec/services/quick_actions/interpret_service_spec.rb b/spec/services/quick_actions/interpret_service_spec.rb index 42f8e715bb3732..3863b930f08696 100644 --- a/spec/services/quick_actions/interpret_service_spec.rb +++ b/spec/services/quick_actions/interpret_service_spec.rb @@ -351,11 +351,11 @@ end shared_examples 'related command' do - it 'fetches issue and populates issue_references if content contains /relate issue_reference' do + it 'fetches issue and populates related_issues if content contains /relate related_issues' do issue_related # populate the issue _, updates = service.execute(content, issuable) - expect(updates[:issue_references]).to match_array([issue_related.to_reference]) + expect(updates[:related_issues]).to match_array([issue_related.to_reference]) end end @@ -1045,6 +1045,13 @@ let(:issuable) { issue } end + it_behaves_like 'related command' do + let(:issue_related) { create(:issue, project: project) } + let(:issue_related_another) { create(:issue, project: project) } + let(:content) { "/relate #{issue_related.to_reference} #{issue_related_another.to_reference}" } + let(:issuable) { issue } + end + it_behaves_like 'empty command' do let(:content) { '/relate' } let(:issuable) { issue } @@ -1058,6 +1065,14 @@ let(:issuable) { issue } end + it_behaves_like 'related command' do + let(:other_project) { create(:project, :public) } + let(:issue_related) { create(:issue, project: other_project) } + let(:issue_related_another) { create(:issue, project: other_project) } + let(:content) { "/relate #{issue_related.to_reference(project)} #{issue_related_another.to_reference(project)}" } + let(:issuable) { issue } + end + it_behaves_like 'empty command' do let(:content) { "/relate imaginary#1234" } let(:issuable) { issue } -- GitLab From 1695ecf53f18d9e116abebb0e2aa4383f1d093fb Mon Sep 17 00:00:00 2001 From: William George Date: Tue, 6 Nov 2018 03:17:51 +0000 Subject: [PATCH 8/8] Update tests --- spec/services/quick_actions/interpret_service_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/services/quick_actions/interpret_service_spec.rb b/spec/services/quick_actions/interpret_service_spec.rb index 3863b930f08696..bb4c2baf067094 100644 --- a/spec/services/quick_actions/interpret_service_spec.rb +++ b/spec/services/quick_actions/interpret_service_spec.rb @@ -355,7 +355,7 @@ issue_related # populate the issue _, updates = service.execute(content, issuable) - expect(updates[:related_issues]).to match_array([issue_related.to_reference]) + expect(updates[:related_issues]).to match_array([issue_related]) end end -- GitLab