summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelipe Artur <felipefac@gmail.com>2016-11-25 17:36:37 -0200
committerFelipe Artur <felipefac@gmail.com>2016-12-15 11:09:31 -0200
commit141faaacf9119ce5d765efe73c6509030ba078cd (patch)
tree1f5cf350087ad524273e0ba80c7ddcc3ce640ad8
parent2d1dfae9b63d35232e4bf537a0aca9b95e2d5e72 (diff)
downloadgitlab-ce-141faaacf9119ce5d765efe73c6509030ba078cd.tar.gz
Mattermost Notifications Service
-rw-r--r--app/models/project.rb1
-rw-r--r--app/models/project_services/chat_message/base_message.rb (renamed from app/models/project_services/slack_service/base_message.rb)2
-rw-r--r--app/models/project_services/chat_message/build_message.rb (renamed from app/models/project_services/slack_service/build_message.rb)2
-rw-r--r--app/models/project_services/chat_message/issue_message.rb (renamed from app/models/project_services/slack_service/issue_message.rb)2
-rw-r--r--app/models/project_services/chat_message/merge_message.rb (renamed from app/models/project_services/slack_service/merge_message.rb)2
-rw-r--r--app/models/project_services/chat_message/note_message.rb (renamed from app/models/project_services/slack_service/note_message.rb)2
-rw-r--r--app/models/project_services/chat_message/pipeline_message.rb (renamed from app/models/project_services/slack_service/pipeline_message.rb)2
-rw-r--r--app/models/project_services/chat_message/push_message.rb (renamed from app/models/project_services/slack_service/push_message.rb)2
-rw-r--r--app/models/project_services/chat_message/wiki_page_message.rb (renamed from app/models/project_services/slack_service/wiki_page_message.rb)2
-rw-r--r--app/models/project_services/chat_service.rb141
-rw-r--r--app/models/project_services/mattermost_service.rb41
-rw-r--r--app/models/project_services/mattermost_slash_commands_service.rb12
-rw-r--r--app/models/project_services/slack_service.rb174
-rw-r--r--app/models/service.rb1
-rw-r--r--changelogs/unreleased/issue_22269.yml4
-rw-r--r--doc/api/services.md38
-rw-r--r--doc/project_services/img/mattermost_configuration.pngbin0 -> 73502 bytes
-rw-r--r--doc/project_services/mattermost.md45
-rw-r--r--doc/project_services/project_services.md3
-rw-r--r--doc/project_services/slack.md4
-rw-r--r--spec/lib/gitlab/import_export/all_models.yml1
-rw-r--r--spec/models/project_services/chat_message/build_message_spec.rb (renamed from spec/models/project_services/slack_service/build_message_spec.rb)4
-rw-r--r--spec/models/project_services/chat_message/issue_message_spec.rb (renamed from spec/models/project_services/slack_service/issue_message_spec.rb)4
-rw-r--r--spec/models/project_services/chat_message/merge_message_spec.rb (renamed from spec/models/project_services/slack_service/merge_message_spec.rb)4
-rw-r--r--spec/models/project_services/chat_message/note_message_spec.rb (renamed from spec/models/project_services/slack_service/note_message_spec.rb)10
-rw-r--r--spec/models/project_services/chat_message/pipeline_message_spec.rb (renamed from spec/models/project_services/slack_service/pipeline_message_spec.rb)4
-rw-r--r--spec/models/project_services/chat_message/push_message_spec.rb (renamed from spec/models/project_services/slack_service/push_message_spec.rb)4
-rw-r--r--spec/models/project_services/chat_message/wiki_page_message_spec.rb (renamed from spec/models/project_services/slack_service/wiki_page_message_spec.rb)2
-rw-r--r--spec/models/project_services/chat_service_spec.rb11
-rw-r--r--spec/models/project_services/mattermost_service_spec.rb5
-rw-r--r--spec/models/project_services/slack_service_spec.rb324
-rw-r--r--spec/models/project_spec.rb1
-rw-r--r--spec/support/slack_mattermost_shared_examples.rb328
33 files changed, 658 insertions, 524 deletions
diff --git a/app/models/project.rb b/app/models/project.rb
index 2c726cfc5df..19c2d24212d 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -95,6 +95,7 @@ class Project < ActiveRecord::Base
has_one :asana_service, dependent: :destroy
has_one :gemnasium_service, dependent: :destroy
has_one :mattermost_slash_commands_service, dependent: :destroy
+ has_one :mattermost_service, dependent: :destroy
has_one :slack_service, dependent: :destroy
has_one :buildkite_service, dependent: :destroy
has_one :bamboo_service, dependent: :destroy
diff --git a/app/models/project_services/slack_service/base_message.rb b/app/models/project_services/chat_message/base_message.rb
index f1182824687..a03605d01fb 100644
--- a/app/models/project_services/slack_service/base_message.rb
+++ b/app/models/project_services/chat_message/base_message.rb
@@ -1,6 +1,6 @@
require 'slack-notifier'
-class SlackService
+module ChatMessage
class BaseMessage
def initialize(params)
raise NotImplementedError
diff --git a/app/models/project_services/slack_service/build_message.rb b/app/models/project_services/chat_message/build_message.rb
index 0fca4267bad..53e35cb21bf 100644
--- a/app/models/project_services/slack_service/build_message.rb
+++ b/app/models/project_services/chat_message/build_message.rb
@@ -1,4 +1,4 @@
-class SlackService
+module ChatMessage
class BuildMessage < BaseMessage
attr_reader :sha
attr_reader :ref_type
diff --git a/app/models/project_services/slack_service/issue_message.rb b/app/models/project_services/chat_message/issue_message.rb
index cd87a79d0c6..14fd64e5332 100644
--- a/app/models/project_services/slack_service/issue_message.rb
+++ b/app/models/project_services/chat_message/issue_message.rb
@@ -1,4 +1,4 @@
-class SlackService
+module ChatMessage
class IssueMessage < BaseMessage
attr_reader :user_name
attr_reader :title
diff --git a/app/models/project_services/slack_service/merge_message.rb b/app/models/project_services/chat_message/merge_message.rb
index b7615c96068..ab5e8b24167 100644
--- a/app/models/project_services/slack_service/merge_message.rb
+++ b/app/models/project_services/chat_message/merge_message.rb
@@ -1,4 +1,4 @@
-class SlackService
+module ChatMessage
class MergeMessage < BaseMessage
attr_reader :user_name
attr_reader :project_name
diff --git a/app/models/project_services/slack_service/note_message.rb b/app/models/project_services/chat_message/note_message.rb
index 797c5937f09..ca1d7207034 100644
--- a/app/models/project_services/slack_service/note_message.rb
+++ b/app/models/project_services/chat_message/note_message.rb
@@ -1,4 +1,4 @@
-class SlackService
+module ChatMessage
class NoteMessage < BaseMessage
attr_reader :message
attr_reader :user_name
diff --git a/app/models/project_services/slack_service/pipeline_message.rb b/app/models/project_services/chat_message/pipeline_message.rb
index b6355fc4171..210027565a8 100644
--- a/app/models/project_services/slack_service/pipeline_message.rb
+++ b/app/models/project_services/chat_message/pipeline_message.rb
@@ -1,4 +1,4 @@
-class SlackService
+module ChatMessage
class PipelineMessage < BaseMessage
attr_reader :ref_type, :ref, :status, :project_name, :project_url,
:user_name, :duration, :pipeline_id
diff --git a/app/models/project_services/slack_service/push_message.rb b/app/models/project_services/chat_message/push_message.rb
index b26f3e9ddce..2d73b71ec37 100644
--- a/app/models/project_services/slack_service/push_message.rb
+++ b/app/models/project_services/chat_message/push_message.rb
@@ -1,4 +1,4 @@
-class SlackService
+module ChatMessage
class PushMessage < BaseMessage
attr_reader :after
attr_reader :before
diff --git a/app/models/project_services/slack_service/wiki_page_message.rb b/app/models/project_services/chat_message/wiki_page_message.rb
index 160ca3ac115..134083e4504 100644
--- a/app/models/project_services/slack_service/wiki_page_message.rb
+++ b/app/models/project_services/chat_message/wiki_page_message.rb
@@ -1,4 +1,4 @@
-class SlackService
+module ChatMessage
class WikiPageMessage < BaseMessage
attr_reader :user_name
attr_reader :title
diff --git a/app/models/project_services/chat_service.rb b/app/models/project_services/chat_service.rb
index d36beff5fa6..8ac049ba939 100644
--- a/app/models/project_services/chat_service.rb
+++ b/app/models/project_services/chat_service.rb
@@ -1,21 +1,148 @@
# Base class for Chat services
# This class is not meant to be used directly, but only to inherrit from.
class ChatService < Service
+ include ChatMessage
+
default_value_for :category, 'chat'
- has_many :chat_names, foreign_key: :service_id
+ prop_accessor :webhook, :username, :channel
+ boolean_accessor :notify_only_broken_builds, :notify_only_broken_pipelines
+
+ validates :webhook, presence: true, url: true, if: :activated?
+
+ def initialize_properties
+ # Custom serialized properties initialization
+ self.supported_events.each { |event| self.class.prop_accessor(event_channel_name(event)) }
- def valid_token?(token)
- self.respond_to?(:token) &&
- self.token.present? &&
- ActiveSupport::SecurityUtils.variable_size_secure_compare(token, self.token)
+ if properties.nil?
+ self.properties = {}
+ self.notify_only_broken_builds = true
+ self.notify_only_broken_pipelines = true
+ end
+ end
+
+ def can_test?
+ valid?
end
def supported_events
- []
+ %w[push issue confidential_issue merge_request note tag_push
+ build pipeline wiki_page]
end
- def trigger(params)
+ def execute(data)
+ return unless supported_events.include?(data[:object_kind])
+ return unless webhook.present?
+
+ object_kind = data[:object_kind]
+
+ data = data.merge(
+ project_url: project_url,
+ project_name: project_name
+ )
+
+ # WebHook events often have an 'update' event that follows a 'open' or
+ # 'close' action. Ignore update events for now to prevent duplicate
+ # messages from arriving.
+
+ message = get_message(object_kind, data)
+
+ return false unless message
+
+ opt = {}
+
+ opt[:channel] = get_channel_field(object_kind).presence || channel || default_channel
+ opt[:username] = username if username
+
+ notifier = Slack::Notifier.new(webhook, opt)
+ notifier.ping(message.pretext, attachments: message.attachments, fallback: message.fallback)
+
+ true
+ end
+
+ def event_channel_names
+ supported_events.map { |event| event_channel_name(event) }
+ end
+
+ def event_field(event)
+ fields.find { |field| field[:name] == event_channel_name(event) }
+ end
+
+ def global_fields
+ fields.reject { |field| field[:name].end_with?('channel') }
+ end
+
+ def default_channel
raise NotImplementedError
end
+
+ private
+
+ def get_message(object_kind, data)
+ case object_kind
+ when "push", "tag_push"
+ PushMessage.new(data)
+ when "issue"
+ IssueMessage.new(data) unless is_update?(data)
+ when "merge_request"
+ MergeMessage.new(data) unless is_update?(data)
+ when "note"
+ NoteMessage.new(data)
+ when "build"
+ BuildMessage.new(data) if should_build_be_notified?(data)
+ when "pipeline"
+ PipelineMessage.new(data) if should_pipeline_be_notified?(data)
+ when "wiki_page"
+ WikiPageMessage.new(data)
+ end
+ end
+
+ def get_channel_field(event)
+ field_name = event_channel_name(event)
+ self.public_send(field_name)
+ end
+
+ def build_event_channels
+ supported_events.reduce([]) do |channels, event|
+ channels << { type: 'text', name: event_channel_name(event), placeholder: default_channel }
+ end
+ end
+
+ def event_channel_name(event)
+ "#{event}_channel"
+ end
+
+ def project_name
+ project.name_with_namespace.gsub(/\s/, '')
+ end
+
+ def project_url
+ project.web_url
+ end
+
+ def is_update?(data)
+ data[:object_attributes][:action] == 'update'
+ end
+
+ def should_build_be_notified?(data)
+ case data[:commit][:status]
+ when 'success'
+ !notify_only_broken_builds?
+ when 'failed'
+ true
+ else
+ false
+ end
+ end
+
+ def should_pipeline_be_notified?(data)
+ case data[:object_attributes][:status]
+ when 'success'
+ !notify_only_broken_pipelines?
+ when 'failed'
+ true
+ else
+ false
+ end
+ end
end
diff --git a/app/models/project_services/mattermost_service.rb b/app/models/project_services/mattermost_service.rb
new file mode 100644
index 00000000000..9d61c251a32
--- /dev/null
+++ b/app/models/project_services/mattermost_service.rb
@@ -0,0 +1,41 @@
+class MattermostService < ChatService
+ def title
+ 'Mattermost notifications'
+ end
+
+ def description
+ 'Receive event notifications in Mattermost'
+ end
+
+ def to_param
+ 'mattermost'
+ end
+
+ def help
+ 'This service sends notifications about projects events to Mattermost channels.<br />
+ To set up this service:
+ <ol>
+ <li><a href="https://docs.mattermost.com/developer/webhooks-incoming.html#enabling-incoming-webhooks">Enable incoming webhooks</a> in your Mattermost installation. </li>
+ <li><a href="https://docs.mattermost.com/developer/webhooks-incoming.html#creating-integrations-using-incoming-webhooks">Add an incoming webhook</a> in your Mattermost team. The default channel can be overridden for each event. </li>
+ <li>Paste the webhook <strong>URL</strong> into the field bellow. </li>
+ <li>Select events below to enable notifications. The channel and username are optional. </li>
+ </ol>'
+ end
+
+ def fields
+ default_fields + build_event_channels
+ end
+
+ def default_fields
+ [
+ { type: 'text', name: 'webhook', placeholder: 'http://mattermost_host/hooks/...' },
+ { type: 'text', name: 'username', placeholder: 'username' },
+ { type: 'checkbox', name: 'notify_only_broken_builds' },
+ { type: 'checkbox', name: 'notify_only_broken_pipelines' },
+ ]
+ end
+
+ def default_channel
+ "#town-square"
+ end
+end
diff --git a/app/models/project_services/mattermost_slash_commands_service.rb b/app/models/project_services/mattermost_slash_commands_service.rb
index 33431f41dc2..3993dfbda17 100644
--- a/app/models/project_services/mattermost_slash_commands_service.rb
+++ b/app/models/project_services/mattermost_slash_commands_service.rb
@@ -1,8 +1,18 @@
-class MattermostSlashCommandsService < ChatService
+class MattermostSlashCommandsService < Service
include TriggersHelper
prop_accessor :token
+ def valid_token?(token)
+ self.respond_to?(:token) &&
+ self.token.present? &&
+ ActiveSupport::SecurityUtils.variable_size_secure_compare(token, self.token)
+ end
+
+ def supported_events
+ []
+ end
+
def can_test?
false
end
diff --git a/app/models/project_services/slack_service.rb b/app/models/project_services/slack_service.rb
index e1b937817f4..0df1743c4ba 100644
--- a/app/models/project_services/slack_service.rb
+++ b/app/models/project_services/slack_service.rb
@@ -1,25 +1,10 @@
-class SlackService < Service
- prop_accessor :webhook, :username, :channel
- boolean_accessor :notify_only_broken_builds, :notify_only_broken_pipelines
- validates :webhook, presence: true, url: true, if: :activated?
-
- def initialize_properties
- # Custom serialized properties initialization
- self.supported_events.each { |event| self.class.prop_accessor(event_channel_name(event)) }
-
- if properties.nil?
- self.properties = {}
- self.notify_only_broken_builds = true
- self.notify_only_broken_pipelines = true
- end
- end
-
+class SlackService < ChatService
def title
- 'Slack'
+ 'Slack notifications'
end
def description
- 'A team communication tool for the 21st century'
+ 'Receive event notifications in Slack'
end
def to_param
@@ -27,150 +12,29 @@ class SlackService < Service
end
def help
- 'This service sends notifications to your Slack channel.<br/>
- To setup this Service you need to create a new <b>"Incoming webhook"</b> in your Slack integration panel,
- and enter the Webhook URL below.'
+ 'This service sends notifications about projects events to Slack channels.<br />
+ To setup this service:
+ <ol>
+ <li><a href="https://slack.com/apps/A0F7XDUAZ-incoming-webhooks">Add an incoming webhook</a> in your Slack team. The default channel can be overridden for each event. </li>
+ <li>Paste the <strong>Webhook URL</strong> into the field below. </li>
+ <li>Select events below to enable notifications. The channel and username are optional. </li>
+ </ol>'
end
def fields
- default_fields =
- [
- { type: 'text', name: 'webhook', placeholder: 'https://hooks.slack.com/services/...' },
- { type: 'text', name: 'username', placeholder: 'username' },
- { type: 'text', name: 'channel', placeholder: "#general" },
- { type: 'checkbox', name: 'notify_only_broken_builds' },
- { type: 'checkbox', name: 'notify_only_broken_pipelines' },
- ]
-
default_fields + build_event_channels
end
- def supported_events
- %w[push issue confidential_issue merge_request note tag_push
- build pipeline wiki_page]
- end
-
- def execute(data)
- return unless supported_events.include?(data[:object_kind])
- return unless webhook.present?
-
- object_kind = data[:object_kind]
-
- data = data.merge(
- project_url: project_url,
- project_name: project_name
- )
-
- # WebHook events often have an 'update' event that follows a 'open' or
- # 'close' action. Ignore update events for now to prevent duplicate
- # messages from arriving.
-
- message = get_message(object_kind, data)
-
- if message
- opt = {}
-
- event_channel = get_channel_field(object_kind) || channel
-
- opt[:channel] = event_channel if event_channel
- opt[:username] = username if username
-
- notifier = Slack::Notifier.new(webhook, opt)
- notifier.ping(message.pretext, attachments: message.attachments, fallback: message.fallback)
-
- true
- else
- false
- end
- end
-
- def event_channel_names
- supported_events.map { |event| event_channel_name(event) }
- end
-
- def event_field(event)
- fields.find { |field| field[:name] == event_channel_name(event) }
+ def default_fields
+ [
+ { type: 'text', name: 'webhook', placeholder: 'https://hooks.slack.com/services/...' },
+ { type: 'text', name: 'username', placeholder: 'username' },
+ { type: 'checkbox', name: 'notify_only_broken_builds' },
+ { type: 'checkbox', name: 'notify_only_broken_pipelines' },
+ ]
end
- def global_fields
- fields.reject { |field| field[:name].end_with?('channel') }
- end
-
- private
-
- def get_message(object_kind, data)
- case object_kind
- when "push", "tag_push"
- PushMessage.new(data)
- when "issue"
- IssueMessage.new(data) unless is_update?(data)
- when "merge_request"
- MergeMessage.new(data) unless is_update?(data)
- when "note"
- NoteMessage.new(data)
- when "build"
- BuildMessage.new(data) if should_build_be_notified?(data)
- when "pipeline"
- PipelineMessage.new(data) if should_pipeline_be_notified?(data)
- when "wiki_page"
- WikiPageMessage.new(data)
- end
- end
-
- def get_channel_field(event)
- field_name = event_channel_name(event)
- self.public_send(field_name)
- end
-
- def build_event_channels
- supported_events.reduce([]) do |channels, event|
- channels << { type: 'text', name: event_channel_name(event), placeholder: "#general" }
- end
- end
-
- def event_channel_name(event)
- "#{event}_channel"
- end
-
- def project_name
- project.name_with_namespace.gsub(/\s/, '')
- end
-
- def project_url
- project.web_url
- end
-
- def is_update?(data)
- data[:object_attributes][:action] == 'update'
- end
-
- def should_build_be_notified?(data)
- case data[:commit][:status]
- when 'success'
- !notify_only_broken_builds?
- when 'failed'
- true
- else
- false
- end
- end
-
- def should_pipeline_be_notified?(data)
- case data[:object_attributes][:status]
- when 'success'
- !notify_only_broken_pipelines?
- when 'failed'
- true
- else
- false
- end
+ def default_channel
+ "#general"
end
end
-
-require "slack_service/issue_message"
-require "slack_service/push_message"
-require "slack_service/merge_message"
-require "slack_service/note_message"
-require "slack_service/build_message"
-require "slack_service/pipeline_message"
-require "slack_service/wiki_page_message"
diff --git a/app/models/service.rb b/app/models/service.rb
index e49a8fa2904..8e58f2a1925 100644
--- a/app/models/service.rb
+++ b/app/models/service.rb
@@ -220,6 +220,7 @@ class Service < ActiveRecord::Base
pivotaltracker
pushover
redmine
+ mattermost
slack
teamcity
]
diff --git a/changelogs/unreleased/issue_22269.yml b/changelogs/unreleased/issue_22269.yml
new file mode 100644
index 00000000000..6b7164aff77
--- /dev/null
+++ b/changelogs/unreleased/issue_22269.yml
@@ -0,0 +1,4 @@
+---
+title: Create mattermost service
+merge_request:
+author:
diff --git a/doc/api/services.md b/doc/api/services.md
index 3dad953cd1e..1466b8189b0 100644
--- a/doc/api/services.md
+++ b/doc/api/services.md
@@ -703,9 +703,9 @@ Get Redmine service settings for a project.
GET /projects/:id/services/redmine
```
-## Slack
+## Slack notifications
-A team communication tool for the 21st century
+Receive event notifications in Slack
### Create/Edit Slack service
@@ -737,6 +737,40 @@ Get Slack service settings for a project.
GET /projects/:id/services/slack
```
+## Mattermost notifications
+
+Receive event notifications in Mattermost
+
+### Create/Edit Mattermost notifications service
+
+Set Mattermost service for a project.
+
+```
+PUT /projects/:id/services/mattermost
+```
+
+Parameters:
+
+- `webhook` (**required**) - https://mattermost.example/hooks/1298aff...
+- `username` (optional) - username
+- `channel` (optional) - #channel
+
+### Delete Mattermost notifications service
+
+Delete Mattermost Notifications service for a project.
+
+```
+DELETE /projects/:id/services/mattermost
+```
+
+### Get Mattermost notifications service settings
+
+Get Mattermost notifications service settings for a project.
+
+```
+GET /projects/:id/services/mattermost
+```
+
## JetBrains TeamCity CI
A continuous integration and build server
diff --git a/doc/project_services/img/mattermost_configuration.png b/doc/project_services/img/mattermost_configuration.png
new file mode 100644
index 00000000000..3c5ff5ee317
--- /dev/null
+++ b/doc/project_services/img/mattermost_configuration.png
Binary files differ
diff --git a/doc/project_services/mattermost.md b/doc/project_services/mattermost.md
new file mode 100644
index 00000000000..fbc7dfeee6d
--- /dev/null
+++ b/doc/project_services/mattermost.md
@@ -0,0 +1,45 @@
+# Mattermost Notifications Service
+
+## On Mattermost
+
+To enable Mattermost integration you must create an incoming webhook integration:
+
+1. Sign in to your Mattermost instance
+1. Visit incoming webhooks, that will be something like: https://mattermost.example/your_team_name/integrations/incoming_webhooks/add
+1. Choose a display name, description and channel, those can be overridden on GitLab
+1. Save it, copy the **Webhook URL**, we'll need this later for GitLab.
+
+There might be some cases that Incoming Webhooks are blocked by admin, ask your mattermost admin to enable
+it on https://mattermost.example/admin_console/integrations/custom.
+
+Display name override is not enabled by default, you need to ask your admin to enable it on that same section.
+
+## On GitLab
+
+After you set up Mattermost, it's time to set up GitLab.
+
+Go to your project's **Settings > Services > Mattermost Notifications** and you will see a
+checkbox with the following events that can be triggered:
+
+- Push
+- Issue
+- Merge request
+- Note
+- Tag push
+- Build
+- Wiki page
+
+Bellow each of these event checkboxes, you will have an input field to insert
+which Mattermost channel you want to send that event message, with `#town-square`
+being the default. The hash sign is optional.
+
+At the end, fill in your Mattermost details:
+
+| Field | Description |
+| ----- | ----------- |
+| **Webhook** | The incoming webhooks which you have to setup on Mattermost, it will be something like: http://mattermost.example/hooks/5xo... |
+| **Username** | Optional username which can be on messages sent to Mattermost. Fill this in if you want to change the username of the bot. |
+| **Notify only broken builds** | If you choose to enable the **Build** event and you want to be only notified about failed builds. |
+
+
+![Mattermost configuration](img/mattermost_configuration.png)
diff --git a/doc/project_services/project_services.md b/doc/project_services/project_services.md
index a7bcd186a8c..0f398874b8f 100644
--- a/doc/project_services/project_services.md
+++ b/doc/project_services/project_services.md
@@ -44,10 +44,11 @@ further configuration instructions and details. Contributions are welcome.
| JetBrains TeamCity CI | A continuous integration and build server |
| [Kubernetes](kubernetes.md) | A containerized deployment service |
| [Mattermost slash commands](mattermost_slash_commands.md) | Mattermost chat and ChatOps slash commands |
+| [Mattermost Notifications](mattermost.md) | Receive event notifications in Mattermost |
+| [Slack Notifications](slack.md) | Receive event notifications in Slack |
| PivotalTracker | Project Management Software (Source Commits Endpoint) |
| Pushover | Pushover makes it easy to get real-time notifications on your Android device, iPhone, iPad, and Desktop |
| [Redmine](redmine.md) | Redmine issue tracker |
-| [Slack](slack.md) | A team communication tool for the 21st century |
## Services Templates
diff --git a/doc/project_services/slack.md b/doc/project_services/slack.md
index 3cfe77c9f85..0b682b43810 100644
--- a/doc/project_services/slack.md
+++ b/doc/project_services/slack.md
@@ -1,4 +1,4 @@
-# Slack Service
+# Slack Notifications Service
## On Slack
@@ -15,7 +15,7 @@ Slack:
After you set up Slack, it's time to set up GitLab.
-Go to your project's **Settings > Services > Slack** and you will see a
+Go to your project's **Settings > Services > Slack Notifications** and you will see a
checkbox with the following events that can be triggered:
- Push
diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml
index c4ee838b7c9..068137f6255 100644
--- a/spec/lib/gitlab/import_export/all_models.yml
+++ b/spec/lib/gitlab/import_export/all_models.yml
@@ -137,6 +137,7 @@ project:
- asana_service
- gemnasium_service
- slack_service
+- mattermost_service
- buildkite_service
- bamboo_service
- teamcity_service
diff --git a/spec/models/project_services/slack_service/build_message_spec.rb b/spec/models/project_services/chat_message/build_message_spec.rb
index 452f4e2782c..b71d153f814 100644
--- a/spec/models/project_services/slack_service/build_message_spec.rb
+++ b/spec/models/project_services/chat_message/build_message_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
-describe SlackService::BuildMessage do
- subject { SlackService::BuildMessage.new(args) }
+describe ChatMessage::BuildMessage do
+ subject { described_class.new(args) }
let(:args) do
{
diff --git a/spec/models/project_services/slack_service/issue_message_spec.rb b/spec/models/project_services/chat_message/issue_message_spec.rb
index 98c36ec088d..ebe0ead4408 100644
--- a/spec/models/project_services/slack_service/issue_message_spec.rb
+++ b/spec/models/project_services/chat_message/issue_message_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
-describe SlackService::IssueMessage, models: true do
- subject { SlackService::IssueMessage.new(args) }
+describe ChatMessage::IssueMessage, models: true do
+ subject { described_class.new(args) }
let(:args) do
{
diff --git a/spec/models/project_services/slack_service/merge_message_spec.rb b/spec/models/project_services/chat_message/merge_message_spec.rb
index c5c052d9af1..07c414c6ca4 100644
--- a/spec/models/project_services/slack_service/merge_message_spec.rb
+++ b/spec/models/project_services/chat_message/merge_message_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
-describe SlackService::MergeMessage, models: true do
- subject { SlackService::MergeMessage.new(args) }
+describe ChatMessage::MergeMessage, models: true do
+ subject { described_class.new(args) }
let(:args) do
{
diff --git a/spec/models/project_services/slack_service/note_message_spec.rb b/spec/models/project_services/chat_message/note_message_spec.rb
index 97f818125d3..31936da40a2 100644
--- a/spec/models/project_services/slack_service/note_message_spec.rb
+++ b/spec/models/project_services/chat_message/note_message_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe SlackService::NoteMessage, models: true do
+describe ChatMessage::NoteMessage, models: true do
let(:color) { '#345' }
before do
@@ -36,7 +36,7 @@ describe SlackService::NoteMessage, models: true do
end
it 'returns a message regarding notes on commits' do
- message = SlackService::NoteMessage.new(@args)
+ message = described_class.new(@args)
expect(message.pretext).to eq("test.user <url|commented on " \
"commit 5f163b2b> in <somewhere.com|project_name>: " \
"*Added a commit message*")
@@ -62,7 +62,7 @@ describe SlackService::NoteMessage, models: true do
end
it 'returns a message regarding notes on a merge request' do
- message = SlackService::NoteMessage.new(@args)
+ message = described_class.new(@args)
expect(message.pretext).to eq("test.user <url|commented on " \
"merge request !30> in <somewhere.com|project_name>: " \
"*merge request title*")
@@ -88,7 +88,7 @@ describe SlackService::NoteMessage, models: true do
end
it 'returns a message regarding notes on an issue' do
- message = SlackService::NoteMessage.new(@args)
+ message = described_class.new(@args)
expect(message.pretext).to eq(
"test.user <url|commented on " \
"issue #20> in <somewhere.com|project_name>: " \
@@ -114,7 +114,7 @@ describe SlackService::NoteMessage, models: true do
end
it 'returns a message regarding notes on a project snippet' do
- message = SlackService::NoteMessage.new(@args)
+ message = described_class.new(@args)
expect(message.pretext).to eq("test.user <url|commented on " \
"snippet #5> in <somewhere.com|project_name>: " \
"*snippet title*")
diff --git a/spec/models/project_services/slack_service/pipeline_message_spec.rb b/spec/models/project_services/chat_message/pipeline_message_spec.rb
index 4098500122f..eca71db07b6 100644
--- a/spec/models/project_services/slack_service/pipeline_message_spec.rb
+++ b/spec/models/project_services/chat_message/pipeline_message_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
-describe SlackService::PipelineMessage do
- subject { SlackService::PipelineMessage.new(args) }
+describe ChatMessage::PipelineMessage do
+ subject { described_class.new(args) }
let(:user) { { name: 'hacker' } }
let(:args) do
diff --git a/spec/models/project_services/slack_service/push_message_spec.rb b/spec/models/project_services/chat_message/push_message_spec.rb
index 17cd05e24f1..b781c4505db 100644
--- a/spec/models/project_services/slack_service/push_message_spec.rb
+++ b/spec/models/project_services/chat_message/push_message_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
-describe SlackService::PushMessage, models: true do
- subject { SlackService::PushMessage.new(args) }
+describe ChatMessage::PushMessage, models: true do
+ subject { described_class.new(args) }
let(:args) do
{
diff --git a/spec/models/project_services/slack_service/wiki_page_message_spec.rb b/spec/models/project_services/chat_message/wiki_page_message_spec.rb
index 093911598b0..94c04dc0865 100644
--- a/spec/models/project_services/slack_service/wiki_page_message_spec.rb
+++ b/spec/models/project_services/chat_message/wiki_page_message_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe SlackService::WikiPageMessage, models: true do
+describe ChatMessage::WikiPageMessage, models: true do
subject { described_class.new(args) }
let(:args) do
diff --git a/spec/models/project_services/chat_service_spec.rb b/spec/models/project_services/chat_service_spec.rb
index c6a45a3e1be..e6314a43501 100644
--- a/spec/models/project_services/chat_service_spec.rb
+++ b/spec/models/project_services/chat_service_spec.rb
@@ -2,14 +2,7 @@ require 'spec_helper'
describe ChatService, models: true do
describe "Associations" do
- it { is_expected.to have_many :chat_names }
- end
-
- describe '#valid_token?' do
- subject { described_class.new }
-
- it 'is false as it has no token' do
- expect(subject.valid_token?('wer')).to be_falsey
- end
+ before { allow(subject).to receive(:activated?).and_return(true) }
+ it { is_expected.to validate_presence_of :webhook }
end
end
diff --git a/spec/models/project_services/mattermost_service_spec.rb b/spec/models/project_services/mattermost_service_spec.rb
new file mode 100644
index 00000000000..1e5b4c715c3
--- /dev/null
+++ b/spec/models/project_services/mattermost_service_spec.rb
@@ -0,0 +1,5 @@
+require 'spec_helper'
+
+describe MattermostService, models: true do
+ it_behaves_like "slack or mattermost"
+end
diff --git a/spec/models/project_services/slack_service_spec.rb b/spec/models/project_services/slack_service_spec.rb
index c07a70a8069..4928391fd7e 100644
--- a/spec/models/project_services/slack_service_spec.rb
+++ b/spec/models/project_services/slack_service_spec.rb
@@ -1,327 +1,5 @@
require 'spec_helper'
describe SlackService, models: true do
- let(:slack) { SlackService.new }
- let(:webhook_url) { 'https://example.gitlab.com/' }
-
- describe "Associations" do
- it { is_expected.to belong_to :project }
- it { is_expected.to have_one :service_hook }
- end
-
- describe 'Validations' do
- context 'when service is active' do
- before { subject.active = true }
-
- it { is_expected.to validate_presence_of(:webhook) }
- it_behaves_like 'issue tracker service URL attribute', :webhook
- end
-
- context 'when service is inactive' do
- before { subject.active = false }
-
- it { is_expected.not_to validate_presence_of(:webhook) }
- end
- end
-
- describe "Execute" do
- let(:user) { create(:user) }
- let(:project) { create(:project) }
- let(:username) { 'slack_username' }
- let(:channel) { 'slack_channel' }
-
- let(:push_sample_data) do
- Gitlab::DataBuilder::Push.build_sample(project, user)
- end
-
- before do
- allow(slack).to receive_messages(
- project: project,
- project_id: project.id,
- service_hook: true,
- webhook: webhook_url
- )
-
- WebMock.stub_request(:post, webhook_url)
-
- opts = {
- title: 'Awesome issue',
- description: 'please fix'
- }
-
- issue_service = Issues::CreateService.new(project, user, opts)
- @issue = issue_service.execute
- @issues_sample_data = issue_service.hook_data(@issue, 'open')
-
- opts = {
- title: 'Awesome merge_request',
- description: 'please fix',
- source_branch: 'feature',
- target_branch: 'master'
- }
- merge_service = MergeRequests::CreateService.new(project,
- user, opts)
- @merge_request = merge_service.execute
- @merge_sample_data = merge_service.hook_data(@merge_request,
- 'open')
-
- opts = {
- title: "Awesome wiki_page",
- content: "Some text describing some thing or another",
- format: "md",
- message: "user created page: Awesome wiki_page"
- }
-
- wiki_page_service = WikiPages::CreateService.new(project, user, opts)
- @wiki_page = wiki_page_service.execute
- @wiki_page_sample_data = wiki_page_service.hook_data(@wiki_page, 'create')
- end
-
- it "calls Slack API for push events" do
- slack.execute(push_sample_data)
-
- expect(WebMock).to have_requested(:post, webhook_url).once
- end
-
- it "calls Slack API for issue events" do
- slack.execute(@issues_sample_data)
-
- expect(WebMock).to have_requested(:post, webhook_url).once
- end
-
- it "calls Slack API for merge requests events" do
- slack.execute(@merge_sample_data)
-
- expect(WebMock).to have_requested(:post, webhook_url).once
- end
-
- it "calls Slack API for wiki page events" do
- slack.execute(@wiki_page_sample_data)
-
- expect(WebMock).to have_requested(:post, webhook_url).once
- end
-
- it 'uses the username as an option for slack when configured' do
- allow(slack).to receive(:username).and_return(username)
- expect(Slack::Notifier).to receive(:new).
- with(webhook_url, username: username).
- and_return(
- double(:slack_service).as_null_object
- )
-
- slack.execute(push_sample_data)
- end
-
- it 'uses the channel as an option when it is configured' do
- allow(slack).to receive(:channel).and_return(channel)
- expect(Slack::Notifier).to receive(:new).
- with(webhook_url, channel: channel).
- and_return(
- double(:slack_service).as_null_object
- )
- slack.execute(push_sample_data)
- end
-
- context "event channels" do
- it "uses the right channel for push event" do
- slack.update_attributes(push_channel: "random")
-
- expect(Slack::Notifier).to receive(:new).
- with(webhook_url, channel: "random").
- and_return(
- double(:slack_service).as_null_object
- )
-
- slack.execute(push_sample_data)
- end
-
- it "uses the right channel for merge request event" do
- slack.update_attributes(merge_request_channel: "random")
-
- expect(Slack::Notifier).to receive(:new).
- with(webhook_url, channel: "random").
- and_return(
- double(:slack_service).as_null_object
- )
-
- slack.execute(@merge_sample_data)
- end
-
- it "uses the right channel for issue event" do
- slack.update_attributes(issue_channel: "random")
-
- expect(Slack::Notifier).to receive(:new).
- with(webhook_url, channel: "random").
- and_return(
- double(:slack_service).as_null_object
- )
-
- slack.execute(@issues_sample_data)
- end
-
- it "uses the right channel for wiki event" do
- slack.update_attributes(wiki_page_channel: "random")
-
- expect(Slack::Notifier).to receive(:new).
- with(webhook_url, channel: "random").
- and_return(
- double(:slack_service).as_null_object
- )
-
- slack.execute(@wiki_page_sample_data)
- end
-
- context "note event" do
- let(:issue_note) do
- create(:note_on_issue, project: project, note: "issue note")
- end
-
- it "uses the right channel" do
- slack.update_attributes(note_channel: "random")
-
- note_data = Gitlab::DataBuilder::Note.build(issue_note, user)
-
- expect(Slack::Notifier).to receive(:new).
- with(webhook_url, channel: "random").
- and_return(
- double(:slack_service).as_null_object
- )
-
- slack.execute(note_data)
- end
- end
- end
- end
-
- describe "Note events" do
- let(:user) { create(:user) }
- let(:project) { create(:project, creator_id: user.id) }
-
- before do
- allow(slack).to receive_messages(
- project: project,
- project_id: project.id,
- service_hook: true,
- webhook: webhook_url
- )
-
- WebMock.stub_request(:post, webhook_url)
- end
-
- context 'when commit comment event executed' do
- let(:commit_note) do
- create(:note_on_commit, author: user,
- project: project,
- commit_id: project.repository.commit.id,
- note: 'a comment on a commit')
- end
-
- it "calls Slack API for commit comment events" do
- data = Gitlab::DataBuilder::Note.build(commit_note, user)
- slack.execute(data)
-
- expect(WebMock).to have_requested(:post, webhook_url).once
- end
- end
-
- context 'when merge request comment event executed' do
- let(:merge_request_note) do
- create(:note_on_merge_request, project: project,
- note: "merge request note")
- end
-
- it "calls Slack API for merge request comment events" do
- data = Gitlab::DataBuilder::Note.build(merge_request_note, user)
- slack.execute(data)
-
- expect(WebMock).to have_requested(:post, webhook_url).once
- end
- end
-
- context 'when issue comment event executed' do
- let(:issue_note) do
- create(:note_on_issue, project: project, note: "issue note")
- end
-
- it "calls Slack API for issue comment events" do
- data = Gitlab::DataBuilder::Note.build(issue_note, user)
- slack.execute(data)
-
- expect(WebMock).to have_requested(:post, webhook_url).once
- end
- end
-
- context 'when snippet comment event executed' do
- let(:snippet_note) do
- create(:note_on_project_snippet, project: project,
- note: "snippet note")
- end
-
- it "calls Slack API for snippet comment events" do
- data = Gitlab::DataBuilder::Note.build(snippet_note, user)
- slack.execute(data)
-
- expect(WebMock).to have_requested(:post, webhook_url).once
- end
- end
- end
-
- describe 'Pipeline events' do
- let(:user) { create(:user) }
- let(:project) { create(:project) }
-
- let(:pipeline) do
- create(:ci_pipeline,
- project: project, status: status,
- sha: project.commit.sha, ref: project.default_branch)
- end
-
- before do
- allow(slack).to receive_messages(
- project: project,
- service_hook: true,
- webhook: webhook_url
- )
- end
-
- shared_examples 'call Slack API' do
- before do
- WebMock.stub_request(:post, webhook_url)
- end
-
- it 'calls Slack API for pipeline events' do
- data = Gitlab::DataBuilder::Pipeline.build(pipeline)
- slack.execute(data)
-
- expect(WebMock).to have_requested(:post, webhook_url).once
- end
- end
-
- context 'with failed pipeline' do
- let(:status) { 'failed' }
-
- it_behaves_like 'call Slack API'
- end
-
- context 'with succeeded pipeline' do
- let(:status) { 'success' }
-
- context 'with default to notify_only_broken_pipelines' do
- it 'does not call Slack API for pipeline events' do
- data = Gitlab::DataBuilder::Pipeline.build(pipeline)
- result = slack.execute(data)
-
- expect(result).to be_falsy
- end
- end
-
- context 'with setting notify_only_broken_pipelines to false' do
- before do
- slack.notify_only_broken_pipelines = false
- end
-
- it_behaves_like 'call Slack API'
- end
- end
- end
+ it_behaves_like "slack or mattermost"
end
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 21ff238841e..1d8e42202ea 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -23,6 +23,7 @@ describe Project, models: true do
it { is_expected.to have_many(:chat_services) }
it { is_expected.to have_one(:forked_project_link).dependent(:destroy) }
it { is_expected.to have_one(:slack_service).dependent(:destroy) }
+ it { is_expected.to have_one(:mattermost_service).dependent(:destroy) }
it { is_expected.to have_one(:pushover_service).dependent(:destroy) }
it { is_expected.to have_one(:asana_service).dependent(:destroy) }
it { is_expected.to have_many(:boards).dependent(:destroy) }
diff --git a/spec/support/slack_mattermost_shared_examples.rb b/spec/support/slack_mattermost_shared_examples.rb
new file mode 100644
index 00000000000..56d4965f74d
--- /dev/null
+++ b/spec/support/slack_mattermost_shared_examples.rb
@@ -0,0 +1,328 @@
+Dir[Rails.root.join("app/models/project_services/chat_message/*.rb")].each { |f| require f }
+
+RSpec.shared_examples 'slack or mattermost' do
+ let(:chat_service) { described_class.new }
+ let(:webhook_url) { 'https://example.gitlab.com/' }
+
+ describe "Associations" do
+ it { is_expected.to belong_to :project }
+ it { is_expected.to have_one :service_hook }
+ end
+
+ describe 'Validations' do
+ context 'when service is active' do
+ before { subject.active = true }
+
+ it { is_expected.to validate_presence_of(:webhook) }
+ it_behaves_like 'issue tracker service URL attribute', :webhook
+ end
+
+ context 'when service is inactive' do
+ before { subject.active = false }
+
+ it { is_expected.not_to validate_presence_of(:webhook) }
+ end
+ end
+
+ describe "#execute" do
+ let(:user) { create(:user) }
+ let(:project) { create(:project) }
+ let(:username) { 'slack_username' }
+ let(:channel) { 'slack_channel' }
+
+ let(:push_sample_data) do
+ Gitlab::DataBuilder::Push.build_sample(project, user)
+ end
+
+ before do
+ allow(chat_service).to receive_messages(
+ project: project,
+ project_id: project.id,
+ service_hook: true,
+ webhook: webhook_url
+ )
+
+ WebMock.stub_request(:post, webhook_url)
+
+ opts = {
+ title: 'Awesome issue',
+ description: 'please fix'
+ }
+
+ issue_service = Issues::CreateService.new(project, user, opts)
+ @issue = issue_service.execute
+ @issues_sample_data = issue_service.hook_data(@issue, 'open')
+
+ opts = {
+ title: 'Awesome merge_request',
+ description: 'please fix',
+ source_branch: 'feature',
+ target_branch: 'master'
+ }
+ merge_service = MergeRequests::CreateService.new(project,
+ user, opts)
+ @merge_request = merge_service.execute
+ @merge_sample_data = merge_service.hook_data(@merge_request,
+ 'open')
+
+ opts = {
+ title: "Awesome wiki_page",
+ content: "Some text describing some thing or another",
+ format: "md",
+ message: "user created page: Awesome wiki_page"
+ }
+
+ wiki_page_service = WikiPages::CreateService.new(project, user, opts)
+ @wiki_page = wiki_page_service.execute
+ @wiki_page_sample_data = wiki_page_service.hook_data(@wiki_page, 'create')
+ end
+
+ it "calls Slack/Mattermost API for push events" do
+ chat_service.execute(push_sample_data)
+
+ expect(WebMock).to have_requested(:post, webhook_url).once
+ end
+
+ it "calls Slack/Mattermost API for issue events" do
+ chat_service.execute(@issues_sample_data)
+
+ expect(WebMock).to have_requested(:post, webhook_url).once
+ end
+
+ it "calls Slack/Mattermost API for merge requests events" do
+ chat_service.execute(@merge_sample_data)
+
+ expect(WebMock).to have_requested(:post, webhook_url).once
+ end
+
+ it "calls Slack/Mattermost API for wiki page events" do
+ chat_service.execute(@wiki_page_sample_data)
+
+ expect(WebMock).to have_requested(:post, webhook_url).once
+ end
+
+ it 'uses the username as an option for slack when configured' do
+ allow(chat_service).to receive(:username).and_return(username)
+
+ expect(Slack::Notifier).to receive(:new).
+ with(webhook_url, username: username, channel: chat_service.default_channel).
+ and_return(
+ double(:slack_service).as_null_object
+ )
+
+ chat_service.execute(push_sample_data)
+ end
+
+ it 'uses the channel as an option when it is configured' do
+ allow(chat_service).to receive(:channel).and_return(channel)
+ expect(Slack::Notifier).to receive(:new).
+ with(webhook_url, channel: channel).
+ and_return(
+ double(:slack_service).as_null_object
+ )
+ chat_service.execute(push_sample_data)
+ end
+
+ context "event channels" do
+ it "uses the right channel for push event" do
+ chat_service.update_attributes(push_channel: "random")
+
+ expect(Slack::Notifier).to receive(:new).
+ with(webhook_url, channel: "random").
+ and_return(
+ double(:slack_service).as_null_object
+ )
+
+ chat_service.execute(push_sample_data)
+ end
+
+ it "uses the right channel for merge request event" do
+ chat_service.update_attributes(merge_request_channel: "random")
+
+ expect(Slack::Notifier).to receive(:new).
+ with(webhook_url, channel: "random").
+ and_return(
+ double(:slack_service).as_null_object
+ )
+
+ chat_service.execute(@merge_sample_data)
+ end
+
+ it "uses the right channel for issue event" do
+ chat_service.update_attributes(issue_channel: "random")
+
+ expect(Slack::Notifier).to receive(:new).
+ with(webhook_url, channel: "random").
+ and_return(
+ double(:slack_service).as_null_object
+ )
+
+ chat_service.execute(@issues_sample_data)
+ end
+
+ it "uses the right channel for wiki event" do
+ chat_service.update_attributes(wiki_page_channel: "random")
+
+ expect(Slack::Notifier).to receive(:new).
+ with(webhook_url, channel: "random").
+ and_return(
+ double(:slack_service).as_null_object
+ )
+
+ chat_service.execute(@wiki_page_sample_data)
+ end
+
+ context "note event" do
+ let(:issue_note) do
+ create(:note_on_issue, project: project, note: "issue note")
+ end
+
+ it "uses the right channel" do
+ chat_service.update_attributes(note_channel: "random")
+
+ note_data = Gitlab::DataBuilder::Note.build(issue_note, user)
+
+ expect(Slack::Notifier).to receive(:new).
+ with(webhook_url, channel: "random").
+ and_return(
+ double(:slack_service).as_null_object
+ )
+
+ chat_service.execute(note_data)
+ end
+ end
+ end
+ end
+
+ describe "Note events" do
+ let(:user) { create(:user) }
+ let(:project) { create(:project, creator_id: user.id) }
+
+ before do
+ allow(chat_service).to receive_messages(
+ project: project,
+ project_id: project.id,
+ service_hook: true,
+ webhook: webhook_url
+ )
+
+ WebMock.stub_request(:post, webhook_url)
+ end
+
+ context 'when commit comment event executed' do
+ let(:commit_note) do
+ create(:note_on_commit, author: user,
+ project: project,
+ commit_id: project.repository.commit.id,
+ note: 'a comment on a commit')
+ end
+
+ it "calls Slack/Mattermost API for commit comment events" do
+ data = Gitlab::DataBuilder::Note.build(commit_note, user)
+ chat_service.execute(data)
+
+ expect(WebMock).to have_requested(:post, webhook_url).once
+ end
+ end
+
+ context 'when merge request comment event executed' do
+ let(:merge_request_note) do
+ create(:note_on_merge_request, project: project,
+ note: "merge request note")
+ end
+
+ it "calls Slack API for merge request comment events" do
+ data = Gitlab::DataBuilder::Note.build(merge_request_note, user)
+ chat_service.execute(data)
+
+ expect(WebMock).to have_requested(:post, webhook_url).once
+ end
+ end
+
+ context 'when issue comment event executed' do
+ let(:issue_note) do
+ create(:note_on_issue, project: project, note: "issue note")
+ end
+
+ it "calls Slack API for issue comment events" do
+ data = Gitlab::DataBuilder::Note.build(issue_note, user)
+ chat_service.execute(data)
+
+ expect(WebMock).to have_requested(:post, webhook_url).once
+ end
+ end
+
+ context 'when snippet comment event executed' do
+ let(:snippet_note) do
+ create(:note_on_project_snippet, project: project,
+ note: "snippet note")
+ end
+
+ it "calls Slack API for snippet comment events" do
+ data = Gitlab::DataBuilder::Note.build(snippet_note, user)
+ chat_service.execute(data)
+
+ expect(WebMock).to have_requested(:post, webhook_url).once
+ end
+ end
+ end
+
+ describe 'Pipeline events' do
+ let(:user) { create(:user) }
+ let(:project) { create(:project) }
+
+ let(:pipeline) do
+ create(:ci_pipeline,
+ project: project, status: status,
+ sha: project.commit.sha, ref: project.default_branch)
+ end
+
+ before do
+ allow(chat_service).to receive_messages(
+ project: project,
+ service_hook: true,
+ webhook: webhook_url
+ )
+ end
+
+ shared_examples 'call Slack/Mattermost API' do
+ before do
+ WebMock.stub_request(:post, webhook_url)
+ end
+
+ it 'calls Slack/Mattermost API for pipeline events' do
+ data = Gitlab::DataBuilder::Pipeline.build(pipeline)
+ chat_service.execute(data)
+
+ expect(WebMock).to have_requested(:post, webhook_url).once
+ end
+ end
+
+ context 'with failed pipeline' do
+ let(:status) { 'failed' }
+
+ it_behaves_like 'call Slack/Mattermost API'
+ end
+
+ context 'with succeeded pipeline' do
+ let(:status) { 'success' }
+
+ context 'with default to notify_only_broken_pipelines' do
+ it 'does not call Slack/Mattermost API for pipeline events' do
+ data = Gitlab::DataBuilder::Pipeline.build(pipeline)
+ result = chat_service.execute(data)
+
+ expect(result).to be_falsy
+ end
+ end
+
+ context 'with setting notify_only_broken_pipelines to false' do
+ before do
+ chat_service.notify_only_broken_pipelines = false
+ end
+
+ it_behaves_like 'call Slack/Mattermost API'
+ end
+ end
+ end
+end