Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Jérome Perrin
gitlab-ce
Commits
029b7d2e
Commit
029b7d2e
authored
Aug 13, 2016
by
Douwe Maan
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fixed specs and fixes based on failing specs
parent
b2b1b4a4
Changes
13
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
365 additions
and
428 deletions
+365
-428
app/controllers/projects/issues_controller.rb
app/controllers/projects/issues_controller.rb
+1
-7
app/services/notes/create_service.rb
app/services/notes/create_service.rb
+16
-7
app/services/notes/slash_commands_service.rb
app/services/notes/slash_commands_service.rb
+14
-5
app/services/slash_commands/interpret_service.rb
app/services/slash_commands/interpret_service.rb
+43
-36
lib/gitlab/slash_commands/command_definition.rb
lib/gitlab/slash_commands/command_definition.rb
+2
-9
lib/gitlab/slash_commands/dsl.rb
lib/gitlab/slash_commands/dsl.rb
+1
-4
lib/gitlab/slash_commands/extractor.rb
lib/gitlab/slash_commands/extractor.rb
+9
-3
spec/lib/gitlab/slash_commands/command_definition_spec.rb
spec/lib/gitlab/slash_commands/command_definition_spec.rb
+143
-0
spec/lib/gitlab/slash_commands/dsl_spec.rb
spec/lib/gitlab/slash_commands/dsl_spec.rb
+46
-154
spec/lib/gitlab/slash_commands/extractor_spec.rb
spec/lib/gitlab/slash_commands/extractor_spec.rb
+33
-22
spec/services/notes/create_service_spec.rb
spec/services/notes/create_service_spec.rb
+1
-1
spec/services/notes/slash_commands_service_spec.rb
spec/services/notes/slash_commands_service_spec.rb
+22
-11
spec/services/slash_commands/interpret_service_spec.rb
spec/services/slash_commands/interpret_service_spec.rb
+34
-169
No files found.
app/controllers/projects/issues_controller.rb
View file @
029b7d2e
...
...
@@ -176,12 +176,7 @@ class Projects::IssuesController < Projects::ApplicationController
protected
def
issue
@noteable
=
@issue
||=
begin
@project
.
issues
.
find_by!
(
iid:
params
[
:id
])
rescue
ActiveRecord
::
RecordNotFound
redirect_old
end
@noteable
=
@issue
||=
@project
.
issues
.
find_by
(
iid:
params
[
:id
])
||
redirect_old
end
alias_method
:subscribable_resource
,
:issue
alias_method
:issuable
,
:issue
...
...
@@ -225,7 +220,6 @@ class Projects::IssuesController < Projects::ApplicationController
if
issue
redirect_to
issue_path
(
issue
)
return
else
raise
ActiveRecord
::
RecordNotFound
.
new
end
...
...
app/services/notes/create_service.rb
View file @
029b7d2e
...
...
@@ -15,21 +15,30 @@ module Notes
# **before** we save the note because if the note consists of commands
# only, there is no need be create a note!
slash_commands_service
=
SlashCommandsService
.
new
(
project
,
current_user
)
if
slash_commands_service
.
supported?
(
note
)
content
,
command_params
=
slash_commands_service
.
extract_commands
(
note
)
only_commands
=
content
.
empty?
note
.
note
=
content
end
if
note
.
save
if
!
only_commands
&&
note
.
save
# Finish the harder work in the background
NewNoteWorker
.
perform_in
(
2
.
seconds
,
note
.
id
,
params
)
todo_service
.
new_note
(
note
,
current_user
)
end
if
command_params
&&
command_params
.
any?
slash_commands_service
.
execute
(
command_params
,
note
)
# We must add the error after we call #save because errors are reset
# when #save is called
if
slash_commands_service
.
execute
(
command_params
,
note
)
&&
note
.
note
.
blank?
if
only_commands
note
.
errors
.
add
(
:commands_only
,
'Your commands have been executed!'
)
end
end
note
end
...
...
app/services/notes/slash_commands_service.rb
View file @
029b7d2e
...
...
@@ -5,10 +5,13 @@ module Notes
'MergeRequest'
=>
MergeRequests
::
UpdateService
}
def
supported?
(
note
)
noteable_update_service
(
note
)
&&
can?
(
current_user
,
:"update_
#{
note
.
noteable_type
.
underscore
}
"
,
note
.
noteable
)
end
def
extract_commands
(
note
)
@noteable_update_service
=
UPDATE_SERVICES
[
note
.
noteable_type
]
return
[]
unless
@noteable_update_service
return
[]
unless
can?
(
current_user
,
:"update_
#{
note
.
noteable_type
.
underscore
}
"
,
note
.
noteable
)
return
[
note
.
note
,
{}]
unless
supported?
(
note
)
SlashCommands
::
InterpretService
.
new
(
project
,
current_user
).
execute
(
note
.
note
,
note
.
noteable
)
...
...
@@ -16,9 +19,15 @@ module Notes
def
execute
(
command_params
,
note
)
return
if
command_params
.
empty?
return
unless
supported?
(
note
)
noteable_update_service
(
note
).
new
(
project
,
current_user
,
command_params
).
execute
(
note
.
noteable
)
end
private
@noteable_update_service
.
new
(
project
,
current_user
,
command_params
).
execute
(
note
.
noteable
)
def
noteable_update_service
(
note
)
UPDATE_SERVICES
[
note
.
noteable_type
]
end
end
end
app/services/slash_commands/interpret_service.rb
View file @
029b7d2e
...
...
@@ -2,16 +2,16 @@ module SlashCommands
class
InterpretService
<
BaseService
include
Gitlab
::
SlashCommands
::
Dsl
attr_reader
:
note
able
attr_reader
:
issu
able
# Takes a text and interpret the commands that are extracted from it.
# Returns a hash of changes to be applied to a record.
def
execute
(
content
,
note
able
)
@
noteable
=
note
able
def
execute
(
content
,
issu
able
)
@
issuable
=
issu
able
@updates
=
{}
opts
=
{
noteable:
note
able
,
issuable:
issu
able
,
current_user:
current_user
,
project:
project
}
...
...
@@ -35,23 +35,24 @@ module SlashCommands
end
desc
do
"Close this
#{
note
able
.
to_ability_name
.
humanize
(
capitalize:
false
)
}
"
"Close this
#{
issu
able
.
to_ability_name
.
humanize
(
capitalize:
false
)
}
"
end
condition
do
note
able
.
persisted?
&&
note
able
.
open?
&&
current_user
.
can?
(
:"update_
#{
noteable
.
to_ability_name
}
"
,
note
able
)
issu
able
.
persisted?
&&
issu
able
.
open?
&&
current_user
.
can?
(
:"update_
#{
issuable
.
to_ability_name
}
"
,
issu
able
)
end
command
:close
do
@updates
[
:state_event
]
=
'close'
end
desc
do
"Reopen this
#{
note
able
.
to_ability_name
.
humanize
(
capitalize:
false
)
}
"
"Reopen this
#{
issu
able
.
to_ability_name
.
humanize
(
capitalize:
false
)
}
"
end
condition
do
noteable
.
closed?
&&
current_user
.
can?
(
:"update_
#{
noteable
.
to_ability_name
}
"
,
noteable
)
issuable
.
persisted?
&&
issuable
.
closed?
&&
current_user
.
can?
(
:"update_
#{
issuable
.
to_ability_name
}
"
,
issuable
)
end
command
:reopen
,
:open
do
@updates
[
:state_event
]
=
'reopen'
...
...
@@ -60,8 +61,8 @@ module SlashCommands
desc
'Change title'
params
'<New title>'
condition
do
note
able
.
persisted?
&&
current_user
.
can?
(
:"update_
#{
noteable
.
to_ability_name
}
"
,
note
able
)
issu
able
.
persisted?
&&
current_user
.
can?
(
:"update_
#{
issuable
.
to_ability_name
}
"
,
issu
able
)
end
command
:title
do
|
title_param
|
@updates
[
:title
]
=
title_param
...
...
@@ -70,7 +71,7 @@ module SlashCommands
desc
'Assign'
params
'@user'
condition
do
current_user
.
can?
(
:"admin_
#{
note
able
.
to_ability_name
}
"
,
project
)
current_user
.
can?
(
:"admin_
#{
issu
able
.
to_ability_name
}
"
,
project
)
end
command
:assign
do
|
assignee_param
|
user
=
extract_references
(
assignee_param
,
:user
).
first
...
...
@@ -82,8 +83,9 @@ module SlashCommands
desc
'Remove assignee'
condition
do
noteable
.
assignee_id?
&&
current_user
.
can?
(
:"admin_
#{
noteable
.
to_ability_name
}
"
,
project
)
issuable
.
persisted?
&&
issuable
.
assignee_id?
&&
current_user
.
can?
(
:"admin_
#{
issuable
.
to_ability_name
}
"
,
project
)
end
command
:unassign
,
:remove_assignee
do
@updates
[
:assignee_id
]
=
nil
...
...
@@ -92,7 +94,7 @@ module SlashCommands
desc
'Set milestone'
params
'%"milestone"'
condition
do
current_user
.
can?
(
:"admin_
#{
note
able
.
to_ability_name
}
"
,
project
)
&&
current_user
.
can?
(
:"admin_
#{
issu
able
.
to_ability_name
}
"
,
project
)
&&
project
.
milestones
.
active
.
any?
end
command
:milestone
do
|
milestone_param
|
...
...
@@ -104,8 +106,9 @@ module SlashCommands
desc
'Remove milestone'
condition
do
noteable
.
milestone_id?
&&
current_user
.
can?
(
:"admin_
#{
noteable
.
to_ability_name
}
"
,
project
)
issuable
.
persisted?
&&
issuable
.
milestone_id?
&&
current_user
.
can?
(
:"admin_
#{
issuable
.
to_ability_name
}
"
,
project
)
end
command
:clear_milestone
,
:remove_milestone
do
@updates
[
:milestone_id
]
=
nil
...
...
@@ -114,7 +117,7 @@ module SlashCommands
desc
'Add label(s)'
params
'~label1 ~"label 2"'
condition
do
current_user
.
can?
(
:"admin_
#{
note
able
.
to_ability_name
}
"
,
project
)
&&
current_user
.
can?
(
:"admin_
#{
issu
able
.
to_ability_name
}
"
,
project
)
&&
project
.
labels
.
any?
end
command
:label
,
:labels
do
|
labels_param
|
...
...
@@ -126,8 +129,9 @@ module SlashCommands
desc
'Remove label(s)'
params
'~label1 ~"label 2"'
condition
do
noteable
.
labels
.
any?
&&
current_user
.
can?
(
:"admin_
#{
noteable
.
to_ability_name
}
"
,
project
)
issuable
.
persisted?
&&
issuable
.
labels
.
any?
&&
current_user
.
can?
(
:"admin_
#{
issuable
.
to_ability_name
}
"
,
project
)
end
command
:unlabel
,
:remove_label
,
:remove_labels
do
|
labels_param
|
label_ids
=
find_label_ids
(
labels_param
)
...
...
@@ -137,8 +141,9 @@ module SlashCommands
desc
'Remove all labels'
condition
do
noteable
.
labels
.
any?
&&
current_user
.
can?
(
:"admin_
#{
noteable
.
to_ability_name
}
"
,
project
)
issuable
.
persisted?
&&
issuable
.
labels
.
any?
&&
current_user
.
can?
(
:"admin_
#{
issuable
.
to_ability_name
}
"
,
project
)
end
command
:clear_labels
,
:clear_label
do
@updates
[
:label_ids
]
=
[]
...
...
@@ -146,8 +151,8 @@ module SlashCommands
desc
'Add a todo'
condition
do
note
able
.
persisted?
&&
!
TodoService
.
new
.
todo_exist?
(
note
able
,
current_user
)
issu
able
.
persisted?
&&
!
TodoService
.
new
.
todo_exist?
(
issu
able
,
current_user
)
end
command
:todo
do
@updates
[
:todo_event
]
=
'add'
...
...
@@ -155,7 +160,8 @@ module SlashCommands
desc
'Mark todo as done'
condition
do
TodoService
.
new
.
todo_exist?
(
noteable
,
current_user
)
issuable
.
persisted?
&&
TodoService
.
new
.
todo_exist?
(
issuable
,
current_user
)
end
command
:done
do
@updates
[
:todo_event
]
=
'done'
...
...
@@ -163,8 +169,8 @@ module SlashCommands
desc
'Subscribe'
condition
do
note
able
.
persisted?
&&
!
note
able
.
subscribed?
(
current_user
)
issu
able
.
persisted?
&&
!
issu
able
.
subscribed?
(
current_user
)
end
command
:subscribe
do
@updates
[
:subscription_event
]
=
'subscribe'
...
...
@@ -172,8 +178,8 @@ module SlashCommands
desc
'Unsubscribe'
condition
do
note
able
.
persisted?
&&
note
able
.
subscribed?
(
current_user
)
issu
able
.
persisted?
&&
issu
able
.
subscribed?
(
current_user
)
end
command
:unsubscribe
do
@updates
[
:subscription_event
]
=
'unsubscribe'
...
...
@@ -182,8 +188,8 @@ module SlashCommands
desc
'Set due date'
params
'<in 2 days; this Friday; December 31st>'
condition
do
note
able
.
respond_to?
(
:due_date
)
&&
current_user
.
can?
(
:"update_
#{
noteable
.
to_ability_name
}
"
,
note
able
)
issu
able
.
respond_to?
(
:due_date
)
&&
current_user
.
can?
(
:"update_
#{
issuable
.
to_ability_name
}
"
,
issu
able
)
end
command
:due
,
:due_date
do
|
due_date_param
|
due_date
=
Chronic
.
parse
(
due_date_param
).
try
(
:to_date
)
...
...
@@ -193,9 +199,10 @@ module SlashCommands
desc
'Remove due date'
condition
do
noteable
.
respond_to?
(
:due_date
)
&&
noteable
.
due_date?
&&
current_user
.
can?
(
:"update_
#{
noteable
.
to_ability_name
}
"
,
noteable
)
issuable
.
persisted?
&&
issuable
.
respond_to?
(
:due_date
)
&&
issuable
.
due_date?
&&
current_user
.
can?
(
:"update_
#{
issuable
.
to_ability_name
}
"
,
issuable
)
end
command
:clear_due_date
do
@updates
[
:due_date
]
=
nil
...
...
lib/gitlab/slash_commands/command_definition.rb
View file @
029b7d2e
...
...
@@ -3,8 +3,8 @@ module Gitlab
class
CommandDefinition
attr_accessor
:name
,
:aliases
,
:description
,
:params
,
:condition_block
,
:action_block
def
valid?
name
.
present?
def
initialize
(
name
)
@name
=
name
end
def
all_names
...
...
@@ -22,13 +22,6 @@ module Gitlab
context
.
instance_exec
(
&
condition_block
)
end
def
to_description
(
opts
)
return
description
unless
description
.
respond_to?
(
:call
)
context
=
OpenStruct
.
new
(
opts
)
context
.
instance_exec
(
&
description
)
rescue
''
end
def
execute
(
context
,
opts
,
*
args
)
return
if
noop?
||
!
available?
(
opts
)
...
...
lib/gitlab/slash_commands/dsl.rb
View file @
029b7d2e
...
...
@@ -73,16 +73,13 @@ module Gitlab
def
command
(
*
command_names
,
&
block
)
name
,
*
aliases
=
command_names
definition
=
CommandDefinition
.
new
definition
.
name
=
name
definition
=
CommandDefinition
.
new
(
name
)
definition
.
aliases
=
aliases
definition
.
description
=
@description
||
''
definition
.
params
=
@params
||
[]
definition
.
condition_block
=
@condition_block
definition
.
action_block
=
block
return
unless
definition
.
valid?
self
.
command_definitions
<<
definition
definition
.
all_names
.
each
do
|
name
|
...
...
lib/gitlab/slash_commands/extractor.rb
View file @
029b7d2e
...
...
@@ -29,8 +29,8 @@ module Gitlab
# commands = extractor.extract_commands(msg) #=> [['labels', '~foo ~"bar baz"']]
# msg #=> "hello\nworld"
# ```
def
extract_commands
(
content
,
opts
)
return
[]
unless
content
def
extract_commands
(
content
,
opts
=
{}
)
return
[
content
,
[]
]
unless
content
content
=
content
.
dup
...
...
@@ -107,7 +107,13 @@ module Gitlab
# Command not in a blockquote, blockcode, or HTML tag:
# /close
^
\/
(?<cmd>
#{
Regexp
.
union
(
names
)
}
)(?:$|
\
(?<args>[^
\/\n
]*)$)
^
\/
(?<cmd>
#{
Regexp
.
union
(
names
)
}
)
(?:
[ ]
(?<args>[^
\/\n
]*)
)?
(?:
\n
|$)
)
}mx
end
...
...
spec/lib/gitlab/slash_commands/command_definition_spec.rb
0 → 100644
View file @
029b7d2e
require
'spec_helper'
describe
Gitlab
::
SlashCommands
::
CommandDefinition
do
subject
{
described_class
.
new
(
:command
)
}
describe
"#all_names"
do
context
"when the command has aliases"
do
before
do
subject
.
aliases
=
[
:alias1
,
:alias2
]
end
it
"returns an array with the name and aliases"
do
expect
(
subject
.
all_names
).
to
eq
([
:command
,
:alias1
,
:alias2
])
end
end
context
"when the command doesn't have aliases"
do
it
"returns an array with the name"
do
expect
(
subject
.
all_names
).
to
eq
([
:command
])
end
end
end
describe
"#noop?"
do
context
"when the command has an action block"
do
before
do
subject
.
action_block
=
->
{
}
end
it
"returns false"
do
expect
(
subject
.
noop?
).
to
be
false
end
end
context
"when the command doesn't have an action block"
do
it
"returns true"
do
expect
(
subject
.
noop?
).
to
be
true
end
end
end
describe
"#available?"
do
let
(
:opts
)
{
{
go:
false
}
}
context
"when the command has a condition block"
do
before
do
subject
.
condition_block
=
->
{
go
}
end
context
"when the condition block returns true"
do
before
do
opts
[
:go
]
=
true
end
it
"returns true"
do
expect
(
subject
.
available?
(
opts
)).
to
be
true
end
end
context
"when the condition block returns false"
do
it
"returns false"
do
expect
(
subject
.
available?
(
opts
)).
to
be
false
end
end
end
context
"when the command doesn't have a condition block"
do
it
"returns true"
do
expect
(
subject
.
available?
(
opts
)).
to
be
true
end
end
end
describe
"#execute"
do
let
(
:context
)
{
OpenStruct
.
new
(
run:
false
)
}
context
"when the command is a noop"
do
it
"doesn't execute the command"
do
expect
(
context
).
not_to
receive
(
:instance_exec
)
subject
.
execute
(
context
,
{})
expect
(
context
.
run
).
to
be
false
end
end
context
"when the command is not a noop"
do
before
do
subject
.
action_block
=
->
{
self
.
run
=
true
}
end
context
"when the command is not available"
do
before
do
subject
.
condition_block
=
->
{
false
}
end
it
"doesn't execute the command"
do
subject
.
execute
(
context
,
{})
expect
(
context
.
run
).
to
be
false
end
end
context
"when the command is available"
do
context
"when the command has an exact number of arguments"
do
before
do
subject
.
action_block
=
->
(
arg
)
{
self
.
run
=
arg
}
end
context
"when the command is provided a wrong number of arguments"
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
subject
.
execute
(
context
,
{},
true
)
expect
(
context
.
run
).
to
be
true
end
end
end
context
"when the command has a variable number of arguments"
do
before
do
subject
.
action_block
=
->
(
*
args
)
{
self
.
run
=
args
.
first
}
end
context
"when the command is provided any number of arguments"
do
it
"executes the command"
do
subject
.
execute
(
context
,
{},
true
,
true
)
expect
(
context
.
run
).
to
be
true
end
end
end
end
end
end
end
spec/lib/gitlab/slash_commands/dsl_spec.rb
View file @
029b7d2e
...
...
@@ -10,9 +10,9 @@ describe Gitlab::SlashCommands::Dsl do
"Hello World!"
end
desc
'A command returning a value'
desc
{
"A command with
#{
something
}
"
}
command
:returning
do
return
42
42
end
params
'The first argument'
...
...
@@ -28,7 +28,7 @@ describe Gitlab::SlashCommands::Dsl do
[
arg1
,
arg2
]
end
command
:cc
,
noop:
true
command
:cc
condition
do
project
==
'foo'
...
...
@@ -49,182 +49,74 @@ describe Gitlab::SlashCommands::Dsl do
{
name: :no_args
,
aliases:
[
:none
],
description:
'A command with no args'
,
params:
[],
condition_block:
nil
,
action_block:
a_kind_of
(
Proc
),
opts:
{}
condition_block:
nil
,
action_block:
a_kind_of
(
Proc
)
},
{
name: :returning
,
aliases:
[],
description:
'A command returning a value'
,
params:
[],
condition_block:
nil
,
action_block:
a_kind_of
(
Proc
),
opts:
{}
condition_block:
nil
,
action_block:
a_kind_of
(
Proc
)
},
{
name: :one_arg
,
aliases:
[
:once
,
:first
],
description:
''
,
params:
[
'The first argument'
],
condition_block:
nil
,
action_block:
a_kind_of
(
Proc
),
opts:
{}
condition_block:
nil
,
action_block:
a_kind_of
(
Proc
)
},
{
name: :two_args
,
aliases:
[],
description:
''
,
params:
[
'The first argument'
,
'The second argument'
],
condition_block:
nil
,
action_block:
a_kind_of
(
Proc
),
opts:
{}
condition_block:
nil
,
action_block:
a_kind_of
(
Proc
)
},
{
name: :cc
,
aliases:
[],
description:
''
,
params:
[],
condition_block:
nil
,
action_block:
nil
,
opts:
{
noop:
true
}
condition_block:
nil
,
action_block:
nil
},
{
name: :wildcard
,
aliases:
[],
description:
''
,
params:
[],
condition_block:
nil
,
action_block:
a_kind_of
(
Proc
),
opts:
{}
condition_block:
nil
,
action_block:
a_kind_of
(
Proc
)
}
]
end
it
'returns an array with commands definitions'
do
expect
(
DummyClass
.
command_definitions
).
to
match_array
base_expected
end
context
'with options passed'
do
context
'when condition is met'
do
let
(
:expected
)
do
base_expected
<<
{
name: :cond_action
,
aliases:
[],
description:
''
,
params:
[],
condition_block:
a_kind_of
(
Proc
),
action_block:
a_kind_of
(
Proc
),
opts:
{}
}
end
it
'returns an array with commands definitions'
do
expect
(
DummyClass
.
command_definitions
(
project:
'foo'
)).
to
match_array
expected
end
end
context
'when condition is not met'
do
it
'returns an array with commands definitions without actions that did not met conditions'
do
expect
(
DummyClass
.
command_definitions
(
project:
'bar'
)).
to
match_array
base_expected
end
end
context
'when description can be generated dynamically'
do
it
'returns an array with commands definitions with dynamic descriptions'
do
base_expected
[
3
][
:description
]
=
'A dynamic description for MERGE REQUEST'
expect
(
DummyClass
.
command_definitions
(
noteable:
'merge request'
)).
to
match_array
base_expected
end
end
end
end
describe
'.command_names'
do
let
(
:base_expected
)
do
[
:no_args
,
:none
,
:returning
,
:one_arg
,
:once
,
:first
,
:two_args
,
:wildcard
]
end
it
'returns an array with commands definitions'
do
expect
(
DummyClass
.
command_names
).
to
eq
base_expected
end
context
'with options passed'
do
context
'when condition is met'
do
let
(
:expected
)
{
base_expected
<<
:cond_action
}
it
'returns an array with commands definitions'
do
expect
(
DummyClass
.
command_names
(
project:
'foo'
)).
to
match_array
expected
end
end
context
'when condition is not met'
do
it
'returns an array with commands definitions without action that did not met conditions'
do
expect
(
DummyClass
.
command_names
(
project:
'bar'
)).
to
match_array
base_expected
end
end
end
end
let
(
:dummy
)
{
DummyClass
.
new
(
nil
)
}
describe
'#execute_command'
do
describe
'command with no args'
do
context
'called with no args'
do
it
'succeeds'
do
expect
(
dummy
.
execute_command
(
:no_args
)).
to
eq
'Hello World!'
end
end
end
describe
'command with an explicit return'
do
context
'called with no args'
do
it
'succeeds'
do
expect
{
dummy
.
execute_command
(
:returning
)
}.
to
raise_error
(
LocalJumpError
)
end
end
end
describe
'command with one arg'
do
context
'called with one arg'
do
it
'succeeds'
do
expect
(
dummy
.
execute_command
(
:one_arg
,
42
)).
to
eq
42
end
end
end
describe
'command with two args'
do
context
'called with two args'
do
it
'succeeds'
do
expect
(
dummy
.
execute_command
(
:two_args
,
42
,
'foo'
)).
to
eq
[
42
,
'foo'
]
end
end
end
describe
'noop command'
do
it
'returns nil'
do
expect
(
dummy
.
execute_command
(
:cc
)).
to
be_nil
end
end
describe
'command with condition'
do
context
'when condition is not met'
do
it
'returns nil'
do
expect
(
dummy
.
execute_command
(
:cond_action
)).
to
be_nil
end
end
context
'when condition is met'
do
let
(
:dummy
)
{
DummyClass
.
new
(
'foo'
)
}
it
'succeeds'
do
expect
(
dummy
.
execute_command
(
:cond_action
,
42
)).
to
eq
42
end
end
end
describe
'command with wildcard'
do
context
'called with no args'
do
it
'succeeds'
do
expect
(
dummy
.
execute_command
(
:wildcard
)).
to
eq
[]
end
end
context
'called with one arg'
do
it
'succeeds'
do
expect
(
dummy
.
execute_command
(
:wildcard
,
42
)).
to
eq
[
42
]
end
end
context
'called with two args'
do
it
'succeeds'
do
expect
(
dummy
.
execute_command
(
:wildcard
,
42
,
'foo'
)).
to
eq
[
42
,
'foo'
]
end
end
no_args_def
,
returning_def
,
one_arg_def
,
two_args_def
,
cc_def
,
cond_action_def
,
wildcard_def
=
DummyClass
.
command_definitions
expect
(
no_args_def
.
name
).
to
eq
(
:no_args
)
expect
(
no_args_def
.
aliases
).
to
eq
([
:none
])
expect
(
no_args_def
.
description
).
to
eq
(
'A command with no args'
)
expect
(
no_args_def
.
params
).
to
eq
([])
expect
(
no_args_def
.
condition_block
).
to
be_nil
expect
(
no_args_def
.
action_block
).
to
be_a_kind_of
(
Proc
)
expect
(
returning_def
.
name
).
to
eq
(
:returning
)
expect
(
returning_def
.
aliases
).
to
eq
([])
expect
(
returning_def
.
description
).
to
be_a_kind_of
(
Proc
)
expect
(
returning_def
.
to_h
(
something:
"a block description"
)[
:description
]).
to
eq
(
'A command with a block description'
)
expect
(
returning_def
.
params
).
to
eq
([])
expect
(
returning_def
.
condition_block
).
to
be_nil
expect
(
returning_def
.
action_block
).
to
be_a_kind_of
(
Proc
)
expect
(
one_arg_def
.
name
).
to
eq
(
:one_arg
)
expect
(
one_arg_def
.
aliases
).
to
eq
([
:once
,
:first
])
expect
(
one_arg_def
.
description
).
to
eq
(
''
)
expect
(
one_arg_def
.
params
).
to
eq
([
'The first argument'
])
expect
(
one_arg_def
.
condition_block
).
to
be_nil
expect
(
one_arg_def
.
action_block
).
to
be_a_kind_of
(
Proc
)
expect
(
cc_def
.
name
).
to
eq
(
:cc
)
expect
(
cc_def
.
aliases
).
to
eq
([])
expect
(
cc_def
.
description
).
to
eq
(
''
)
expect
(
cc_def
.
params
).
to
eq
([])
expect
(
cc_def
.
condition_block
).
to
be_nil
expect
(
cc_def
.
action_block
).
to
be_nil
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
spec/lib/gitlab/slash_commands/extractor_spec.rb
View file @
029b7d2e
require
'spec_helper'
describe
Gitlab
::
SlashCommands
::
Extractor
do
let
(
:extractor
)
{
described_class
.
new
([
:open
,
:assign
,
:labels
,
:power
])
}
let
(
:definitions
)
do
Class
.
new
do
include
Gitlab
::
SlashCommands
::
Dsl
command
(
:reopen
,
:open
)
{
}
command
(
:assign
)
{
}
command
(
:labels
)
{
}
command
(
:power
)
{
}
end
.
command_definitions
end
let
(
:extractor
)
{
described_class
.
new
(
definitions
)
}
shared_examples
'command with no argument'
do
it
'extracts command'
do
commands
=
extractor
.
extract_commands
(
original_msg
)
msg
,
commands
=
extractor
.
extract_commands
(
original_msg
)
expect
(
commands
).
to
eq
[[
'open'
]]
expect
(
original_
msg
).
to
eq
final_msg
expect
(
msg
).
to
eq
final_msg
end
end
shared_examples
'command with a single argument'
do
it
'extracts command'
do
commands
=
extractor
.
extract_commands
(
original_msg
)
msg
,
commands
=
extractor
.
extract_commands
(
original_msg
)
expect
(
commands
).
to
eq
[[
'assign'
,
'@joe'
]]
expect
(
original_
msg
).
to
eq
final_msg
expect
(
msg
).
to
eq
final_msg
end
end
shared_examples
'command with multiple arguments'
do
it
'extracts command'
do
commands
=
extractor
.
extract_commands
(
original_msg
)
msg
,
commands
=
extractor
.
extract_commands
(
original_msg
)
expect
(
commands
).
to
eq
[[
'labels'
,
'~foo ~"bar baz" label'
]]
expect
(
original_
msg
).
to
eq
final_msg
expect
(
msg
).
to
eq
final_msg
end
end
...
...
@@ -49,7 +60,7 @@ describe Gitlab::SlashCommands::Extractor do
context
'in the middle of a line'
do
it
'does not extract command'
do
msg
=
"hello
\n
world /open"
commands
=
extractor
.
extract_commands
(
msg
)
msg
,
commands
=
extractor
.
extract_commands
(
msg
)
expect
(
commands
).
to
be_empty
expect
(
msg
).
to
eq
"hello
\n
world /open"
...
...
@@ -59,7 +70,7 @@ describe Gitlab::SlashCommands::Extractor do
context
'at the end of content'
do
it_behaves_like
'command with no argument'
do
let
(
:original_msg
)
{
"hello
\n
/open"
}
let
(
:final_msg
)
{
"hello
\n
"
}
let
(
:final_msg
)
{
"hello"
}
end
end
end
...
...
@@ -82,7 +93,7 @@ describe Gitlab::SlashCommands::Extractor do
context
'in the middle of a line'
do
it
'does not extract command'
do
msg
=
"hello
\n
world /assign @joe"
commands
=
extractor
.
extract_commands
(
msg
)
msg
,
commands
=
extractor
.
extract_commands
(
msg
)
expect
(
commands
).
to
be_empty
expect
(
msg
).
to
eq
"hello
\n
world /assign @joe"
...
...
@@ -92,14 +103,14 @@ describe Gitlab::SlashCommands::Extractor do
context
'at the end of content'
do
it_behaves_like
'command with a single argument'
do
let
(
:original_msg
)
{
"hello
\n
/assign @joe"
}
let
(
:final_msg
)
{
"hello
\n
"
}
let
(
:final_msg
)
{
"hello"
}
end
end
context
'when argument is not separated with a space'
do
it
'does not extract command'
do
msg
=
"hello
\n
/assign@joe
\n
world"
commands
=
extractor
.
extract_commands
(
msg
)
msg
,
commands
=
extractor
.
extract_commands
(
msg
)
expect
(
commands
).
to
be_empty
expect
(
msg
).
to
eq
"hello
\n
/assign@joe
\n
world"
...
...
@@ -125,7 +136,7 @@ describe Gitlab::SlashCommands::Extractor do
context
'in the middle of a line'
do
it
'does not extract command'
do
msg
=
%(hello\nworld /labels ~foo ~"bar baz" label)
commands
=
extractor
.
extract_commands
(
msg
)
msg
,
commands
=
extractor
.
extract_commands
(
msg
)
expect
(
commands
).
to
be_empty
expect
(
msg
).
to
eq
%(hello\nworld /labels ~foo ~"bar baz" label)
...
...
@@ -135,14 +146,14 @@ describe Gitlab::SlashCommands::Extractor do
context
'at the end of content'
do
it_behaves_like
'command with multiple arguments'
do
let
(
:original_msg
)
{
%(hello\n/labels ~foo ~"bar baz" label)
}
let
(
:final_msg
)
{
"hello
\n
"
}
let
(
:final_msg
)
{
"hello"
}
end
end
context
'when argument is not separated with a space'
do
it
'does not extract command'
do
msg
=
%(hello\n/labels~foo ~"bar baz" label\nworld)
commands
=
extractor
.
extract_commands
(
msg
)
msg
,
commands
=
extractor
.
extract_commands
(
msg
)
expect
(
commands
).
to
be_empty
expect
(
msg
).
to
eq
%(hello\n/labels~foo ~"bar baz" label\nworld)
...
...
@@ -152,7 +163,7 @@ describe Gitlab::SlashCommands::Extractor do
it
'extracts command with multiple arguments and various prefixes'
do
msg
=
%(hello\n/power @user.name %9.10 ~"bar baz.2"\nworld)
commands
=
extractor
.
extract_commands
(
msg
)
msg
,
commands
=
extractor
.
extract_commands
(
msg
)
expect
(
commands
).
to
eq
[[
'power'
,
'@user.name %9.10 ~"bar baz.2"'
]]
expect
(
msg
).
to
eq
"hello
\n
world"
...
...
@@ -160,15 +171,15 @@ describe Gitlab::SlashCommands::Extractor do
it
'extracts multiple commands'
do
msg
=
%(hello\n/power @user.name %9.10 ~"bar baz.2" label\nworld\n/open)
commands
=
extractor
.
extract_commands
(
msg
)
msg
,
commands
=
extractor
.
extract_commands
(
msg
)
expect
(
commands
).
to
eq
[[
'power'
,
'@user.name %9.10 ~"bar baz.2" label'
],
[
'open'
]]
expect
(
msg
).
to
eq
"hello
\n
world
\n
"
expect
(
msg
).
to
eq
"hello
\n
world"
end
it
'does not alter original content if no command is found'
do
msg
=
'Fixes #123'
commands
=
extractor
.
extract_commands
(
msg
)
msg
,
commands
=
extractor
.
extract_commands
(
msg
)
expect
(
commands
).
to
be_empty
expect
(
msg
).
to
eq
'Fixes #123'
...
...
@@ -177,7 +188,7 @@ describe Gitlab::SlashCommands::Extractor do
it
'does not extract commands inside a blockcode'
do
msg
=
"Hello
\r\n
```
\r\n
This is some text
\r\n
/close
\r\n
/assign @user
\r\n
```
\r\n\r\n
World"
expected
=
msg
.
delete
(
"
\r
"
)
commands
=
extractor
.
extract_commands
(
msg
)
msg
,
commands
=
extractor
.
extract_commands
(
msg
)
expect
(
commands
).
to
be_empty
expect
(
msg
).
to
eq
expected
...
...
@@ -186,7 +197,7 @@ describe Gitlab::SlashCommands::Extractor do
it
'does not extract commands inside a blockquote'
do
msg
=
"Hello
\r\n
>>>
\r\n
This is some text
\r\n
/close
\r\n
/assign @user
\r\n
>>>
\r\n\r\n
World"
expected
=
msg
.
delete
(
"
\r
"
)
commands
=
extractor
.
extract_commands
(
msg
)
msg
,
commands
=
extractor
.
extract_commands
(
msg
)
expect
(
commands
).
to
be_empty
expect
(
msg
).
to
eq
expected
...
...
@@ -195,7 +206,7 @@ describe Gitlab::SlashCommands::Extractor do
it
'does not extract commands inside a HTML tag'
do
msg
=
"Hello
\r\n
<div>
\r\n
This is some text
\r\n
/close
\r\n
/assign @user
\r\n
</div>
\r\n\r\n
World"
expected
=
msg
.
delete
(
"
\r
"
)
commands
=
extractor
.
extract_commands
(
msg
)
msg
,
commands
=
extractor
.
extract_commands
(
msg
)
expect
(
commands
).
to
be_empty
expect
(
msg
).
to
eq
expected
...
...
spec/services/notes/create_service_spec.rb
View file @
029b7d2e
...
...
@@ -56,7 +56,7 @@ describe Notes::CreateService, services: true do
it
"creates regular note if emoji name is invalid"
do
opts
=
{
note:
':smile: moretext:
'
,
note:
':smile: moretext:'
,
noteable_type:
'Issue'
,
noteable_id:
issue
.
id
}
...
...
spec/services/notes/slash_commands_service_spec.rb
View file @
029b7d2e
...
...
@@ -12,7 +12,6 @@ describe Notes::SlashCommandsService, services: true do
before
do
note
.
note
=
note_text
described_class
.
new
(
project
,
master
).
execute
(
note
)
end
describe
'note with only command'
do
...
...
@@ -20,7 +19,10 @@ describe Notes::SlashCommandsService, services: true do
let
(
:note_text
)
{
%(/close\n/assign @#{assignee.username}")
}
it
'saves the note and does not alter the note text'
do
expect
(
note
.
note
).
to
eq
note_text
content
,
command_params
=
service
.
extract_commands
(
note
)
expect
(
content
).
to
eq
note_text
expect
(
command_params
).
to
be_empty
end
end
end
...
...
@@ -30,7 +32,10 @@ describe Notes::SlashCommandsService, services: true do
let
(
:note_text
)
{
%(HELLO\n/close\n/assign @#{assignee.username}\nWORLD)
}
it
'saves the note and does not alter the note text'
do
expect
(
note
.
note
).
to
eq
note_text
content
,
command_params
=
service
.
extract_commands
(
note
)
expect
(
content
).
to
eq
note_text
expect
(
command_params
).
to
be_empty
end
end
end
...
...
@@ -53,9 +58,10 @@ describe Notes::SlashCommandsService, services: true do
end
it
'closes noteable, sets labels, assigns, and sets milestone to noteable, and leave no note'
do
described_class
.
new
(
project
,
master
).
execute
(
note
)
content
,
command_params
=
service
.
extract_commands
(
note
)
service
.
execute
(
command_params
,
note
)
expect
(
note
.
note
).
to
eq
''
expect
(
content
).
to
eq
''
expect
(
note
.
noteable
).
to
be_closed
expect
(
note
.
noteable
.
labels
).
to
match_array
(
labels
)
expect
(
note
.
noteable
.
assignee
).
to
eq
(
assignee
)
...
...
@@ -71,9 +77,10 @@ describe Notes::SlashCommandsService, services: true do
let
(
:note_text
)
{
'/open'
}
it
'opens the noteable, and leave no note'
do
described_class
.
new
(
project
,
master
).
execute
(
note
)
content
,
command_params
=
service
.
extract_commands
(
note
)
service
.
execute
(
command_params
,
note
)
expect
(
note
.
note
).
to
eq
''
expect
(
content
).
to
eq
''
expect
(
note
.
noteable
).
to
be_open
end
end
...
...
@@ -86,9 +93,10 @@ describe Notes::SlashCommandsService, services: true do
end
it
'closes noteable, sets labels, assigns, and sets milestone to noteable'
do
described_class
.
new
(
project
,
master
).
execute
(
note
)
content
,
command_params
=
service
.
extract_commands
(
note
)
service
.
execute
(
command_params
,
note
)
expect
(
note
.
note
).
to
eq
"HELLO
\n
WORLD"
expect
(
content
).
to
eq
"HELLO
\n
WORLD"
expect
(
note
.
noteable
).
to
be_closed
expect
(
note
.
noteable
.
labels
).
to
match_array
(
labels
)
expect
(
note
.
noteable
.
assignee
).
to
eq
(
assignee
)
...
...
@@ -104,9 +112,10 @@ describe Notes::SlashCommandsService, services: true do
let
(
:note_text
)
{
"HELLO
\n
/open
\n
WORLD"
}
it
'opens the noteable'
do
described_class
.
new
(
project
,
master
).
execute
(
note
)
content
,
command_params
=
service
.
extract_commands
(
note
)
service
.
execute
(
command_params
,
note
)
expect
(
note
.
note
).
to
eq
"HELLO
\n
WORLD"
expect
(
content
).
to
eq
"HELLO
\n
WORLD"
expect
(
note
.
noteable
).
to
be_open
end
end
...
...
@@ -114,6 +123,8 @@ describe Notes::SlashCommandsService, services: true do
end
describe
'#execute'
do
let
(
:service
)
{
described_class
.
new
(
project
,
master
)
}
it_behaves_like
'note on noteable that supports slash commands'
do
let
(
:note
)
{
build
(
:note_on_issue
,
project:
project
)
}
end
...
...
spec/services/slash_commands/interpret_service_spec.rb
View file @
029b7d2e
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment