diff options
author | Kamil Trzciński <ayufan@ayufan.eu> | 2016-12-16 13:23:19 +0000 |
---|---|---|
committer | Kamil Trzciński <ayufan@ayufan.eu> | 2016-12-16 13:23:19 +0000 |
commit | bdb5e6771856c280fa1cf92b19a47fb83a4988ec (patch) | |
tree | e1d191d266b80b224673afe90431018e78443e79 | |
parent | ea59a84f9cdb88fc829a71fbfb7bd7c8809ef6f9 (diff) | |
parent | 18b65cb8e07548c67056fe7994f1cee6da4de08e (diff) | |
download | gitlab-ce-bdb5e6771856c280fa1cf92b19a47fb83a4988ec.tar.gz |
Merge branch 'issue_22269' into 'master'
Mattermost Notifications Service
## What does this MR do?
closes #22269
## Screenshots
![mattermost](/uploads/de71c121f544a91305b6dfa6dc4c5738/mattermost.png)
![slack](/uploads/081d75d49239319d94332abda214fb98/slack.png)
## Does this MR meet the acceptance criteria?
- [x] [Changelog entry](https://docs.gitlab.com/ce/development/changelog.html) added
- [x] [Documentation created/updated](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/development/doc_styleguide.md)
- [x] API support added
- Tests
- [x] Added for this feature/bug
- [x] All builds are passing
- [x] Conform by the [merge request performance guides](http://docs.gitlab.com/ce/development/merge_request_performance_guidelines.html)
- [x] Conform by the [style guides](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#style-guides)
- [x] Branch has no merge conflicts with `master` (if it does - rebase it please)
- [x] [Squashed related commits together](https://git-scm.com/book/en/Git-Tools-Rewriting-History#Squashing-Commits)
See merge request !7764
39 files changed, 321 insertions, 133 deletions
diff --git a/app/models/project.rb b/app/models/project.rb index 2c726cfc5df..5d092ca42c2 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -95,7 +95,8 @@ 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 :slack_service, dependent: :destroy + has_one :mattermost_notification_service, dependent: :destroy + has_one :slack_notification_service, dependent: :destroy has_one :buildkite_service, dependent: :destroy has_one :bamboo_service, dependent: :destroy has_one :teamcity_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/slack_service.rb b/app/models/project_services/chat_notification_service.rb index e1b937817f4..b0556987721 100644 --- a/app/models/project_services/slack_service.rb +++ b/app/models/project_services/chat_notification_service.rb @@ -1,6 +1,13 @@ -class SlackService < Service +# Base class for Chat notifications services +# This class is not meant to be used directly, but only to inherit from. +class ChatNotificationService < Service + include ChatMessage + + default_value_for :category, 'chat' + 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 @@ -14,35 +21,8 @@ class SlackService < Service end end - def title - 'Slack' - end - - def description - 'A team communication tool for the 21st century' - end - - def to_param - 'slack' - 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.' - 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 + def can_test? + valid? end def supported_events @@ -67,21 +47,16 @@ class SlackService < Service message = get_message(object_kind, data) - if message - opt = {} - - event_channel = get_channel_field(object_kind) || channel + return false unless message - opt[:channel] = event_channel if event_channel - opt[:username] = username if username + opt = {} - notifier = Slack::Notifier.new(webhook, opt) - notifier.ping(message.pretext, attachments: message.attachments, fallback: message.fallback) + 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 - else - false - end + true end def event_channel_names @@ -96,6 +71,10 @@ class SlackService < Service fields.reject { |field| field[:name].end_with?('channel') } end + def default_channel + raise NotImplementedError + end + private def get_message(object_kind, data) @@ -124,7 +103,7 @@ class SlackService < Service def build_event_channels supported_events.reduce([]) do |channels, event| - channels << { type: 'text', name: event_channel_name(event), placeholder: "#general" } + channels << { type: 'text', name: event_channel_name(event), placeholder: default_channel } end end @@ -166,11 +145,3 @@ class SlackService < Service end 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/project_services/chat_service.rb b/app/models/project_services/chat_service.rb index d36beff5fa6..574788462de 100644 --- a/app/models/project_services/chat_service.rb +++ b/app/models/project_services/chat_service.rb @@ -1,5 +1,5 @@ # Base class for Chat services -# This class is not meant to be used directly, but only to inherrit from. +# This class is not meant to be used directly, but only to inherit from. class ChatService < Service default_value_for :category, 'chat' diff --git a/app/models/project_services/mattermost_notification_service.rb b/app/models/project_services/mattermost_notification_service.rb new file mode 100644 index 00000000000..de18c4b1f00 --- /dev/null +++ b/app/models/project_services/mattermost_notification_service.rb @@ -0,0 +1,41 @@ +class MattermostNotificationService < ChatNotificationService + def title + 'Mattermost notifications' + end + + def description + 'Receive event notifications in Mattermost' + end + + def to_param + 'mattermost_notification' + 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/slack_notification_service.rb b/app/models/project_services/slack_notification_service.rb new file mode 100644 index 00000000000..3cbf89efba4 --- /dev/null +++ b/app/models/project_services/slack_notification_service.rb @@ -0,0 +1,40 @@ +class SlackNotificationService < ChatNotificationService + def title + 'Slack notifications' + end + + def description + 'Receive event notifications in Slack' + end + + def to_param + 'slack_notification' + end + + def help + '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 + build_event_channels + end + + 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 default_channel + "#general" + end +end diff --git a/app/models/service.rb b/app/models/service.rb index e49a8fa2904..0bbab078cf6 100644 --- a/app/models/service.rb +++ b/app/models/service.rb @@ -220,7 +220,8 @@ class Service < ActiveRecord::Base pivotaltracker pushover redmine - slack + mattermost_notification + slack_notification teamcity ] end 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/db/migrate/20141006143943_move_slack_service_to_webhook.rb b/db/migrate/20141006143943_move_slack_service_to_webhook.rb index 8cb120f7007..42e88d6d6e3 100644 --- a/db/migrate/20141006143943_move_slack_service_to_webhook.rb +++ b/db/migrate/20141006143943_move_slack_service_to_webhook.rb @@ -1,7 +1,11 @@ # rubocop:disable all class MoveSlackServiceToWebhook < ActiveRecord::Migration + + DOWNTIME = true + DOWNTIME_REASON = 'Move old fields "token" and "subdomain" to one single field "webhook"' + def change - SlackService.all.each do |slack_service| + SlackNotificationService.all.each do |slack_service| if ["token", "subdomain"].all? { |property| slack_service.properties.key? property } token = slack_service.properties['token'] subdomain = slack_service.properties['subdomain'] diff --git a/db/migrate/20161213172958_change_slack_service_to_slack_notification_service.rb b/db/migrate/20161213172958_change_slack_service_to_slack_notification_service.rb new file mode 100644 index 00000000000..a7278d7b5a6 --- /dev/null +++ b/db/migrate/20161213172958_change_slack_service_to_slack_notification_service.rb @@ -0,0 +1,14 @@ +class ChangeSlackServiceToSlackNotificationService < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + DOWNTIME = true + DOWNTIME_REASON = 'Rename SlackService to SlackNotificationService' + + def up + execute("UPDATE services SET type = 'SlackNotificationService' WHERE type = 'SlackService'") + end + + def down + execute("UPDATE services SET type = 'SlackService' WHERE type = 'SlackNotificationService'") + end +end diff --git a/db/schema.rb b/db/schema.rb index 67ff83d96d9..3786a41f9a9 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20161212142807) do +ActiveRecord::Schema.define(version: 20161213172958) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" 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 Binary files differnew file mode 100644 index 00000000000..3c5ff5ee317 --- /dev/null +++ b/doc/project_services/img/mattermost_configuration.png 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/lib/api/services.rb b/lib/api/services.rb index b1e072b4f47..59232c84c24 100644 --- a/lib/api/services.rb +++ b/lib/api/services.rb @@ -473,7 +473,7 @@ module API desc: 'The description of the tracker' } ], - 'slack' => [ + 'slack-notification' => [ { required: true, name: :webhook, @@ -493,6 +493,14 @@ module API desc: 'The channel name' } ], + 'mattermost-notification' => [ + { + required: true, + name: :webhook, + type: String, + desc: 'The Mattermost webhook. e.g. http://mattermost_host/hooks/...' + } + ], 'teamcity' => [ { required: true, diff --git a/spec/features/projects/import_export/test_project_export.tar.gz b/spec/features/projects/import_export/test_project_export.tar.gz Binary files differindex bfe59bdb90e..d3165d07d7b 100644 --- a/spec/features/projects/import_export/test_project_export.tar.gz +++ b/spec/features/projects/import_export/test_project_export.tar.gz diff --git a/spec/features/projects/services/slack_service_spec.rb b/spec/features/projects/services/slack_service_spec.rb index 16541f51d98..320ed13a01d 100644 --- a/spec/features/projects/services/slack_service_spec.rb +++ b/spec/features/projects/services/slack_service_spec.rb @@ -2,8 +2,8 @@ require 'spec_helper' feature 'Projects > Slack service > Setup events', feature: true do let(:user) { create(:user) } - let(:service) { SlackService.new } - let(:project) { create(:project, slack_service: service) } + let(:service) { SlackNotificationService.new } + let(:project) { create(:project, slack_notification_service: service) } background do service.fields diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml index c4ee838b7c9..9b49d6837c3 100644 --- a/spec/lib/gitlab/import_export/all_models.yml +++ b/spec/lib/gitlab/import_export/all_models.yml @@ -136,7 +136,8 @@ project: - assembla_service - asana_service - gemnasium_service -- slack_service +- slack_notification_service +- mattermost_notification_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_notification_service_spec.rb b/spec/models/project_services/chat_notification_service_spec.rb new file mode 100644 index 00000000000..c98e7ee14fd --- /dev/null +++ b/spec/models/project_services/chat_notification_service_spec.rb @@ -0,0 +1,11 @@ +require 'spec_helper' + +describe ChatNotificationService, models: true do + describe "Associations" do + before do + allow(subject).to receive(:activated?).and_return(true) + end + + it { is_expected.to validate_presence_of :webhook } + end +end diff --git a/spec/models/project_services/mattermost_notification_service_spec.rb b/spec/models/project_services/mattermost_notification_service_spec.rb new file mode 100644 index 00000000000..c01e64b4c8e --- /dev/null +++ b/spec/models/project_services/mattermost_notification_service_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe MattermostNotificationService, models: true do + it_behaves_like "slack or mattermost" +end diff --git a/spec/models/project_services/slack_notification_service_spec.rb b/spec/models/project_services/slack_notification_service_spec.rb new file mode 100644 index 00000000000..59ddddf7454 --- /dev/null +++ b/spec/models/project_services/slack_notification_service_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe SlackNotificationService, models: true do + it_behaves_like "slack or mattermost" +end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 21ff238841e..bab3c3dbb02 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -22,7 +22,8 @@ describe Project, models: true do it { is_expected.to have_many(:protected_branches).dependent(:destroy) } 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(:slack_notification_service).dependent(:destroy) } + it { is_expected.to have_one(:mattermost_notification_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/models/project_services/slack_service_spec.rb b/spec/support/slack_mattermost_shared_examples.rb index c07a70a8069..56d4965f74d 100644 --- a/spec/models/project_services/slack_service_spec.rb +++ b/spec/support/slack_mattermost_shared_examples.rb @@ -1,7 +1,7 @@ -require 'spec_helper' +Dir[Rails.root.join("app/models/project_services/chat_message/*.rb")].each { |f| require f } -describe SlackService, models: true do - let(:slack) { SlackService.new } +RSpec.shared_examples 'slack or mattermost' do + let(:chat_service) { described_class.new } let(:webhook_url) { 'https://example.gitlab.com/' } describe "Associations" do @@ -24,7 +24,7 @@ describe SlackService, models: true do end end - describe "Execute" do + describe "#execute" do let(:user) { create(:user) } let(:project) { create(:project) } let(:username) { 'slack_username' } @@ -35,7 +35,7 @@ describe SlackService, models: true do end before do - allow(slack).to receive_messages( + allow(chat_service).to receive_messages( project: project, project_id: project.id, service_hook: true, @@ -77,54 +77,55 @@ describe SlackService, models: true do @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) + 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 API for issue events" do - slack.execute(@issues_sample_data) + 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 API for merge requests events" do - slack.execute(@merge_sample_data) + 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 API for wiki page events" do - slack.execute(@wiki_page_sample_data) + 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(slack).to receive(:username).and_return(username) + allow(chat_service).to receive(:username).and_return(username) + expect(Slack::Notifier).to receive(:new). - with(webhook_url, username: username). + with(webhook_url, username: username, channel: chat_service.default_channel). and_return( double(:slack_service).as_null_object ) - slack.execute(push_sample_data) + chat_service.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) + 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 ) - slack.execute(push_sample_data) + chat_service.execute(push_sample_data) end context "event channels" do it "uses the right channel for push event" do - slack.update_attributes(push_channel: "random") + chat_service.update_attributes(push_channel: "random") expect(Slack::Notifier).to receive(:new). with(webhook_url, channel: "random"). @@ -132,11 +133,11 @@ describe SlackService, models: true do double(:slack_service).as_null_object ) - slack.execute(push_sample_data) + chat_service.execute(push_sample_data) end it "uses the right channel for merge request event" do - slack.update_attributes(merge_request_channel: "random") + chat_service.update_attributes(merge_request_channel: "random") expect(Slack::Notifier).to receive(:new). with(webhook_url, channel: "random"). @@ -144,11 +145,11 @@ describe SlackService, models: true do double(:slack_service).as_null_object ) - slack.execute(@merge_sample_data) + chat_service.execute(@merge_sample_data) end it "uses the right channel for issue event" do - slack.update_attributes(issue_channel: "random") + chat_service.update_attributes(issue_channel: "random") expect(Slack::Notifier).to receive(:new). with(webhook_url, channel: "random"). @@ -156,11 +157,11 @@ describe SlackService, models: true do double(:slack_service).as_null_object ) - slack.execute(@issues_sample_data) + chat_service.execute(@issues_sample_data) end it "uses the right channel for wiki event" do - slack.update_attributes(wiki_page_channel: "random") + chat_service.update_attributes(wiki_page_channel: "random") expect(Slack::Notifier).to receive(:new). with(webhook_url, channel: "random"). @@ -168,7 +169,7 @@ describe SlackService, models: true do double(:slack_service).as_null_object ) - slack.execute(@wiki_page_sample_data) + chat_service.execute(@wiki_page_sample_data) end context "note event" do @@ -177,7 +178,7 @@ describe SlackService, models: true do end it "uses the right channel" do - slack.update_attributes(note_channel: "random") + chat_service.update_attributes(note_channel: "random") note_data = Gitlab::DataBuilder::Note.build(issue_note, user) @@ -187,7 +188,7 @@ describe SlackService, models: true do double(:slack_service).as_null_object ) - slack.execute(note_data) + chat_service.execute(note_data) end end end @@ -198,7 +199,7 @@ describe SlackService, models: true do let(:project) { create(:project, creator_id: user.id) } before do - allow(slack).to receive_messages( + allow(chat_service).to receive_messages( project: project, project_id: project.id, service_hook: true, @@ -216,9 +217,9 @@ describe SlackService, models: true do note: 'a comment on a commit') end - it "calls Slack API for commit comment events" do + it "calls Slack/Mattermost API for commit comment events" do data = Gitlab::DataBuilder::Note.build(commit_note, user) - slack.execute(data) + chat_service.execute(data) expect(WebMock).to have_requested(:post, webhook_url).once end @@ -232,7 +233,7 @@ describe SlackService, models: true do it "calls Slack API for merge request comment events" do data = Gitlab::DataBuilder::Note.build(merge_request_note, user) - slack.execute(data) + chat_service.execute(data) expect(WebMock).to have_requested(:post, webhook_url).once end @@ -245,7 +246,7 @@ describe SlackService, models: true do it "calls Slack API for issue comment events" do data = Gitlab::DataBuilder::Note.build(issue_note, user) - slack.execute(data) + chat_service.execute(data) expect(WebMock).to have_requested(:post, webhook_url).once end @@ -259,7 +260,7 @@ describe SlackService, models: true do it "calls Slack API for snippet comment events" do data = Gitlab::DataBuilder::Note.build(snippet_note, user) - slack.execute(data) + chat_service.execute(data) expect(WebMock).to have_requested(:post, webhook_url).once end @@ -277,21 +278,21 @@ describe SlackService, models: true do end before do - allow(slack).to receive_messages( + allow(chat_service).to receive_messages( project: project, service_hook: true, webhook: webhook_url ) end - shared_examples 'call Slack API' do + shared_examples 'call Slack/Mattermost API' do before do WebMock.stub_request(:post, webhook_url) end - it 'calls Slack API for pipeline events' do + it 'calls Slack/Mattermost API for pipeline events' do data = Gitlab::DataBuilder::Pipeline.build(pipeline) - slack.execute(data) + chat_service.execute(data) expect(WebMock).to have_requested(:post, webhook_url).once end @@ -300,16 +301,16 @@ describe SlackService, models: true do context 'with failed pipeline' do let(:status) { 'failed' } - it_behaves_like 'call Slack API' + 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 API for pipeline events' do + it 'does not call Slack/Mattermost API for pipeline events' do data = Gitlab::DataBuilder::Pipeline.build(pipeline) - result = slack.execute(data) + result = chat_service.execute(data) expect(result).to be_falsy end @@ -317,10 +318,10 @@ describe SlackService, models: true do context 'with setting notify_only_broken_pipelines to false' do before do - slack.notify_only_broken_pipelines = false + chat_service.notify_only_broken_pipelines = false end - it_behaves_like 'call Slack API' + it_behaves_like 'call Slack/Mattermost API' end end end |