From 39f7f63fe951ff861ad151125188e6cdd598b6ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Tue, 9 Aug 2016 20:54:18 +0200 Subject: [PATCH] Add the /title slash command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- app/services/issuable_base_service.rb | 2 +- .../slash_commands/interpret_service.rb | 6 +++ doc/workflow/slash_commands.md | 3 +- .../email/handler/create_note_handler_spec.rb | 15 +++++++- .../slash_commands/interpret_service_spec.rb | 38 +++++++++++++++---- ...issuable_slash_commands_shared_examples.rb | 37 ++++++++++++++++++ 6 files changed, 89 insertions(+), 12 deletions(-) diff --git a/app/services/issuable_base_service.rb b/app/services/issuable_base_service.rb index 3512e2b735e..1ef7a2433dc 100644 --- a/app/services/issuable_base_service.rb +++ b/app/services/issuable_base_service.rb @@ -86,7 +86,7 @@ class IssuableBaseService < BaseService remove_label_ids = attributes.delete(:remove_label_ids) new_label_ids = base_label_ids - new_label_ids = label_ids if label_ids && (merge_all || (add_label_ids.empty? && remove_label_ids.empty?)) + new_label_ids = label_ids if label_ids && (merge_all || (add_label_ids.blank? && remove_label_ids.blank?)) new_label_ids |= add_label_ids if add_label_ids new_label_ids -= remove_label_ids if remove_label_ids diff --git a/app/services/slash_commands/interpret_service.rb b/app/services/slash_commands/interpret_service.rb index bff61683976..74825f30868 100644 --- a/app/services/slash_commands/interpret_service.rb +++ b/app/services/slash_commands/interpret_service.rb @@ -34,6 +34,12 @@ module SlashCommands @updates[:state_event] = 'reopen' end + desc 'Change title' + params '' + command :title do |title_param| + @updates[:title] = title_param + end + desc 'Reassign' params '@user' command :assign, :reassign do |assignee_param| diff --git a/doc/workflow/slash_commands.md b/doc/workflow/slash_commands.md index 3bfc66309ba..bf5b8ebe1c8 100644 --- a/doc/workflow/slash_commands.md +++ b/doc/workflow/slash_commands.md @@ -13,6 +13,7 @@ do. |:---------------------------|:--------------------|:-------------| | `/close` | None | Close the issue or merge request | | `/open` | `/reopen` | Reopen the issue or merge request | +| `/title ` | None | Change title | | `/assign @username` | `/reassign` | Reassign | | `/unassign` | `/remove_assignee` | Remove assignee | | `/milestone %milestone` | None | Change milestone | @@ -24,5 +25,5 @@ do. | `/done` | None | Mark todo as done | | `/subscribe` | None | Subscribe | | `/unsubscribe` | None | Unsubscribe | -| `/due_date` | None | Set a due date | +| `/due_date | ` | None | Set a due date | | `/clear_due_date` | None | Remove due date | diff --git a/spec/lib/gitlab/email/handler/create_note_handler_spec.rb b/spec/lib/gitlab/email/handler/create_note_handler_spec.rb index e2339c5e103..afb072105cf 100644 --- a/spec/lib/gitlab/email/handler/create_note_handler_spec.rb +++ b/spec/lib/gitlab/email/handler/create_note_handler_spec.rb @@ -64,10 +64,21 @@ describe Gitlab::Email::Handler::CreateNoteHandler, lib: true do context 'because the note was commands only' do let!(:email_raw) { fixture_file("emails/commands_only_reply.eml") } - it 'raises a CommandsOnlyNoteError' do - expect { receiver.execute }.not_to raise_error + context 'and current user cannot update noteable' do + it 'raises a CommandsOnlyNoteError' do + expect { receiver.execute }.to raise_error(Gitlab::Email::InvalidNoteError) + end end + context 'and current user can update noteable' do + before do + project.team << [user, :developer] + end + + it 'raises a CommandsOnlyNoteError' do + expect { receiver.execute }.not_to raise_error + end + end end end diff --git a/spec/services/slash_commands/interpret_service_spec.rb b/spec/services/slash_commands/interpret_service_spec.rb index d03c84f59b3..66ebe091893 100644 --- a/spec/services/slash_commands/interpret_service_spec.rb +++ b/spec/services/slash_commands/interpret_service_spec.rb @@ -15,6 +15,7 @@ describe SlashCommands::InterpretService, services: true do is_expected.to match_array([ :open, :reopen, :close, + :title, :assign, :reassign, :unassign, :remove_assignee, :milestone, @@ -53,6 +54,14 @@ describe SlashCommands::InterpretService, services: true do end end + shared_examples 'title command' do + it 'populates title: "A brand new title" if content contains /title A brand new title' do + changes = service.execute(content, issuable) + + expect(changes).to eq(title: 'A brand new title') + end + end + shared_examples 'assign command' do it 'fetches assignee and populates assignee_id if content contains /assign' do changes = service.execute(content, issuable) @@ -190,6 +199,21 @@ describe SlashCommands::InterpretService, services: true do let(:issuable) { merge_request } end + it_behaves_like 'title command' do + let(:content) { '/title A brand new title' } + let(:issuable) { issue } + end + + it_behaves_like 'title command' do + let(:content) { '/title A brand new title' } + let(:issuable) { merge_request } + end + + it_behaves_like 'empty command' do + let(:content) { '/title' } + let(:issuable) { issue } + end + it_behaves_like 'assign command' do let(:content) { "/assign @#{user.username}" } let(:issuable) { issue } @@ -200,16 +224,14 @@ describe SlashCommands::InterpretService, services: true do let(:issuable) { merge_request } end - it 'does not populate assignee_id if content contains /assign with an unknown user' do - changes = service.execute('/assign joe', issue) - - expect(changes).to be_empty + it_behaves_like 'empty command' do + let(:content) { '/assign @abcd1234' } + let(:issuable) { issue } end - it 'does not populate assignee_id if content contains /assign without user' do - changes = service.execute('/assign', issue) - - expect(changes).to be_empty + it_behaves_like 'empty command' do + let(:content) { '/assign' } + let(:issuable) { issue } end it_behaves_like 'unassign command' do diff --git a/spec/support/issuable_slash_commands_shared_examples.rb b/spec/support/issuable_slash_commands_shared_examples.rb index 824ccb0ddfb..4f2e7c3bee8 100644 --- a/spec/support/issuable_slash_commands_shared_examples.rb +++ b/spec/support/issuable_slash_commands_shared_examples.rb @@ -166,6 +166,43 @@ shared_examples 'issuable record that supports slash commands in its description end end + context "with a note changing the #{issuable_type}'s title" do + context "when current user can change title of #{issuable_type}" do + it "reopens the #{issuable_type}" do + page.within('.js-main-target-form') do + fill_in 'note[note]', with: "/title Awesome new title" + click_button 'Comment' + end + + expect(page).not_to have_content '/title' + expect(page).to have_content 'Your commands are being executed.' + + expect(issuable.reload.title).to eq 'Awesome new title' + end + end + + context "when current user cannot change title of #{issuable_type}" do + before do + logout + login_with(guest) + visit public_send("namespace_project_#{issuable_type}_path", project.namespace, project, issuable) + end + + it "does not reopen the #{issuable_type}" do + current_title = issuable.title + page.within('.js-main-target-form') do + fill_in 'note[note]', with: "/title Awesome new title" + click_button 'Comment' + end + + expect(page).not_to have_content '/title' + expect(page).not_to have_content 'Your commands are being executed.' + + expect(issuable.reload.title).not_to eq 'Awesome new title' + end + end + end + context "with a note marking the #{issuable_type} as todo" do it "creates a new todo for the #{issuable_type}" do page.within('.js-main-target-form') do