Commit ea090291 authored by Eric Eastwood's avatar Eric Eastwood

Rename "Slash commands" to "Quick actions"

Fix https://gitlab.com/gitlab-org/gitlab-ce/issues/27070

Deprecate "chat commands" in favor of "slash commands"

We looked for things like:

 - `slash commmand`
 - `slash_command`
 - `slash-command`
 - `SlashCommand`
parent 42aaae99
......@@ -34,7 +34,7 @@ class GfmAutoComplete {
const $input = $(input);
$input.off('focus.setupAtWho').on('focus.setupAtWho', this.setupAtWho.bind(this, $input));
// This triggers at.js again
// Needed for slash commands with suffixes (ex: /label ~)
// Needed for quick actions with suffixes (ex: /label ~)
$input.on('inserted-commands.atwho', $input.trigger.bind($input, 'keyup'));
$input.on('clear-commands-cache.atwho', () => this.clearCache());
});
......@@ -48,8 +48,8 @@ class GfmAutoComplete {
if (this.enableMap.mergeRequests) this.setupMergeRequests($input);
if (this.enableMap.labels) this.setupLabels($input);
// We don't instantiate the slash commands autocomplete for note and issue/MR edit forms
$input.filter('[data-supports-slash-commands="true"]').atwho({
// We don't instantiate the quick actions autocomplete for note and issue/MR edit forms
$input.filter('[data-supports-quick-actions="true"]').atwho({
at: '/',
alias: 'commands',
searchKey: 'search',
......
......@@ -41,7 +41,7 @@
<textarea
id="issue-description"
class="note-textarea js-gfm-input js-autosize markdown-area"
data-supports-slash-commands="false"
data-supports-quick-actionss="false"
aria-label="Description"
v-model="formState.description"
ref="textarea"
......
......@@ -32,7 +32,7 @@ const normalizeNewlines = function(str) {
(function() {
this.Notes = (function() {
const MAX_VISIBLE_COMMIT_LIST_COUNT = 3;
const REGEX_SLASH_COMMANDS = /^\/\w+.*$/gm;
const REGEX_QUICK_ACTIONS = /^\/\w+.*$/gm;
Notes.interval = null;
......@@ -280,7 +280,7 @@ const normalizeNewlines = function(str) {
return this.initRefresh();
};
Notes.prototype.handleSlashCommands = function(noteEntity) {
Notes.prototype.handleQuickActions = function(noteEntity) {
var votesBlock;
if (noteEntity.commands_changes) {
if ('merge' in noteEntity.commands_changes) {
......@@ -1198,27 +1198,27 @@ const normalizeNewlines = function(str) {
};
/**
* Identify if comment has any slash commands
* Identify if comment has any quick actions
*/
Notes.prototype.hasSlashCommands = function(formContent) {
return REGEX_SLASH_COMMANDS.test(formContent);
Notes.prototype.hasQuickActions = function(formContent) {
return REGEX_QUICK_ACTIONS.test(formContent);
};
/**
* Remove slash commands and leave comment with pure message
* Remove quick actions and leave comment with pure message
*/
Notes.prototype.stripSlashCommands = function(formContent) {
return formContent.replace(REGEX_SLASH_COMMANDS, '').trim();
Notes.prototype.stripQuickActions = function(formContent) {
return formContent.replace(REGEX_QUICK_ACTIONS, '').trim();
};
/**
* Gets appropriate description from slash commands found in provided `formContent`
* Gets appropriate description from quick actions found in provided `formContent`
*/
Notes.prototype.getSlashCommandDescription = function (formContent, availableSlashCommands = []) {
Notes.prototype.getQuickActionDescription = function (formContent, availableQuickActions = []) {
let tempFormContent;
// Identify executed slash commands from `formContent`
const executedCommands = availableSlashCommands.filter((command, index) => {
// Identify executed quick actions from `formContent`
const executedCommands = availableQuickActions.filter((command, index) => {
const commandRegex = new RegExp(`/${command.name}`);
return commandRegex.test(formContent);
});
......@@ -1276,7 +1276,7 @@ const normalizeNewlines = function(str) {
};
/**
* Create Placeholder System Note DOM element populated with slash command description
* Create Placeholder System Note DOM element populated with quick action description
*/
Notes.prototype.createPlaceholderSystemNote = function ({ formContent, uniqueId }) {
const $tempNote = $(
......@@ -1325,7 +1325,7 @@ const normalizeNewlines = function(str) {
const { formData, formContent, formAction } = this.getFormData($form);
let noteUniqueId;
let systemNoteUniqueId;
let hasSlashCommands = false;
let hasQuickActions = false;
let $notesContainer;
let tempFormContent;
......@@ -1344,9 +1344,9 @@ const normalizeNewlines = function(str) {
}
tempFormContent = formContent;
if (this.hasSlashCommands(formContent)) {
tempFormContent = this.stripSlashCommands(formContent);
hasSlashCommands = true;
if (this.hasQuickActions(formContent)) {
tempFormContent = this.stripQuickActions(formContent);
hasQuickActions = true;
}
// Show placeholder note
......@@ -1363,10 +1363,10 @@ const normalizeNewlines = function(str) {
}
// Show placeholder system note
if (hasSlashCommands) {
if (hasQuickActions) {
systemNoteUniqueId = _.uniqueId('tempSystemNote_');
$notesContainer.append(this.createPlaceholderSystemNote({
formContent: this.getSlashCommandDescription(formContent, AjaxCache.get(gl.GfmAutoComplete.dataSources.commands)),
formContent: this.getQuickActionDescription(formContent, AjaxCache.get(gl.GfmAutoComplete.dataSources.commands)),
uniqueId: systemNoteUniqueId,
}));
}
......@@ -1388,7 +1388,7 @@ const normalizeNewlines = function(str) {
$notesContainer.find(`#${noteUniqueId}`).remove();
// Reset cached commands list when command is applied
if (hasSlashCommands) {
if (hasQuickActions) {
$form.find('textarea.js-note-text').trigger('clear-commands-cache.atwho');
}
......@@ -1422,7 +1422,7 @@ const normalizeNewlines = function(str) {
}
if (note.commands_changes) {
this.handleSlashCommands(note);
this.handleQuickActions(note);
}
$form.trigger('ajax:success', [note]);
......@@ -1430,7 +1430,7 @@ const normalizeNewlines = function(str) {
// Submission failed, remove placeholder note and show Flash error message
$notesContainer.find(`#${noteUniqueId}`).remove();
if (hasSlashCommands) {
if (hasQuickActions) {
$notesContainer.find(`#${systemNoteUniqueId}`).remove();
}
......
......@@ -3,7 +3,7 @@
// MarkdownPreview
//
// Handles toggling the "Write" and "Preview" tab clicks, rendering the preview
// (including the explanation of slash commands), and showing a warning when
// (including the explanation of quick actions), and showing a warning when
// more than `x` users are referenced.
//
(function () {
......
......@@ -15,10 +15,10 @@ export default {
<div class="time-tracking-help-state">
<div class="time-tracking-info">
<h4>
Track time with slash commands
Track time with quick actions
</h4>
<p>
Slash commands can be used in the issues description and comment boxes.
Quick actions can be used in the issues description and comment boxes.
</p>
<p>
<code>
......
......@@ -16,10 +16,10 @@ export default {
'issuable-time-tracker': timeTracker,
},
methods: {
listenForSlashCommands() {
$(document).on('ajax:success', '.gfm-form', this.slashCommandListened);
listenForQuickActions() {
$(document).on('ajax:success', '.gfm-form', this.quickActionListened);
},
slashCommandListened(e, data) {
quickActionListened(e, data) {
const subscribedCommands = ['spend_time', 'time_estimate'];
let changedCommands;
if (data !== undefined) {
......@@ -35,7 +35,7 @@ export default {
},
},
mounted() {
this.listenForSlashCommands();
this.listenForQuickActions();
},
template: `
<div class="block">
......
......@@ -10,8 +10,8 @@ module NotesHelper
Ability.can_edit_note?(current_user, note)
end
def note_supports_slash_commands?(note)
Notes::SlashCommandsService.supported?(note, current_user)
def note_supports_quick_actions?(note)
Notes::QuickActionsService.supported?(note, current_user)
end
def noteable_json(noteable)
......
......@@ -889,7 +889,7 @@ class MergeRequest < ActiveRecord::Base
!has_commits?
end
def mergeable_with_slash_command?(current_user, autocomplete_precheck: false, last_diff_sha: nil)
def mergeable_with_quick_action?(current_user, autocomplete_precheck: false, last_diff_sha: nil)
return false unless can_be_merged_by?(current_user)
return true if autocomplete_precheck
......
......@@ -32,7 +32,7 @@ class Note < ActiveRecord::Base
# Banzai::ObjectRenderer
attr_accessor :user_visible_reference_count
# Attribute used to store the attributes that have ben changed by slash commands.
# Attribute used to store the attributes that have ben changed by quick actions.
attr_accessor :commands_changes
default_value_for :system, false
......
class MattermostSlashCommandsService < ChatSlashCommandsService
class MattermostSlashCommandsService < SlashCommandsService
include TriggersHelper
prop_accessor :token
......
class SlackSlashCommandsService < ChatSlashCommandsService
class SlackSlashCommandsService < SlashCommandsService
include TriggersHelper
def title
......
# Base class for Chat services
# This class is not meant to be used directly, but only to inherrit from.
class ChatSlashCommandsService < Service
class SlashCommandsService < Service
default_value_for :category, 'chat'
prop_accessor :token
......@@ -33,10 +33,10 @@ class ChatSlashCommandsService < Service
user = find_chat_user(params)
if user
Gitlab::ChatCommands::Command.new(project, user, params).execute
Gitlab::SlashCommands::Command.new(project, user, params).execute
else
url = authorize_chat_name_url(params)
Gitlab::ChatCommands::Presenters::Access.new(url).authorize
Gitlab::SlashCommands::Presenters::Access.new(url).authorize
end
end
......
......@@ -10,7 +10,7 @@ class GlobalPolicy < BasePolicy
can! :access_api
can! :access_git
can! :receive_notifications
can! :use_slash_commands
can! :use_quick_actions
end
end
end
......@@ -142,9 +142,9 @@ class IssuableBaseService < BaseService
LabelsFinder.new(current_user, project_id: @project.id).execute
end
def merge_slash_commands_into_params!(issuable)
def merge_quick_actions_into_params!(issuable)
description, command_params =
SlashCommands::InterpretService.new(project, current_user).
QuickActions::InterpretService.new(project, current_user).
execute(params[:description], issuable)
# Avoid a description already set on an issuable to be overwritten by a nil
......@@ -162,7 +162,7 @@ class IssuableBaseService < BaseService
end
def create(issuable)
merge_slash_commands_into_params!(issuable)
merge_quick_actions_into_params!(issuable)
filter_params(issuable)
params.delete(:state_event)
......
......@@ -7,7 +7,7 @@ module MergeRequests
params.except!(:target_project_id)
params.except!(:source_branch)
merge_from_slash_command(merge_request) if params[:merge]
merge_from_quick_action(merge_request) if params[:merge]
if merge_request.closed_without_fork?
params.except!(:target_branch, :force_remove_source_branch)
......@@ -74,9 +74,9 @@ module MergeRequests
end
end
def merge_from_slash_command(merge_request)
def merge_from_quick_action(merge_request)
last_diff_sha = params.delete(:merge)
return unless merge_request.mergeable_with_slash_command?(current_user, last_diff_sha: last_diff_sha)
return unless merge_request.mergeable_with_quick_action?(current_user, last_diff_sha: last_diff_sha)
merge_request.update(merge_error: nil)
......
......@@ -9,11 +9,11 @@ module Notes
# We execute commands (extracted from `params[:note]`) on the noteable
# **before** we save the note because if the note consists of commands
# only, there is no need be create a note!
slash_commands_service = SlashCommandsService.new(project, current_user)
quick_actions_service = QuickActionsService.new(project, current_user)
if slash_commands_service.supported?(note)
if quick_actions_service.supported?(note)
options = { merge_request_diff_head_sha: merge_request_diff_head_sha }
content, command_params = slash_commands_service.extract_commands(note, options)
content, command_params = quick_actions_service.extract_commands(note, options)
only_commands = content.empty?
......@@ -30,7 +30,7 @@ module Notes
end
if command_params.present?
slash_commands_service.execute(command_params, note)
quick_actions_service.execute(command_params, note)
# We must add the error after we call #save because errors are reset
# when #save is called
......
module Notes
class SlashCommandsService < BaseService
class QuickActionsService < BaseService
UPDATE_SERVICES = {
'Issue' => Issues::UpdateService,
'MergeRequest' => MergeRequests::UpdateService
......@@ -22,7 +22,7 @@ module Notes
def extract_commands(note, options = {})
return [note.note, {}] unless supported?(note)
SlashCommands::InterpretService.new(project, current_user, options).
QuickActions::InterpretService.new(project, current_user, options).
execute(note.note, note.noteable)
end
......
class PreviewMarkdownService < BaseService
def execute
text, commands = explain_slash_commands(params[:text])
text, commands = explain_quick_actions(params[:text])
users = find_user_references(text)
success(
......@@ -12,11 +12,11 @@ class PreviewMarkdownService < BaseService
private
def explain_slash_commands(text)
def explain_quick_actions(text)
return text, [] unless %w(Issue MergeRequest).include?(commands_target_type)
slash_commands_service = SlashCommands::InterpretService.new(project, current_user)
slash_commands_service.explain(text, find_commands_target)
quick_actions_service = QuickActions::InterpretService.new(project, current_user)
quick_actions_service.explain(text, find_commands_target)
end
def find_user_references(text)
......@@ -36,10 +36,10 @@ class PreviewMarkdownService < BaseService
end
def commands_target_type
params[:slash_commands_target_type]
params[:quick_actions_target_type]
end
def commands_target_id
params[:slash_commands_target_id]
params[:quick_actions_target_id]
end
end
......@@ -32,7 +32,7 @@ module Projects
issuable: noteable,
current_user: current_user
}
SlashCommands::InterpretService.command_definitions.map do |definition|
QuickActions::InterpretService.command_definitions.map do |definition|
next unless definition.available?(opts)
definition.to_h(opts)
......
module SlashCommands
module QuickActions
class InterpretService < BaseService
include Gitlab::SlashCommands::Dsl
include Gitlab::QuickActions::Dsl
attr_reader :issuable
# 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.
def execute(content, issuable)
return [content, {}] unless current_user.can?(:use_slash_commands)
return [content, {}] unless current_user.can?(:use_quick_actions)
@issuable = issuable
@updates = {}
......@@ -20,7 +20,7 @@ module SlashCommands
# Takes a text and interprets the commands that are extracted from it.
# Returns the content without commands, and array of changes explained.
def explain(content, issuable)
return [content, []] unless current_user.can?(:use_slash_commands)
return [content, []] unless current_user.can?(:use_quick_actions)
@issuable = issuable
......@@ -32,7 +32,7 @@ module SlashCommands
private
def extractor
Gitlab::SlashCommands::Extractor.new(self.class.command_definitions)
Gitlab::QuickActions::Extractor.new(self.class.command_definitions)
end
desc do
......@@ -71,7 +71,7 @@ module SlashCommands
last_diff_sha = params && params[:merge_request_diff_head_sha]
issuable.is_a?(MergeRequest) &&
issuable.persisted? &&
issuable.mergeable_with_slash_command?(current_user, autocomplete_precheck: !last_diff_sha, last_diff_sha: last_diff_sha)
issuable.mergeable_with_quick_action?(current_user, autocomplete_precheck: !last_diff_sha, last_diff_sha: last_diff_sha)
end
command :merge do
@updates[:merge] = params[:merge_request_diff_head_sha]
......
- @gfm_form = true
- current_text ||= nil
- supports_slash_commands = local_assigns.fetch(:supports_slash_commands, false)
- supports_quick_actions = local_assigns.fetch(:supports_quick_actions, false)
.zen-backdrop
- classes << ' js-gfm-input js-autosize markdown-area'
- if defined?(f) && f
= f.text_area attr, class: classes, placeholder: placeholder, data: { supports_slash_commands: supports_slash_commands }
= f.text_area attr, class: classes, placeholder: placeholder, data: { supports_quick_actions: supports_quick_actions }
- else
= text_area_tag attr, current_text, class: classes, placeholder: placeholder
%a.zen-control.zen-control-leave.js-zen-leave{ href: "#" }
......
......@@ -20,7 +20,7 @@
%p
The subject will be used as the title of the new issue, and the message will be the description.
= link_to 'Slash commands', help_page_path('user/project/slash_commands'), target: '_blank', tabindex: -1
= link_to 'Quick actions', help_page_path('user/project/quick_actions'), target: '_blank', tabindex: -1
and styling with
= link_to 'Markdown', help_page_path('user/markdown'), target: '_blank', tabindex: -1
are supported.
......
......@@ -2,10 +2,10 @@
- model = local_assigns.fetch(:model)
- form = local_assigns.fetch(:form)
- supports_slash_commands = model.new_record?
- supports_quick_actions = model.new_record?
- if supports_slash_commands
- preview_url = preview_markdown_path(project, slash_commands_target_type: model.class.name)
- if supports_quick_actions
- preview_url = preview_markdown_path(project, quick_actions_target_type: model.class.name)
- else
- preview_url = preview_markdown_path(project)
......@@ -17,7 +17,7 @@
= render 'projects/zen', f: form, attr: :description,
classes: 'note-textarea',
placeholder: "Write a comment or drag your files here...",
supports_slash_commands: supports_slash_commands
= render 'shared/notes/hints', supports_slash_commands: supports_slash_commands
supports_quick_actions: supports_quick_actions
= render 'shared/notes/hints', supports_quick_actions: supports_quick_actions
.clearfix
.error-alert
- supports_slash_commands = note_supports_slash_commands?(@note)
- if supports_slash_commands
- preview_url = preview_markdown_path(@project, slash_commands_target_type: @note.noteable_type, slash_commands_target_id: @note.noteable_id)
- supports_quick_actions = note_supports_quick_actions?(@note)
- if supports_quick_actions
- preview_url = preview_markdown_path(@project, quick_actions_target_type: @note.noteable_type, quick_actions_target_id: @note.noteable_id)
- else
- preview_url = preview_markdown_path(@project)
......@@ -27,8 +27,8 @@
attr: :note,
classes: 'note-textarea js-note-text',
placeholder: "Write a comment or drag your files here...",
supports_slash_commands: supports_slash_commands
= render 'shared/notes/hints', supports_slash_commands: supports_slash_commands
supports_quick_actions: supports_quick_actions
= render 'shared/notes/hints', supports_quick_actions: supports_quick_actions
.error-alert
.note-form-actions.clearfix
......
- supports_slash_commands = local_assigns.fetch(:supports_slash_commands, false)
- supports_quick_actions = local_assigns.fetch(:supports_quick_actions, false)
.comment-toolbar.clearfix
.toolbar-text
= link_to 'Markdown', help_page_path('user/markdown'), target: '_blank', tabindex: -1
- if supports_slash_commands
- if supports_quick_actions
and
= link_to 'slash commands', help_page_path('user/project/slash_commands'), target: '_blank', tabindex: -1
= link_to 'quick actions', help_page_path('user/project/quick_actions'), target: '_blank', tabindex: -1
are
- else
is
......
---
title: Rename "Slash commands" to "Quick actions" and deprecate "chat commands" in favor
of "slash commands"
merge_request:
author:
......@@ -24,7 +24,7 @@ Shortcuts to GitLab's most visited docs:
- [GitLab Workflow](workflow/README.md): Enhance your workflow with the best of GitLab Workflow.
- See also [GitLab Workflow - an overview](https://about.gitlab.com/2016/10/25/gitlab-workflow-an-overview/).
- [GitLab Markdown](user/markdown.md): GitLab's advanced formatting system (GitLab Flavored Markdown).
- [GitLab Slash Commands](user/project/slash_commands.md): Textual shortcuts for common actions on issues or merge requests that are usually done by clicking buttons or dropdowns in GitLab's UI.
- [GitLab Quick Actions](user/project/quick_actions.md): Textual shortcuts for common actions on issues or merge requests that are usually done by clicking buttons or dropdowns in GitLab's UI.
### User account
......
......@@ -166,8 +166,8 @@ For instance this kind of thing:
= render 'projects/zen', f: form, attr: :description,
classes: 'note-textarea',
placeholder: "Write a comment or drag your files here...",
supports_slash_commands: !issuable.persisted?
= render 'projects/notes/hints', supports_slash_commands: !issuable.persisted?
supports_quick_actions: !issuable.persisted?
= render 'projects/notes/hints', supports_quick_actions: !issuable.persisted?
.clearfix
.error-alert
- if issuable.is_a?(Issue)
......
# Chat Commands
Chat commands in Mattermost and Slack (also called Slack slash commands) allow you to control GitLab and view GitLab content right inside your chat client, without having to leave it. For Slack, this requires a [project service configuration](../user/project/integrations/slack_slash_commands.md). Simply type the command as a message in your chat client to activate it.
Commands are scoped to a project, with a trigger term that is specified during configuration. (We suggest you use the project name as the trigger term for simplicty and clarity.) Taking the trigger term as `project-name`, the commands are:
| Command | Effect |
| ------- | ------ |
| `/project-name help` | Shows all available chat commands |
| `/project-name issue new <title> <shift+return> <description>` | Creates a new issue with title `<title>` and description `<description>` |
| `/project-name issue show <id>` | Shows the issue with id `<id>` |
| `/project-name issue search <query>` | Shows up to 5 issues matching `<query>` |
| `/project-name deploy <from> to <to>` | Deploy from the `<from>` environment to the `<to>` environment |
\ No newline at end of file
This document was moved to [integration/slash_commands.md](slash_commands.md).
# Slash Commands
Slash commands in Mattermost and Slack allow you to control GitLab and view GitLab content right inside your chat client, without having to leave it. For Slack, this requires a [project service configuration](../user/project/integrations/slack_slash_commands.md). Simply type the command as a message in your chat client to activate it.
Commands are scoped to a project, with a trigger term that is specified during configuration. (We suggest you use the project name as the trigger term for simplicty and clarity.) Taking the trigger term as `project-name`, the commands are:
| Command | Effect |
| ------- | ------ |
| `/project-name help` | Shows all available slash commands |
| `/project-name issue new <title> <shift+return> <description>` | Creates a new issue with title `<title>` and description `<description>` |
| `/project-name issue show <id>` | Shows the issue with id `<id>` |
| `/project-name issue search <query>` | Shows up to 5 issues matching `<query>` |
| `/project-name deploy <from> to <to>` | Deploy from the `<from>` environment to the `<to>` environment |
......@@ -10,7 +10,7 @@ You can leave a comment in the following places:
- commits
- commit diffs
The comment area supports [Markdown] and [slash commands]. One can edit their
The comment area supports [Markdown] and [quick actions]. One can edit their
own comment at any time, and anyone with [Master access level][permissions] or
higher can also edit a comment made by someone else.
......@@ -146,5 +146,5 @@ comments in greater detail.
[discussion-view]: img/discussion_view.png
[discussions-resolved]: img/discussions_resolved.png
[markdown]: ../markdown.md
[slash commands]: ../project/slash_commands.md
[quick actions]: ../project/quick_actions.md
[permissions]: ../permissions.md
......@@ -2,7 +2,7 @@
> Introduced in GitLab 8.15
Slack slash commands (also known as chat commmands) allow you to control GitLab and view content right inside Slack, without having to leave it. This requires configurations in both Slack and GitLab.
Slack slash commands allow you to control GitLab and view content right inside Slack, without having to leave it. This requires configurations in both Slack and GitLab.
> Note: GitLab can also send events (e.g. issue created) to Slack as notifications. This is the separately configured [Slack Notifications Service](slack.md).
......@@ -20,4 +20,4 @@ Slack slash commands (also known as chat commmands) allow you to control GitLab
## Usage
You can now use the [Slack slash commands](../../../integration/chat_commands.md).
\ No newline at end of file
You can now use the [Slack slash commands](../../../integration/slash_commands.md).
......@@ -68,7 +68,7 @@ This feature is available only in [GitLab Enterprise Edition](https://about.gitl
- Spend: add the time spent on the implementation of that issue
> **Note:**
both estimate and spend times are set via [GitLab Slash Commands](../slash_commands.md).
both estimate and spend times are set via [GitLab Quick Actions](../quick_actions.md).
Learn more on the [Time Tracking documentation](https://docs.gitlab.com/ee/workflow/time_tracking.html).
......
# GitLab quick actions
Quick actions are textual shortcuts for common actions on issues or merge
requests that are usually done by clicking buttons or dropdowns in GitLab's UI.
You can enter these commands while creating a new issue or merge request, and
in comments. Each command should be on a separate line in order to be properly
detected and executed. The commands are removed from the issue, merge request or
comment body before it is saved and will not be visible to anyone else.
Below is a list of all of the available commands and descriptions about what they
do.
| Command | Action |
|:---------------------------|:-------------|
| `/close` | Close the issue or merge request |
| `/reopen` | Reopen the issue or merge request |
| `/merge` | Merge (when pipeline succeeds) |
| `/title <New title>` | Change title |
| `/assign @username` | Assign |
| `/unassign` | Remove assignee |
| `/milestone %milestone` | Set milestone |
| `/remove_milestone` | Remove milestone |
| `/label ~foo ~"bar baz"` | Add label(s) |
| `/unlabel ~foo ~"bar baz"` | Remove all or specific label(s) |
| `/relabel ~foo ~"bar baz"` | Replace all label(s) |
| `/todo` | Add a todo |
| `/done` | Mark todo as done |
| `/subscribe` | Subscribe |
| `/unsubscribe` | Unsubscribe |
| <code>/due &lt;in 2 days &#124; this Friday &#124; December 31st&gt;</code> | Set due date |
| `/remove_due_date` | Remove due date |
| `/wip` | Toggle the Work In Progress status |
| <code>/estimate &lt;1w 3d 2h 14m&gt;</code> | Set time estimate |
| `/remove_estimate` | Remove estimated time |
| <code>/spend &lt;1h 30m &#124; -1h 5m&gt;</code> | Add or subtract spent time |
| `/remove_time_spent` | Remove time spent |
| `/target_branch <Branch Name>` | Set target branch for current merge request |
| `/award :emoji:` | Toggle award for :emoji: |
| `/board_move ~column` | Move issue to column on the board |
# GitLab slash commands
Slash commands are textual shortcuts for common actions on issues or merge
requests that are usually done by clicking buttons or dropdowns in GitLab's UI.
You can enter these commands while creating a new issue or merge request, and
in comments. Each command should be on a separate line in order to be properly
detected and executed. The commands are removed from the issue, merge request or
comment body before it is saved and will not be visible to anyone else.
Below is a list of all of the available commands and descriptions about what they
do.
| Command | Action |
|:---------------------------|:-------------|
| `/close` | Close the issue or merge request |
| `/reopen` | Reopen the issue or merge request |
| `/merge` | Merge (when pipeline succeeds) |
| `/title <New title>` | Change title |
| `/assign @username` | Assign |
| `/unassign` | Remove assignee |
| `/milestone %milestone` | Set milestone |
| `/remove_milestone` | Remove milestone |
| `/label ~foo ~"bar baz"` | Add label(s) |
| `/unlabel ~foo ~"bar baz"` | Remove all or specific label(s) |
| `/relabel ~foo ~"bar baz"` | Replace all label(s) |
| `/todo` | Add a todo |
| `/done` | Mark todo as done |
| `/subscribe` | Subscribe |
| `/unsubscribe` | Unsubscribe |
| <code>/due &lt;in 2 days &#124; this Friday &#124; December 31st&gt;</code> | Set due date |
| `/remove_due_date` | Remove due date |
| `/wip` | Toggle the Work In Progress status |
| <code>/estimate &lt;1w 3d 2h 14m&gt;</code> | Set time estimate |
| `/remove_estimate` | Remove estimated time |
| <code>/spend &lt;1h 30m &#124; -1h 5m&gt;</code> | Add or subtract spent time |
| `/remove_time_spent` | Remove time spent |
| `/target_branch <Branch Name>` | Set target branch for current merge request |
| `/award :emoji:` | Toggle award for :emoji: |
| `/board_move ~column` | Move issue to column on the board |
This document was moved to [user/project/quick_actions.md](quick_actions.md).
......@@ -21,7 +21,7 @@
- [Project users](add-user/add-user.md)
- [Protected branches](../user/project/protected_branches.md)
- [Protected tags](../user/project/protected_tags.md)
- [Slash commands](../user/project/slash_commands.md)
- [Quick Actions](../user/project/quick_actions.md)
- [Sharing a project with a group](share_with_group.md)
- [Share projects with other groups](share_projects_with_other_groups.md)
- [Time tracking](time_tracking.md)
......
......@@ -21,13 +21,13 @@ below.
## How to enter data
Time Tracking uses two [slash commands] that GitLab introduced with this new
Time Tracking uses two [quick actions] that GitLab introduced with this new
feature: `/spend` and `/estimate`.
Slash commands can be used in the body of an issue or a merge request, but also
Quick actions can be used in the body of an issue or a merge request, but also
in a comment in both an issue or a merge request.
Below is an example of how you can use those new slash commands inside a comment.
Below is an example of how you can use those new quick actions inside a comment.
![Time tracking example in a comment](time-tracking/time-tracking-example.png)
......@@ -70,4 +70,4 @@ The following time units are available:
Default conversion rates are 1w = 5d and 1d = 8h.
[landing]: https://about.gitlab.com/features/time-tracking
[slash-commands]: ../user/project/slash_commands.md
[quick actions]: ../user/project/quick_actions.md
......@@ -685,7 +685,7 @@ module API
trigger_services.each do |service_slug, settings|
helpers do
def chat_command_service(project, service_slug, params)
def slash_command_service(project, service_slug, params)
project.services.active.where(template: false).find do |service|
service.try(:token) == params[:token] && service.to_param == service_slug.underscore
end
......@@ -710,7 +710,7 @@ module API
# This is not accurate, but done to prevent leakage of the project names
not_found!('Service') unless project
service = chat_command_service(project, service_slug, params)
service = slash_command_service(project, service_slug, params)
result = service.try(:trigger, params)
if result
......
......@@ -608,7 +608,7 @@ module API
trigger_services.each do |service_slug, settings|
helpers do
def chat_command_service(project, service_slug, params)
def slash_command_service(project, service_slug, params)
project.services.active.where(template: false).find do |service|
service.try(:token) == params[:token] && service.to_param == service_slug.underscore
end
......@@ -633,7 +633,7 @@ module API
# This is not accurate, but done to prevent leakage of the project names
not_found!('Service') unless project
service = chat_command_service(project, service_slug, params)
service = slash_command_service(project, service_slug, params)
result = service.try(:trigger, params)
if result
......
module Gitlab
module SlashCommands
module QuickActions
class CommandDefinition
attr_accessor :name, :aliases, :description, :explanation, :params,
:condition_block, :parse_params_block, :action_block
......
module Gitlab
module SlashCommands
module QuickActions
module Dsl
extend ActiveSupport::Concern
......@@ -14,7 +14,7 @@ module Gitlab
end
class_methods do
# Allows to give a description to the next slash command.
# Allows to give a description to the next quick action.
# This description is shown in the autocomplete menu.
# It accepts a block that will be evaluated with the context given to
# `CommandDefintion#to_h`.
......@@ -31,7 +31,7 @@ module Gitlab
@description = block_given? ? block : text
end
# Allows to define params for the next slash command.
# Allows to define params for the next quick action.
# These params are shown in the autocomplete menu.
#
# Example:
......
module Gitlab
module SlashCommands
module QuickActions
# This class takes an array of commands that should be extracted from a
# given text.
#
# ```
# extractor = Gitlab::SlashCommands::Extractor.new([:open, :assign, :labels])
# extractor = Gitlab::QuickActions::Extractor.new([:open, :assign, :labels])
# ```
class Extractor
attr_reader :command_definitions
......@@ -24,7 +24,7 @@ module Gitlab
#
# Usage:
# ```
# extractor = Gitlab::SlashCommands::Extractor.new([:open, :assign, :labels])
# extractor = Gitlab::QuickActions::Extractor.new([:open, :assign, :labels])
# msg = %(hello\n/labels ~foo ~"bar baz"\nworld)
# commands = extractor.extract_commands(msg) #=> [['labels', '~foo ~"bar baz"']]
# msg #=> "hello\nworld"
......
module Gitlab
module ChatCommands
module SlashCommands
class BaseCommand
QUERY_LIMIT = 5
......
module Gitlab
module ChatCommands
module SlashCommands
class Command < BaseCommand
COMMANDS = [
Gitlab::ChatCommands::IssueShow,
Gitlab::ChatCommands::IssueNew,
Gitlab::ChatCommands::IssueSearch,
Gitlab::ChatCommands::Deploy
Gitlab::SlashCommands::IssueShow,
Gitlab::SlashCommands::IssueNew,
Gitlab::SlashCommands::IssueSearch,
Gitlab::SlashCommands::Deploy
].freeze
def execute
......@@ -15,10 +15,10 @@ module Gitlab
if command.allowed?(project, current_user)
command.new(project, current_user, params).execute(match)
else
Gitlab::ChatCommands::Presenters::Access.new.access_denied
Gitlab::SlashCommands::Presenters::Access.new.access_denied
end
else
Gitlab::ChatCommands::Help.new(project, current_user, params).execute(available_commands, params[:text])
Gitlab::SlashCommands::Help.new(project, current_user, params).execute(available_commands, params[:text])
end
end
......
module Gitlab
module ChatCommands
module SlashCommands
class Deploy < BaseCommand
def self.match(text)
/\Adeploy\s+(?<from>\S+.*)\s+to+\s+(?<to>\S+.*)\z/.match(text)
......@@ -24,12 +24,12 @@ module Gitlab
actions = find_actions(from, to)
if actions.none?
Gitlab::ChatCommands::Presenters::Deploy.new(nil).no_actions
Gitlab::SlashCommands::Presenters::Deploy.new(nil).no_actions
elsif actions.one?
action = play!(from, to, actions.first)
Gitlab::ChatCommands::Presenters::Deploy.new(action).present(from, to)
Gitlab::SlashCommands::Presenters::Deploy.new(action).present(from, to)
else
Gitlab::ChatCommands::Presenters::Deploy.new(actions).too_many_actions
Gitlab::SlashCommands::Presenters::Deploy.new(actions).too_many_actions
end
end
......
module Gitlab
module ChatCommands
module SlashCommands
class Help < BaseCommand
# This class has to be used last, as it always matches. It has to match
# because other commands were not triggered and we want to show the help
......@@ -17,7 +17,7 @@ module Gitlab
end
def execute(commands, text)
Gitlab::ChatCommands::Presenters::Help.new(commands).present(trigger, text)
Gitlab::SlashCommands::Presenters::Help.new(commands).present(trigger, text)
end
def trigger
......
module Gitlab
module ChatCommands
module SlashCommands
class IssueCommand < BaseCommand
def self.available?(project)
project.issues_enabled? && project.default_issues_tracker?
......
module Gitlab
module ChatCommands
module SlashCommands
class IssueNew < IssueCommand
def self.match(text)
# we can not match \n with the dot by passing the m modifier as than
......@@ -35,7 +35,7 @@ module Gitlab
end
def presenter(issue)
Gitlab::ChatCommands::Presenters::IssueNew.new(issue)
Gitlab::SlashCommands::Presenters::IssueNew.new(issue)
end
end
end
......
module Gitlab
module ChatCommands
module SlashCommands
class IssueSearch < IssueCommand
def self.match(text)
/\Aissue\s+search\s+(?<query>.*)/.match(text)
......
module Gitlab
module ChatCommands
module SlashCommands
class IssueShow < IssueCommand
def self.match(text)
/\Aissue\s+show\s+#{Issue.reference_prefix}?(?<iid>\d+)/.match(text)
......@@ -13,9 +13,9 @@ module Gitlab
issue = find_by_iid(match[:iid])
if issue
Gitlab::ChatCommands::Presenters::IssueShow.new(issue).present
Gitlab::SlashCommands::Presenters::IssueShow.new(issue).present
else
Gitlab::ChatCommands::Presenters::Access.new.not_found
Gitlab::SlashCommands::Presenters::Access.new.not_found
end
end
end
......
module Gitlab
module ChatCommands
module SlashCommands
module Presenters
class Access < Presenters::Base
def access_denied
......
module Gitlab
module ChatCommands
module SlashCommands
module Presenters
class Base
include Gitlab::Routing.url_helpers
......
module Gitlab
module ChatCommands
module SlashCommands
module Presenters
class Deploy < Presenters::Base
def present(from, to)
......
module Gitlab
module ChatCommands
module SlashCommands
module Presenters
class Help < Presenters::Base
def present(trigger, text)
......
module Gitlab
module ChatCommands
module SlashCommands
module Presenters
module IssueBase
def color(issuable)
......
module Gitlab
module ChatCommands
module SlashCommands
module Presenters
class IssueNew < Presenters::Base
include Presenters::IssueBase
......
module Gitlab
module ChatCommands
module SlashCommands
module Presenters
class IssueSearch < Presenters::Base
include Presenters::IssueBase
......
module Gitlab
module ChatCommands
module SlashCommands
module Presenters
class IssueShow < Presenters::Base
include Presenters::IssueBase
......
module Gitlab
module ChatCommands
module SlashCommands
Result = Struct.new(:type, :message)
end
end
......@@ -702,7 +702,7 @@ describe Projects::IssuesController do
end
end
context 'when description has slash commands' do
context 'when description has quick actions' do
before do
sign_in(user)
end
......
......@@ -81,13 +81,13 @@ describe 'Awards Emoji', feature: true do
end
end
context 'execute /award slash command' do
context 'execute /award quick action' do
it 'toggles the emoji award on noteable', js: true do
execute_slash_command('/award :100:')
execute_quick_action('/award :100:')
expect(find(noteable_award_counter)).to have_text("1")
execute_slash_command('/award :100:')
execute_quick_action('/award :100:')
expect(page).not_to have_selector(noteable_award_counter)
end
......@@ -105,7 +105,7 @@ describe 'Awards Emoji', feature: true do
end
end
def execute_slash_command(cmd)
def execute_quick_action(cmd)
within('.js-main-target-form') do
fill_in 'note[note]', with: cmd
click_button 'Comment'
......
......@@ -208,7 +208,7 @@ feature 'GFM autocomplete', feature: true, js: true do
expect(page).not_to have_selector('.atwho-view')
end
it 'triggers autocomplete after selecting a slash command' do
it 'triggers autocomplete after selecting a quick action' do
note = find('#note_note')
page.within '.timeline-content-form' do
note.native.send_keys('')
......
require 'rails_helper'
feature 'Issues > User uses slash commands', feature: true, js: true do
include SlashCommandsHelpers
feature 'Issues > User uses quick actions', feature: true, js: true do
include QuickActionsHelpers
it_behaves_like 'issuable record that supports slash commands in its description and notes', :issue do
it_behaves_like 'issuable record that supports quick actions in its description and notes', :issue do
let(:issuable) { create(:issue, project: project) }
end
......
require 'rails_helper'
feature 'Merge Requests > User uses slash commands', feature: true, js: true do
include SlashCommandsHelpers
feature 'Merge Requests > User uses quick actions', feature: true, js: true do
include QuickActionsHelpers
let(:user) { create(:user) }
let(:project) { create(:project, :public) }
let(:merge_request) { create(:merge_request, source_project: project) }
let!(:milestone) { create(:milestone, project: project, title: 'ASAP') }
it_behaves_like 'issuable record that supports slash commands in its description and notes', :merge_request do
it_behaves_like 'issuable record that supports quick actions in its description and notes', :merge_request do
let(:issuable) { create(:merge_request, source_project: project) }
let(:new_url_opts) { { merge_request: { source_branch: 'feature', target_branch: 'master' } } }
end
......
......@@ -550,46 +550,46 @@ import '~/notes';
});
});
describe('hasSlashCommands', () => {
describe('hasQuickActions', () => {
beforeEach(() => {
this.notes = new Notes('', []);
});
it('should return true when comment begins with a slash command', () => {
it('should return true when comment begins with a quick action', () => {
const sampleComment = '/wip\n/milestone %1.0\n/merge\n/unassign Merging this';
const hasSlashCommands = this.notes.hasSlashCommands(sampleComment);
const hasQuickActions = this.notes.hasQuickActions(sampleComment);
expect(hasSlashCommands).toBeTruthy();
expect(hasQuickActions).toBeTruthy();
});
it('should return false when comment does NOT begin with a slash command', () => {
it('should return false when comment does NOT begin with a quick action', () => {
const sampleComment = 'Hey, /unassign Merging this';
const hasSlashCommands = this.notes.hasSlashCommands(sampleComment);
const hasQuickActions = this.notes.hasQuickActions(sampleComment);
expect(hasSlashCommands).toBeFalsy();
expect(hasQuickActions).toBeFalsy();
});
it('should return false when comment does NOT have any slash commands', () => {
it('should return false when comment does NOT have any quick actions', () => {
const sampleComment = 'Looking good, Awesome!';
const hasSlashCommands = this.notes.hasSlashCommands(sampleComment);
const hasQuickActions = this.notes.hasQuickActions(sampleComment);
expect(hasSlashCommands).toBeFalsy();
expect(hasQuickActions).toBeFalsy();
});
});
describe('stripSlashCommands', () => {
it('should strip slash commands from the comment which begins with a slash command', () => {
describe('stripQuickActions', () => {
it('should strip quick actions from the comment which begins with a quick action', () => {
this.notes = new Notes();
const sampleComment = '/wip\n/milestone %1.0\n/merge\n/unassign Merging this';
const stripedComment = this.notes.stripSlashCommands(sampleComment);
const stripedComment = this.notes.stripQuickActions(sampleComment);
expect(stripedComment).toBe('');
});
it('should strip slash commands from the comment but leaves plain comment if it is present', () => {
it('should strip quick actions from the comment but leaves plain comment if it is present', () => {
this.notes = new Notes();
const sampleComment = '/wip\n/milestone %1.0\n/merge\n/unassign\nMerging this';
const stripedComment = this.notes.stripSlashCommands(sampleComment);
const stripedComment = this.notes.stripQuickActions(sampleComment);
expect(stripedComment).toBe('Merging this');
});
......@@ -597,14 +597,14 @@ import '~/notes';
it('should NOT strip string that has slashes within', () => {
this.notes = new Notes();
const sampleComment = 'http://127.0.0.1:3000/root/gitlab-shell/issues/1';
const stripedComment = this.notes.stripSlashCommands(sampleComment);
const stripedComment = this.notes.stripQuickActions(sampleComment);
expect(stripedComment).toBe(sampleComment);
});
});
describe('getSlashCommandDescription', () => {
const availableSlashCommands = [
describe('getQuickActionDescription', () => {
const availableQuickActions = [
{ name: 'close', description: 'Close this issue', params: [] },
{ name: 'title', description: 'Change title', params: [{}] },
{ name: 'estimate', description: 'Set time estimate', params: [{}] }
......@@ -614,19 +614,19 @@ import '~/notes';
this.notes = new Notes();
});
it('should return executing slash command description when note has single slash command', () => {
it('should return executing quick action description when note has single quick action', () => {
const sampleComment = '/close';
expect(this.notes.getSlashCommandDescription(sampleComment, availableSlashCommands)).toBe('Applying command to close this issue');
expect(this.notes.getQuickActionDescription(sampleComment, availableQuickActions)).toBe('Applying command to close this issue');
});
it('should return generic multiple slash command description when note has multiple slash commands', () => {
it('should return generic multiple quick action description when note has multiple quick actions', () => {
const sampleComment = '/close\n/title [Duplicate] Issue foobar';
expect(this.notes.getSlashCommandDescription(sampleComment, availableSlashCommands)).toBe('Applying multiple commands');
expect(this.notes.getQuickActionDescription(sampleComment, availableQuickActions)).toBe('Applying multiple commands');
});
it('should return generic slash command description when available slash commands list is not populated', () => {
it('should return generic quick action description when available quick actions list is not populated', () => {
const sampleComment = '/close\n/title [Duplicate] Issue foobar';
expect(this.notes.getSlashCommandDescription(sampleComment)).toBe('Applying command');
expect(this.notes.getQuickActionDescription(sampleComment)).toBe('Applying command');
});
});
......
......@@ -91,7 +91,7 @@ describe Gitlab::Email::Handler::CreateNoteHandler, lib: true do
end
end
context 'when the note contains slash commands' do
context 'when the note contains quick actions' do
let!(:email_raw) { fixture_file("emails/commands_in_reply.eml") }
context 'and current user cannot update noteable' do
......
require 'spec_helper'
describe Gitlab::SlashCommands::CommandDefinition do
describe Gitlab::QuickActions::CommandDefinition do
subject { described_class.new(:command) }
describe "#all_names" do
......
require 'spec_helper'
describe Gitlab::SlashCommands::Dsl do
describe Gitlab::QuickActions::Dsl do
before :all do
DummyClass = Struct.new(:project) do
include Gitlab::SlashCommands::Dsl # rubocop:disable RSpec/DescribedClass
include Gitlab::QuickActions::Dsl # rubocop:disable RSpec/DescribedClass
desc 'A command with no args'
command :no_args, :none do
......
require 'spec_helper'
describe Gitlab::SlashCommands::Extractor do
describe Gitlab::QuickActions::Extractor do
let(:definitions) do
Class.new do
include Gitlab::SlashCommands::Dsl
include Gitlab::QuickActions::Dsl
command(:reopen, :open) { }
command(:assign) { }
......
require 'spec_helper'
describe Gitlab::ChatCommands::Command, service: true do
describe Gitlab::SlashCommands::Command, service: true do
let(:project) { create(:empty_project) }
let(:user) { create(:user) }
......@@ -93,19 +93,19 @@ describe Gitlab::ChatCommands::Command, service: true do
context 'IssueShow is triggered' do
let(:params) { { text: 'issue show 123' } }
it { is_expected.to eq(Gitlab::ChatCommands::IssueShow) }
it { is_expected.to eq(Gitlab::SlashCommands::IssueShow) }
end
context 'IssueCreate is triggered' do
let(:params) { { text: 'issue create my title' } }
it { is_expected.to eq(Gitlab::ChatCommands::IssueNew) }
it { is_expected.to eq(Gitlab::SlashCommands::IssueNew) }
end
context 'IssueSearch is triggered' do
let(:params) { { text: 'issue search my query' } }
it { is_expected.to eq(Gitlab::ChatCommands::IssueSearch) }
it { is_expected.to eq(Gitlab::SlashCommands::IssueSearch) }
end
end
end
require 'spec_helper'
describe Gitlab::ChatCommands::Deploy, service: true do
describe Gitlab::SlashCommands::Deploy, service: true do
describe '#execute' do
let(:project) { create(:empty_project) }
let(:user) { create(:user) }
......
require 'spec_helper'
describe Gitlab::ChatCommands::IssueNew, service: true do
describe Gitlab::SlashCommands::IssueNew, service: true do
describe '#execute' do
let(:project) { create(:empty_project) }
let(:user) { create(:user) }
......
require 'spec_helper'
describe Gitlab::ChatCommands::IssueSearch, service: true do
describe Gitlab::SlashCommands::IssueSearch, service: true do
describe '#execute' do
let!(:issue) { create(:issue, project: project, title: 'find me') }
let!(:confidential) { create(:issue, :confidential, project: project, title: 'mepmep find') }
......
require 'spec_helper'
describe Gitlab::ChatCommands::IssueShow, service: true do
describe Gitlab::SlashCommands::IssueShow, service: true do
describe '#execute' do
let(:issue) { create(:issue, project: project) }
let(:project) { create(:empty_project) }
......
require 'spec_helper'
describe Gitlab::ChatCommands::Presenters::Access do
describe Gitlab::SlashCommands::Presenters::Access do
describe '#access_denied' do
subject { described_class.new.access_denied }
......
require 'spec_helper'
describe Gitlab::ChatCommands::Presenters::Deploy do
describe Gitlab::SlashCommands::Presenters::Deploy do
let(:build) { create(:ci_build) }
describe '#present' do
......
require 'spec_helper'
describe Gitlab::ChatCommands::Presenters::IssueNew do
describe Gitlab::SlashCommands::Presenters::IssueNew do
let(:project) { create(:empty_project) }
let(:issue) { create(:issue, project: project) }
let(:attachment) { subject[:attachments].first }
......
require 'spec_helper'
describe Gitlab::ChatCommands::Presenters::IssueSearch do
describe Gitlab::SlashCommands::Presenters::IssueSearch do
let(:project) { create(:empty_project) }
let(:message) { subject[:text] }
......
require 'spec_helper'
describe Gitlab::ChatCommands::Presenters::IssueShow do
describe Gitlab::SlashCommands::Presenters::IssueShow do
let(:project) { create(:empty_project) }
let(:issue) { create(:issue, project: project) }
let(:attachment) { subject[:attachments].first }
......
......@@ -1397,7 +1397,7 @@ describe MergeRequest, models: true do
end
end
describe '#mergeable_with_slash_command?' do
describe '#mergeable_with_quick_action?' do
def create_pipeline(status)
pipeline = create(:ci_pipeline_with_one_job,
project: project,
......@@ -1421,21 +1421,21 @@ describe MergeRequest, models: true do
context 'when autocomplete_precheck is set to true' do
it 'is mergeable by developer' do
expect(merge_request.mergeable_with_slash_command?(developer, autocomplete_precheck: true)).to be_truthy
expect(merge_request.mergeable_with_quick_action?(developer, autocomplete_precheck: true)).to be_truthy
end
it 'is not mergeable by normal user' do
expect(merge_request.mergeable_with_slash_command?(user, autocomplete_precheck: true)).to be_falsey
expect(merge_request.mergeable_with_quick_action?(user, autocomplete_precheck: true)).to be_falsey
end
end
context 'when autocomplete_precheck is set to false' do
it 'is mergeable by developer' do
expect(merge_request.mergeable_with_slash_command?(developer, last_diff_sha: mr_sha)).to be_truthy
expect(merge_request.mergeable_with_quick_action?(developer, last_diff_sha: mr_sha)).to be_truthy
end
it 'is not mergeable by normal user' do
expect(merge_request.mergeable_with_slash_command?(user, last_diff_sha: mr_sha)).to be_falsey
expect(merge_request.mergeable_with_quick_action?(user, last_diff_sha: mr_sha)).to be_falsey
end
context 'closed MR' do
......@@ -1444,7 +1444,7 @@ describe MergeRequest, models: true do
end
it 'is not mergeable' do
expect(merge_request.mergeable_with_slash_command?(developer, last_diff_sha: mr_sha)).to be_falsey
expect(merge_request.mergeable_with_quick_action?(developer, last_diff_sha: mr_sha)).to be_falsey
end
end
......@@ -1454,19 +1454,19 @@ describe MergeRequest, models: true do
end
it 'is not mergeable' do
expect(merge_request.mergeable_with_slash_command?(developer, last_diff_sha: mr_sha)).to be_falsey
expect(merge_request.mergeable_with_quick_action?(developer, last_diff_sha: mr_sha)).to be_falsey
end
end
context 'sha differs from the MR diff_head_sha' do
it 'is not mergeable' do
expect(merge_request.mergeable_with_slash_command?(developer, last_diff_sha: 'some other sha')).to be_falsey
expect(merge_request.mergeable_with_quick_action?(developer, last_diff_sha: 'some other sha')).to be_falsey
end
end
context 'sha is not provided' do
it 'is not mergeable' do
expect(merge_request.mergeable_with_slash_command?(developer)).to be_falsey
expect(merge_request.mergeable_with_quick_action?(developer)).to be_falsey
end
end
......@@ -1476,7 +1476,7 @@ describe MergeRequest, models: true do
end
it 'is mergeable' do
expect(merge_request.mergeable_with_slash_command?(developer, last_diff_sha: mr_sha)).to be_truthy
expect(merge_request.mergeable_with_quick_action?(developer, last_diff_sha: mr_sha)).to be_truthy
end
end
......@@ -1486,7 +1486,7 @@ describe MergeRequest, models: true do
end
it 'is not mergeable' do
expect(merge_request.mergeable_with_slash_command?(developer, last_diff_sha: mr_sha)).to be_falsey
expect(merge_request.mergeable_with_quick_action?(developer, last_diff_sha: mr_sha)).to be_falsey
end
end
......@@ -1496,7 +1496,7 @@ describe MergeRequest, models: true do
end
it 'is mergeable' do
expect(merge_request.mergeable_with_slash_command?(developer, last_diff_sha: mr_sha)).to be_truthy
expect(merge_request.mergeable_with_quick_action?(developer, last_diff_sha: mr_sha)).to be_truthy
end
end
end
......
......@@ -206,9 +206,9 @@ describe Issues::CreateService, services: true do
end
end
it_behaves_like 'new issuable record that supports slash commands'
it_behaves_like 'new issuable record that supports quick actions'
context 'Slash commands' do
context 'Quick actions' do
context 'with assignee and milestone in params and command' do
let(:opts) do
{
......
......@@ -108,7 +108,7 @@ describe MergeRequests::CreateService, services: true do
end
end
it_behaves_like 'new issuable record that supports slash commands' do
it_behaves_like 'new issuable record that supports quick actions' do
let(:default_params) do
{
source_branch: 'feature',
......@@ -117,7 +117,7 @@ describe MergeRequests::CreateService, services: true do
end
end
context 'Slash commands' do
context 'Quick actions' do
context 'with assignee and milestone in params and command' do
let(:merge_request) { described_class.new(project, user, opts).execute }
let(:milestone) { create(:milestone, project: project) }
......
require 'spec_helper'
describe Notes::SlashCommandsService, services: true do
describe Notes::QuickActionsService, services: true do
shared_context 'note on noteable' do
let(:project) { create(:empty_project) }
let(:master) { create(:user).tap { |u| project.team << [u, :master] } }
......@@ -11,7 +11,7 @@ describe Notes::SlashCommandsService, services: true do
end
end
shared_examples 'note on noteable that does not support slash commands' do
shared_examples 'note on noteable that does not support quick actions' do
include_context 'note on noteable'
before do
......@@ -45,7 +45,7 @@ describe Notes::SlashCommandsService, services: true do
end
end
shared_examples 'note on noteable that supports slash commands' do
shared_examples 'note on noteable that supports quick actions' do
include_context 'note on noteable'
before do
......@@ -210,15 +210,15 @@ describe Notes::SlashCommandsService, services: true do
describe '#execute' do
let(:service) { described_class.new(project, master) }
it_behaves_like 'note on noteable that supports slash commands' do
it_behaves_like 'note on noteable that supports quick actions' do
let(:note) { build(:note_on_issue, project: project) }
end
it_behaves_like 'note on noteable that supports slash commands' do
it_behaves_like 'note on noteable that supports quick actions' do
let(:note) { build(:note_on_merge_request, project: project) }
end
it_behaves_like 'note on noteable that does not support slash commands' do
it_behaves_like 'note on noteable that does not support quick actions' do
let(:note) { build(:note_on_commit, project: project) }
end
end
......
......@@ -19,24 +19,24 @@ describe PreviewMarkdownService do
end
end
context 'new note with slash commands' do
context 'new note with quick actions' do
let(:issue) { create(:issue, project: project) }
let(:params) do
{
text: "Please do it\n/assign #{user.to_reference}",
slash_commands_target_type: 'Issue',
slash_commands_target_id: issue.id
quick_actions_target_type: 'Issue',
quick_actions_target_id: issue.id
}
end
let(:service) { described_class.new(project, user, params) }
it 'removes slash commands from text' do
it 'removes quick actions from text' do
result = service.execute
expect(result[:text]).to eq 'Please do it'
end
it 'explains slash commands effect' do
it 'explains quick actions effect' do
result = service.execute
expect(result[:commands]).to eq "Assigns #{user.to_reference}."
......@@ -47,18 +47,18 @@ describe PreviewMarkdownService do
let(:params) do
{
text: "My work\n/estimate 2y",
slash_commands_target_type: 'MergeRequest'
quick_actions_target_type: 'MergeRequest'
}
end
let(:service) { described_class.new(project, user, params) }
it 'removes slash commands from text' do
it 'removes quick actions from text' do
result = service.execute
expect(result[:text]).to eq 'My work'
end
it 'explains slash commands effect' do
it 'explains quick actions effect' do
result = service.execute
expect(result[:commands]).to eq 'Sets time estimate to 2y.'
......
require 'spec_helper'
describe SlashCommands::InterpretService, services: true do
describe QuickActions::InterpretService, services: true do
let(:project) { create(:empty_project, :public) }
let(:developer) { create(:user) }
let(:developer2) { create(:user) }
......
......@@ -87,7 +87,7 @@ RSpec.shared_examples 'chat slash commands service' do
end
it 'triggers the command' do
expect_any_instance_of(Gitlab::ChatCommands::Command).to receive(:execute)
expect_any_instance_of(Gitlab::SlashCommands::Command).to receive(:execute)
subject.trigger(params)
end
......
# Specifications for behavior common to all objects with executable attributes.
# It takes a `issuable_type`, and expect an `issuable`.
shared_examples 'issuable record that supports slash commands in its description and notes' do |issuable_type|
include SlashCommandsHelpers
shared_examples 'issuable record that supports quick actions in its description and notes' do |issuable_type|
include QuickActionsHelpers
let(:master) { create(:user) }
let(:assignee) { create(:user, username: 'bob') }
......@@ -260,7 +260,7 @@ shared_examples 'issuable record that supports slash commands in its description
end
describe "preview of note on #{issuable_type}" do
it 'removes slash commands from note and explains them' do
it 'removes quick actions from note and explains them' do
visit public_send("namespace_project_#{issuable_type}_path", project.namespace, project, issuable)
page.within('.js-main-target-form') do
......
module SlashCommandsHelpers
module QuickActionsHelpers
def write_note(text)
Sidekiq::Testing.fake! do
page.within('.js-main-target-form') do
......
# Specifications for behavior common to all objects with executable attributes.
# It can take a `default_params`.
shared_examples 'new issuable record that supports slash commands' do
shared_examples 'new issuable record that supports quick actions' do
let!(:project) { create(:project, :repository) }
let(:user) { create(:user).tap { |u| project.team << [u, :master] } }
let(:assignee) { create(:user) }
......
......@@ -54,7 +54,7 @@ shared_examples 'issuable time tracker' do
it 'shows the help state when icon is clicked' do
page.within '.time-tracking-component-wrap' do
find('.help-button').click
expect(page).to have_content 'Track time with slash commands'
expect(page).to have_content 'Track time with quick actions'
expect(page).to have_content 'Learn more'
end
end
......@@ -64,7 +64,7 @@ shared_examples 'issuable time tracker' do
find('.help-button').click
find('.close-help-button').click
expect(page).not_to have_content 'Track time with slash commands'
expect(page).not_to have_content 'Track time with quick actions'
expect(page).not_to have_content 'Learn more'
end
end
......@@ -78,8 +78,8 @@ shared_examples 'issuable time tracker' do
end
end
def submit_time(slash_command)
fill_in 'note[note]', with: slash_command
def submit_time(quick_action)
fill_in 'note[note]', with: quick_action
find('.js-comment-submit-button').trigger('click')
wait_for_requests
end
......@@ -20,8 +20,8 @@ describe 'shared/notes/_form' do
context "with a note on #{noteable}" do
let(:note) { build(:"note_on_#{noteable}", project: project) }
it 'says that markdown and slash commands are supported' do
expect(rendered).to have_content('Markdown and slash commands are supported')
it 'says that markdown and quick actions are supported' do
expect(rendered).to have_content('Markdown and quick actions are supported')
end
end
end
......@@ -29,7 +29,7 @@ describe 'shared/notes/_form' do
context 'with a note on a commit' do
let(:note) { build(:note_on_commit, project: project) }
it 'says that only markdown is supported, not slash commands' do
it 'says that only markdown is supported, not quick actions' do
expect(rendered).to have_content('Markdown is supported')
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