From b149774dbf871c2178a8ec00894996c5fb56a7f4 Mon Sep 17 00:00:00 2001 From: Mehdi Lahmam Date: Sun, 5 Nov 2017 23:52:39 +0100 Subject: [PATCH 1/4] Add /lock and /unlock quick actions Closes #39173 --- .../quick_actions/interpret_service.rb | 24 ++++++ .../unreleased/lock-unlock-quick-actions.yml | 5 ++ doc/user/project/quick_actions.md | 2 + .../quick_actions/interpret_service_spec.rb | 52 +++++++++++++ ...issuable_slash_commands_shared_examples.rb | 74 +++++++++++++++++++ 5 files changed, 157 insertions(+) create mode 100644 changelogs/unreleased/lock-unlock-quick-actions.yml diff --git a/app/services/quick_actions/interpret_service.rb b/app/services/quick_actions/interpret_service.rb index 8a9fe835a16460..7c28b09363ca5d 100644 --- a/app/services/quick_actions/interpret_service.rb +++ b/app/services/quick_actions/interpret_service.rb @@ -490,6 +490,30 @@ def extractor "#{comment} #{TABLEFLIP}" end + desc "Lock the discussion" + explanation "Locks the discussion" + condition do + issuable.is_a?(Issuable) && + issuable.persisted? && + !issuable.discussion_locked? && + current_user.can?(:"admin_#{issuable.to_ability_name}", issuable) + end + command :lock do + @updates[:discussion_locked] = true + end + + desc "Unlock the discussion" + explanation "Unlocks the discussion" + condition do + issuable.is_a?(Issuable) && + issuable.persisted? && + issuable.discussion_locked? && + current_user.can?(:"admin_#{issuable.to_ability_name}", issuable) + end + command :unlock do + @updates[:discussion_locked] = false + end + # This is a dummy command, so that it appears in the autocomplete commands desc 'CC' params '@user' diff --git a/changelogs/unreleased/lock-unlock-quick-actions.yml b/changelogs/unreleased/lock-unlock-quick-actions.yml new file mode 100644 index 00000000000000..9322d60ba528d7 --- /dev/null +++ b/changelogs/unreleased/lock-unlock-quick-actions.yml @@ -0,0 +1,5 @@ +--- +title: Add /lock and /unlock quick actions +merge_request: 15197 +author: Mehdi Lahmam (@mehlah) +type: added diff --git a/doc/user/project/quick_actions.md b/doc/user/project/quick_actions.md index a4e08022353830..54e6078fd041de 100644 --- a/doc/user/project/quick_actions.md +++ b/doc/user/project/quick_actions.md @@ -49,6 +49,8 @@ do. | `/confidential` | Makes the issue confidential | | `/epic ` | Adds an issue to an epic | | `/remove_epic` | Removes an issue from an epic | +| `/lock` | Lock the discussion | +| `/unlock` | Unlock the discussion | Note: In GitLab Starter every issue can have more than one assignee, so commands `/assign`, `/unassign` and `/reassign` support multiple assignees. diff --git a/spec/services/quick_actions/interpret_service_spec.rb b/spec/services/quick_actions/interpret_service_spec.rb index aea96f58c0ab15..df7a6168aa9cb3 100644 --- a/spec/services/quick_actions/interpret_service_spec.rb +++ b/spec/services/quick_actions/interpret_service_spec.rb @@ -275,6 +275,28 @@ end end + shared_examples 'lock command' do + let(:issue) { create(:issue, project: project, discussion_locked: false) } + let(:merge_request) { create(:merge_request, source_project: project, discussion_locked: false) } + + it 'returns discussion_locked: true if content contains /lock' do + _, updates = service.execute(content, issuable) + + expect(updates).to eq(discussion_locked: true) + end + end + + shared_examples 'unlock command' do + let(:issue) { create(:issue, project: project, discussion_locked: true) } + let(:merge_request) { create(:merge_request, source_project: project, discussion_locked: true) } + + it 'returns discussion_locked: true if content contains /unlock' do + _, updates = service.execute(content, issuable) + + expect(updates).to eq(discussion_locked: false) + end + end + shared_examples 'empty command' do it 'populates {} if content contains an unsupported command' do _, updates = service.execute(content, issuable) @@ -829,6 +851,26 @@ let(:issuable) { issue } end + it_behaves_like 'lock command' do + let(:content) { '/lock' } + let(:issuable) { issue } + end + + it_behaves_like 'lock command' do + let(:content) { '/lock' } + let(:issuable) { merge_request } + end + + it_behaves_like 'unlock command' do + let(:content) { '/unlock' } + let(:issuable) { issue } + end + + it_behaves_like 'unlock command' do + let(:content) { '/unlock' } + let(:issuable) { merge_request } + end + context 'issuable weights licensed' do before do stub_licensed_features(issue_weights: true) @@ -1038,6 +1080,16 @@ let(:content) { '/duplicate #{issue.to_reference}' } let(:issuable) { issue } end + + it_behaves_like 'empty command' do + let(:content) { '/lock' } + let(:issuable) { issue } + end + + it_behaves_like 'empty command' do + let(:content) { '/unlock' } + let(:issuable) { issue } + end end context '/award command' do diff --git a/spec/support/features/issuable_slash_commands_shared_examples.rb b/spec/support/features/issuable_slash_commands_shared_examples.rb index 9b44c532ff60b3..f19ba3c5cf950f 100644 --- a/spec/support/features/issuable_slash_commands_shared_examples.rb +++ b/spec/support/features/issuable_slash_commands_shared_examples.rb @@ -285,6 +285,80 @@ expect(issuable.reload.assignees).to eq [maintainer] end end + + context "with a note locking the #{issuable_type} discussion" do + before do + issuable.update(discussion_locked: false) + expect(issuable).not_to be_discussion_locked + end + + context "when current user can lock #{issuable_type} discussion" do + it "locks the #{issuable_type} discussion" do + add_note("/lock") + + expect(page).not_to have_content '/lock' + expect(page).to have_content 'Commands applied' + + expect(issuable.reload).to be_discussion_locked + end + end + + context "when current user cannot lock #{issuable_type}" do + before do + guest = create(:user) + project.add_guest(guest) + + gitlab_sign_out + gitlab_sign_in(guest) + visit public_send("namespace_project_#{issuable_type}_path", project.namespace, project, issuable) + end + + it "does not lock the #{issuable_type} discussion" do + add_note("/lock") + + expect(page).not_to have_content 'Commands applied' + + expect(issuable).not_to be_discussion_locked + end + end + end + + context "with a note unlocking the #{issuable_type} discussion" do + before do + issuable.update(discussion_locked: true) + expect(issuable).to be_discussion_locked + end + + context "when current user can unlock #{issuable_type} discussion" do + it "unlocks the #{issuable_type} discussion" do + add_note("/unlock") + + expect(page).not_to have_content '/unlock' + expect(page).to have_content 'Commands applied' + + expect(issuable.reload).not_to be_discussion_locked + end + end + + context "when current user cannot unlock #{issuable_type}" do + before do + guest = create(:user) + project.add_guest(guest) + + gitlab_sign_out + gitlab_sign_in(guest) + visit public_send("namespace_project_#{issuable_type}_path", project.namespace, project, issuable) + end + + it "does not unlock the #{issuable_type} discussion" do + add_note("/unlock") + + expect(page).not_to have_content 'Commands applied' + + expect(issuable).to be_discussion_locked + end + end + end end describe "preview of note on #{issuable_type}", :js do -- GitLab From 070a9161485820e0ee8a86d4de968c81ef1c7fa9 Mon Sep 17 00:00:00 2001 From: Mehdi Lahmam Date: Fri, 31 Aug 2018 14:51:18 +0200 Subject: [PATCH 2/4] Rename `slash_commands` ~> `quick_actions` in specs files Leftover from ea090291. --- ...ses_slash_commands_spec.rb => user_uses_quick_actions_spec.rb} | 0 ...ses_slash_commands_spec.rb => user_uses_quick_actions_spec.rb} | 0 ...ses_slash_commands_spec.rb => user_uses_quick_actions_spec.rb} | 0 ...ared_examples.rb => issuable_quick_actions_shared_examples.rb} | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename spec/features/commits/{user_uses_slash_commands_spec.rb => user_uses_quick_actions_spec.rb} (100%) rename spec/features/issues/{user_uses_slash_commands_spec.rb => user_uses_quick_actions_spec.rb} (100%) rename spec/features/merge_request/{user_uses_slash_commands_spec.rb => user_uses_quick_actions_spec.rb} (100%) rename spec/support/features/{issuable_slash_commands_shared_examples.rb => issuable_quick_actions_shared_examples.rb} (100%) diff --git a/spec/features/commits/user_uses_slash_commands_spec.rb b/spec/features/commits/user_uses_quick_actions_spec.rb similarity index 100% rename from spec/features/commits/user_uses_slash_commands_spec.rb rename to spec/features/commits/user_uses_quick_actions_spec.rb diff --git a/spec/features/issues/user_uses_slash_commands_spec.rb b/spec/features/issues/user_uses_quick_actions_spec.rb similarity index 100% rename from spec/features/issues/user_uses_slash_commands_spec.rb rename to spec/features/issues/user_uses_quick_actions_spec.rb diff --git a/spec/features/merge_request/user_uses_slash_commands_spec.rb b/spec/features/merge_request/user_uses_quick_actions_spec.rb similarity index 100% rename from spec/features/merge_request/user_uses_slash_commands_spec.rb rename to spec/features/merge_request/user_uses_quick_actions_spec.rb diff --git a/spec/support/features/issuable_slash_commands_shared_examples.rb b/spec/support/features/issuable_quick_actions_shared_examples.rb similarity index 100% rename from spec/support/features/issuable_slash_commands_shared_examples.rb rename to spec/support/features/issuable_quick_actions_shared_examples.rb -- GitLab From bf3faeda05a2806575b7b86d65ed3aa3f1b3956e Mon Sep 17 00:00:00 2001 From: Mehdi Lahmam Date: Thu, 6 Sep 2018 15:34:55 +0200 Subject: [PATCH 3/4] Use un-namespaced project issuables path helper in specs --- .../issuable_quick_actions_shared_examples.rb | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/spec/support/features/issuable_quick_actions_shared_examples.rb b/spec/support/features/issuable_quick_actions_shared_examples.rb index f19ba3c5cf950f..fa2b3db3bdfa7e 100644 --- a/spec/support/features/issuable_quick_actions_shared_examples.rb +++ b/spec/support/features/issuable_quick_actions_shared_examples.rb @@ -55,7 +55,7 @@ describe "note on #{issuable_type}", :js do before do - visit public_send("namespace_project_#{issuable_type}_path", project.namespace, project, issuable) + visit public_send("project_#{issuable_type}_path", project, issuable) end context 'with a note containing commands' do @@ -121,7 +121,7 @@ gitlab_sign_out gitlab_sign_in(guest) - visit public_send("namespace_project_#{issuable_type}_path", project.namespace, project, issuable) + visit public_send("project_#{issuable_type}_path", project, issuable) end it "does not close the #{issuable_type}" do @@ -158,7 +158,7 @@ gitlab_sign_out gitlab_sign_in(guest) - visit public_send("namespace_project_#{issuable_type}_path", project.namespace, project, issuable) + visit public_send("project_#{issuable_type}_path", project, issuable) end it "does not reopen the #{issuable_type}" do @@ -190,7 +190,7 @@ gitlab_sign_out gitlab_sign_in(guest) - visit public_send("namespace_project_#{issuable_type}_path", project.namespace, project, issuable) + visit public_send("project_#{issuable_type}_path", project, issuable) end it "does not change the #{issuable_type} title" do @@ -310,7 +310,7 @@ gitlab_sign_out gitlab_sign_in(guest) - visit public_send("namespace_project_#{issuable_type}_path", project.namespace, project, issuable) + visit public_send("project_#{issuable_type}_path", project, issuable) end it "does not lock the #{issuable_type} discussion" do @@ -347,7 +347,7 @@ gitlab_sign_out gitlab_sign_in(guest) - visit public_send("namespace_project_#{issuable_type}_path", project.namespace, project, issuable) + visit public_send("project_#{issuable_type}_path", project, issuable) end it "does not unlock the #{issuable_type} discussion" do @@ -365,7 +365,7 @@ it 'removes quick actions from note and explains them' do create(:user, username: 'bob') - visit public_send("namespace_project_#{issuable_type}_path", project.namespace, project, issuable) + visit public_send("project_#{issuable_type}_path", project, issuable) page.within('.js-main-target-form') do fill_in 'note[note]', with: "Awesome!\n/assign @bob " -- GitLab From d661d9e02eb537d630abcb8870bd2414ea89ded5 Mon Sep 17 00:00:00 2001 From: Mehdi Lahmam Date: Thu, 6 Sep 2018 22:33:38 +0200 Subject: [PATCH 4/4] Prefer `sign_in` over `gitlab_sign_in` as its faster Devise helpers acts on Warden which is faster than our own helpers. Note that `gitlab_sign_out` is still necessary due to the same issue mentioned at 60814985e033e4941ff3eb5d33ca55e3fc81593e --- .../features/issuable_quick_actions_shared_examples.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/support/features/issuable_quick_actions_shared_examples.rb b/spec/support/features/issuable_quick_actions_shared_examples.rb index fa2b3db3bdfa7e..846e697eb964e0 100644 --- a/spec/support/features/issuable_quick_actions_shared_examples.rb +++ b/spec/support/features/issuable_quick_actions_shared_examples.rb @@ -309,7 +309,7 @@ project.add_guest(guest) gitlab_sign_out - gitlab_sign_in(guest) + sign_in(guest) visit public_send("project_#{issuable_type}_path", project, issuable) end @@ -346,7 +346,7 @@ project.add_guest(guest) gitlab_sign_out - gitlab_sign_in(guest) + sign_in(guest) visit public_send("project_#{issuable_type}_path", project, issuable) end -- GitLab