Fix behavior around commands with optional arguments
This commit is contained in:
parent
6f2f2a6baa
commit
2703330a19
5 changed files with 67 additions and 46 deletions
|
@ -18,11 +18,11 @@ module SlashCommands
|
||||||
|
|
||||||
content, commands = extractor.extract_commands(content, opts)
|
content, commands = extractor.extract_commands(content, opts)
|
||||||
|
|
||||||
commands.each do |name, args|
|
commands.each do |name, arg|
|
||||||
definition = self.class.command_definitions_by_name[name.to_sym]
|
definition = self.class.command_definitions_by_name[name.to_sym]
|
||||||
next unless definition
|
next unless definition
|
||||||
|
|
||||||
definition.execute(self, opts, args)
|
definition.execute(self, opts, arg)
|
||||||
end
|
end
|
||||||
|
|
||||||
[content, @updates]
|
[content, @updates]
|
||||||
|
|
|
@ -28,13 +28,14 @@ module Gitlab
|
||||||
context.instance_exec(&condition_block)
|
context.instance_exec(&condition_block)
|
||||||
end
|
end
|
||||||
|
|
||||||
def execute(context, opts, args)
|
def execute(context, opts, arg)
|
||||||
return if noop? || !available?(opts)
|
return if noop? || !available?(opts)
|
||||||
|
|
||||||
block_arity = action_block.arity
|
if arg.present?
|
||||||
return unless (args.present? && block_arity == 1) || (args.blank? && block_arity <= 0)
|
context.instance_exec(arg, &action_block)
|
||||||
|
elsif action_block.arity == 0
|
||||||
context.instance_exec(args, &action_block)
|
context.instance_exec(&action_block)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_h(opts)
|
def to_h(opts)
|
||||||
|
|
|
@ -39,7 +39,7 @@ module Gitlab
|
||||||
content.delete!("\r")
|
content.delete!("\r")
|
||||||
content.gsub!(commands_regex(opts)) do
|
content.gsub!(commands_regex(opts)) do
|
||||||
if $~[:cmd]
|
if $~[:cmd]
|
||||||
commands << [$~[:cmd], $~[:args]].reject(&:blank?)
|
commands << [$~[:cmd], $~[:arg]].reject(&:blank?)
|
||||||
''
|
''
|
||||||
else
|
else
|
||||||
$~[0]
|
$~[0]
|
||||||
|
@ -50,13 +50,14 @@ module Gitlab
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
# Builds a regular expression to match known commands.
|
# Builds a regular expression to match known commands.
|
||||||
# First match group captures the command name and
|
# First match group captures the command name and
|
||||||
# second match group captures its arguments.
|
# second match group captures its arguments.
|
||||||
#
|
#
|
||||||
# It looks something like:
|
# It looks something like:
|
||||||
#
|
#
|
||||||
# /^\/(?<cmd>close|reopen|...)(?:( |$))(?<args>[^\/\n]*)(?:\n|$)/
|
# /^\/(?<cmd>close|reopen|...)(?:( |$))(?<arg>[^\/\n]*)(?:\n|$)/
|
||||||
def commands_regex(opts)
|
def commands_regex(opts)
|
||||||
names = command_names(opts).map(&:to_s)
|
names = command_names(opts).map(&:to_s)
|
||||||
|
|
||||||
|
@ -64,7 +65,7 @@ module Gitlab
|
||||||
(?<code>
|
(?<code>
|
||||||
# Code blocks:
|
# Code blocks:
|
||||||
# ```
|
# ```
|
||||||
# Anything, including `/cmd args` which are ignored by this filter
|
# Anything, including `/cmd arg` which are ignored by this filter
|
||||||
# ```
|
# ```
|
||||||
|
|
||||||
^```
|
^```
|
||||||
|
@ -75,7 +76,7 @@ module Gitlab
|
||||||
(?<html>
|
(?<html>
|
||||||
# HTML block:
|
# HTML block:
|
||||||
# <tag>
|
# <tag>
|
||||||
# Anything, including `/cmd args` which are ignored by this filter
|
# Anything, including `/cmd arg` which are ignored by this filter
|
||||||
# </tag>
|
# </tag>
|
||||||
|
|
||||||
^<[^>]+?>\n
|
^<[^>]+?>\n
|
||||||
|
@ -86,7 +87,7 @@ module Gitlab
|
||||||
(?<html>
|
(?<html>
|
||||||
# Quote block:
|
# Quote block:
|
||||||
# >>>
|
# >>>
|
||||||
# Anything, including `/cmd args` which are ignored by this filter
|
# Anything, including `/cmd arg` which are ignored by this filter
|
||||||
# >>>
|
# >>>
|
||||||
|
|
||||||
^>>>
|
^>>>
|
||||||
|
@ -102,7 +103,7 @@ module Gitlab
|
||||||
(?<cmd>#{Regexp.union(names)})
|
(?<cmd>#{Regexp.union(names)})
|
||||||
(?:
|
(?:
|
||||||
[ ]
|
[ ]
|
||||||
(?<args>[^\/\n]*)
|
(?<arg>[^\/\n]*)
|
||||||
)?
|
)?
|
||||||
(?:\n|$)
|
(?:\n|$)
|
||||||
)
|
)
|
||||||
|
|
|
@ -24,7 +24,7 @@ describe Gitlab::SlashCommands::CommandDefinition do
|
||||||
describe "#noop?" do
|
describe "#noop?" do
|
||||||
context "when the command has an action block" do
|
context "when the command has an action block" do
|
||||||
before do
|
before do
|
||||||
subject.action_block = -> { }
|
subject.action_block = proc { }
|
||||||
end
|
end
|
||||||
|
|
||||||
it "returns false" do
|
it "returns false" do
|
||||||
|
@ -44,7 +44,7 @@ describe Gitlab::SlashCommands::CommandDefinition do
|
||||||
|
|
||||||
context "when the command has a condition block" do
|
context "when the command has a condition block" do
|
||||||
before do
|
before do
|
||||||
subject.condition_block = -> { go }
|
subject.condition_block = proc { go }
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when the condition block returns true" do
|
context "when the condition block returns true" do
|
||||||
|
@ -78,7 +78,7 @@ describe Gitlab::SlashCommands::CommandDefinition do
|
||||||
it "doesn't execute the command" do
|
it "doesn't execute the command" do
|
||||||
expect(context).not_to receive(:instance_exec)
|
expect(context).not_to receive(:instance_exec)
|
||||||
|
|
||||||
subject.execute(context, {})
|
subject.execute(context, {}, nil)
|
||||||
|
|
||||||
expect(context.run).to be false
|
expect(context.run).to be false
|
||||||
end
|
end
|
||||||
|
@ -86,52 +86,82 @@ describe Gitlab::SlashCommands::CommandDefinition do
|
||||||
|
|
||||||
context "when the command is not a noop" do
|
context "when the command is not a noop" do
|
||||||
before do
|
before do
|
||||||
subject.action_block = -> { self.run = true }
|
subject.action_block = proc { self.run = true }
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when the command is not available" do
|
context "when the command is not available" do
|
||||||
before do
|
before do
|
||||||
subject.condition_block = -> { false }
|
subject.condition_block = proc { false }
|
||||||
end
|
end
|
||||||
|
|
||||||
it "doesn't execute the command" do
|
it "doesn't execute the command" do
|
||||||
subject.execute(context, {})
|
subject.execute(context, {}, nil)
|
||||||
|
|
||||||
expect(context.run).to be false
|
expect(context.run).to be false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when the command is available" do
|
context "when the command is available" do
|
||||||
context "when the command has an exact number of arguments" do
|
context "when the commnd has no arguments" do
|
||||||
before do
|
before do
|
||||||
subject.action_block = ->(arg) { self.run = arg }
|
subject.action_block = proc { self.run = true }
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when the command is provided a wrong number of arguments" do
|
context "when the command is provided an argument" do
|
||||||
it "doesn't execute the command" do
|
|
||||||
subject.execute(context, {}, true, true)
|
|
||||||
|
|
||||||
expect(context.run).to be false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "when the command is provided the right number of arguments" do
|
|
||||||
it "executes the command" do
|
it "executes the command" do
|
||||||
subject.execute(context, {}, true)
|
subject.execute(context, {}, true)
|
||||||
|
|
||||||
expect(context.run).to be true
|
expect(context.run).to be true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "when the command is not provided an argument" do
|
||||||
|
it "executes the command" do
|
||||||
|
subject.execute(context, {}, nil)
|
||||||
|
|
||||||
|
expect(context.run).to be true
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when the command has a variable number of arguments" do
|
context "when the command has 1 required argument" do
|
||||||
before do
|
before do
|
||||||
subject.action_block = ->(*args) { self.run = args.first }
|
subject.action_block = ->(arg) { self.run = arg }
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when the command is provided any number of arguments" do
|
context "when the command is provided an argument" do
|
||||||
it "executes the command" do
|
it "executes the command" do
|
||||||
subject.execute(context, {}, true, true)
|
subject.execute(context, {}, true)
|
||||||
|
|
||||||
|
expect(context.run).to be true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when the command is not provided an argument" do
|
||||||
|
it "doesn't execute the command" do
|
||||||
|
subject.execute(context, {}, nil)
|
||||||
|
|
||||||
|
expect(context.run).to be false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when the command has 1 optional argument" do
|
||||||
|
before do
|
||||||
|
subject.action_block = proc { |arg = nil| self.run = arg || true }
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when the command is provided an argument" do
|
||||||
|
it "executes the command" do
|
||||||
|
subject.execute(context, {}, true)
|
||||||
|
|
||||||
|
expect(context.run).to be true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when the command is not provided an argument" do
|
||||||
|
it "executes the command" do
|
||||||
|
subject.execute(context, {}, nil)
|
||||||
|
|
||||||
expect(context.run).to be true
|
expect(context.run).to be true
|
||||||
end
|
end
|
||||||
|
|
|
@ -31,16 +31,12 @@ describe Gitlab::SlashCommands::Dsl do
|
||||||
command :cond_action do |arg|
|
command :cond_action do |arg|
|
||||||
arg
|
arg
|
||||||
end
|
end
|
||||||
|
|
||||||
command :wildcard do |*args|
|
|
||||||
args
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '.command_definitions' do
|
describe '.command_definitions' do
|
||||||
it 'returns an array with commands definitions' do
|
it 'returns an array with commands definitions' do
|
||||||
no_args_def, one_arg_def, two_args_def, cc_def, cond_action_def, wildcard_def = DummyClass.command_definitions
|
no_args_def, one_arg_def, two_args_def, cc_def, cond_action_def = DummyClass.command_definitions
|
||||||
|
|
||||||
expect(no_args_def.name).to eq(:no_args)
|
expect(no_args_def.name).to eq(:no_args)
|
||||||
expect(no_args_def.aliases).to eq([:none])
|
expect(no_args_def.aliases).to eq([:none])
|
||||||
|
@ -76,13 +72,6 @@ describe Gitlab::SlashCommands::Dsl do
|
||||||
expect(cond_action_def.params).to eq([])
|
expect(cond_action_def.params).to eq([])
|
||||||
expect(cond_action_def.condition_block).to be_a_kind_of(Proc)
|
expect(cond_action_def.condition_block).to be_a_kind_of(Proc)
|
||||||
expect(cond_action_def.action_block).to be_a_kind_of(Proc)
|
expect(cond_action_def.action_block).to be_a_kind_of(Proc)
|
||||||
|
|
||||||
expect(wildcard_def.name).to eq(:wildcard)
|
|
||||||
expect(wildcard_def.aliases).to eq([])
|
|
||||||
expect(wildcard_def.description).to eq('')
|
|
||||||
expect(wildcard_def.params).to eq([])
|
|
||||||
expect(wildcard_def.condition_block).to be_nil
|
|
||||||
expect(wildcard_def.action_block).to be_a_kind_of(Proc)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue