Commit 4501e458 authored by Dmytro Zaporozhets (DZ)'s avatar Dmytro Zaporozhets (DZ)

Merge branch '323497-improve-error-when-command-is-unavailable' into 'master'

Show error when quick action is not available

See merge request gitlab-org/gitlab!57570
parents 9e2a2cec cdf3115a
---
title: Give better feedback when quick actions have no effect
merge_request: 57570
author: Hilco van der Wilk
type: fixed
......@@ -390,11 +390,11 @@ RSpec.describe QuickActions::InterpretService do
allow(current_user).to receive(:can?).with(:admin_issue, project).and_return(false)
end
it 'returns empty message' do
it 'returns an error message' do
_, updates, message = service.execute(content, issue)
expect(updates).to be_empty
expect(message).to be_empty
expect(message).to eq('Could not apply iteration command.')
end
end
end
......@@ -458,11 +458,11 @@ RSpec.describe QuickActions::InterpretService do
allow(current_user).to receive(:can?).with(:admin_issue, project).and_return(false)
end
it 'returns empty message' do
it 'returns an error message' do
_, updates, message = service.execute(content, issue)
expect(updates).to be_empty
expect(message).to be_empty
expect(message).to eq('Could not apply remove_iteration command.')
end
end
end
......
......@@ -56,15 +56,18 @@ module Gitlab
end
def execute(context, arg)
return unless executable?(context)
return if noop?
count_commands_executed_in(context)
return unless available?(context)
execute_block(action_block, context, arg)
end
def execute_message(context, arg)
return unless executable?(context)
return if noop?
return _('Could not apply %{name} command.') % { name: name } unless available?(context)
if execution_message.respond_to?(:call)
execute_block(execution_message, context, arg)
......@@ -101,10 +104,6 @@ module Gitlab
private
def executable?(context)
!noop? && available?(context)
end
def count_commands_executed_in(context)
return unless context.respond_to?(:commands_executed_count=)
......
......@@ -8645,6 +8645,9 @@ msgstr ""
msgid "Could not add admins as members"
msgstr ""
msgid "Could not apply %{name} command."
msgstr ""
msgid "Could not archive %{design}. Please try again."
msgstr ""
......
Return-Path: <jake@adventuretime.ooo>
Received: from iceking.adventuretime.ooo ([unix socket]) by iceking (Cyrus v2.2.13-Debian-2.2.13-19+squeeze3) with LMTPA; Thu, 13 Jun 2013 17:03:50 -0400
Received: from mail-ie0-x234.google.com (mail-ie0-x234.google.com [IPv6:2607:f8b0:4001:c03::234]) by iceking.adventuretime.ooo (8.14.3/8.14.3/Debian-9.4) with ESMTP id r5DL3nFJ016967 (version=TLSv1/SSLv3 cipher=RC4-SHA bits=128 verify=NOT) for <reply+59d8df8370b7e95c5a49fbf86aeb2c93@appmail.adventuretime.ooo>; Thu, 13 Jun 2013 17:03:50 -0400
Received: by mail-ie0-f180.google.com with SMTP id f4so21977375iea.25 for <reply+59d8df8370b7e95c5a49fbf86aeb2c93@appmail.adventuretime.ooo>; Thu, 13 Jun 2013 14:03:48 -0700
Received: by 10.0.0.1 with HTTP; Thu, 13 Jun 2013 14:03:48 -0700
Date: Thu, 13 Jun 2013 17:03:48 -0400
From: Jake the Dog <jake@adventuretime.ooo>
To: reply+59d8df8370b7e95c5a49fbf86aeb2c93@appmail.adventuretime.ooo
Message-ID: <CADkmRc+rNGAGGbV2iE5p918UVy4UyJqVcXRO2=otppgzduJSg@mail.gmail.com>
In-Reply-To: <issue_1@localhost>
References: <reply-59d8df8370b7e95c5a49fbf86aeb2c93@localhost> <issue_1@localhost>
Subject: re: [Discourse Meta] eviltrout posted in 'Adventure Time Sux'
Mime-Version: 1.0
Content-Type: text/plain;
charset=ISO-8859-1
Content-Transfer-Encoding: 7bit
X-Sieve: CMU Sieve 2.2
X-Received: by 10.0.0.1 with SMTP id n7mr11234144ipb.85.1371157428600; Thu,
13 Jun 2013 14:03:48 -0700 (PDT)
X-Scanned-By: MIMEDefang 2.69 on IPv6:2001:470:1d:165::1
/close
......@@ -22,7 +22,7 @@ RSpec.describe Gitlab::Email::Handler::CreateNoteOnIssuableHandler do
it_behaves_like :note_handler_shared_examples, true do
let_it_be(:recipient) { user }
let(:update_commands_only) { email_reply_fixture('emails/update_commands_only_reply.eml') }
let(:update_commands_only) { email_reply_fixture('emails/update_commands_only.eml') }
let(:no_content) { email_reply_fixture('emails/no_content_reply.eml') }
let(:commands_in_reply) { email_reply_fixture('emails/commands_in_reply.eml') }
let(:with_quick_actions) { email_reply_fixture('emails/valid_reply_with_quick_actions.eml') }
......
......@@ -127,10 +127,10 @@ RSpec.describe Gitlab::QuickActions::CommandDefinition do
subject.condition_block = proc { false }
end
it "doesn't execute the command" do
it "counts the command as executed" do
subject.execute(context, nil)
expect(context.commands_executed_count).to be_nil
expect(context.commands_executed_count).to eq(1)
expect(context.run).to be false
end
end
......@@ -238,8 +238,8 @@ RSpec.describe Gitlab::QuickActions::CommandDefinition do
subject.condition_block = proc { false }
end
it 'returns nil' do
expect(subject.execute_message({}, nil)).to be_nil
it 'returns an error message' do
expect(subject.execute_message({}, nil)).to eq('Could not apply command command.')
end
end
......
......@@ -345,6 +345,24 @@ RSpec.describe Notes::CreateService do
expect(note.errors[:commands_only]).to be_present
end
it 'adds commands failed message to note errors' do
note_text = %(/reopen)
note = described_class.new(project, user, opts.merge(note: note_text)).execute
expect(note.errors[:commands_only]).to contain_exactly('Could not apply reopen command.')
end
it 'generates success and failed error messages' do
note_text = %(/close\n/reopen)
service = double(:service)
allow(Issues::UpdateService).to receive(:new).and_return(service)
expect(service).to receive(:execute)
note = described_class.new(project, user, opts.merge(note: note_text)).execute
expect(note.errors[:commands_only]).to contain_exactly('Closed this issue. Could not apply reopen command.')
end
end
end
......
......@@ -478,7 +478,7 @@ RSpec.describe QuickActions::InterpretService do
end
end
shared_examples 'empty command' do |error_msg|
shared_examples 'failed command' do |error_msg|
it 'populates {} if content contains an unsupported command' do
_, updates, _ = service.execute(content, issuable)
......@@ -607,10 +607,10 @@ RSpec.describe QuickActions::InterpretService do
issuable.update!(confidential: true)
end
it 'does not return the success message' do
it 'returns an error message' do
_, _, message = service.execute(content, issuable)
expect(message).to be_empty
expect(message).to eq('Could not apply confidential command.')
end
it 'is not part of the available commands' do
......@@ -728,7 +728,7 @@ RSpec.describe QuickActions::InterpretService do
context 'can not be merged when logged user does not have permissions' do
let(:service) { described_class.new(project, create(:user)) }
it_behaves_like 'empty command' do
it_behaves_like 'failed command', 'Could not apply merge command.' do
let(:content) { "/merge" }
let(:issuable) { merge_request }
end
......@@ -737,7 +737,7 @@ RSpec.describe QuickActions::InterpretService do
context 'can not be merged when sha does not match' do
let(:service) { described_class.new(project, developer, { merge_request_diff_head_sha: 'othersha' }) }
it_behaves_like 'empty command' do
it_behaves_like 'failed command', 'Could not apply merge command.' do
let(:content) { "/merge" }
let(:issuable) { merge_request }
end
......@@ -755,21 +755,21 @@ RSpec.describe QuickActions::InterpretService do
end
context 'issue can not be merged' do
it_behaves_like 'empty command' do
it_behaves_like 'failed command', 'Could not apply merge command.' do
let(:content) { "/merge" }
let(:issuable) { issue }
end
end
context 'non persisted merge request cant be merged' do
it_behaves_like 'empty command' do
it_behaves_like 'failed command', 'Could not apply merge command.' do
let(:content) { "/merge" }
let(:issuable) { build(:merge_request) }
end
end
context 'not persisted merge request can not be merged' do
it_behaves_like 'empty command' do
it_behaves_like 'failed command', 'Could not apply merge command.' do
let(:content) { "/merge" }
let(:issuable) { build(:merge_request, source_project: project) }
end
......@@ -786,7 +786,7 @@ RSpec.describe QuickActions::InterpretService do
let(:issuable) { merge_request }
end
it_behaves_like 'empty command' do
it_behaves_like 'failed command' do
let(:content) { '/title' }
let(:issuable) { issue }
end
......@@ -869,12 +869,12 @@ RSpec.describe QuickActions::InterpretService do
end
end
it_behaves_like 'empty command', "Failed to assign a user because no user was found." do
it_behaves_like 'failed command', "Failed to assign a user because no user was found." do
let(:content) { '/assign @abcd1234' }
let(:issuable) { issue }
end
it_behaves_like 'empty command', "Failed to assign a user because no user was found." do
it_behaves_like 'failed command', "Failed to assign a user because no user was found." do
let(:content) { '/assign' }
let(:issuable) { issue }
end
......@@ -890,7 +890,7 @@ RSpec.describe QuickActions::InterpretService do
context 'with an issue instead of a merge request' do
let(:issuable) { issue }
it_behaves_like 'empty command'
it_behaves_like 'failed command', 'Could not apply assign_reviewer command.'
end
# CE does not have multiple reviewers
......@@ -935,7 +935,7 @@ RSpec.describe QuickActions::InterpretService do
context 'with an incorrect user' do
let(:content) { '/assign_reviewer @abcd1234' }
it_behaves_like 'empty command', "Failed to assign a reviewer because no user was found."
it_behaves_like 'failed command', "Failed to assign a reviewer because no user was found."
end
context 'with the "reviewer" alias' do
......@@ -953,7 +953,7 @@ RSpec.describe QuickActions::InterpretService do
context 'with no user' do
let(:content) { '/assign_reviewer' }
it_behaves_like 'empty command', "Failed to assign a reviewer because no user was found."
it_behaves_like 'failed command', "Failed to assign a reviewer because no user was found."
end
context 'includes only the user reference with extra text' do
......@@ -977,7 +977,7 @@ RSpec.describe QuickActions::InterpretService do
context 'with an issue instead of a merge request' do
let(:issuable) { issue }
it_behaves_like 'empty command'
it_behaves_like 'failed command', 'Could not apply unassign_reviewer command.'
end
context 'with anything after the command' do
......@@ -1035,6 +1035,11 @@ RSpec.describe QuickActions::InterpretService do
end
end
context 'project milestones' do
before do
milestone
end
it_behaves_like 'milestone command' do
let(:content) { "/milestone %#{milestone.title}" }
let(:issuable) { issue }
......@@ -1044,6 +1049,7 @@ RSpec.describe QuickActions::InterpretService do
let(:content) { "/milestone %#{milestone.title}" }
let(:issuable) { merge_request }
end
end
context 'only group milestones available' do
let_it_be(:ancestor_group) { create(:group) }
......@@ -1181,7 +1187,7 @@ RSpec.describe QuickActions::InterpretService do
let(:issuable) { merge_request }
end
it_behaves_like 'empty command' do
it_behaves_like 'failed command', 'Could not apply due command.' do
let(:content) { '/due 2016-08-28' }
let(:issuable) { merge_request }
end
......@@ -1211,7 +1217,7 @@ RSpec.describe QuickActions::InterpretService do
let(:issuable) { merge_request }
end
it_behaves_like 'empty command' do
it_behaves_like 'failed command', 'Could not apply remove_due_date command.' do
let(:content) { '/remove_due_date' }
let(:issuable) { merge_request }
end
......@@ -1221,12 +1227,12 @@ RSpec.describe QuickActions::InterpretService do
let(:issuable) { issue }
end
it_behaves_like 'empty command' do
it_behaves_like 'failed command' do
let(:content) { '/estimate' }
let(:issuable) { issue }
end
it_behaves_like 'empty command' do
it_behaves_like 'failed command' do
let(:content) { '/estimate abc' }
let(:issuable) { issue }
end
......@@ -1257,12 +1263,12 @@ RSpec.describe QuickActions::InterpretService do
let(:issuable) { issue }
end
it_behaves_like 'empty command' do
it_behaves_like 'failed command' do
let(:content) { '/spend' }
let(:issuable) { issue }
end
it_behaves_like 'empty command' do
it_behaves_like 'failed command' do
let(:content) { '/spend abc' }
let(:issuable) { issue }
end
......@@ -1323,7 +1329,7 @@ RSpec.describe QuickActions::InterpretService do
end
context 'if issuable is a Commit' do
it_behaves_like 'empty command' do
it_behaves_like 'failed command', 'Could not apply todo command.' do
let(:issuable) { commit }
end
end
......@@ -1379,7 +1385,7 @@ RSpec.describe QuickActions::InterpretService do
end
end
it_behaves_like 'empty command' do
it_behaves_like 'failed command' do
let(:content) { '/copy_metadata' }
let(:issuable) { issue }
end
......@@ -1419,19 +1425,19 @@ RSpec.describe QuickActions::InterpretService do
end
context 'cross project references' do
it_behaves_like 'empty command' do
it_behaves_like 'failed command' do
let(:other_project) { create(:project, :public) }
let(:source_issuable) { create(:labeled_issue, project: other_project, labels: [todo_label, inreview_label]) }
let(:content) { "/copy_metadata #{source_issuable.to_reference(project)}" }
let(:issuable) { issue }
end
it_behaves_like 'empty command' do
it_behaves_like 'failed command' do
let(:content) { "/copy_metadata imaginary##{non_existing_record_iid}" }
let(:issuable) { issue }
end
it_behaves_like 'empty command' do
it_behaves_like 'failed command' do
let(:other_project) { create(:project, :private) }
let(:source_issuable) { create(:issue, project: other_project) }
......@@ -1448,7 +1454,7 @@ RSpec.describe QuickActions::InterpretService do
let(:issuable) { issue }
end
it_behaves_like 'empty command' do
it_behaves_like 'failed command' do
let(:content) { '/duplicate' }
let(:issuable) { issue }
end
......@@ -1461,12 +1467,12 @@ RSpec.describe QuickActions::InterpretService do
let(:issuable) { issue }
end
it_behaves_like 'empty command', _('Failed to mark this issue as a duplicate because referenced issue was not found.') do
it_behaves_like 'failed command', _('Failed to mark this issue as a duplicate because referenced issue was not found.') do
let(:content) { "/duplicate imaginary##{non_existing_record_iid}" }
let(:issuable) { issue }
end
it_behaves_like 'empty command', _('Failed to mark this issue as a duplicate because referenced issue was not found.') do
it_behaves_like 'failed command', _('Failed to mark this issue as a duplicate because referenced issue was not found.') do
let(:other_project) { create(:project, :private) }
let(:issue_duplicate) { create(:issue, project: other_project) }
......@@ -1481,62 +1487,62 @@ RSpec.describe QuickActions::InterpretService do
let(:issue) { create(:issue, project: project, author: visitor) }
let(:service) { described_class.new(project, visitor) }
it_behaves_like 'empty command' do
it_behaves_like 'failed command', 'Could not apply assign command.' do
let(:content) { "/assign @#{developer.username}" }
let(:issuable) { issue }
end
it_behaves_like 'empty command' do
it_behaves_like 'failed command', 'Could not apply unassign command.' do
let(:content) { '/unassign' }
let(:issuable) { issue }
end
it_behaves_like 'empty command' do
it_behaves_like 'failed command', 'Could not apply milestone command.' do
let(:content) { "/milestone %#{milestone.title}" }
let(:issuable) { issue }
end
it_behaves_like 'empty command' do
it_behaves_like 'failed command', 'Could not apply remove_milestone command.' do
let(:content) { '/remove_milestone' }
let(:issuable) { issue }
end
it_behaves_like 'empty command' do
it_behaves_like 'failed command', 'Could not apply label command.' do
let(:content) { %(/label ~"#{inprogress.title}" ~#{bug.title} ~unknown) }
let(:issuable) { issue }
end
it_behaves_like 'empty command' do
it_behaves_like 'failed command', 'Could not apply unlabel command.' do
let(:content) { %(/unlabel ~"#{inprogress.title}") }
let(:issuable) { issue }
end
it_behaves_like 'empty command' do
it_behaves_like 'failed command', 'Could not apply relabel command.' do
let(:content) { %(/relabel ~"#{inprogress.title}") }
let(:issuable) { issue }
end
it_behaves_like 'empty command' do
it_behaves_like 'failed command', 'Could not apply due command.' do
let(:content) { '/due tomorrow' }
let(:issuable) { issue }
end
it_behaves_like 'empty command' do
it_behaves_like 'failed command', 'Could not apply remove_due_date command.' do
let(:content) { '/remove_due_date' }
let(:issuable) { issue }
end
it_behaves_like 'empty command' do
it_behaves_like 'failed command', 'Could not apply confidential command.' do
let(:content) { '/confidential' }
let(:issuable) { issue }
end
it_behaves_like 'empty command' do
it_behaves_like 'failed command', 'Could not apply lock command.' do
let(:content) { '/lock' }
let(:issuable) { issue }
end
it_behaves_like 'empty command' do
it_behaves_like 'failed command', 'Could not apply unlock command.' do
let(:content) { '/unlock' }
let(:issuable) { issue }
end
......@@ -1554,19 +1560,19 @@ RSpec.describe QuickActions::InterpretService do
end
context 'ignores command with no argument' do
it_behaves_like 'empty command' do
it_behaves_like 'failed command' do
let(:content) { '/award' }
let(:issuable) { issue }
end
end
context 'ignores non-existing / invalid emojis' do
it_behaves_like 'empty command' do
it_behaves_like 'failed command' do
let(:content) { '/award noop' }
let(:issuable) { issue }
end
it_behaves_like 'empty command' do
it_behaves_like 'failed command' do
let(:content) { '/award :lorem_ipsum:' }
let(:issuable) { issue }
end
......@@ -1576,7 +1582,7 @@ RSpec.describe QuickActions::InterpretService do
let(:content) { '/award :100:' }
let(:issuable) { commit }
it_behaves_like 'empty command'
it_behaves_like 'failed command', 'Could not apply award command.'
end
end
......@@ -1622,14 +1628,14 @@ RSpec.describe QuickActions::InterpretService do
end
context 'ignores command with no argument' do
it_behaves_like 'empty command' do
it_behaves_like 'failed command', 'Could not apply target_branch command.' do
let(:content) { '/target_branch' }
let(:issuable) { another_merge_request }
end
end
context 'ignores non-existing target branch' do
it_behaves_like 'empty command' do
it_behaves_like 'failed command', 'Could not apply target_branch command.' do
let(:content) { '/target_branch totally_non_existing_branch' }
let(:issuable) { another_merge_request }
end
......@@ -1697,34 +1703,34 @@ RSpec.describe QuickActions::InterpretService do
create(:board, project: project)
end
it_behaves_like 'empty command'
it_behaves_like 'failed command', 'Could not apply board_move command.'
end
context 'if the given label does not exist' do
let(:issuable) { issue }
let(:content) { '/board_move ~"Fake Label"' }
it_behaves_like 'empty command', 'Failed to move this issue because label was not found.'
it_behaves_like 'failed command', 'Failed to move this issue because label was not found.'
end
context 'if multiple labels are given' do
let(:issuable) { issue }
let(:content) { %{/board_move ~"#{inreview.title}" ~"#{todo.title}"} }
it_behaves_like 'empty command', 'Failed to move this issue because only a single label can be provided.'
it_behaves_like 'failed command', 'Failed to move this issue because only a single label can be provided.'
end
context 'if the given label is not a list on the board' do
let(:issuable) { issue }
let(:content) { %{/board_move ~"#{bug.title}"} }
it_behaves_like 'empty command', 'Failed to move this issue because label was not found.'
it_behaves_like 'failed command', 'Failed to move this issue because label was not found.'
end
context 'if issuable is not an Issue' do
let(:issuable) { merge_request }
it_behaves_like 'empty command'
it_behaves_like 'failed command', 'Could not apply board_move command.'
end
end
......@@ -1732,7 +1738,7 @@ RSpec.describe QuickActions::InterpretService do
let(:issuable) { commit }
context 'ignores command with no argument' do
it_behaves_like 'empty command' do
it_behaves_like 'failed command' do
let(:content) { '/tag' }
end
end
......@@ -1797,7 +1803,7 @@ RSpec.describe QuickActions::InterpretService do
context 'if issuable is not an Issue' do
let(:issuable) { merge_request }
it_behaves_like 'empty command'
it_behaves_like 'failed command', 'Could not apply create_merge_request command.'
end
context "when logged user cannot create_merge_requests in the project" do
......@@ -1807,14 +1813,14 @@ RSpec.describe QuickActions::InterpretService do
project.add_developer(developer)
end
it_behaves_like 'empty command'
it_behaves_like 'failed command', 'Could not apply create_merge_request command.'
end
context 'when logged user cannot push code to the project' do
let(:project) { create(:project, :private) }
let(:service) { described_class.new(project, create(:user)) }
it_behaves_like 'empty command'
it_behaves_like 'failed command', 'Could not apply create_merge_request command.'
end
it 'populates create_merge_request with branch_name and issue iid' do
......@@ -1953,7 +1959,7 @@ RSpec.describe QuickActions::InterpretService do
context 'invite_email command' do
let_it_be(:issuable) { issue }
it_behaves_like 'empty command', "No email participants were added. Either none were provided, or they already exist." do
it_behaves_like 'failed command', "No email participants were added. Either none were provided, or they already exist." do
let(:content) { '/invite_email' }
end
......@@ -1964,7 +1970,7 @@ RSpec.describe QuickActions::InterpretService do
issuable.issue_email_participants.create!(email: "a@gitlab.com")
end
it_behaves_like 'empty command', "No email participants were added. Either none were provided, or they already exist."
it_behaves_like 'failed command', "No email participants were added. Either none were provided, or they already exist."
end
context 'with new email participants' do
......
......@@ -82,8 +82,8 @@ RSpec.shared_examples :note_handler_shared_examples do |forwardable|
let!(:email_raw) { update_commands_only }
context 'and current user cannot update noteable' do
it 'raises a CommandsOnlyNoteError' do
expect { receiver.execute }.to raise_error(Gitlab::Email::InvalidNoteError)
it 'does not raise an error' do
expect { receiver.execute }.not_to raise_error
end
end
......@@ -92,15 +92,11 @@ RSpec.shared_examples :note_handler_shared_examples do |forwardable|
project.add_developer(user)
end
it 'does not raise an error', unless: forwardable do
it 'does not raise an error' do
expect { receiver.execute }.to change { noteable.resource_state_events.count }.by(1)
expect(noteable.reload).to be_closed
end
it 'raises an InvalidNoteError', if: forwardable do
expect { receiver.execute }.to raise_error(Gitlab::Email::InvalidNoteError)
end
end
end
end
......
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