Commit 95838fe4 authored by Mayra Cabrera's avatar Mayra Cabrera

Merge branch '56100-make-quick-action-commands-applied-banner-more-useful' into 'master'

Resolve "Make quick action "commands applied" banner more useful"

Closes #56100

See merge request gitlab-org/gitlab-ce!26672
parents 8b9ad9c6 c96e1257
...@@ -137,6 +137,10 @@ class Label < ApplicationRecord ...@@ -137,6 +137,10 @@ class Label < ApplicationRecord
where(id: ids) where(id: ids)
end end
def self.on_project_board?(project_id, label_id)
on_project_boards(project_id).where(id: label_id).exists?
end
def open_issues_count(user = nil) def open_issues_count(user = nil)
issues_count(user, state: 'opened') issues_count(user, state: 'opened')
end end
......
...@@ -21,7 +21,7 @@ module Notes ...@@ -21,7 +21,7 @@ module Notes
if quick_actions_service.supported?(note) if quick_actions_service.supported?(note)
options = { merge_request_diff_head_sha: merge_request_diff_head_sha } options = { merge_request_diff_head_sha: merge_request_diff_head_sha }
content, update_params = quick_actions_service.execute(note, options) content, update_params, message = quick_actions_service.execute(note, options)
only_commands = content.empty? only_commands = content.empty?
...@@ -52,7 +52,7 @@ module Notes ...@@ -52,7 +52,7 @@ module Notes
# We must add the error after we call #save because errors are reset # We must add the error after we call #save because errors are reset
# when #save is called # when #save is called
if only_commands if only_commands
note.errors.add(:commands_only, 'Commands applied') note.errors.add(:commands_only, message.presence || _('Commands did not apply'))
end end
end end
......
...@@ -31,17 +31,19 @@ module QuickActions ...@@ -31,17 +31,19 @@ module QuickActions
end end
# 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, a hash of changes to be applied to a record
# and a string containing the execution_message to show to the user.
def execute(content, quick_action_target, only: nil) def execute(content, quick_action_target, only: nil)
return [content, {}] unless current_user.can?(:use_quick_actions) return [content, {}, ''] unless current_user.can?(:use_quick_actions)
@quick_action_target = quick_action_target @quick_action_target = quick_action_target
@updates = {} @updates = {}
@execution_message = {}
content, commands = extractor.extract_commands(content, only: only) content, commands = extractor.extract_commands(content, only: only)
extract_updates(commands) extract_updates(commands)
[content, @updates] [content, @updates, execution_messages_for(commands)]
end end
# Takes a text and interprets the commands that are extracted from it. # Takes a text and interprets the commands that are extracted from it.
...@@ -119,8 +121,12 @@ module QuickActions ...@@ -119,8 +121,12 @@ module QuickActions
labels_params.scan(/"([^"]+)"|([^ ]+)/).flatten.compact labels_params.scan(/"([^"]+)"|([^ ]+)/).flatten.compact
end end
def find_label_references(labels_param) def find_label_references(labels_param, format = :id)
find_labels(labels_param).map(&:to_reference) labels_to_reference(find_labels(labels_param), format)
end
def labels_to_reference(labels, format = :id)
labels.map { |l| l.to_reference(format: format) }
end end
def find_label_ids(labels_param) def find_label_ids(labels_param)
...@@ -128,11 +134,24 @@ module QuickActions ...@@ -128,11 +134,24 @@ module QuickActions
end end
def explain_commands(commands) def explain_commands(commands)
map_commands(commands, :explain)
end
def execution_messages_for(commands)
map_commands(commands, :execute_message).join(' ')
end
def map_commands(commands, method)
commands.map do |name, arg| commands.map do |name, arg|
definition = self.class.definition_by_name(name) definition = self.class.definition_by_name(name)
next unless definition next unless definition
definition.explain(self, arg) case method
when :explain
definition.explain(self, arg)
when :execute_message
@execution_message[name.to_sym] || definition.execute_message(self, arg)
end
end.compact end.compact
end end
......
---
title: Make quick action commands applied banner more useful
merge_request: 26672
author: Jacopo Beschi @jacopo-beschi
type: added
...@@ -9,7 +9,8 @@ and commits that are usually done by clicking buttons or dropdowns in GitLab's U ...@@ -9,7 +9,8 @@ and commits that are usually done by clicking buttons or dropdowns in GitLab's U
You can enter these commands while creating a new issue or merge request, or You can enter these commands while creating a new issue or merge request, or
in comments of issues, epics, merge requests, and commits. Each command should be in comments of issues, epics, merge requests, and commits. Each command should be
on a separate line in order to be properly detected and executed. Once executed, on a separate line in order to be properly detected and executed. Once executed,
the commands are removed from the text body and not visible to anyone else.
> From [GitLab 12.1](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/26672), an alert is displayed when a quick action is successfully applied.
## Quick Actions for issues and merge requests ## Quick Actions for issues and merge requests
......
...@@ -3,8 +3,8 @@ ...@@ -3,8 +3,8 @@
module Gitlab module Gitlab
module QuickActions module QuickActions
class CommandDefinition class CommandDefinition
attr_accessor :name, :aliases, :description, :explanation, :params, attr_accessor :name, :aliases, :description, :explanation, :execution_message,
:condition_block, :parse_params_block, :action_block, :warning, :types :params, :condition_block, :parse_params_block, :action_block, :warning, :types
def initialize(name, attributes = {}) def initialize(name, attributes = {})
@name = name @name = name
...@@ -13,6 +13,7 @@ module Gitlab ...@@ -13,6 +13,7 @@ module Gitlab
@description = attributes[:description] || '' @description = attributes[:description] || ''
@warning = attributes[:warning] || '' @warning = attributes[:warning] || ''
@explanation = attributes[:explanation] || '' @explanation = attributes[:explanation] || ''
@execution_message = attributes[:execution_message] || ''
@params = attributes[:params] || [] @params = attributes[:params] || []
@condition_block = attributes[:condition_block] @condition_block = attributes[:condition_block]
@parse_params_block = attributes[:parse_params_block] @parse_params_block = attributes[:parse_params_block]
...@@ -48,13 +49,23 @@ module Gitlab ...@@ -48,13 +49,23 @@ module Gitlab
end end
def execute(context, arg) def execute(context, arg)
return if noop? || !available?(context) return unless executable?(context)
count_commands_executed_in(context) count_commands_executed_in(context)
execute_block(action_block, context, arg) execute_block(action_block, context, arg)
end end
def execute_message(context, arg)
return unless executable?(context)
if execution_message.respond_to?(:call)
execute_block(execution_message, context, arg)
else
execution_message
end
end
def to_h(context) def to_h(context)
desc = description desc = description
if desc.respond_to?(:call) if desc.respond_to?(:call)
...@@ -77,6 +88,10 @@ module Gitlab ...@@ -77,6 +88,10 @@ module Gitlab
private private
def executable?(context)
!noop? && available?(context)
end
def count_commands_executed_in(context) def count_commands_executed_in(context)
return unless context.respond_to?(:commands_executed_count=) return unless context.respond_to?(:commands_executed_count=)
......
...@@ -16,6 +16,13 @@ module Gitlab ...@@ -16,6 +16,13 @@ module Gitlab
_("Tags this commit to %{tag_name}.") % { tag_name: tag_name } _("Tags this commit to %{tag_name}.") % { tag_name: tag_name }
end end
end end
execution_message do |tag_name, message|
if message.present?
_("Tagged this commit to %{tag_name} with \"%{message}\".") % { tag_name: tag_name, message: message }
else
_("Tagged this commit to %{tag_name}.") % { tag_name: tag_name }
end
end
params 'v1.2.3 <message>' params 'v1.2.3 <message>'
parse_params do |tag_name_and_message| parse_params do |tag_name_and_message|
tag_name_and_message.split(' ', 2) tag_name_and_message.split(' ', 2)
......
...@@ -66,6 +66,35 @@ module Gitlab ...@@ -66,6 +66,35 @@ module Gitlab
@explanation = block_given? ? block : text @explanation = block_given? ? block : text
end end
# Allows to provide a message about quick action execution result, success or failure.
# This message is shown after quick action execution and after saving the note.
#
# Example:
#
# execution_message do |arguments|
# "Added label(s) #{arguments.join(' ')}"
# end
# command :command_key do |arguments|
# # Awesome code block
# end
#
# Note: The execution_message won't be executed unless the condition block returns true.
# execution_message block is executed always after the command block has run,
# for this reason if the condition block doesn't return true after the command block has
# run you need to set the @execution_message variable inside the command block instead as
# shown in the following example.
#
# Example using instance variable:
#
# command :command_key do |arguments|
# # Awesome code block
# @execution_message[:command_key] = 'command_key executed successfully'
# end
#
def execution_message(text = '', &block)
@execution_message = block_given? ? block : text
end
# Allows to define type(s) that must be met in order for the command # Allows to define type(s) that must be met in order for the command
# to be returned by `.command_names` & `.command_definitions`. # to be returned by `.command_names` & `.command_definitions`.
# #
...@@ -121,10 +150,16 @@ module Gitlab ...@@ -121,10 +150,16 @@ module Gitlab
# comment. # comment.
# It accepts aliases and takes a block. # It accepts aliases and takes a block.
# #
# You can also set the @execution_message instance variable, on conflicts with
# execution_message method the instance variable has precedence.
#
# Example: # Example:
# #
# command :my_command, :alias_for_my_command do |arguments| # command :my_command, :alias_for_my_command do |arguments|
# # Awesome code block # # Awesome code block
# @updates[:my_command] = 'foo'
#
# @execution_message[:my_command] = 'my_command executed successfully'
# end # end
def command(*command_names, &block) def command(*command_names, &block)
define_command(CommandDefinition, *command_names, &block) define_command(CommandDefinition, *command_names, &block)
...@@ -158,6 +193,7 @@ module Gitlab ...@@ -158,6 +193,7 @@ module Gitlab
description: @description, description: @description,
warning: @warning, warning: @warning,
explanation: @explanation, explanation: @explanation,
execution_message: @execution_message,
params: @params, params: @params,
condition_block: @condition_block, condition_block: @condition_block,
parse_params_block: @parse_params_block, parse_params_block: @parse_params_block,
...@@ -173,6 +209,7 @@ module Gitlab ...@@ -173,6 +209,7 @@ module Gitlab
@description = nil @description = nil
@explanation = nil @explanation = nil
@execution_message = nil
@params = nil @params = nil
@condition_block = nil @condition_block = nil
@warning = nil @warning = nil
......
...@@ -12,10 +12,16 @@ module Gitlab ...@@ -12,10 +12,16 @@ module Gitlab
included do included do
# Issue, MergeRequest, Epic: quick actions definitions # Issue, MergeRequest, Epic: quick actions definitions
desc do desc do
"Close this #{quick_action_target.to_ability_name.humanize(capitalize: false)}" _('Close this %{quick_action_target}') %
{ quick_action_target: quick_action_target.to_ability_name.humanize(capitalize: false) }
end end
explanation do explanation do
"Closes this #{quick_action_target.to_ability_name.humanize(capitalize: false)}." _('Closes this %{quick_action_target}.') %
{ quick_action_target: quick_action_target.to_ability_name.humanize(capitalize: false) }
end
execution_message do
_('Closed this %{quick_action_target}.') %
{ quick_action_target: quick_action_target.to_ability_name.humanize(capitalize: false) }
end end
types Issuable types Issuable
condition do condition do
...@@ -28,10 +34,16 @@ module Gitlab ...@@ -28,10 +34,16 @@ module Gitlab
end end
desc do desc do
"Reopen this #{quick_action_target.to_ability_name.humanize(capitalize: false)}" _('Reopen this %{quick_action_target}') %
{ quick_action_target: quick_action_target.to_ability_name.humanize(capitalize: false) }
end end
explanation do explanation do
"Reopens this #{quick_action_target.to_ability_name.humanize(capitalize: false)}." _('Reopens this %{quick_action_target}.') %
{ quick_action_target: quick_action_target.to_ability_name.humanize(capitalize: false) }
end
execution_message do
_('Reopened this %{quick_action_target}.') %
{ quick_action_target: quick_action_target.to_ability_name.humanize(capitalize: false) }
end end
types Issuable types Issuable
condition do condition do
...@@ -45,7 +57,10 @@ module Gitlab ...@@ -45,7 +57,10 @@ module Gitlab
desc _('Change title') desc _('Change title')
explanation do |title_param| explanation do |title_param|
_("Changes the title to \"%{title_param}\".") % { title_param: title_param } _('Changes the title to "%{title_param}".') % { title_param: title_param }
end
execution_message do |title_param|
_('Changed the title to "%{title_param}".') % { title_param: title_param }
end end
params '<New title>' params '<New title>'
types Issuable types Issuable
...@@ -61,7 +76,10 @@ module Gitlab ...@@ -61,7 +76,10 @@ module Gitlab
explanation do |labels_param| explanation do |labels_param|
labels = find_label_references(labels_param) labels = find_label_references(labels_param)
"Adds #{labels.join(' ')} #{'label'.pluralize(labels.count)}." if labels.any? if labels.any?
_("Adds %{labels} %{label_text}.") %
{ labels: labels.join(' '), label_text: 'label'.pluralize(labels.count) }
end
end end
params '~label1 ~"label 2"' params '~label1 ~"label 2"'
types Issuable types Issuable
...@@ -71,21 +89,15 @@ module Gitlab ...@@ -71,21 +89,15 @@ module Gitlab
find_labels.any? find_labels.any?
end end
command :label do |labels_param| command :label do |labels_param|
label_ids = find_label_ids(labels_param) run_label_command(labels: find_labels(labels_param), command: :label, updates_key: :add_label_ids)
if label_ids.any?
@updates[:add_label_ids] ||= []
@updates[:add_label_ids] += label_ids
@updates[:add_label_ids].uniq!
end
end end
desc _('Remove all or specific label(s)') desc _('Remove all or specific label(s)')
explanation do |labels_param = nil| explanation do |labels_param = nil|
if labels_param.present? label_references = labels_param.present? ? find_label_references(labels_param) : []
labels = find_label_references(labels_param) if label_references.any?
"Removes #{labels.join(' ')} #{'label'.pluralize(labels.count)}." if labels.any? _("Removes %{label_references} %{label_text}.") %
{ label_references: label_references.join(' '), label_text: 'label'.pluralize(label_references.count) }
else else
_('Removes all labels.') _('Removes all labels.')
end end
...@@ -99,7 +111,9 @@ module Gitlab ...@@ -99,7 +111,9 @@ module Gitlab
end end
command :unlabel do |labels_param = nil| command :unlabel do |labels_param = nil|
if labels_param.present? if labels_param.present?
label_ids = find_label_ids(labels_param) labels = find_labels(labels_param)
label_ids = labels.map(&:id)
label_references = labels_to_reference(labels, :name)
if label_ids.any? if label_ids.any?
@updates[:remove_label_ids] ||= [] @updates[:remove_label_ids] ||= []
...@@ -109,7 +123,10 @@ module Gitlab ...@@ -109,7 +123,10 @@ module Gitlab
end end
else else
@updates[:label_ids] = [] @updates[:label_ids] = []
label_references = []
end end
@execution_message[:unlabel] = remove_label_message(label_references)
end end
desc _('Replace all label(s)') desc _('Replace all label(s)')
...@@ -125,18 +142,12 @@ module Gitlab ...@@ -125,18 +142,12 @@ module Gitlab
current_user.can?(:"admin_#{quick_action_target.to_ability_name}", parent) current_user.can?(:"admin_#{quick_action_target.to_ability_name}", parent)
end end
command :relabel do |labels_param| command :relabel do |labels_param|
label_ids = find_label_ids(labels_param) run_label_command(labels: find_labels(labels_param), command: :relabel, updates_key: :label_ids)
if label_ids.any?
@updates[:label_ids] ||= []
@updates[:label_ids] += label_ids
@updates[:label_ids].uniq!
end
end end
desc _('Add a todo') desc _('Add a todo')
explanation _('Adds a todo.') explanation _('Adds a todo.')
execution_message _('Added a todo.')
types Issuable types Issuable
condition do condition do
quick_action_target.persisted? && quick_action_target.persisted? &&
...@@ -148,6 +159,7 @@ module Gitlab ...@@ -148,6 +159,7 @@ module Gitlab
desc _('Mark to do as done') desc _('Mark to do as done')
explanation _('Marks to do as done.') explanation _('Marks to do as done.')
execution_message _('Marked to do as done.')
types Issuable types Issuable
condition do condition do
quick_action_target.persisted? && quick_action_target.persisted? &&
...@@ -159,7 +171,12 @@ module Gitlab ...@@ -159,7 +171,12 @@ module Gitlab
desc _('Subscribe') desc _('Subscribe')
explanation do explanation do
"Subscribes to this #{quick_action_target.to_ability_name.humanize(capitalize: false)}." _('Subscribes to this %{quick_action_target}.') %
{ quick_action_target: quick_action_target.to_ability_name.humanize(capitalize: false) }
end
execution_message do
_('Subscribed to this %{quick_action_target}.') %
{ quick_action_target: quick_action_target.to_ability_name.humanize(capitalize: false) }
end end
types Issuable types Issuable
condition do condition do
...@@ -172,7 +189,12 @@ module Gitlab ...@@ -172,7 +189,12 @@ module Gitlab
desc _('Unsubscribe') desc _('Unsubscribe')
explanation do explanation do
"Unsubscribes from this #{quick_action_target.to_ability_name.humanize(capitalize: false)}." _('Unsubscribes from this %{quick_action_target}.') %
{ quick_action_target: quick_action_target.to_ability_name.humanize(capitalize: false) }
end
execution_message do
_('Unsubscribed from this %{quick_action_target}.') %
{ quick_action_target: quick_action_target.to_ability_name.humanize(capitalize: false) }
end end
types Issuable types Issuable
condition do condition do
...@@ -187,6 +209,9 @@ module Gitlab ...@@ -187,6 +209,9 @@ module Gitlab
explanation do |name| explanation do |name|
_("Toggles :%{name}: emoji award.") % { name: name } if name _("Toggles :%{name}: emoji award.") % { name: name } if name
end end
execution_message do |name|
_("Toggled :%{name}: emoji award.") % { name: name } if name
end
params ':emoji:' params ':emoji:'
types Issuable types Issuable
condition do condition do
...@@ -215,6 +240,41 @@ module Gitlab ...@@ -215,6 +240,41 @@ module Gitlab
substitution :tableflip do |comment| substitution :tableflip do |comment|
"#{comment} #{TABLEFLIP}" "#{comment} #{TABLEFLIP}"
end end
private
def run_label_command(labels:, command:, updates_key:)
return if labels.empty?
@updates[updates_key] ||= []
@updates[updates_key] += labels.map(&:id)
@updates[updates_key].uniq!
label_references = labels_to_reference(labels, :name)
@execution_message[command] = case command
when :relabel
_('Replaced all labels with %{label_references} %{label_text}.') %
{
label_references: label_references.join(' '),
label_text: 'label'.pluralize(label_references.count)
}
when :label
_('Added %{label_references} %{label_text}.') %
{
label_references: label_references.join(' '),
label_text: 'label'.pluralize(labels.count)
}
end
end
def remove_label_message(label_references)
if label_references.any?
_("Removed %{label_references} %{label_text}.") %
{ label_references: label_references.join(' '), label_text: 'label'.pluralize(label_references.count) }
else
_('Removed all labels.')
end
end
end end
end end
end end
......
...@@ -12,6 +12,9 @@ module Gitlab ...@@ -12,6 +12,9 @@ module Gitlab
explanation do |due_date| explanation do |due_date|
_("Sets the due date to %{due_date}.") % { due_date: due_date.strftime('%b %-d, %Y') } if due_date _("Sets the due date to %{due_date}.") % { due_date: due_date.strftime('%b %-d, %Y') } if due_date
end end
execution_message do |due_date|
_("Set the due date to %{due_date}.") % { due_date: due_date.strftime('%b %-d, %Y') } if due_date
end
params '<in 2 days | this Friday | December 31st>' params '<in 2 days | this Friday | December 31st>'
types Issue types Issue
condition do condition do
...@@ -27,6 +30,7 @@ module Gitlab ...@@ -27,6 +30,7 @@ module Gitlab
desc _('Remove due date') desc _('Remove due date')
explanation _('Removes the due date.') explanation _('Removes the due date.')
execution_message _('Removed the due date.')
types Issue types Issue
condition do condition do
quick_action_target.persisted? && quick_action_target.persisted? &&
...@@ -49,22 +53,27 @@ module Gitlab ...@@ -49,22 +53,27 @@ module Gitlab
current_user.can?(:"update_#{quick_action_target.to_ability_name}", quick_action_target) && current_user.can?(:"update_#{quick_action_target.to_ability_name}", quick_action_target) &&
quick_action_target.project.boards.count == 1 quick_action_target.project.boards.count == 1
end end
# rubocop: disable CodeReuse/ActiveRecord
command :board_move do |target_list_name| command :board_move do |target_list_name|
label_ids = find_label_ids(target_list_name) labels = find_labels(target_list_name)
label_ids = labels.map(&:id)
if label_ids.size == 1 if label_ids.size == 1
label_id = label_ids.first label_id = label_ids.first
# Ensure this label corresponds to a list on the board # Ensure this label corresponds to a list on the board
next unless Label.on_project_boards(quick_action_target.project_id).where(id: label_id).exists? next unless Label.on_project_board?(quick_action_target.project_id, label_id)
@updates[:remove_label_ids] = @updates[:remove_label_ids] =
quick_action_target.labels.on_project_boards(quick_action_target.project_id).where.not(id: label_id).pluck(:id) quick_action_target.labels.on_project_boards(quick_action_target.project_id).where.not(id: label_id).pluck(:id) # rubocop: disable CodeReuse/ActiveRecord
@updates[:add_label_ids] = [label_id] @updates[:add_label_ids] = [label_id]
message = _("Moved issue to %{label} column in the board.") % { label: labels_to_reference(labels).first }
else
message = _('Move this issue failed because you need to specify only one label.')
end end
@execution_message[:board_move] = message
end end
# rubocop: enable CodeReuse/ActiveRecord
desc _('Mark this issue as a duplicate of another issue') desc _('Mark this issue as a duplicate of another issue')
explanation do |duplicate_reference| explanation do |duplicate_reference|
...@@ -81,7 +90,13 @@ module Gitlab ...@@ -81,7 +90,13 @@ module Gitlab
if canonical_issue.present? if canonical_issue.present?
@updates[:canonical_issue_id] = canonical_issue.id @updates[:canonical_issue_id] = canonical_issue.id
message = _("Marked this issue as a duplicate of %{duplicate_param}.") % { duplicate_param: duplicate_param }
else
message = _('Mark as duplicate failed because referenced issue was not found')
end end
@execution_message[:duplicate] = message
end end
desc _('Move this issue to another project.') desc _('Move this issue to another project.')
...@@ -99,13 +114,22 @@ module Gitlab ...@@ -99,13 +114,22 @@ module Gitlab
if target_project.present? if target_project.present?
@updates[:target_project] = target_project @updates[:target_project] = target_project
message = _("Moved this issue to %{path_to_project}.") % { path_to_project: target_project_path }
else
message = _("Move this issue failed because target project doesn't exists")
end end
@execution_message[:move] = message
end end
desc _('Make issue confidential.') desc _('Make issue confidential.')
explanation do explanation do
_('Makes this issue confidential') _('Makes this issue confidential')
end end
execution_message do
_('Made this issue confidential')
end
types Issue types Issue
condition do condition do
current_user.can?(:"admin_#{quick_action_target.to_ability_name}", quick_action_target) current_user.can?(:"admin_#{quick_action_target.to_ability_name}", quick_action_target)
...@@ -119,7 +143,14 @@ module Gitlab ...@@ -119,7 +143,14 @@ module Gitlab
if branch_name if branch_name
_("Creates branch '%{branch_name}' and a merge request to resolve this issue") % { branch_name: branch_name } _("Creates branch '%{branch_name}' and a merge request to resolve this issue") % { branch_name: branch_name }
else else
"Creates a branch and a merge request to resolve this issue" _('Creates a branch and a merge request to resolve this issue')
end
end
execution_message do |branch_name = nil|
if branch_name
_("Created branch '%{branch_name}' and a merge request to resolve this issue") % { branch_name: branch_name }
else
_('Created a branch and a merge request to resolve this issue')
end end
end end
params "<branch name>" params "<branch name>"
......
...@@ -9,12 +9,9 @@ module Gitlab ...@@ -9,12 +9,9 @@ module Gitlab
included do included do
# Issue, MergeRequest: quick actions definitions # Issue, MergeRequest: quick actions definitions
desc _('Assign') desc _('Assign')
# rubocop: disable CodeReuse/ActiveRecord
explanation do |users| explanation do |users|
users = quick_action_target.allows_multiple_assignees? ? users : users.take(1) _('Assigns %{assignee_users_sentence}.') % { assignee_users_sentence: assignee_users_sentence(users) }
"Assigns #{users.map(&:to_reference).to_sentence}."
end end
# rubocop: enable CodeReuse/ActiveRecord
params do params do
quick_action_target.allows_multiple_assignees? ? '@user1 @user2' : '@user' quick_action_target.allows_multiple_assignees? ? '@user1 @user2' : '@user'
end end
...@@ -26,7 +23,10 @@ module Gitlab ...@@ -26,7 +23,10 @@ module Gitlab
extract_users(assignee_param) extract_users(assignee_param)
end end
command :assign do |users| command :assign do |users|
next if users.empty? if users.empty?
@execution_message[:assign] = _("Assign command failed because no user was found")
next
end
if quick_action_target.allows_multiple_assignees? if quick_action_target.allows_multiple_assignees?
@updates[:assignee_ids] ||= quick_action_target.assignees.map(&:id) @updates[:assignee_ids] ||= quick_action_target.assignees.map(&:id)
...@@ -34,6 +34,8 @@ module Gitlab ...@@ -34,6 +34,8 @@ module Gitlab
else else
@updates[:assignee_ids] = [users.first.id] @updates[:assignee_ids] = [users.first.id]
end end
@execution_message[:assign] = _('Assigned %{assignee_users_sentence}.') % { assignee_users_sentence: assignee_users_sentence(users) }
end end
desc do desc do
...@@ -44,9 +46,14 @@ module Gitlab ...@@ -44,9 +46,14 @@ module Gitlab
end end
end end
explanation do |users = nil| explanation do |users = nil|
assignees = quick_action_target.assignees assignees = assignees_for_removal(users)
assignees &= users if users.present? && quick_action_target.allows_multiple_assignees? _("Removes %{assignee_text} %{assignee_references}.") %
"Removes #{'assignee'.pluralize(assignees.size)} #{assignees.map(&:to_reference).to_sentence}." { assignee_text: 'assignee'.pluralize(assignees.size), assignee_references: assignees.map(&:to_reference).to_sentence }
end
execution_message do |users = nil|
assignees = assignees_for_removal(users)
_("Removed %{assignee_text} %{assignee_references}.") %
{ assignee_text: 'assignee'.pluralize(assignees.size), assignee_references: assignees.map(&:to_reference).to_sentence }
end end
params do params do
quick_action_target.allows_multiple_assignees? ? '@user1 @user2' : '' quick_action_target.allows_multiple_assignees? ? '@user1 @user2' : ''
...@@ -74,6 +81,9 @@ module Gitlab ...@@ -74,6 +81,9 @@ module Gitlab
explanation do |milestone| explanation do |milestone|
_("Sets the milestone to %{milestone_reference}.") % { milestone_reference: milestone.to_reference } if milestone _("Sets the milestone to %{milestone_reference}.") % { milestone_reference: milestone.to_reference } if milestone
end end
execution_message do |milestone|
_("Set the milestone to %{milestone_reference}.") % { milestone_reference: milestone.to_reference } if milestone
end
params '%"milestone"' params '%"milestone"'
types Issue, MergeRequest types Issue, MergeRequest
condition do condition do
...@@ -92,6 +102,9 @@ module Gitlab ...@@ -92,6 +102,9 @@ module Gitlab
explanation do explanation do
_("Removes %{milestone_reference} milestone.") % { milestone_reference: quick_action_target.milestone.to_reference(format: :name) } _("Removes %{milestone_reference} milestone.") % { milestone_reference: quick_action_target.milestone.to_reference(format: :name) }
end end
execution_message do
_("Removed %{milestone_reference} milestone.") % { milestone_reference: quick_action_target.milestone.to_reference(format: :name) }
end
types Issue, MergeRequest types Issue, MergeRequest
condition do condition do
quick_action_target.persisted? && quick_action_target.persisted? &&
...@@ -116,17 +129,22 @@ module Gitlab ...@@ -116,17 +129,22 @@ module Gitlab
extract_references(issuable_param, :merge_request).first extract_references(issuable_param, :merge_request).first
end end
command :copy_metadata do |source_issuable| command :copy_metadata do |source_issuable|
if source_issuable.present? && source_issuable.project.id == quick_action_target.project.id if can_copy_metadata?(source_issuable)
@updates[:add_label_ids] = source_issuable.labels.map(&:id) @updates[:add_label_ids] = source_issuable.labels.map(&:id)
@updates[:milestone_id] = source_issuable.milestone.id if source_issuable.milestone @updates[:milestone_id] = source_issuable.milestone.id if source_issuable.milestone
@execution_message[:copy_metadata] = _("Copied labels and milestone from %{source_issuable_reference}.") % { source_issuable_reference: source_issuable.to_reference }
end end
end end
desc _('Set time estimate') desc _('Set time estimate')
explanation do |time_estimate| explanation do |time_estimate|
time_estimate = Gitlab::TimeTrackingFormatter.output(time_estimate) formatted_time_estimate = format_time_estimate(time_estimate)
_("Sets time estimate to %{time_estimate}.") % { time_estimate: formatted_time_estimate } if formatted_time_estimate
_("Sets time estimate to %{time_estimate}.") % { time_estimate: time_estimate } if time_estimate end
execution_message do |time_estimate|
formatted_time_estimate = format_time_estimate(time_estimate)
_("Set time estimate to %{time_estimate}.") % { time_estimate: formatted_time_estimate } if formatted_time_estimate
end end
params '<1w 3d 2h 14m>' params '<1w 3d 2h 14m>'
types Issue, MergeRequest types Issue, MergeRequest
...@@ -144,18 +162,12 @@ module Gitlab ...@@ -144,18 +162,12 @@ module Gitlab
desc _('Add or subtract spent time') desc _('Add or subtract spent time')
explanation do |time_spent, time_spent_date| explanation do |time_spent, time_spent_date|
if time_spent spend_time_message(time_spent, time_spent_date, false)
if time_spent > 0
verb = _('Adds')
value = time_spent
else
verb = _('Subtracts')
value = -time_spent
end
_("%{verb} %{time_spent_value} spent time.") % { verb: verb, time_spent_value: Gitlab::TimeTrackingFormatter.output(value) }
end
end end
execution_message do |time_spent, time_spent_date|
spend_time_message(time_spent, time_spent_date, true)
end
params '<time(1h30m | -1h30m)> <date(YYYY-MM-DD)>' params '<time(1h30m | -1h30m)> <date(YYYY-MM-DD)>'
types Issue, MergeRequest types Issue, MergeRequest
condition do condition do
...@@ -176,6 +188,7 @@ module Gitlab ...@@ -176,6 +188,7 @@ module Gitlab
desc _('Remove time estimate') desc _('Remove time estimate')
explanation _('Removes time estimate.') explanation _('Removes time estimate.')
execution_message _('Removed time estimate.')
types Issue, MergeRequest types Issue, MergeRequest
condition do condition do
quick_action_target.persisted? && quick_action_target.persisted? &&
...@@ -187,6 +200,7 @@ module Gitlab ...@@ -187,6 +200,7 @@ module Gitlab
desc _('Remove spent time') desc _('Remove spent time')
explanation _('Removes spent time.') explanation _('Removes spent time.')
execution_message _('Removed spent time.')
condition do condition do
quick_action_target.persisted? && quick_action_target.persisted? &&
current_user.can?(:"admin_#{quick_action_target.to_ability_name}", project) current_user.can?(:"admin_#{quick_action_target.to_ability_name}", project)
...@@ -198,6 +212,7 @@ module Gitlab ...@@ -198,6 +212,7 @@ module Gitlab
desc _("Lock the discussion") desc _("Lock the discussion")
explanation _("Locks the discussion") explanation _("Locks the discussion")
execution_message _("Locked the discussion")
types Issue, MergeRequest types Issue, MergeRequest
condition do condition do
quick_action_target.persisted? && quick_action_target.persisted? &&
...@@ -210,6 +225,7 @@ module Gitlab ...@@ -210,6 +225,7 @@ module Gitlab
desc _("Unlock the discussion") desc _("Unlock the discussion")
explanation _("Unlocks the discussion") explanation _("Unlocks the discussion")
execution_message _("Unlocked the discussion")
types Issue, MergeRequest types Issue, MergeRequest
condition do condition do
quick_action_target.persisted? && quick_action_target.persisted? &&
...@@ -219,6 +235,47 @@ module Gitlab ...@@ -219,6 +235,47 @@ module Gitlab
command :unlock do command :unlock do
@updates[:discussion_locked] = false @updates[:discussion_locked] = false
end end
private
def assignee_users_sentence(users)
if quick_action_target.allows_multiple_assignees?
users
else
[users.first]
end.map(&:to_reference).to_sentence
end
def assignees_for_removal(users)
assignees = quick_action_target.assignees
if users.present? && quick_action_target.allows_multiple_assignees?
assignees & users
else
assignees
end
end
def can_copy_metadata?(source_issuable)
source_issuable.present? && source_issuable.project_id == quick_action_target.project_id
end
def format_time_estimate(time_estimate)
Gitlab::TimeTrackingFormatter.output(time_estimate)
end
def spend_time_message(time_spent, time_spent_date, paste_tense)
return unless time_spent
if time_spent > 0
verb = paste_tense ? _('Added') : _('Adds')
value = time_spent
else
verb = paste_tense ? _('Subtracted') : _('Subtracts')
value = -time_spent
end
_("%{verb} %{time_spent_value} spent time.") % { verb: verb, time_spent_value: format_time_estimate(value) }
end
end end
end end
end end
......
...@@ -8,8 +8,9 @@ module Gitlab ...@@ -8,8 +8,9 @@ module Gitlab
included do included do
# MergeRequest only quick actions definitions # MergeRequest only quick actions definitions
desc 'Merge (when the pipeline succeeds)' desc _('Merge (when the pipeline succeeds)')
explanation 'Merges this merge request when the pipeline succeeds.' explanation _('Merges this merge request when the pipeline succeeds.')
execution_message _('Scheduled to merge this merge request when the pipeline succeeds.')
types MergeRequest types MergeRequest
condition do condition do
last_diff_sha = params && params[:merge_request_diff_head_sha] last_diff_sha = params && params[:merge_request_diff_head_sha]
...@@ -22,10 +23,22 @@ module Gitlab ...@@ -22,10 +23,22 @@ module Gitlab
desc 'Toggle the Work In Progress status' desc 'Toggle the Work In Progress status'
explanation do explanation do
verb = quick_action_target.work_in_progress? ? 'Unmarks' : 'Marks'
noun = quick_action_target.to_ability_name.humanize(capitalize: false) noun = quick_action_target.to_ability_name.humanize(capitalize: false)
"#{verb} this #{noun} as Work In Progress." if quick_action_target.work_in_progress?
_("Unmarks this %{noun} as Work In Progress.")
else
_("Marks this %{noun} as Work In Progress.")
end % { noun: noun }
end end
execution_message do
noun = quick_action_target.to_ability_name.humanize(capitalize: false)
if quick_action_target.work_in_progress?
_("Unmarked this %{noun} as Work In Progress.")
else
_("Marked this %{noun} as Work In Progress.")
end % { noun: noun }
end
types MergeRequest types MergeRequest
condition do condition do
quick_action_target.respond_to?(:work_in_progress?) && quick_action_target.respond_to?(:work_in_progress?) &&
...@@ -36,9 +49,12 @@ module Gitlab ...@@ -36,9 +49,12 @@ module Gitlab
@updates[:wip_event] = quick_action_target.work_in_progress? ? 'unwip' : 'wip' @updates[:wip_event] = quick_action_target.work_in_progress? ? 'unwip' : 'wip'
end end
desc 'Set target branch' desc _('Set target branch')
explanation do |branch_name| explanation do |branch_name|
"Sets target branch to #{branch_name}." _('Sets target branch to %{branch_name}.') % { branch_name: branch_name }
end
execution_message do |branch_name|
_('Set target branch to %{branch_name}.') % { branch_name: branch_name }
end end
params '<Local branch name>' params '<Local branch name>'
types MergeRequest types MergeRequest
......
...@@ -735,6 +735,15 @@ msgstr "" ...@@ -735,6 +735,15 @@ msgstr ""
msgid "AddMember|Too many users specified (limit is %{user_limit})" msgid "AddMember|Too many users specified (limit is %{user_limit})"
msgstr "" msgstr ""
msgid "Added"
msgstr ""
msgid "Added %{label_references} %{label_text}."
msgstr ""
msgid "Added a todo."
msgstr ""
msgid "Added at" msgid "Added at"
msgstr "" msgstr ""
...@@ -744,6 +753,9 @@ msgstr "" ...@@ -744,6 +753,9 @@ msgstr ""
msgid "Adds" msgid "Adds"
msgstr "" msgstr ""
msgid "Adds %{labels} %{label_text}."
msgstr ""
msgid "Adds a todo." msgid "Adds a todo."
msgstr "" msgstr ""
...@@ -1332,6 +1344,9 @@ msgstr "" ...@@ -1332,6 +1344,9 @@ msgstr ""
msgid "Assign" msgid "Assign"
msgstr "" msgstr ""
msgid "Assign command failed because no user was found"
msgstr ""
msgid "Assign custom color like #FF0000" msgid "Assign custom color like #FF0000"
msgstr "" msgstr ""
...@@ -1353,6 +1368,9 @@ msgstr "" ...@@ -1353,6 +1368,9 @@ msgstr ""
msgid "Assign yourself to this issue" msgid "Assign yourself to this issue"
msgstr "" msgstr ""
msgid "Assigned %{assignee_users_sentence}."
msgstr ""
msgid "Assigned Issues" msgid "Assigned Issues"
msgstr "" msgstr ""
...@@ -1370,6 +1388,9 @@ msgstr[1] "" ...@@ -1370,6 +1388,9 @@ msgstr[1] ""
msgid "Assignee(s)" msgid "Assignee(s)"
msgstr "" msgstr ""
msgid "Assigns %{assignee_users_sentence}."
msgstr ""
msgid "Attach a file" msgid "Attach a file"
msgstr "" msgstr ""
...@@ -2005,6 +2026,9 @@ msgstr "" ...@@ -2005,6 +2026,9 @@ msgstr ""
msgid "ChangeTypeAction|This will create a new commit in order to revert the existing changes." msgid "ChangeTypeAction|This will create a new commit in order to revert the existing changes."
msgstr "" msgstr ""
msgid "Changed the title to \"%{title_param}\"."
msgstr ""
msgid "Changes" msgid "Changes"
msgstr "" msgstr ""
...@@ -2341,9 +2365,18 @@ msgstr "" ...@@ -2341,9 +2365,18 @@ msgstr ""
msgid "Close sidebar" msgid "Close sidebar"
msgstr "" msgstr ""
msgid "Close this %{quick_action_target}"
msgstr ""
msgid "Closed" msgid "Closed"
msgstr "" msgstr ""
msgid "Closed this %{quick_action_target}."
msgstr ""
msgid "Closes this %{quick_action_target}."
msgstr ""
msgid "ClusterIntegration| %{custom_domain_start}More information%{custom_domain_end}." msgid "ClusterIntegration| %{custom_domain_start}More information%{custom_domain_end}."
msgstr "" msgstr ""
...@@ -2887,6 +2920,9 @@ msgstr "" ...@@ -2887,6 +2920,9 @@ msgstr ""
msgid "Commands applied" msgid "Commands applied"
msgstr "" msgstr ""
msgid "Commands did not apply"
msgstr ""
msgid "Comment" msgid "Comment"
msgstr "" msgstr ""
...@@ -3186,6 +3222,9 @@ msgstr "" ...@@ -3186,6 +3222,9 @@ msgstr ""
msgid "Copied" msgid "Copied"
msgstr "" msgstr ""
msgid "Copied labels and milestone from %{source_issuable_reference}."
msgstr ""
msgid "Copy %{http_label} clone URL" msgid "Copy %{http_label} clone URL"
msgstr "" msgstr ""
...@@ -3396,6 +3435,12 @@ msgstr "" ...@@ -3396,6 +3435,12 @@ msgstr ""
msgid "Created At" msgid "Created At"
msgstr "" msgstr ""
msgid "Created a branch and a merge request to resolve this issue"
msgstr ""
msgid "Created branch '%{branch_name}' and a merge request to resolve this issue"
msgstr ""
msgid "Created by me" msgid "Created by me"
msgstr "" msgstr ""
...@@ -3405,6 +3450,9 @@ msgstr "" ...@@ -3405,6 +3450,9 @@ msgstr ""
msgid "Created on:" msgid "Created on:"
msgstr "" msgstr ""
msgid "Creates a branch and a merge request to resolve this issue"
msgstr ""
msgid "Creates branch '%{branch_name}' and a merge request to resolve this issue" msgid "Creates branch '%{branch_name}' and a merge request to resolve this issue"
msgstr "" msgstr ""
...@@ -6337,6 +6385,9 @@ msgstr "" ...@@ -6337,6 +6385,9 @@ msgstr ""
msgid "Locked by %{fileLockUserName}" msgid "Locked by %{fileLockUserName}"
msgstr "" msgstr ""
msgid "Locked the discussion"
msgstr ""
msgid "Locked to current projects" msgid "Locked to current projects"
msgstr "" msgstr ""
...@@ -6355,6 +6406,9 @@ msgstr "" ...@@ -6355,6 +6406,9 @@ msgstr ""
msgid "MRDiff|Show full file" msgid "MRDiff|Show full file"
msgstr "" msgstr ""
msgid "Made this issue confidential"
msgstr ""
msgid "Make and review changes in the browser with the Web IDE" msgid "Make and review changes in the browser with the Web IDE"
msgstr "" msgstr ""
...@@ -6436,6 +6490,9 @@ msgstr "" ...@@ -6436,6 +6490,9 @@ msgstr ""
msgid "Mark as done" msgid "Mark as done"
msgstr "" msgstr ""
msgid "Mark as duplicate failed because referenced issue was not found"
msgstr ""
msgid "Mark as resolved" msgid "Mark as resolved"
msgstr "" msgstr ""
...@@ -6454,6 +6511,18 @@ msgstr "" ...@@ -6454,6 +6511,18 @@ msgstr ""
msgid "Markdown enabled" msgid "Markdown enabled"
msgstr "" msgstr ""
msgid "Marked this %{noun} as Work In Progress."
msgstr ""
msgid "Marked this issue as a duplicate of %{duplicate_param}."
msgstr ""
msgid "Marked to do as done."
msgstr ""
msgid "Marks this %{noun} as Work In Progress."
msgstr ""
msgid "Marks this issue as a duplicate of %{duplicate_reference}." msgid "Marks this issue as a duplicate of %{duplicate_reference}."
msgstr "" msgstr ""
...@@ -6499,6 +6568,9 @@ msgstr "" ...@@ -6499,6 +6568,9 @@ msgstr ""
msgid "Merge" msgid "Merge"
msgstr "" msgstr ""
msgid "Merge (when the pipeline succeeds)"
msgstr ""
msgid "Merge Request" msgid "Merge Request"
msgstr "" msgstr ""
...@@ -6622,6 +6694,9 @@ msgstr "" ...@@ -6622,6 +6694,9 @@ msgstr ""
msgid "Merged branches are being deleted. This can take some time depending on the number of branches. Please refresh the page to see changes." msgid "Merged branches are being deleted. This can take some time depending on the number of branches. Please refresh the page to see changes."
msgstr "" msgstr ""
msgid "Merges this merge request when the pipeline succeeds."
msgstr ""
msgid "Messages" msgid "Messages"
msgstr "" msgstr ""
...@@ -6805,6 +6880,12 @@ msgstr "" ...@@ -6805,6 +6880,12 @@ msgstr ""
msgid "Move issue from one column of the board to another" msgid "Move issue from one column of the board to another"
msgstr "" msgstr ""
msgid "Move this issue failed because target project doesn't exists"
msgstr ""
msgid "Move this issue failed because you need to specify only one label."
msgstr ""
msgid "Move this issue to another project." msgid "Move this issue to another project."
msgstr "" msgstr ""
...@@ -6814,6 +6895,12 @@ msgstr "" ...@@ -6814,6 +6895,12 @@ msgstr ""
msgid "MoveIssue|Cannot move issue to project it originates from!" msgid "MoveIssue|Cannot move issue to project it originates from!"
msgstr "" msgstr ""
msgid "Moved issue to %{label} column in the board."
msgstr ""
msgid "Moved this issue to %{path_to_project}."
msgstr ""
msgid "Moves issue to %{label} column in the board." msgid "Moves issue to %{label} column in the board."
msgstr "" msgstr ""
...@@ -8986,12 +9073,39 @@ msgstr "" ...@@ -8986,12 +9073,39 @@ msgstr ""
msgid "Remove time estimate" msgid "Remove time estimate"
msgstr "" msgstr ""
msgid "Removed %{assignee_text} %{assignee_references}."
msgstr ""
msgid "Removed %{label_references} %{label_text}."
msgstr ""
msgid "Removed %{milestone_reference} milestone."
msgstr ""
msgid "Removed all labels."
msgstr ""
msgid "Removed group can not be restored!" msgid "Removed group can not be restored!"
msgstr "" msgstr ""
msgid "Removed projects cannot be restored!" msgid "Removed projects cannot be restored!"
msgstr "" msgstr ""
msgid "Removed spent time."
msgstr ""
msgid "Removed the due date."
msgstr ""
msgid "Removed time estimate."
msgstr ""
msgid "Removes %{assignee_text} %{assignee_references}."
msgstr ""
msgid "Removes %{label_references} %{label_text}."
msgstr ""
msgid "Removes %{milestone_reference} milestone." msgid "Removes %{milestone_reference} milestone."
msgstr "" msgstr ""
...@@ -9025,12 +9139,24 @@ msgstr "" ...@@ -9025,12 +9139,24 @@ msgstr ""
msgid "Reopen milestone" msgid "Reopen milestone"
msgstr "" msgstr ""
msgid "Reopen this %{quick_action_target}"
msgstr ""
msgid "Reopened this %{quick_action_target}."
msgstr ""
msgid "Reopens this %{quick_action_target}."
msgstr ""
msgid "Replace" msgid "Replace"
msgstr "" msgstr ""
msgid "Replace all label(s)" msgid "Replace all label(s)"
msgstr "" msgstr ""
msgid "Replaced all labels with %{label_references} %{label_text}."
msgstr ""
msgid "Reply by email" msgid "Reply by email"
msgstr "" msgstr ""
...@@ -9369,6 +9495,9 @@ msgstr "" ...@@ -9369,6 +9495,9 @@ msgstr ""
msgid "Scheduled" msgid "Scheduled"
msgstr "" msgstr ""
msgid "Scheduled to merge this merge request when the pipeline succeeds."
msgstr ""
msgid "Schedules" msgid "Schedules"
msgstr "" msgstr ""
...@@ -9696,18 +9825,33 @@ msgstr "" ...@@ -9696,18 +9825,33 @@ msgstr ""
msgid "Set requirements for a user to sign-in. Enable mandatory two-factor authentication." msgid "Set requirements for a user to sign-in. Enable mandatory two-factor authentication."
msgstr "" msgstr ""
msgid "Set target branch"
msgstr ""
msgid "Set target branch to %{branch_name}."
msgstr ""
msgid "Set the default expiration time for each job's artifacts. 0 for unlimited. The default unit is in seconds, but you can define an alternative. For example: <code>4 mins 2 sec</code>, <code>2h42min</code>." msgid "Set the default expiration time for each job's artifacts. 0 for unlimited. The default unit is in seconds, but you can define an alternative. For example: <code>4 mins 2 sec</code>, <code>2h42min</code>."
msgstr "" msgstr ""
msgid "Set the due date to %{due_date}."
msgstr ""
msgid "Set the duration for which the jobs will be considered as old and expired. Once that time passes, the jobs will be archived and no longer able to be retried. Make it empty to never expire jobs. It has to be no less than 1 day, for example: <code>15 days</code>, <code>1 month</code>, <code>2 years</code>." msgid "Set the duration for which the jobs will be considered as old and expired. Once that time passes, the jobs will be archived and no longer able to be retried. Make it empty to never expire jobs. It has to be no less than 1 day, for example: <code>15 days</code>, <code>1 month</code>, <code>2 years</code>."
msgstr "" msgstr ""
msgid "Set the maximum file size for each job's artifacts" msgid "Set the maximum file size for each job's artifacts"
msgstr "" msgstr ""
msgid "Set the milestone to %{milestone_reference}."
msgstr ""
msgid "Set time estimate" msgid "Set time estimate"
msgstr "" msgstr ""
msgid "Set time estimate to %{time_estimate}."
msgstr ""
msgid "Set up CI/CD" msgid "Set up CI/CD"
msgstr "" msgstr ""
...@@ -9753,6 +9897,9 @@ msgstr "" ...@@ -9753,6 +9897,9 @@ msgstr ""
msgid "SetStatusModal|What's your status?" msgid "SetStatusModal|What's your status?"
msgstr "" msgstr ""
msgid "Sets target branch to %{branch_name}."
msgstr ""
msgid "Sets the due date to %{due_date}." msgid "Sets the due date to %{due_date}."
msgstr "" msgstr ""
...@@ -10334,9 +10481,18 @@ msgstr "" ...@@ -10334,9 +10481,18 @@ msgstr ""
msgid "Subscribed" msgid "Subscribed"
msgstr "" msgstr ""
msgid "Subscribed to this %{quick_action_target}."
msgstr ""
msgid "Subscribes to this %{quick_action_target}."
msgstr ""
msgid "Subscription" msgid "Subscription"
msgstr "" msgstr ""
msgid "Subtracted"
msgstr ""
msgid "Subtracts" msgid "Subtracts"
msgstr "" msgstr ""
...@@ -10484,6 +10640,12 @@ msgstr "" ...@@ -10484,6 +10640,12 @@ msgstr ""
msgid "Tag this commit." msgid "Tag this commit."
msgstr "" msgstr ""
msgid "Tagged this commit to %{tag_name} with \"%{message}\"."
msgstr ""
msgid "Tagged this commit to %{tag_name}."
msgstr ""
msgid "Tags" msgid "Tags"
msgstr "" msgstr ""
...@@ -11543,6 +11705,9 @@ msgstr "" ...@@ -11543,6 +11705,9 @@ msgstr ""
msgid "ToggleButton|Toggle Status: ON" msgid "ToggleButton|Toggle Status: ON"
msgstr "" msgstr ""
msgid "Toggled :%{name}: emoji award."
msgstr ""
msgid "Toggles :%{name}: emoji award." msgid "Toggles :%{name}: emoji award."
msgstr "" msgstr ""
...@@ -11750,9 +11915,18 @@ msgstr "" ...@@ -11750,9 +11915,18 @@ msgstr ""
msgid "Unlocked" msgid "Unlocked"
msgstr "" msgstr ""
msgid "Unlocked the discussion"
msgstr ""
msgid "Unlocks the discussion" msgid "Unlocks the discussion"
msgstr "" msgstr ""
msgid "Unmarked this %{noun} as Work In Progress."
msgstr ""
msgid "Unmarks this %{noun} as Work In Progress."
msgstr ""
msgid "Unresolve discussion" msgid "Unresolve discussion"
msgstr "" msgstr ""
...@@ -11795,6 +11969,12 @@ msgstr "" ...@@ -11795,6 +11969,12 @@ msgstr ""
msgid "Unsubscribe from %{type}" msgid "Unsubscribe from %{type}"
msgstr "" msgstr ""
msgid "Unsubscribed from this %{quick_action_target}."
msgstr ""
msgid "Unsubscribes from this %{quick_action_target}."
msgstr ""
msgid "Until" msgid "Until"
msgstr "" msgstr ""
......
...@@ -219,6 +219,52 @@ describe Gitlab::QuickActions::CommandDefinition do ...@@ -219,6 +219,52 @@ describe Gitlab::QuickActions::CommandDefinition do
end end
end end
describe "#execute_message" do
context "when the command is a noop" do
it 'returns nil' do
expect(subject.execute_message({}, nil)).to be_nil
end
end
context "when the command is not a noop" do
before do
subject.action_block = proc { self.run = true }
end
context "when the command is not available" do
before do
subject.condition_block = proc { false }
end
it 'returns nil' do
expect(subject.execute_message({}, nil)).to be_nil
end
end
context "when the command is available" do
context 'when the execution_message is a static string' do
before do
subject.execution_message = 'Assigned jacopo'
end
it 'returns this static string' do
expect(subject.execute_message({}, nil)).to eq('Assigned jacopo')
end
end
context 'when the explanation is dynamic' do
before do
subject.execution_message = proc { |arg| "Assigned #{arg}" }
end
it 'invokes the proc' do
expect(subject.execute_message({}, 'Jacopo')).to eq('Assigned Jacopo')
end
end
end
end
end
describe '#explain' do describe '#explain' do
context 'when the command is not available' do context 'when the command is not available' do
before do before do
......
...@@ -20,6 +20,9 @@ describe Gitlab::QuickActions::Dsl do ...@@ -20,6 +20,9 @@ describe Gitlab::QuickActions::Dsl do
desc do desc do
"A dynamic description for #{noteable.upcase}" "A dynamic description for #{noteable.upcase}"
end end
execution_message do |arg|
"A dynamic execution message for #{noteable.upcase} passing #{arg}"
end
params 'The first argument', 'The second argument' params 'The first argument', 'The second argument'
command :dynamic_description do |args| command :dynamic_description do |args|
args.split args.split
...@@ -30,6 +33,7 @@ describe Gitlab::QuickActions::Dsl do ...@@ -30,6 +33,7 @@ describe Gitlab::QuickActions::Dsl do
explanation do |arg| explanation do |arg|
"Action does something with #{arg}" "Action does something with #{arg}"
end end
execution_message 'Command applied correctly'
condition do condition do
project == 'foo' project == 'foo'
end end
...@@ -67,6 +71,7 @@ describe Gitlab::QuickActions::Dsl do ...@@ -67,6 +71,7 @@ describe Gitlab::QuickActions::Dsl do
expect(no_args_def.aliases).to eq([:none]) expect(no_args_def.aliases).to eq([:none])
expect(no_args_def.description).to eq('A command with no args') expect(no_args_def.description).to eq('A command with no args')
expect(no_args_def.explanation).to eq('') expect(no_args_def.explanation).to eq('')
expect(no_args_def.execution_message).to eq('')
expect(no_args_def.params).to eq([]) expect(no_args_def.params).to eq([])
expect(no_args_def.condition_block).to be_nil expect(no_args_def.condition_block).to be_nil
expect(no_args_def.types).to eq([]) expect(no_args_def.types).to eq([])
...@@ -78,6 +83,8 @@ describe Gitlab::QuickActions::Dsl do ...@@ -78,6 +83,8 @@ describe Gitlab::QuickActions::Dsl do
expect(explanation_with_aliases_def.aliases).to eq([:once, :first]) expect(explanation_with_aliases_def.aliases).to eq([:once, :first])
expect(explanation_with_aliases_def.description).to eq('') expect(explanation_with_aliases_def.description).to eq('')
expect(explanation_with_aliases_def.explanation).to eq('Static explanation') expect(explanation_with_aliases_def.explanation).to eq('Static explanation')
expect(explanation_with_aliases_def.execution_message).to eq('')
expect(no_args_def.params).to eq([])
expect(explanation_with_aliases_def.params).to eq(['The first argument']) expect(explanation_with_aliases_def.params).to eq(['The first argument'])
expect(explanation_with_aliases_def.condition_block).to be_nil expect(explanation_with_aliases_def.condition_block).to be_nil
expect(explanation_with_aliases_def.types).to eq([]) expect(explanation_with_aliases_def.types).to eq([])
...@@ -88,7 +95,7 @@ describe Gitlab::QuickActions::Dsl do ...@@ -88,7 +95,7 @@ describe Gitlab::QuickActions::Dsl do
expect(dynamic_description_def.name).to eq(:dynamic_description) expect(dynamic_description_def.name).to eq(:dynamic_description)
expect(dynamic_description_def.aliases).to eq([]) expect(dynamic_description_def.aliases).to eq([])
expect(dynamic_description_def.to_h(OpenStruct.new(noteable: 'issue'))[:description]).to eq('A dynamic description for ISSUE') expect(dynamic_description_def.to_h(OpenStruct.new(noteable: 'issue'))[:description]).to eq('A dynamic description for ISSUE')
expect(dynamic_description_def.explanation).to eq('') expect(dynamic_description_def.execute_message(OpenStruct.new(noteable: 'issue'), 'arg')).to eq('A dynamic execution message for ISSUE passing arg')
expect(dynamic_description_def.params).to eq(['The first argument', 'The second argument']) expect(dynamic_description_def.params).to eq(['The first argument', 'The second argument'])
expect(dynamic_description_def.condition_block).to be_nil expect(dynamic_description_def.condition_block).to be_nil
expect(dynamic_description_def.types).to eq([]) expect(dynamic_description_def.types).to eq([])
...@@ -100,6 +107,7 @@ describe Gitlab::QuickActions::Dsl do ...@@ -100,6 +107,7 @@ describe Gitlab::QuickActions::Dsl do
expect(cc_def.aliases).to eq([]) expect(cc_def.aliases).to eq([])
expect(cc_def.description).to eq('') expect(cc_def.description).to eq('')
expect(cc_def.explanation).to eq('') expect(cc_def.explanation).to eq('')
expect(cc_def.execution_message).to eq('')
expect(cc_def.params).to eq([]) expect(cc_def.params).to eq([])
expect(cc_def.condition_block).to be_nil expect(cc_def.condition_block).to be_nil
expect(cc_def.types).to eq([]) expect(cc_def.types).to eq([])
...@@ -111,6 +119,7 @@ describe Gitlab::QuickActions::Dsl do ...@@ -111,6 +119,7 @@ describe Gitlab::QuickActions::Dsl do
expect(cond_action_def.aliases).to eq([]) expect(cond_action_def.aliases).to eq([])
expect(cond_action_def.description).to eq('') expect(cond_action_def.description).to eq('')
expect(cond_action_def.explanation).to be_a_kind_of(Proc) expect(cond_action_def.explanation).to be_a_kind_of(Proc)
expect(cond_action_def.execution_message).to eq('Command applied correctly')
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.types).to eq([]) expect(cond_action_def.types).to eq([])
...@@ -122,6 +131,7 @@ describe Gitlab::QuickActions::Dsl do ...@@ -122,6 +131,7 @@ describe Gitlab::QuickActions::Dsl do
expect(with_params_parsing_def.aliases).to eq([]) expect(with_params_parsing_def.aliases).to eq([])
expect(with_params_parsing_def.description).to eq('') expect(with_params_parsing_def.description).to eq('')
expect(with_params_parsing_def.explanation).to eq('') expect(with_params_parsing_def.explanation).to eq('')
expect(with_params_parsing_def.execution_message).to eq('')
expect(with_params_parsing_def.params).to eq([]) expect(with_params_parsing_def.params).to eq([])
expect(with_params_parsing_def.condition_block).to be_nil expect(with_params_parsing_def.condition_block).to be_nil
expect(with_params_parsing_def.types).to eq([]) expect(with_params_parsing_def.types).to eq([])
...@@ -133,6 +143,7 @@ describe Gitlab::QuickActions::Dsl do ...@@ -133,6 +143,7 @@ describe Gitlab::QuickActions::Dsl do
expect(substitution_def.aliases).to eq([]) expect(substitution_def.aliases).to eq([])
expect(substitution_def.description).to eq('') expect(substitution_def.description).to eq('')
expect(substitution_def.explanation).to eq('') expect(substitution_def.explanation).to eq('')
expect(substitution_def.execution_message).to eq('')
expect(substitution_def.params).to eq(['<Comment>']) expect(substitution_def.params).to eq(['<Comment>'])
expect(substitution_def.condition_block).to be_nil expect(substitution_def.condition_block).to be_nil
expect(substitution_def.types).to eq([]) expect(substitution_def.types).to eq([])
...@@ -144,6 +155,7 @@ describe Gitlab::QuickActions::Dsl do ...@@ -144,6 +155,7 @@ describe Gitlab::QuickActions::Dsl do
expect(has_types.aliases).to eq([]) expect(has_types.aliases).to eq([])
expect(has_types.description).to eq('A command with types') expect(has_types.description).to eq('A command with types')
expect(has_types.explanation).to eq('') expect(has_types.explanation).to eq('')
expect(has_types.execution_message).to eq('')
expect(has_types.params).to eq([]) expect(has_types.params).to eq([])
expect(has_types.condition_block).to be_nil expect(has_types.condition_block).to be_nil
expect(has_types.types).to eq([Issue, Commit]) expect(has_types.types).to eq([Issue, Commit])
......
...@@ -28,61 +28,108 @@ describe QuickActions::InterpretService do ...@@ -28,61 +28,108 @@ describe QuickActions::InterpretService do
shared_examples 'reopen command' do shared_examples 'reopen command' do
it 'returns state_event: "reopen" if content contains /reopen' do it 'returns state_event: "reopen" if content contains /reopen' do
issuable.close! issuable.close!
_, updates = service.execute(content, issuable) _, updates, _ = service.execute(content, issuable)
expect(updates).to eq(state_event: 'reopen') expect(updates).to eq(state_event: 'reopen')
end end
it 'returns the reopen message' do
issuable.close!
_, _, message = service.execute(content, issuable)
expect(message).to eq("Reopened this #{issuable.to_ability_name.humanize(capitalize: false)}.")
end
end end
shared_examples 'close command' do shared_examples 'close command' do
it 'returns state_event: "close" if content contains /close' do it 'returns state_event: "close" if content contains /close' do
_, updates = service.execute(content, issuable) _, updates, _ = service.execute(content, issuable)
expect(updates).to eq(state_event: 'close') expect(updates).to eq(state_event: 'close')
end end
it 'returns the close message' do
_, _, message = service.execute(content, issuable)
expect(message).to eq("Closed this #{issuable.to_ability_name.humanize(capitalize: false)}.")
end
end end
shared_examples 'title command' do shared_examples 'title command' do
it 'populates title: "A brand new title" if content contains /title A brand new title' do it 'populates title: "A brand new title" if content contains /title A brand new title' do
_, updates = service.execute(content, issuable) _, updates, _ = service.execute(content, issuable)
expect(updates).to eq(title: 'A brand new title') expect(updates).to eq(title: 'A brand new title')
end end
it 'returns the title message' do
_, _, message = service.execute(content, issuable)
expect(message).to eq(%{Changed the title to "A brand new title".})
end
end end
shared_examples 'milestone command' do shared_examples 'milestone command' do
it 'fetches milestone and populates milestone_id if content contains /milestone' do it 'fetches milestone and populates milestone_id if content contains /milestone' do
milestone # populate the milestone milestone # populate the milestone
_, updates = service.execute(content, issuable) _, updates, _ = service.execute(content, issuable)
expect(updates).to eq(milestone_id: milestone.id) expect(updates).to eq(milestone_id: milestone.id)
end end
it 'returns the milestone message' do
milestone # populate the milestone
_, _, message = service.execute(content, issuable)
expect(message).to eq("Set the milestone to #{milestone.to_reference}.")
end
it 'returns empty milestone message when milestone is wrong' do
_, _, message = service.execute('/milestone %wrong-milestone', issuable)
expect(message).to be_empty
end
end end
shared_examples 'remove_milestone command' do shared_examples 'remove_milestone command' do
it 'populates milestone_id: nil if content contains /remove_milestone' do it 'populates milestone_id: nil if content contains /remove_milestone' do
issuable.update!(milestone_id: milestone.id) issuable.update!(milestone_id: milestone.id)
_, updates = service.execute(content, issuable) _, updates, _ = service.execute(content, issuable)
expect(updates).to eq(milestone_id: nil) expect(updates).to eq(milestone_id: nil)
end end
it 'returns removed milestone message' do
issuable.update!(milestone_id: milestone.id)
_, _, message = service.execute(content, issuable)
expect(message).to eq("Removed #{milestone.to_reference} milestone.")
end
end end
shared_examples 'label command' do shared_examples 'label command' do
it 'fetches label ids and populates add_label_ids if content contains /label' do it 'fetches label ids and populates add_label_ids if content contains /label' do
bug # populate the label bug # populate the label
inprogress # populate the label inprogress # populate the label
_, updates = service.execute(content, issuable) _, updates, _ = service.execute(content, issuable)
expect(updates).to eq(add_label_ids: [bug.id, inprogress.id]) expect(updates).to eq(add_label_ids: [bug.id, inprogress.id])
end end
it 'returns the label message' do
bug # populate the label
inprogress # populate the label
_, _, message = service.execute(content, issuable)
expect(message).to eq("Added #{bug.to_reference(format: :name)} #{inprogress.to_reference(format: :name)} labels.")
end
end end
shared_examples 'multiple label command' do shared_examples 'multiple label command' do
it 'fetches label ids and populates add_label_ids if content contains multiple /label' do it 'fetches label ids and populates add_label_ids if content contains multiple /label' do
bug # populate the label bug # populate the label
inprogress # populate the label inprogress # populate the label
_, updates = service.execute(content, issuable) _, updates, _ = service.execute(content, issuable)
expect(updates).to eq(add_label_ids: [inprogress.id, bug.id]) expect(updates).to eq(add_label_ids: [inprogress.id, bug.id])
end end
...@@ -91,7 +138,7 @@ describe QuickActions::InterpretService do ...@@ -91,7 +138,7 @@ describe QuickActions::InterpretService do
shared_examples 'multiple label with same argument' do shared_examples 'multiple label with same argument' do
it 'prevents duplicate label ids and populates add_label_ids if content contains multiple /label' do it 'prevents duplicate label ids and populates add_label_ids if content contains multiple /label' do
inprogress # populate the label inprogress # populate the label
_, updates = service.execute(content, issuable) _, updates, _ = service.execute(content, issuable)
expect(updates).to eq(add_label_ids: [inprogress.id]) expect(updates).to eq(add_label_ids: [inprogress.id])
end end
...@@ -120,16 +167,23 @@ describe QuickActions::InterpretService do ...@@ -120,16 +167,23 @@ describe QuickActions::InterpretService do
shared_examples 'unlabel command' do shared_examples 'unlabel command' do
it 'fetches label ids and populates remove_label_ids if content contains /unlabel' do it 'fetches label ids and populates remove_label_ids if content contains /unlabel' do
issuable.update!(label_ids: [inprogress.id]) # populate the label issuable.update!(label_ids: [inprogress.id]) # populate the label
_, updates = service.execute(content, issuable) _, updates, _ = service.execute(content, issuable)
expect(updates).to eq(remove_label_ids: [inprogress.id]) expect(updates).to eq(remove_label_ids: [inprogress.id])
end end
it 'returns the unlabel message' do
issuable.update!(label_ids: [inprogress.id]) # populate the label
_, _, message = service.execute(content, issuable)
expect(message).to eq("Removed #{inprogress.to_reference(format: :name)} label.")
end
end end
shared_examples 'multiple unlabel command' do shared_examples 'multiple unlabel command' do
it 'fetches label ids and populates remove_label_ids if content contains mutiple /unlabel' do it 'fetches label ids and populates remove_label_ids if content contains mutiple /unlabel' do
issuable.update!(label_ids: [inprogress.id, bug.id]) # populate the label issuable.update!(label_ids: [inprogress.id, bug.id]) # populate the label
_, updates = service.execute(content, issuable) _, updates, _ = service.execute(content, issuable)
expect(updates).to eq(remove_label_ids: [inprogress.id, bug.id]) expect(updates).to eq(remove_label_ids: [inprogress.id, bug.id])
end end
...@@ -138,7 +192,7 @@ describe QuickActions::InterpretService do ...@@ -138,7 +192,7 @@ describe QuickActions::InterpretService do
shared_examples 'unlabel command with no argument' do shared_examples 'unlabel command with no argument' do
it 'populates label_ids: [] if content contains /unlabel with no arguments' do it 'populates label_ids: [] if content contains /unlabel with no arguments' do
issuable.update!(label_ids: [inprogress.id]) # populate the label issuable.update!(label_ids: [inprogress.id]) # populate the label
_, updates = service.execute(content, issuable) _, updates, _ = service.execute(content, issuable)
expect(updates).to eq(label_ids: []) expect(updates).to eq(label_ids: [])
end end
...@@ -148,91 +202,161 @@ describe QuickActions::InterpretService do ...@@ -148,91 +202,161 @@ describe QuickActions::InterpretService do
it 'populates label_ids: [] if content contains /relabel' do it 'populates label_ids: [] if content contains /relabel' do
issuable.update!(label_ids: [bug.id]) # populate the label issuable.update!(label_ids: [bug.id]) # populate the label
inprogress # populate the label inprogress # populate the label
_, updates = service.execute(content, issuable) _, updates, _ = service.execute(content, issuable)
expect(updates).to eq(label_ids: [inprogress.id]) expect(updates).to eq(label_ids: [inprogress.id])
end end
it 'returns the relabel message' do
issuable.update!(label_ids: [bug.id]) # populate the label
inprogress # populate the label
_, _, message = service.execute(content, issuable)
expect(message).to eq("Replaced all labels with #{inprogress.to_reference(format: :name)} label.")
end
end end
shared_examples 'todo command' do shared_examples 'todo command' do
it 'populates todo_event: "add" if content contains /todo' do it 'populates todo_event: "add" if content contains /todo' do
_, updates = service.execute(content, issuable) _, updates, _ = service.execute(content, issuable)
expect(updates).to eq(todo_event: 'add') expect(updates).to eq(todo_event: 'add')
end end
it 'returns the todo message' do
_, _, message = service.execute(content, issuable)
expect(message).to eq('Added a todo.')
end
end end
shared_examples 'done command' do shared_examples 'done command' do
it 'populates todo_event: "done" if content contains /done' do it 'populates todo_event: "done" if content contains /done' do
TodoService.new.mark_todo(issuable, developer) TodoService.new.mark_todo(issuable, developer)
_, updates = service.execute(content, issuable) _, updates, _ = service.execute(content, issuable)
expect(updates).to eq(todo_event: 'done') expect(updates).to eq(todo_event: 'done')
end end
it 'returns the done message' do
TodoService.new.mark_todo(issuable, developer)
_, _, message = service.execute(content, issuable)
expect(message).to eq('Marked to do as done.')
end
end end
shared_examples 'subscribe command' do shared_examples 'subscribe command' do
it 'populates subscription_event: "subscribe" if content contains /subscribe' do it 'populates subscription_event: "subscribe" if content contains /subscribe' do
_, updates = service.execute(content, issuable) _, updates, _ = service.execute(content, issuable)
expect(updates).to eq(subscription_event: 'subscribe') expect(updates).to eq(subscription_event: 'subscribe')
end end
it 'returns the subscribe message' do
_, _, message = service.execute(content, issuable)
expect(message).to eq("Subscribed to this #{issuable.to_ability_name.humanize(capitalize: false)}.")
end
end end
shared_examples 'unsubscribe command' do shared_examples 'unsubscribe command' do
it 'populates subscription_event: "unsubscribe" if content contains /unsubscribe' do it 'populates subscription_event: "unsubscribe" if content contains /unsubscribe' do
issuable.subscribe(developer, project) issuable.subscribe(developer, project)
_, updates = service.execute(content, issuable) _, updates, _ = service.execute(content, issuable)
expect(updates).to eq(subscription_event: 'unsubscribe') expect(updates).to eq(subscription_event: 'unsubscribe')
end end
it 'returns the unsubscribe message' do
issuable.subscribe(developer, project)
_, _, message = service.execute(content, issuable)
expect(message).to eq("Unsubscribed from this #{issuable.to_ability_name.humanize(capitalize: false)}.")
end
end end
shared_examples 'due command' do shared_examples 'due command' do
let(:expected_date) { Date.new(2016, 8, 28) }
it 'populates due_date: Date.new(2016, 8, 28) if content contains /due 2016-08-28' do it 'populates due_date: Date.new(2016, 8, 28) if content contains /due 2016-08-28' do
_, updates = service.execute(content, issuable) _, updates, _ = service.execute(content, issuable)
expect(updates).to eq(due_date: expected_date)
end
expect(updates).to eq(due_date: defined?(expected_date) ? expected_date : Date.new(2016, 8, 28)) it 'returns due_date message: Date.new(2016, 8, 28) if content contains /due 2016-08-28' do
_, _, message = service.execute(content, issuable)
expect(message).to eq("Set the due date to #{expected_date.to_s(:medium)}.")
end end
end end
shared_examples 'remove_due_date command' do shared_examples 'remove_due_date command' do
it 'populates due_date: nil if content contains /remove_due_date' do before do
issuable.update!(due_date: Date.today) issuable.update!(due_date: Date.today)
_, updates = service.execute(content, issuable) end
it 'populates due_date: nil if content contains /remove_due_date' do
_, updates, _ = service.execute(content, issuable)
expect(updates).to eq(due_date: nil) expect(updates).to eq(due_date: nil)
end end
it 'returns Removed the due date' do
_, _, message = service.execute(content, issuable)
expect(message).to eq('Removed the due date.')
end
end end
shared_examples 'wip command' do shared_examples 'wip command' do
it 'returns wip_event: "wip" if content contains /wip' do it 'returns wip_event: "wip" if content contains /wip' do
_, updates = service.execute(content, issuable) _, updates, _ = service.execute(content, issuable)
expect(updates).to eq(wip_event: 'wip') expect(updates).to eq(wip_event: 'wip')
end end
it 'returns the wip message' do
_, _, message = service.execute(content, issuable)
expect(message).to eq("Marked this #{issuable.to_ability_name.humanize(capitalize: false)} as Work In Progress.")
end
end end
shared_examples 'unwip command' do shared_examples 'unwip command' do
it 'returns wip_event: "unwip" if content contains /wip' do it 'returns wip_event: "unwip" if content contains /wip' do
issuable.update!(title: issuable.wip_title) issuable.update!(title: issuable.wip_title)
_, updates = service.execute(content, issuable) _, updates, _ = service.execute(content, issuable)
expect(updates).to eq(wip_event: 'unwip') expect(updates).to eq(wip_event: 'unwip')
end end
it 'returns the unwip message' do
issuable.update!(title: issuable.wip_title)
_, _, message = service.execute(content, issuable)
expect(message).to eq("Unmarked this #{issuable.to_ability_name.humanize(capitalize: false)} as Work In Progress.")
end
end end
shared_examples 'estimate command' do shared_examples 'estimate command' do
it 'populates time_estimate: 3600 if content contains /estimate 1h' do it 'populates time_estimate: 3600 if content contains /estimate 1h' do
_, updates = service.execute(content, issuable) _, updates, _ = service.execute(content, issuable)
expect(updates).to eq(time_estimate: 3600) expect(updates).to eq(time_estimate: 3600)
end end
it 'returns the time_estimate formatted message' do
_, _, message = service.execute('/estimate 79d', issuable)
expect(message).to eq('Set time estimate to 3mo 3w 4d.')
end
end end
shared_examples 'spend command' do shared_examples 'spend command' do
it 'populates spend_time: 3600 if content contains /spend 1h' do it 'populates spend_time: 3600 if content contains /spend 1h' do
_, updates = service.execute(content, issuable) _, updates, _ = service.execute(content, issuable)
expect(updates).to eq(spend_time: { expect(updates).to eq(spend_time: {
duration: 3600, duration: 3600,
...@@ -240,11 +364,17 @@ describe QuickActions::InterpretService do ...@@ -240,11 +364,17 @@ describe QuickActions::InterpretService do
spent_at: DateTime.now.to_date spent_at: DateTime.now.to_date
}) })
end end
it 'returns the spend_time message including the formatted duration and verb' do
_, _, message = service.execute('/spend -120m', issuable)
expect(message).to eq('Subtracted 2h spent time.')
end
end end
shared_examples 'spend command with negative time' do shared_examples 'spend command with negative time' do
it 'populates spend_time: -1800 if content contains /spend -30m' do it 'populates spend_time: -1800 if content contains /spend -30m' do
_, updates = service.execute(content, issuable) _, updates, _ = service.execute(content, issuable)
expect(updates).to eq(spend_time: { expect(updates).to eq(spend_time: {
duration: -1800, duration: -1800,
...@@ -256,7 +386,7 @@ describe QuickActions::InterpretService do ...@@ -256,7 +386,7 @@ describe QuickActions::InterpretService do
shared_examples 'spend command with valid date' do shared_examples 'spend command with valid date' do
it 'populates spend time: 1800 with date in date type format' do it 'populates spend time: 1800 with date in date type format' do
_, updates = service.execute(content, issuable) _, updates, _ = service.execute(content, issuable)
expect(updates).to eq(spend_time: { expect(updates).to eq(spend_time: {
duration: 1800, duration: 1800,
...@@ -268,7 +398,7 @@ describe QuickActions::InterpretService do ...@@ -268,7 +398,7 @@ describe QuickActions::InterpretService do
shared_examples 'spend command with invalid date' do shared_examples 'spend command with invalid date' do
it 'will not create any note and timelog' do it 'will not create any note and timelog' do
_, updates = service.execute(content, issuable) _, updates, _ = service.execute(content, issuable)
expect(updates).to eq({}) expect(updates).to eq({})
end end
...@@ -276,7 +406,7 @@ describe QuickActions::InterpretService do ...@@ -276,7 +406,7 @@ describe QuickActions::InterpretService do
shared_examples 'spend command with future date' do shared_examples 'spend command with future date' do
it 'will not create any note and timelog' do it 'will not create any note and timelog' do
_, updates = service.execute(content, issuable) _, updates, _ = service.execute(content, issuable)
expect(updates).to eq({}) expect(updates).to eq({})
end end
...@@ -284,18 +414,30 @@ describe QuickActions::InterpretService do ...@@ -284,18 +414,30 @@ describe QuickActions::InterpretService do
shared_examples 'remove_estimate command' do shared_examples 'remove_estimate command' do
it 'populates time_estimate: 0 if content contains /remove_estimate' do it 'populates time_estimate: 0 if content contains /remove_estimate' do
_, updates = service.execute(content, issuable) _, updates, _ = service.execute(content, issuable)
expect(updates).to eq(time_estimate: 0) expect(updates).to eq(time_estimate: 0)
end end
it 'returns the remove_estimate message' do
_, _, message = service.execute(content, issuable)
expect(message).to eq('Removed time estimate.')
end
end end
shared_examples 'remove_time_spent command' do shared_examples 'remove_time_spent command' do
it 'populates spend_time: :reset if content contains /remove_time_spent' do it 'populates spend_time: :reset if content contains /remove_time_spent' do
_, updates = service.execute(content, issuable) _, updates, _ = service.execute(content, issuable)
expect(updates).to eq(spend_time: { duration: :reset, user_id: developer.id }) expect(updates).to eq(spend_time: { duration: :reset, user_id: developer.id })
end end
it 'returns the remove_time_spent message' do
_, _, message = service.execute(content, issuable)
expect(message).to eq('Removed spent time.')
end
end end
shared_examples 'lock command' do shared_examples 'lock command' do
...@@ -303,10 +445,16 @@ describe QuickActions::InterpretService do ...@@ -303,10 +445,16 @@ describe QuickActions::InterpretService do
let(:merge_request) { create(:merge_request, source_project: project, discussion_locked: false) } let(:merge_request) { create(:merge_request, source_project: project, discussion_locked: false) }
it 'returns discussion_locked: true if content contains /lock' do it 'returns discussion_locked: true if content contains /lock' do
_, updates = service.execute(content, issuable) _, updates, _ = service.execute(content, issuable)
expect(updates).to eq(discussion_locked: true) expect(updates).to eq(discussion_locked: true)
end end
it 'returns the lock discussion message' do
_, _, message = service.execute(content, issuable)
expect(message).to eq('Locked the discussion')
end
end end
shared_examples 'unlock command' do shared_examples 'unlock command' do
...@@ -314,45 +462,79 @@ describe QuickActions::InterpretService do ...@@ -314,45 +462,79 @@ describe QuickActions::InterpretService do
let(:merge_request) { create(:merge_request, source_project: project, discussion_locked: true) } let(:merge_request) { create(:merge_request, source_project: project, discussion_locked: true) }
it 'returns discussion_locked: true if content contains /unlock' do it 'returns discussion_locked: true if content contains /unlock' do
_, updates = service.execute(content, issuable) _, updates, _ = service.execute(content, issuable)
expect(updates).to eq(discussion_locked: false) expect(updates).to eq(discussion_locked: false)
end end
it 'returns the unlock discussion message' do
_, _, message = service.execute(content, issuable)
expect(message).to eq('Unlocked the discussion')
end
end end
shared_examples 'empty command' do shared_examples 'empty command' do |error_msg|
it 'populates {} if content contains an unsupported command' do it 'populates {} if content contains an unsupported command' do
_, updates = service.execute(content, issuable) _, updates, _ = service.execute(content, issuable)
expect(updates).to be_empty expect(updates).to be_empty
end end
it "returns #{error_msg || 'an empty'} message" do
_, _, message = service.execute(content, issuable)
if error_msg
expect(message).to eq(error_msg)
else
expect(message).to be_empty
end
end
end end
shared_examples 'merge command' do shared_examples 'merge command' do
let(:project) { create(:project, :repository) } let(:project) { create(:project, :repository) }
it 'runs merge command if content contains /merge' do it 'runs merge command if content contains /merge' do
_, updates = service.execute(content, issuable) _, updates, _ = service.execute(content, issuable)
expect(updates).to eq(merge: merge_request.diff_head_sha) expect(updates).to eq(merge: merge_request.diff_head_sha)
end end
it 'returns them merge message' do
_, _, message = service.execute(content, issuable)
expect(message).to eq('Scheduled to merge this merge request when the pipeline succeeds.')
end
end end
shared_examples 'award command' do shared_examples 'award command' do
it 'toggle award 100 emoji if content contains /award :100:' do it 'toggle award 100 emoji if content contains /award :100:' do
_, updates = service.execute(content, issuable) _, updates, _ = service.execute(content, issuable)
expect(updates).to eq(emoji_award: "100") expect(updates).to eq(emoji_award: "100")
end end
it 'returns the award message' do
_, _, message = service.execute(content, issuable)
expect(message).to eq('Toggled :100: emoji award.')
end
end end
shared_examples 'duplicate command' do shared_examples 'duplicate command' do
it 'fetches issue and populates canonical_issue_id if content contains /duplicate issue_reference' do it 'fetches issue and populates canonical_issue_id if content contains /duplicate issue_reference' do
issue_duplicate # populate the issue issue_duplicate # populate the issue
_, updates = service.execute(content, issuable) _, updates, _ = service.execute(content, issuable)
expect(updates).to eq(canonical_issue_id: issue_duplicate.id) expect(updates).to eq(canonical_issue_id: issue_duplicate.id)
end end
it 'returns the duplicate message' do
_, _, message = service.execute(content, issuable)
expect(message).to eq("Marked this issue as a duplicate of #{issue_duplicate.to_reference(project)}.")
end
end end
shared_examples 'copy_metadata command' do shared_examples 'copy_metadata command' do
...@@ -360,7 +542,7 @@ describe QuickActions::InterpretService do ...@@ -360,7 +542,7 @@ describe QuickActions::InterpretService do
source_issuable # populate the issue source_issuable # populate the issue
todo_label # populate this label todo_label # populate this label
inreview_label # populate this label inreview_label # populate this label
_, updates = service.execute(content, issuable) _, updates, _ = service.execute(content, issuable)
expect(updates[:add_label_ids]).to match_array([inreview_label.id, todo_label.id]) expect(updates[:add_label_ids]).to match_array([inreview_label.id, todo_label.id])
...@@ -370,19 +552,45 @@ describe QuickActions::InterpretService do ...@@ -370,19 +552,45 @@ describe QuickActions::InterpretService do
expect(updates).not_to have_key(:milestone_id) expect(updates).not_to have_key(:milestone_id)
end end
end end
it 'returns the copy metadata message' do
_, _, message = service.execute("/copy_metadata #{source_issuable.to_reference}", issuable)
expect(message).to eq("Copied labels and milestone from #{source_issuable.to_reference}.")
end
end
describe 'move issue command' do
it 'returns the move issue message' do
_, _, message = service.execute("/move #{project.full_path}", issue)
expect(message).to eq("Moved this issue to #{project.full_path}.")
end
it 'returns move issue failure message when the referenced issue is not found' do
_, _, message = service.execute('/move invalid', issue)
expect(message).to eq("Move this issue failed because target project doesn't exists")
end
end end
shared_examples 'confidential command' do shared_examples 'confidential command' do
it 'marks issue as confidential if content contains /confidential' do it 'marks issue as confidential if content contains /confidential' do
_, updates = service.execute(content, issuable) _, updates, _ = service.execute(content, issuable)
expect(updates).to eq(confidential: true) expect(updates).to eq(confidential: true)
end end
it 'returns the confidential message' do
_, _, message = service.execute(content, issuable)
expect(message).to eq('Made this issue confidential')
end
end end
shared_examples 'shrug command' do shared_examples 'shrug command' do
it 'appends ¯\_(ツ)_/¯ to the comment' do it 'appends ¯\_(ツ)_/¯ to the comment' do
new_content, _ = service.execute(content, issuable) new_content, _, _ = service.execute(content, issuable)
expect(new_content).to end_with(described_class::SHRUG) expect(new_content).to end_with(described_class::SHRUG)
end end
...@@ -390,7 +598,7 @@ describe QuickActions::InterpretService do ...@@ -390,7 +598,7 @@ describe QuickActions::InterpretService do
shared_examples 'tableflip command' do shared_examples 'tableflip command' do
it 'appends (╯°□°)╯︵ ┻━┻ to the comment' do it 'appends (╯°□°)╯︵ ┻━┻ to the comment' do
new_content, _ = service.execute(content, issuable) new_content, _, _ = service.execute(content, issuable)
expect(new_content).to end_with(described_class::TABLEFLIP) expect(new_content).to end_with(described_class::TABLEFLIP)
end end
...@@ -398,18 +606,34 @@ describe QuickActions::InterpretService do ...@@ -398,18 +606,34 @@ describe QuickActions::InterpretService do
shared_examples 'tag command' do shared_examples 'tag command' do
it 'tags a commit' do it 'tags a commit' do
_, updates = service.execute(content, issuable) _, updates, _ = service.execute(content, issuable)
expect(updates).to eq(tag_name: tag_name, tag_message: tag_message) expect(updates).to eq(tag_name: tag_name, tag_message: tag_message)
end end
it 'returns the tag message' do
_, _, message = service.execute(content, issuable)
if tag_message.present?
expect(message).to eq(%{Tagged this commit to #{tag_name} with "#{tag_message}".})
else
expect(message).to eq("Tagged this commit to #{tag_name}.")
end
end
end end
shared_examples 'assign command' do shared_examples 'assign command' do
it 'assigns to a single user' do it 'assigns to a single user' do
_, updates = service.execute(content, issuable) _, updates, _ = service.execute(content, issuable)
expect(updates).to eq(assignee_ids: [developer.id]) expect(updates).to eq(assignee_ids: [developer.id])
end end
it 'returns the assign message' do
_, _, message = service.execute(content, issuable)
expect(message).to eq("Assigned #{developer.to_reference}.")
end
end end
it_behaves_like 'reopen command' do it_behaves_like 'reopen command' do
...@@ -463,7 +687,7 @@ describe QuickActions::InterpretService do ...@@ -463,7 +687,7 @@ describe QuickActions::InterpretService do
let(:service) { described_class.new(project, developer, {}) } let(:service) { described_class.new(project, developer, {}) }
it 'precheck passes and returns merge command' do it 'precheck passes and returns merge command' do
_, updates = service.execute('/merge', merge_request) _, updates, _ = service.execute('/merge', merge_request)
expect(updates).to eq(merge: nil) expect(updates).to eq(merge: nil)
end end
...@@ -559,7 +783,7 @@ describe QuickActions::InterpretService do ...@@ -559,7 +783,7 @@ describe QuickActions::InterpretService do
end end
end end
it_behaves_like 'empty command' do it_behaves_like 'empty command', "Assign command failed because no user was found" do
let(:content) { '/assign @abcd1234' } let(:content) { '/assign @abcd1234' }
let(:issuable) { issue } let(:issuable) { issue }
end end
...@@ -575,19 +799,33 @@ describe QuickActions::InterpretService do ...@@ -575,19 +799,33 @@ describe QuickActions::InterpretService do
context 'Issue' do context 'Issue' do
it 'populates assignee_ids: [] if content contains /unassign' do it 'populates assignee_ids: [] if content contains /unassign' do
issue.update!(assignee_ids: [developer.id]) issue.update!(assignee_ids: [developer.id])
_, updates = service.execute(content, issue) _, updates, _ = service.execute(content, issue)
expect(updates).to eq(assignee_ids: []) expect(updates).to eq(assignee_ids: [])
end end
it 'returns the unassign message for all the assignee if content contains /unassign' do
issue.update(assignee_ids: [developer.id, developer2.id])
_, _, message = service.execute(content, issue)
expect(message).to eq("Removed assignees #{developer.to_reference} and #{developer2.to_reference}.")
end
end end
context 'Merge Request' do context 'Merge Request' do
it 'populates assignee_ids: [] if content contains /unassign' do it 'populates assignee_ids: [] if content contains /unassign' do
merge_request.update!(assignee_ids: [developer.id]) merge_request.update!(assignee_ids: [developer.id])
_, updates = service.execute(content, merge_request) _, updates, _ = service.execute(content, merge_request)
expect(updates).to eq(assignee_ids: []) expect(updates).to eq(assignee_ids: [])
end end
it 'returns the unassign message for all the assignee if content contains /unassign' do
merge_request.update(assignee_ids: [developer.id, developer2.id])
_, _, message = service.execute(content, merge_request)
expect(message).to eq("Removed assignees #{developer.to_reference} and #{developer2.to_reference}.")
end
end end
end end
...@@ -979,12 +1217,12 @@ describe QuickActions::InterpretService do ...@@ -979,12 +1217,12 @@ describe QuickActions::InterpretService do
let(:issuable) { issue } let(:issuable) { issue }
end end
it_behaves_like 'empty command' do it_behaves_like 'empty command', 'Mark as duplicate failed because referenced issue was not found' do
let(:content) { "/duplicate imaginary#1234" } let(:content) { "/duplicate imaginary#1234" }
let(:issuable) { issue } let(:issuable) { issue }
end end
it_behaves_like 'empty command' do it_behaves_like 'empty command', 'Mark as duplicate failed because referenced issue was not found' do
let(:other_project) { create(:project, :private) } let(:other_project) { create(:project, :private) }
let(:issue_duplicate) { create(:issue, project: other_project) } let(:issue_duplicate) { create(:issue, project: other_project) }
...@@ -1049,7 +1287,7 @@ describe QuickActions::InterpretService do ...@@ -1049,7 +1287,7 @@ describe QuickActions::InterpretService do
let(:issuable) { issue } let(:issuable) { issue }
end end
it_behaves_like 'empty command' do it_behaves_like 'empty command', 'Mark as duplicate failed because referenced issue was not found' do
let(:content) { '/duplicate #{issue.to_reference}' } let(:content) { '/duplicate #{issue.to_reference}' }
let(:issuable) { issue } let(:issuable) { issue }
end end
...@@ -1132,13 +1370,13 @@ describe QuickActions::InterpretService do ...@@ -1132,13 +1370,13 @@ describe QuickActions::InterpretService do
let(:service) { described_class.new(non_empty_project, developer)} let(:service) { described_class.new(non_empty_project, developer)}
it 'updates target_branch if /target_branch command is executed' do it 'updates target_branch if /target_branch command is executed' do
_, updates = service.execute('/target_branch merge-test', merge_request) _, updates, _ = service.execute('/target_branch merge-test', merge_request)
expect(updates).to eq(target_branch: 'merge-test') expect(updates).to eq(target_branch: 'merge-test')
end end
it 'handles blanks around param' do it 'handles blanks around param' do
_, updates = service.execute('/target_branch merge-test ', merge_request) _, updates, _ = service.execute('/target_branch merge-test ', merge_request)
expect(updates).to eq(target_branch: 'merge-test') expect(updates).to eq(target_branch: 'merge-test')
end end
...@@ -1156,6 +1394,12 @@ describe QuickActions::InterpretService do ...@@ -1156,6 +1394,12 @@ describe QuickActions::InterpretService do
let(:issuable) { another_merge_request } let(:issuable) { another_merge_request }
end end
end end
it 'returns the target_branch message' do
_, _, message = service.execute('/target_branch merge-test', merge_request)
expect(message).to eq('Set target branch to merge-test.')
end
end end
context '/board_move command' do context '/board_move command' do
...@@ -1171,13 +1415,13 @@ describe QuickActions::InterpretService do ...@@ -1171,13 +1415,13 @@ describe QuickActions::InterpretService do
it 'populates remove_label_ids for all current board columns' do it 'populates remove_label_ids for all current board columns' do
issue.update!(label_ids: [todo.id, inprogress.id]) issue.update!(label_ids: [todo.id, inprogress.id])
_, updates = service.execute(content, issue) _, updates, _ = service.execute(content, issue)
expect(updates[:remove_label_ids]).to match_array([todo.id, inprogress.id]) expect(updates[:remove_label_ids]).to match_array([todo.id, inprogress.id])
end end
it 'populates add_label_ids with the id of the given label' do it 'populates add_label_ids with the id of the given label' do
_, updates = service.execute(content, issue) _, updates, _ = service.execute(content, issue)
expect(updates[:add_label_ids]).to eq([inreview.id]) expect(updates[:add_label_ids]).to eq([inreview.id])
end end
...@@ -1185,7 +1429,7 @@ describe QuickActions::InterpretService do ...@@ -1185,7 +1429,7 @@ describe QuickActions::InterpretService do
it 'does not include the given label id in remove_label_ids' do it 'does not include the given label id in remove_label_ids' do
issue.update!(label_ids: [todo.id, inreview.id]) issue.update!(label_ids: [todo.id, inreview.id])
_, updates = service.execute(content, issue) _, updates, _ = service.execute(content, issue)
expect(updates[:remove_label_ids]).to match_array([todo.id]) expect(updates[:remove_label_ids]).to match_array([todo.id])
end end
...@@ -1193,11 +1437,19 @@ describe QuickActions::InterpretService do ...@@ -1193,11 +1437,19 @@ describe QuickActions::InterpretService do
it 'does not remove label ids that are not lists on the board' do it 'does not remove label ids that are not lists on the board' do
issue.update!(label_ids: [todo.id, bug.id]) issue.update!(label_ids: [todo.id, bug.id])
_, updates = service.execute(content, issue) _, updates, _ = service.execute(content, issue)
expect(updates[:remove_label_ids]).to match_array([todo.id]) expect(updates[:remove_label_ids]).to match_array([todo.id])
end end
it 'returns board_move message' do
issue.update!(label_ids: [todo.id, inprogress.id])
_, _, message = service.execute(content, issue)
expect(message).to eq("Moved issue to ~#{inreview.id} column in the board.")
end
context 'if the project has multiple boards' do context 'if the project has multiple boards' do
let(:issuable) { issue } let(:issuable) { issue }
...@@ -1211,13 +1463,13 @@ describe QuickActions::InterpretService do ...@@ -1211,13 +1463,13 @@ describe QuickActions::InterpretService do
context 'if the given label does not exist' do context 'if the given label does not exist' do
let(:issuable) { issue } let(:issuable) { issue }
let(:content) { '/board_move ~"Fake Label"' } let(:content) { '/board_move ~"Fake Label"' }
it_behaves_like 'empty command' it_behaves_like 'empty command', 'Move this issue failed because you need to specify only one label.'
end end
context 'if multiple labels are given' do context 'if multiple labels are given' do
let(:issuable) { issue } let(:issuable) { issue }
let(:content) { %{/board_move ~"#{inreview.title}" ~"#{todo.title}"} } let(:content) { %{/board_move ~"#{inreview.title}" ~"#{todo.title}"} }
it_behaves_like 'empty command' it_behaves_like 'empty command', 'Move this issue failed because you need to specify only one label.'
end end
context 'if the given label is not a list on the board' do context 'if the given label is not a list on the board' do
...@@ -1292,10 +1544,16 @@ describe QuickActions::InterpretService do ...@@ -1292,10 +1544,16 @@ describe QuickActions::InterpretService do
end end
it 'populates create_merge_request with branch_name and issue iid' do it 'populates create_merge_request with branch_name and issue iid' do
_, updates = service.execute(content, issuable) _, updates, _ = service.execute(content, issuable)
expect(updates).to eq(create_merge_request: { branch_name: branch_name, issue_iid: issuable.iid }) expect(updates).to eq(create_merge_request: { branch_name: branch_name, issue_iid: issuable.iid })
end end
it 'returns the create_merge_request message' do
_, _, message = service.execute(content, issuable)
expect(message).to eq("Created branch '#{branch_name}' and a merge request to resolve this issue")
end
end end
end end
...@@ -1558,6 +1816,12 @@ describe QuickActions::InterpretService do ...@@ -1558,6 +1816,12 @@ describe QuickActions::InterpretService do
expect(explanations).to eq(['Creates a branch and a merge request to resolve this issue']) expect(explanations).to eq(['Creates a branch and a merge request to resolve this issue'])
end end
it 'returns the execution message using the default branch name' do
_, _, message = service.execute(content, issue)
expect(message).to eq('Created a branch and a merge request to resolve this issue')
end
end end
context 'with a branch name' do context 'with a branch name' do
...@@ -1568,6 +1832,12 @@ describe QuickActions::InterpretService do ...@@ -1568,6 +1832,12 @@ describe QuickActions::InterpretService do
expect(explanations).to eq(["Creates branch 'foo' and a merge request to resolve this issue"]) expect(explanations).to eq(["Creates branch 'foo' and a merge request to resolve this issue"])
end end
it 'returns the execution message using the given branch name' do
_, _, message = service.execute(content, issue)
expect(message).to eq("Created branch 'foo' and a merge request to resolve this issue")
end
end end
end end
......
...@@ -5,7 +5,7 @@ shared_examples 'tag quick action' do ...@@ -5,7 +5,7 @@ shared_examples 'tag quick action' do
it 'tags this commit' do it 'tags this commit' do
add_note("/tag #{tag_name} #{tag_message}") add_note("/tag #{tag_name} #{tag_message}")
expect(page).to have_content 'Commands applied' expect(page).to have_content %{Tagged this commit to #{tag_name} with "#{tag_message}".}
expect(page).to have_content "tagged commit #{truncated_commit_sha}" expect(page).to have_content "tagged commit #{truncated_commit_sha}"
expect(page).to have_content tag_name expect(page).to have_content tag_name
......
...@@ -68,7 +68,7 @@ shared_examples 'close quick action' do |issuable_type| ...@@ -68,7 +68,7 @@ shared_examples 'close quick action' do |issuable_type|
it "does not close the #{issuable_type}" do it "does not close the #{issuable_type}" do
add_note('/close') add_note('/close')
expect(page).not_to have_content 'Commands applied' expect(page).not_to have_content "Closed this #{issuable.to_ability_name.humanize(capitalize: false)}."
expect(issuable).to be_open expect(issuable).to be_open
end end
end end
......
...@@ -2,8 +2,14 @@ ...@@ -2,8 +2,14 @@
shared_examples 'create_merge_request quick action' do shared_examples 'create_merge_request quick action' do
context 'create a merge request starting from an issue' do context 'create a merge request starting from an issue' do
def expect_mr_quickaction(success) def expect_mr_quickaction(success, branch_name = nil)
expect(page).to have_content 'Commands applied' command_message = if branch_name
"Created branch '#{branch_name}' and a merge request to resolve this issue"
else
"Created a branch and a merge request to resolve this issue"
end
expect(page).to have_content command_message
if success if success
expect(page).to have_content 'created merge request' expect(page).to have_content 'created merge request'
...@@ -13,19 +19,21 @@ shared_examples 'create_merge_request quick action' do ...@@ -13,19 +19,21 @@ shared_examples 'create_merge_request quick action' do
end end
it "doesn't create a merge request when the branch name is invalid" do it "doesn't create a merge request when the branch name is invalid" do
add_note("/create_merge_request invalid branch name") branch_name = 'invalid branch name'
add_note("/create_merge_request #{branch_name}")
wait_for_requests wait_for_requests
expect_mr_quickaction(false) expect_mr_quickaction(false, branch_name)
end end
it "doesn't create a merge request when a branch with that name already exists" do it "doesn't create a merge request when a branch with that name already exists" do
add_note("/create_merge_request feature") branch_name = 'feature'
add_note("/create_merge_request #{branch_name}")
wait_for_requests wait_for_requests
expect_mr_quickaction(false) expect_mr_quickaction(false, branch_name)
end end
it 'creates a new merge request using issue iid and title as branch name when the branch name is empty' do it 'creates a new merge request using issue iid and title as branch name when the branch name is empty' do
...@@ -46,7 +54,7 @@ shared_examples 'create_merge_request quick action' do ...@@ -46,7 +54,7 @@ shared_examples 'create_merge_request quick action' do
branch_name = '1-feature' branch_name = '1-feature'
add_note("/create_merge_request #{branch_name}") add_note("/create_merge_request #{branch_name}")
expect_mr_quickaction(true) expect_mr_quickaction(true, branch_name)
created_mr = project.merge_requests.last created_mr = project.merge_requests.last
expect(created_mr.source_branch).to eq(branch_name) expect(created_mr.source_branch).to eq(branch_name)
......
...@@ -9,7 +9,6 @@ shared_examples 'duplicate quick action' do ...@@ -9,7 +9,6 @@ shared_examples 'duplicate quick action' do
add_note("/duplicate ##{original_issue.to_reference}") add_note("/duplicate ##{original_issue.to_reference}")
expect(page).not_to have_content "/duplicate #{original_issue.to_reference}" expect(page).not_to have_content "/duplicate #{original_issue.to_reference}"
expect(page).to have_content 'Commands applied'
expect(page).to have_content "marked this issue as a duplicate of #{original_issue.to_reference}" expect(page).to have_content "marked this issue as a duplicate of #{original_issue.to_reference}"
expect(issue.reload).to be_closed expect(issue.reload).to be_closed
...@@ -28,7 +27,6 @@ shared_examples 'duplicate quick action' do ...@@ -28,7 +27,6 @@ shared_examples 'duplicate quick action' do
it 'does not create a note, and does not mark the issue as a duplicate' do it 'does not create a note, and does not mark the issue as a duplicate' do
add_note("/duplicate ##{original_issue.to_reference}") add_note("/duplicate ##{original_issue.to_reference}")
expect(page).not_to have_content 'Commands applied'
expect(page).not_to have_content "marked this issue as a duplicate of #{original_issue.to_reference}" expect(page).not_to have_content "marked this issue as a duplicate of #{original_issue.to_reference}"
expect(issue.reload).to be_open expect(issue.reload).to be_open
......
...@@ -12,7 +12,7 @@ shared_examples 'move quick action' do ...@@ -12,7 +12,7 @@ shared_examples 'move quick action' do
it 'moves the issue' do it 'moves the issue' do
add_note("/move #{target_project.full_path}") add_note("/move #{target_project.full_path}")
expect(page).to have_content 'Commands applied' expect(page).to have_content "Moved this issue to #{target_project.full_path}."
expect(issue.reload).to be_closed expect(issue.reload).to be_closed
visit project_issue_path(target_project, issue) visit project_issue_path(target_project, issue)
...@@ -29,7 +29,7 @@ shared_examples 'move quick action' do ...@@ -29,7 +29,7 @@ shared_examples 'move quick action' do
wait_for_requests wait_for_requests
expect(page).to have_content 'Commands applied' expect(page).to have_content "Moved this issue to #{project_unauthorized.full_path}."
expect(issue.reload).to be_open expect(issue.reload).to be_open
end end
end end
...@@ -40,7 +40,7 @@ shared_examples 'move quick action' do ...@@ -40,7 +40,7 @@ shared_examples 'move quick action' do
wait_for_requests wait_for_requests
expect(page).to have_content 'Commands applied' expect(page).to have_content "Move this issue failed because target project doesn't exists"
expect(issue.reload).to be_open expect(issue.reload).to be_open
end end
end end
...@@ -56,7 +56,7 @@ shared_examples 'move quick action' do ...@@ -56,7 +56,7 @@ shared_examples 'move quick action' do
shared_examples 'applies the commands to issues in both projects, target and source' do shared_examples 'applies the commands to issues in both projects, target and source' do
it "applies quick actions" do it "applies quick actions" do
expect(page).to have_content 'Commands applied' expect(page).to have_content "Moved this issue to #{target_project.full_path}."
expect(issue.reload).to be_closed expect(issue.reload).to be_closed
visit project_issue_path(target_project, issue) visit project_issue_path(target_project, issue)
......
...@@ -10,7 +10,7 @@ shared_examples 'merge quick action' do ...@@ -10,7 +10,7 @@ shared_examples 'merge quick action' do
it 'merges the MR' do it 'merges the MR' do
add_note("/merge") add_note("/merge")
expect(page).to have_content 'Commands applied' expect(page).to have_content 'Scheduled to merge this merge request when the pipeline succeeds.'
expect(merge_request.reload).to be_merged expect(merge_request.reload).to be_merged
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