diff options
author | Eric Eastwood <contact@ericeastwood.com> | 2017-05-31 08:50:53 +0300 |
---|---|---|
committer | Eric Eastwood <contact@ericeastwood.com> | 2017-06-15 17:01:56 +0300 |
commit | ea090291bba6bb665b3631cc5a2659e6673a6959 (patch) | |
tree | 1daf4c15aee8afc0eebef94a345eb077d0390632 /lib/gitlab/slash_commands | |
parent | 42aaae9916b7b76da968579fcc722067947df018 (diff) |
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`
Diffstat (limited to 'lib/gitlab/slash_commands')
20 files changed, 641 insertions, 351 deletions
diff --git a/lib/gitlab/slash_commands/base_command.rb b/lib/gitlab/slash_commands/base_command.rb new file mode 100644 index 00000000000..cc3c9a50555 --- /dev/null +++ b/lib/gitlab/slash_commands/base_command.rb @@ -0,0 +1,47 @@ +module Gitlab + module SlashCommands + class BaseCommand + QUERY_LIMIT = 5 + + def self.match(_text) + raise NotImplementedError + end + + def self.help_message + raise NotImplementedError + end + + def self.available?(_project) + raise NotImplementedError + end + + def self.allowed?(_user, _ability) + true + end + + def self.can?(object, action, subject) + Ability.allowed?(object, action, subject) + end + + def execute(_) + raise NotImplementedError + end + + def collection + raise NotImplementedError + end + + attr_accessor :project, :current_user, :params + + def initialize(project, user, params = {}) + @project, @current_user, @params = project, user, params.dup + end + + private + + def find_by_iid(iid) + collection.find_by(iid: iid) + end + end + end +end diff --git a/lib/gitlab/slash_commands/command.rb b/lib/gitlab/slash_commands/command.rb new file mode 100644 index 00000000000..a78408b0519 --- /dev/null +++ b/lib/gitlab/slash_commands/command.rb @@ -0,0 +1,44 @@ +module Gitlab + module SlashCommands + class Command < BaseCommand + COMMANDS = [ + Gitlab::SlashCommands::IssueShow, + Gitlab::SlashCommands::IssueNew, + Gitlab::SlashCommands::IssueSearch, + Gitlab::SlashCommands::Deploy + ].freeze + + def execute + command, match = match_command + + if command + if command.allowed?(project, current_user) + command.new(project, current_user, params).execute(match) + else + Gitlab::SlashCommands::Presenters::Access.new.access_denied + end + else + Gitlab::SlashCommands::Help.new(project, current_user, params).execute(available_commands, params[:text]) + end + end + + def match_command + match = nil + service = + available_commands.find do |klass| + match = klass.match(params[:text]) + end + + [service, match] + end + + private + + def available_commands + COMMANDS.select do |klass| + klass.available?(project) + end + end + end + end +end diff --git a/lib/gitlab/slash_commands/command_definition.rb b/lib/gitlab/slash_commands/command_definition.rb deleted file mode 100644 index caab8856014..00000000000 --- a/lib/gitlab/slash_commands/command_definition.rb +++ /dev/null @@ -1,89 +0,0 @@ -module Gitlab - module SlashCommands - class CommandDefinition - attr_accessor :name, :aliases, :description, :explanation, :params, - :condition_block, :parse_params_block, :action_block - - def initialize(name, attributes = {}) - @name = name - - @aliases = attributes[:aliases] || [] - @description = attributes[:description] || '' - @explanation = attributes[:explanation] || '' - @params = attributes[:params] || [] - @condition_block = attributes[:condition_block] - @parse_params_block = attributes[:parse_params_block] - @action_block = attributes[:action_block] - end - - def all_names - [name, *aliases] - end - - def noop? - action_block.nil? - end - - def available?(opts) - return true unless condition_block - - context = OpenStruct.new(opts) - context.instance_exec(&condition_block) - end - - def explain(context, opts, arg) - return unless available?(opts) - - if explanation.respond_to?(:call) - execute_block(explanation, context, arg) - else - explanation - end - end - - def execute(context, opts, arg) - return if noop? || !available?(opts) - - execute_block(action_block, context, arg) - end - - def to_h(opts) - context = OpenStruct.new(opts) - - desc = description - if desc.respond_to?(:call) - desc = context.instance_exec(&desc) rescue '' - end - - prms = params - if prms.respond_to?(:call) - prms = Array(context.instance_exec(&prms)) rescue params - end - - { - name: name, - aliases: aliases, - description: desc, - params: prms - } - end - - private - - def execute_block(block, context, arg) - if arg.present? - parsed = parse_params(arg, context) - context.instance_exec(parsed, &block) - elsif block.arity == 0 - context.instance_exec(&block) - end - end - - def parse_params(arg, context) - return arg unless parse_params_block - - context.instance_exec(arg, &parse_params_block) - end - end - end -end diff --git a/lib/gitlab/slash_commands/deploy.rb b/lib/gitlab/slash_commands/deploy.rb new file mode 100644 index 00000000000..e71eb15d604 --- /dev/null +++ b/lib/gitlab/slash_commands/deploy.rb @@ -0,0 +1,50 @@ +module Gitlab + module SlashCommands + class Deploy < BaseCommand + def self.match(text) + /\Adeploy\s+(?<from>\S+.*)\s+to+\s+(?<to>\S+.*)\z/.match(text) + end + + def self.help_message + 'deploy <environment> to <target-environment>' + end + + def self.available?(project) + project.builds_enabled? + end + + def self.allowed?(project, user) + can?(user, :create_deployment, project) + end + + def execute(match) + from = match[:from] + to = match[:to] + + actions = find_actions(from, to) + + if actions.none? + Gitlab::SlashCommands::Presenters::Deploy.new(nil).no_actions + elsif actions.one? + action = play!(from, to, actions.first) + Gitlab::SlashCommands::Presenters::Deploy.new(action).present(from, to) + else + Gitlab::SlashCommands::Presenters::Deploy.new(actions).too_many_actions + end + end + + private + + def play!(from, to, action) + action.play(current_user) + end + + def find_actions(from, to) + environment = project.environments.find_by(name: from) + return [] unless environment + + environment.actions_for(to).select(&:starts_environment?) + end + end + end +end diff --git a/lib/gitlab/slash_commands/dsl.rb b/lib/gitlab/slash_commands/dsl.rb deleted file mode 100644 index 1b5b4566d81..00000000000 --- a/lib/gitlab/slash_commands/dsl.rb +++ /dev/null @@ -1,140 +0,0 @@ -module Gitlab - module SlashCommands - module Dsl - extend ActiveSupport::Concern - - included do - cattr_accessor :command_definitions, instance_accessor: false do - [] - end - - cattr_accessor :command_definitions_by_name, instance_accessor: false do - {} - end - end - - class_methods do - # Allows to give a description to the next slash command. - # This description is shown in the autocomplete menu. - # It accepts a block that will be evaluated with the context given to - # `CommandDefintion#to_h`. - # - # Example: - # - # desc do - # "This is a dynamic description for #{noteable.to_ability_name}" - # end - # command :command_key do |arguments| - # # Awesome code block - # end - def desc(text = '', &block) - @description = block_given? ? block : text - end - - # Allows to define params for the next slash command. - # These params are shown in the autocomplete menu. - # - # Example: - # - # params "~label ~label2" - # command :command_key do |arguments| - # # Awesome code block - # end - def params(*params, &block) - @params = block_given? ? block : params - end - - # Allows to give an explanation of what the command will do when - # executed. This explanation is shown when rendering the Markdown - # preview. - # - # Example: - # - # explanation do |arguments| - # "Adds label(s) #{arguments.join(' ')}" - # end - # command :command_key do |arguments| - # # Awesome code block - # end - def explanation(text = '', &block) - @explanation = block_given? ? block : text - end - - # Allows to define conditions that must be met in order for the command - # to be returned by `.command_names` & `.command_definitions`. - # It accepts a block that will be evaluated with the context given to - # `CommandDefintion#to_h`. - # - # Example: - # - # condition do - # project.public? - # end - # command :command_key do |arguments| - # # Awesome code block - # end - def condition(&block) - @condition_block = block - end - - # Allows to perform initial parsing of parameters. The result is passed - # both to `command` and `explanation` blocks, instead of the raw - # parameters. - # It accepts a block that will be evaluated with the context given to - # `CommandDefintion#to_h`. - # - # Example: - # - # parse_params do |raw| - # raw.strip - # end - # command :command_key do |parsed| - # # Awesome code block - # end - def parse_params(&block) - @parse_params_block = block - end - - # Registers a new command which is recognizeable from body of email or - # comment. - # It accepts aliases and takes a block. - # - # Example: - # - # command :my_command, :alias_for_my_command do |arguments| - # # Awesome code block - # end - def command(*command_names, &block) - name, *aliases = command_names - - definition = CommandDefinition.new( - name, - aliases: aliases, - description: @description, - explanation: @explanation, - params: @params, - condition_block: @condition_block, - parse_params_block: @parse_params_block, - action_block: block - ) - - self.command_definitions << definition - - definition.all_names.each do |name| - self.command_definitions_by_name[name] = definition - end - - @description = nil - @explanation = nil - @params = nil - @condition_block = nil - @parse_params_block = nil - end - - def definition_by_name(name) - command_definitions_by_name[name.to_sym] - end - end - end - end -end diff --git a/lib/gitlab/slash_commands/extractor.rb b/lib/gitlab/slash_commands/extractor.rb deleted file mode 100644 index 6dbb467d70d..00000000000 --- a/lib/gitlab/slash_commands/extractor.rb +++ /dev/null @@ -1,122 +0,0 @@ -module Gitlab - module SlashCommands - # This class takes an array of commands that should be extracted from a - # given text. - # - # ``` - # extractor = Gitlab::SlashCommands::Extractor.new([:open, :assign, :labels]) - # ``` - class Extractor - attr_reader :command_definitions - - def initialize(command_definitions) - @command_definitions = command_definitions - end - - # Extracts commands from content and return an array of commands. - # The array looks like the following: - # [ - # ['command1'], - # ['command3', 'arg1 arg2'], - # ] - # The command and the arguments are stripped. - # The original command text is removed from the given `content`. - # - # Usage: - # ``` - # extractor = Gitlab::SlashCommands::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" - # ``` - def extract_commands(content, opts = {}) - return [content, []] unless content - - content = content.dup - - commands = [] - - content.delete!("\r") - content.gsub!(commands_regex(opts)) do - if $~[:cmd] - commands << [$~[:cmd], $~[:arg]].reject(&:blank?) - '' - else - $~[0] - end - end - - [content.strip, commands] - end - - private - - # Builds a regular expression to match known commands. - # First match group captures the command name and - # second match group captures its arguments. - # - # It looks something like: - # - # /^\/(?<cmd>close|reopen|...)(?:( |$))(?<arg>[^\/\n]*)(?:\n|$)/ - def commands_regex(opts) - names = command_names(opts).map(&:to_s) - - @commands_regex ||= %r{ - (?<code> - # Code blocks: - # ``` - # Anything, including `/cmd arg` which are ignored by this filter - # ``` - - ^``` - .+? - \n```$ - ) - | - (?<html> - # HTML block: - # <tag> - # Anything, including `/cmd arg` which are ignored by this filter - # </tag> - - ^<[^>]+?>\n - .+? - \n<\/[^>]+?>$ - ) - | - (?<html> - # Quote block: - # >>> - # Anything, including `/cmd arg` which are ignored by this filter - # >>> - - ^>>> - .+? - \n>>>$ - ) - | - (?: - # Command not in a blockquote, blockcode, or HTML tag: - # /close - - ^\/ - (?<cmd>#{Regexp.union(names)}) - (?: - [ ] - (?<arg>[^\n]*) - )? - (?:\n|$) - ) - }mx - end - - def command_names(opts) - command_definitions.flat_map do |command| - next if command.noop? - - command.all_names - end.compact - end - end - end -end diff --git a/lib/gitlab/slash_commands/help.rb b/lib/gitlab/slash_commands/help.rb new file mode 100644 index 00000000000..81f3707e03e --- /dev/null +++ b/lib/gitlab/slash_commands/help.rb @@ -0,0 +1,28 @@ +module Gitlab + 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 + # command + def self.match(_text) + true + end + + def self.help_message + 'help' + end + + def self.allowed?(_project, _user) + true + end + + def execute(commands, text) + Gitlab::SlashCommands::Presenters::Help.new(commands).present(trigger, text) + end + + def trigger + params[:command] + end + end + end +end diff --git a/lib/gitlab/slash_commands/issue_command.rb b/lib/gitlab/slash_commands/issue_command.rb new file mode 100644 index 00000000000..87ea19b8806 --- /dev/null +++ b/lib/gitlab/slash_commands/issue_command.rb @@ -0,0 +1,13 @@ +module Gitlab + module SlashCommands + class IssueCommand < BaseCommand + def self.available?(project) + project.issues_enabled? && project.default_issues_tracker? + end + + def collection + IssuesFinder.new(current_user, project_id: project.id).execute + end + end + end +end diff --git a/lib/gitlab/slash_commands/issue_new.rb b/lib/gitlab/slash_commands/issue_new.rb new file mode 100644 index 00000000000..25f965e843d --- /dev/null +++ b/lib/gitlab/slash_commands/issue_new.rb @@ -0,0 +1,42 @@ +module Gitlab + module SlashCommands + class IssueNew < IssueCommand + def self.match(text) + # we can not match \n with the dot by passing the m modifier as than + # the title and description are not seperated + /\Aissue\s+(new|create)\s+(?<title>[^\n]*)\n*(?<description>(.|\n)*)/.match(text) + end + + def self.help_message + 'issue new <title> *`⇧ Shift`*+*`↵ Enter`* <description>' + end + + def self.allowed?(project, user) + can?(user, :create_issue, project) + end + + def execute(match) + title = match[:title] + description = match[:description].to_s.rstrip + + issue = create_issue(title: title, description: description) + + if issue.persisted? + presenter(issue).present + else + presenter(issue).display_errors + end + end + + private + + def create_issue(title:, description:) + Issues::CreateService.new(project, current_user, title: title, description: description).execute + end + + def presenter(issue) + Gitlab::SlashCommands::Presenters::IssueNew.new(issue) + end + end + end +end diff --git a/lib/gitlab/slash_commands/issue_search.rb b/lib/gitlab/slash_commands/issue_search.rb new file mode 100644 index 00000000000..acba84b54b4 --- /dev/null +++ b/lib/gitlab/slash_commands/issue_search.rb @@ -0,0 +1,23 @@ +module Gitlab + module SlashCommands + class IssueSearch < IssueCommand + def self.match(text) + /\Aissue\s+search\s+(?<query>.*)/.match(text) + end + + def self.help_message + "issue search <your query>" + end + + def execute(match) + issues = collection.search(match[:query]).limit(QUERY_LIMIT) + + if issues.present? + Presenters::IssueSearch.new(issues).present + else + Presenters::Access.new(issues).not_found + end + end + end + end +end diff --git a/lib/gitlab/slash_commands/issue_show.rb b/lib/gitlab/slash_commands/issue_show.rb new file mode 100644 index 00000000000..ffa5184e5cb --- /dev/null +++ b/lib/gitlab/slash_commands/issue_show.rb @@ -0,0 +1,23 @@ +module Gitlab + module SlashCommands + class IssueShow < IssueCommand + def self.match(text) + /\Aissue\s+show\s+#{Issue.reference_prefix}?(?<iid>\d+)/.match(text) + end + + def self.help_message + "issue show <id>" + end + + def execute(match) + issue = find_by_iid(match[:iid]) + + if issue + Gitlab::SlashCommands::Presenters::IssueShow.new(issue).present + else + Gitlab::SlashCommands::Presenters::Access.new.not_found + end + end + end + end +end diff --git a/lib/gitlab/slash_commands/presenters/access.rb b/lib/gitlab/slash_commands/presenters/access.rb new file mode 100644 index 00000000000..1a817eb735b --- /dev/null +++ b/lib/gitlab/slash_commands/presenters/access.rb @@ -0,0 +1,40 @@ +module Gitlab + module SlashCommands + module Presenters + class Access < Presenters::Base + def access_denied + ephemeral_response(text: "Whoops! This action is not allowed. This incident will be [reported](https://xkcd.com/838/).") + end + + def not_found + ephemeral_response(text: "404 not found! GitLab couldn't find what you were looking for! :boom:") + end + + def authorize + message = + if @resource + ":wave: Hi there! Before I do anything for you, please [connect your GitLab account](#{@resource})." + else + ":sweat_smile: Couldn't identify you, nor can I autorize you!" + end + + ephemeral_response(text: message) + end + + def unknown_command(commands) + ephemeral_response(text: help_message(trigger)) + end + + private + + def help_message(trigger) + header_with_list("Command not found, these are the commands you can use", full_commands(trigger)) + end + + def full_commands(trigger) + @resource.map { |command| "#{trigger} #{command.help_message}" } + end + end + end + end +end diff --git a/lib/gitlab/slash_commands/presenters/base.rb b/lib/gitlab/slash_commands/presenters/base.rb new file mode 100644 index 00000000000..27696436574 --- /dev/null +++ b/lib/gitlab/slash_commands/presenters/base.rb @@ -0,0 +1,77 @@ +module Gitlab + module SlashCommands + module Presenters + class Base + include Gitlab::Routing.url_helpers + + def initialize(resource = nil) + @resource = resource + end + + def display_errors + message = header_with_list("The action was not successful, because:", @resource.errors.full_messages) + + ephemeral_response(text: message) + end + + private + + def header_with_list(header, items) + message = [header] + + items.each do |item| + message << "- #{item}" + end + + message.join("\n") + end + + def ephemeral_response(message) + response = { + response_type: :ephemeral, + status: 200 + }.merge(message) + + format_response(response) + end + + def in_channel_response(message) + response = { + response_type: :in_channel, + status: 200 + }.merge(message) + + format_response(response) + end + + def format_response(response) + response[:text] = format(response[:text]) if response.key?(:text) + + if response.key?(:attachments) + response[:attachments].each do |attachment| + attachment[:pretext] = format(attachment[:pretext]) if attachment[:pretext] + attachment[:text] = format(attachment[:text]) if attachment[:text] + end + end + + response + end + + # Convert Markdown to slacks format + def format(string) + Slack::Notifier::LinkFormatter.format(string) + end + + def resource_url + url_for( + [ + @resource.project.namespace.becomes(Namespace), + @resource.project, + @resource + ] + ) + end + end + end + end +end diff --git a/lib/gitlab/slash_commands/presenters/deploy.rb b/lib/gitlab/slash_commands/presenters/deploy.rb new file mode 100644 index 00000000000..b8dc77bd37b --- /dev/null +++ b/lib/gitlab/slash_commands/presenters/deploy.rb @@ -0,0 +1,21 @@ +module Gitlab + module SlashCommands + module Presenters + class Deploy < Presenters::Base + def present(from, to) + message = "Deployment started from #{from} to #{to}. [Follow its progress](#{resource_url})." + + in_channel_response(text: message) + end + + def no_actions + ephemeral_response(text: "No action found to be executed") + end + + def too_many_actions + ephemeral_response(text: "Too many actions defined") + end + end + end + end +end diff --git a/lib/gitlab/slash_commands/presenters/help.rb b/lib/gitlab/slash_commands/presenters/help.rb new file mode 100644 index 00000000000..ea611a4d629 --- /dev/null +++ b/lib/gitlab/slash_commands/presenters/help.rb @@ -0,0 +1,27 @@ +module Gitlab + module SlashCommands + module Presenters + class Help < Presenters::Base + def present(trigger, text) + ephemeral_response(text: help_message(trigger, text)) + end + + private + + def help_message(trigger, text) + return "No commands available :thinking_face:" unless @resource.present? + + if text.start_with?('help') + header_with_list("Available commands", full_commands(trigger)) + else + header_with_list("Unknown command, these commands are available", full_commands(trigger)) + end + end + + def full_commands(trigger) + @resource.map { |command| "#{trigger} #{command.help_message}" } + end + end + end + end +end diff --git a/lib/gitlab/slash_commands/presenters/issue_base.rb b/lib/gitlab/slash_commands/presenters/issue_base.rb new file mode 100644 index 00000000000..341f2aabdd0 --- /dev/null +++ b/lib/gitlab/slash_commands/presenters/issue_base.rb @@ -0,0 +1,43 @@ +module Gitlab + module SlashCommands + module Presenters + module IssueBase + def color(issuable) + issuable.open? ? '#38ae67' : '#d22852' + end + + def status_text(issuable) + issuable.open? ? 'Open' : 'Closed' + end + + def project + @resource.project + end + + def author + @resource.author + end + + def fields + [ + { + title: "Assignee", + value: @resource.assignees.any? ? @resource.assignees.first.name : "_None_", + short: true + }, + { + title: "Milestone", + value: @resource.milestone ? @resource.milestone.title : "_None_", + short: true + }, + { + title: "Labels", + value: @resource.labels.any? ? @resource.label_names.join(', ') : "_None_", + short: true + } + ] + end + end + end + end +end diff --git a/lib/gitlab/slash_commands/presenters/issue_new.rb b/lib/gitlab/slash_commands/presenters/issue_new.rb new file mode 100644 index 00000000000..86490a39cc1 --- /dev/null +++ b/lib/gitlab/slash_commands/presenters/issue_new.rb @@ -0,0 +1,50 @@ +module Gitlab + module SlashCommands + module Presenters + class IssueNew < Presenters::Base + include Presenters::IssueBase + + def present + in_channel_response(new_issue) + end + + private + + def new_issue + { + attachments: [ + { + title: "#{@resource.title} · #{@resource.to_reference}", + title_link: resource_url, + author_name: author.name, + author_icon: author.avatar_url, + fallback: "New issue #{@resource.to_reference}: #{@resource.title}", + pretext: pretext, + color: color(@resource), + fields: fields, + mrkdwn_in: [ + :title, + :pretext, + :text, + :fields + ] + } + ] + } + end + + def pretext + "I created an issue on #{author_profile_link}'s behalf: **#{@resource.to_reference}** in #{project_link}" + end + + def project_link + "[#{project.name_with_namespace}](#{project.web_url})" + end + + def author_profile_link + "[#{author.to_reference}](#{url_for(author)})" + end + end + end + end +end diff --git a/lib/gitlab/slash_commands/presenters/issue_search.rb b/lib/gitlab/slash_commands/presenters/issue_search.rb new file mode 100644 index 00000000000..4e27d668685 --- /dev/null +++ b/lib/gitlab/slash_commands/presenters/issue_search.rb @@ -0,0 +1,47 @@ +module Gitlab + module SlashCommands + module Presenters + class IssueSearch < Presenters::Base + include Presenters::IssueBase + + def present + text = if @resource.count >= 5 + "Here are the first 5 issues I found:" + elsif @resource.one? + "Here is the only issue I found:" + else + "Here are the #{@resource.count} issues I found:" + end + + ephemeral_response(text: text, attachments: attachments) + end + + private + + def attachments + @resource.map do |issue| + url = "[#{issue.to_reference}](#{url_for([namespace, project, issue])})" + + { + color: color(issue), + fallback: "#{issue.to_reference} #{issue.title}", + text: "#{url} · #{issue.title} (#{status_text(issue)})", + + mrkdwn_in: [ + :text + ] + } + end + end + + def project + @project ||= @resource.first.project + end + + def namespace + @namespace ||= project.namespace.becomes(Namespace) + end + end + end + end +end diff --git a/lib/gitlab/slash_commands/presenters/issue_show.rb b/lib/gitlab/slash_commands/presenters/issue_show.rb new file mode 100644 index 00000000000..c99316df667 --- /dev/null +++ b/lib/gitlab/slash_commands/presenters/issue_show.rb @@ -0,0 +1,61 @@ +module Gitlab + module SlashCommands + module Presenters + class IssueShow < Presenters::Base + include Presenters::IssueBase + + def present + if @resource.confidential? + ephemeral_response(show_issue) + else + in_channel_response(show_issue) + end + end + + private + + def show_issue + { + attachments: [ + { + title: "#{@resource.title} · #{@resource.to_reference}", + title_link: resource_url, + author_name: author.name, + author_icon: author.avatar_url, + fallback: "Issue #{@resource.to_reference}: #{@resource.title}", + pretext: pretext, + text: text, + color: color(@resource), + fields: fields, + mrkdwn_in: [ + :pretext, + :text, + :fields + ] + } + ] + } + end + + def text + message = "**#{status_text(@resource)}**" + + if @resource.upvotes.zero? && @resource.downvotes.zero? && @resource.user_notes_count.zero? + return message + end + + message << " · " + message << ":+1: #{@resource.upvotes} " unless @resource.upvotes.zero? + message << ":-1: #{@resource.downvotes} " unless @resource.downvotes.zero? + message << ":speech_balloon: #{@resource.user_notes_count}" unless @resource.user_notes_count.zero? + + message + end + + def pretext + "Issue *#{@resource.to_reference}* from #{project.name_with_namespace}" + end + end + end + end +end diff --git a/lib/gitlab/slash_commands/result.rb b/lib/gitlab/slash_commands/result.rb new file mode 100644 index 00000000000..7021b4b01b2 --- /dev/null +++ b/lib/gitlab/slash_commands/result.rb @@ -0,0 +1,5 @@ +module Gitlab + module SlashCommands + Result = Struct.new(:type, :message) + end +end |