summaryrefslogtreecommitdiff
path: root/lib/gitlab/chat_commands
diff options
context:
space:
mode:
Diffstat (limited to 'lib/gitlab/chat_commands')
-rw-r--r--lib/gitlab/chat_commands/base_command.rb49
-rw-r--r--lib/gitlab/chat_commands/command.rb62
-rw-r--r--lib/gitlab/chat_commands/deploy.rb57
-rw-r--r--lib/gitlab/chat_commands/issue_command.rb17
-rw-r--r--lib/gitlab/chat_commands/issue_create.rb26
-rw-r--r--lib/gitlab/chat_commands/issue_show.rb17
-rw-r--r--lib/gitlab/chat_commands/result.rb5
7 files changed, 233 insertions, 0 deletions
diff --git a/lib/gitlab/chat_commands/base_command.rb b/lib/gitlab/chat_commands/base_command.rb
new file mode 100644
index 00000000000..e59d69b72b9
--- /dev/null
+++ b/lib/gitlab/chat_commands/base_command.rb
@@ -0,0 +1,49 @@
+module Gitlab
+ module ChatCommands
+ 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)
+ resource = collection.find_by(iid: iid)
+
+ readable?(resource) ? resource : nil
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/chat_commands/command.rb b/lib/gitlab/chat_commands/command.rb
new file mode 100644
index 00000000000..0ec358debc7
--- /dev/null
+++ b/lib/gitlab/chat_commands/command.rb
@@ -0,0 +1,62 @@
+module Gitlab
+ module ChatCommands
+ class Command < BaseCommand
+ COMMANDS = [
+ Gitlab::ChatCommands::IssueShow,
+ Gitlab::ChatCommands::IssueCreate,
+ Gitlab::ChatCommands::Deploy,
+ ].freeze
+
+ def execute
+ command, match = match_command
+
+ if command
+ if command.allowed?(project, current_user)
+ present command.new(project, current_user, params).execute(match)
+ else
+ access_denied
+ end
+ else
+ help(help_messages)
+ end
+ end
+
+ private
+
+ def match_command
+ match = nil
+ service = available_commands.find do |klass|
+ match = klass.match(command)
+ end
+
+ [service, match]
+ end
+
+ def help_messages
+ available_commands.map(&:help_message)
+ end
+
+ def available_commands
+ COMMANDS.select do |klass|
+ klass.available?(project)
+ end
+ end
+
+ def command
+ params[:text]
+ end
+
+ def help(messages)
+ Mattermost::Presenter.help(messages, params[:command])
+ end
+
+ def access_denied
+ Mattermost::Presenter.access_denied
+ end
+
+ def present(resource)
+ Mattermost::Presenter.present(resource)
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/chat_commands/deploy.rb b/lib/gitlab/chat_commands/deploy.rb
new file mode 100644
index 00000000000..0eed1fce0dc
--- /dev/null
+++ b/lib/gitlab/chat_commands/deploy.rb
@@ -0,0 +1,57 @@
+module Gitlab
+ module ChatCommands
+ class Deploy < BaseCommand
+ include Gitlab::Routing.url_helpers
+
+ def self.match(text)
+ /\Adeploy\s+(?<from>.*)\s+to+\s+(?<to>.*)\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)
+ return unless actions.present?
+
+ if actions.one?
+ play!(from, to, actions.first)
+ else
+ Result.new(:error, 'Too many actions defined')
+ end
+ end
+
+ private
+
+ def play!(from, to, action)
+ new_action = action.play(current_user)
+
+ Result.new(:success, "Deployment from #{from} to #{to} started. Follow the progress: #{url(new_action)}.")
+ end
+
+ def find_actions(from, to)
+ environment = project.environments.find_by(name: from)
+ return unless environment
+
+ environment.actions_for(to).select(&:starts_environment?)
+ end
+
+ def url(subject)
+ polymorphic_url(
+ [ subject.project.namespace.becomes(Namespace), subject.project, subject ])
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/chat_commands/issue_command.rb b/lib/gitlab/chat_commands/issue_command.rb
new file mode 100644
index 00000000000..f1bc36239d5
--- /dev/null
+++ b/lib/gitlab/chat_commands/issue_command.rb
@@ -0,0 +1,17 @@
+module Gitlab
+ module ChatCommands
+ class IssueCommand < BaseCommand
+ def self.available?(project)
+ project.issues_enabled? && project.default_issues_tracker?
+ end
+
+ def collection
+ project.issues
+ end
+
+ def readable?(issue)
+ self.class.can?(current_user, :read_issue, issue)
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/chat_commands/issue_create.rb b/lib/gitlab/chat_commands/issue_create.rb
new file mode 100644
index 00000000000..99c1382af44
--- /dev/null
+++ b/lib/gitlab/chat_commands/issue_create.rb
@@ -0,0 +1,26 @@
+module Gitlab
+ module ChatCommands
+ class IssueCreate < 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+create\s+(?<title>[^\n]*)\n*(?<description>(.|\n)*)/.match(text)
+ end
+
+ def self.help_message
+ 'issue create <title>\n<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
+
+ Issues::CreateService.new(project, current_user, title: title, description: description).execute
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/chat_commands/issue_show.rb b/lib/gitlab/chat_commands/issue_show.rb
new file mode 100644
index 00000000000..f5bceb038e5
--- /dev/null
+++ b/lib/gitlab/chat_commands/issue_show.rb
@@ -0,0 +1,17 @@
+module Gitlab
+ module ChatCommands
+ class IssueShow < IssueCommand
+ def self.match(text)
+ /\Aissue\s+show\s+(?<iid>\d+)/.match(text)
+ end
+
+ def self.help_message
+ "issue show <id>"
+ end
+
+ def execute(match)
+ find_by_iid(match[:iid])
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/chat_commands/result.rb b/lib/gitlab/chat_commands/result.rb
new file mode 100644
index 00000000000..324d7ef43a3
--- /dev/null
+++ b/lib/gitlab/chat_commands/result.rb
@@ -0,0 +1,5 @@
+module Gitlab
+ module ChatCommands
+ Result = Struct.new(:type, :message)
+ end
+end