Allow limiting quick actions to execute

Sometimes we don't want to trigger any quick actions that cause side
effects. For example when building a record to validate. This allows
listing the quick actions that need to be performed.
This commit is contained in:
Bob Van Landuyt 2018-11-07 13:33:42 +01:00
parent 6fbdc5ed52
commit c85a19f920
6 changed files with 44 additions and 10 deletions

View file

@ -126,12 +126,12 @@ class IssuableBaseService < BaseService
merge_quick_actions_into_params!(issuable) merge_quick_actions_into_params!(issuable)
end end
def merge_quick_actions_into_params!(issuable) def merge_quick_actions_into_params!(issuable, only: nil)
original_description = params.fetch(:description, issuable.description) original_description = params.fetch(:description, issuable.description)
description, command_params = description, command_params =
QuickActions::InterpretService.new(project, current_user) QuickActions::InterpretService.new(project, current_user)
.execute(original_description, issuable) .execute(original_description, issuable, only: only)
# Avoid a description already set on an issuable to be overwritten by a nil # Avoid a description already set on an issuable to be overwritten by a nil
params[:description] = description if description params[:description] = description if description

View file

@ -7,7 +7,9 @@ module MergeRequests
def execute def execute
@params_issue_iid = params.delete(:issue_iid) @params_issue_iid = params.delete(:issue_iid)
self.merge_request = MergeRequest.new self.merge_request = MergeRequest.new
merge_quick_actions_into_params!(merge_request) # TODO: this should handle all quick actions that don't have side effects
# https://gitlab.com/gitlab-org/gitlab-ce/issues/53658
merge_quick_actions_into_params!(merge_request, only: [:target_branch])
merge_request.assign_attributes(params) merge_request.assign_attributes(params)
merge_request.author = current_user merge_request.author = current_user

View file

@ -23,13 +23,13 @@ module QuickActions
# Takes a text and interprets the commands that are extracted from it. # Takes a text and interprets the commands that are extracted from it.
# Returns the content without commands, and hash of changes to be applied to a record. # Returns the content without commands, and hash of changes to be applied to a record.
def execute(content, issuable) def execute(content, issuable, only: nil)
return [content, {}] unless current_user.can?(:use_quick_actions) return [content, {}] unless current_user.can?(:use_quick_actions)
@issuable = issuable @issuable = issuable
@updates = {} @updates = {}
content, commands = extractor.extract_commands(content) content, commands = extractor.extract_commands(content, only: only)
extract_updates(commands) extract_updates(commands)
[content, @updates] [content, @updates]

View file

@ -29,7 +29,7 @@ module Gitlab
# commands = extractor.extract_commands(msg) #=> [['labels', '~foo ~"bar baz"']] # commands = extractor.extract_commands(msg) #=> [['labels', '~foo ~"bar baz"']]
# msg #=> "hello\nworld" # msg #=> "hello\nworld"
# ``` # ```
def extract_commands(content) def extract_commands(content, only: nil)
return [content, []] unless content return [content, []] unless content
content = content.dup content = content.dup
@ -37,7 +37,7 @@ module Gitlab
commands = [] commands = []
content.delete!("\r") content.delete!("\r")
content.gsub!(commands_regex) do content.gsub!(commands_regex(only: only)) do
if $~[:cmd] if $~[:cmd]
commands << [$~[:cmd].downcase, $~[:arg]].reject(&:blank?) commands << [$~[:cmd].downcase, $~[:arg]].reject(&:blank?)
'' ''
@ -60,8 +60,8 @@ module Gitlab
# It looks something like: # It looks something like:
# #
# /^\/(?<cmd>close|reopen|...)(?:( |$))(?<arg>[^\/\n]*)(?:\n|$)/ # /^\/(?<cmd>close|reopen|...)(?:( |$))(?<arg>[^\/\n]*)(?:\n|$)/
def commands_regex def commands_regex(only:)
names = command_names.map(&:to_s) names = command_names(limit_to_commands: only).map(&:to_s)
@commands_regex ||= %r{ @commands_regex ||= %r{
(?<code> (?<code>
@ -133,10 +133,14 @@ module Gitlab
[content, commands] [content, commands]
end end
def command_names def command_names(limit_to_commands:)
command_definitions.flat_map do |command| command_definitions.flat_map do |command|
next if command.noop? next if command.noop?
if limit_to_commands && (command.all_names & limit_to_commands).empty?
next
end
command.all_names command.all_names
end.compact end.compact
end end

View file

@ -272,5 +272,24 @@ describe Gitlab::QuickActions::Extractor do
expect(commands).to be_empty expect(commands).to be_empty
expect(msg).to eq expected expect(msg).to eq expected
end end
it 'limits to passed commands when they are passed' do
msg = <<~MSG.strip
Hello, we should only extract the commands passed
/reopen
/labels hello world
/power
MSG
expected_msg = <<~EXPECTED.strip
Hello, we should only extract the commands passed
/power
EXPECTED
expected_commands = [['reopen'], ['labels', 'hello world']]
msg, commands = extractor.extract_commands(msg, only: [:open, :labels])
expect(commands).to eq(expected_commands)
expect(msg).to eq expected_msg
end
end end
end end

View file

@ -1213,6 +1213,15 @@ describe QuickActions::InterpretService do
end end
end end
end end
it 'limits to commands passed ' do
content = "/shrug\n/close"
text, commands = service.execute(content, issue, only: [:shrug])
expect(commands).to be_empty
expect(text).to eq("#{described_class::SHRUG}\n/close")
end
end end
describe '#explain' do describe '#explain' do