Commit 42f5ee01 authored by Andy Soiron's avatar Andy Soiron Committed by Igor Drozdov

Label filter for chat notification services

Adds a configuration to only notify
chat services for specific labels
parent b162cbb2
...@@ -12,6 +12,7 @@ module ServiceParams ...@@ -12,6 +12,7 @@ module ServiceParams
:api_version, :api_version,
:bamboo_url, :bamboo_url,
:branches_to_be_notified, :branches_to_be_notified,
:labels_to_be_notified,
:build_key, :build_key,
:build_type, :build_type,
:ca_pem, :ca_pem,
......
...@@ -11,11 +11,13 @@ class ChatNotificationService < Service ...@@ -11,11 +11,13 @@ class ChatNotificationService < Service
tag_push pipeline wiki_page deployment tag_push pipeline wiki_page deployment
].freeze ].freeze
SUPPORTED_EVENTS_FOR_LABEL_FILTER = %w[issue confidential_issue merge_request note confidential_note].freeze
EVENT_CHANNEL = proc { |event| "#{event}_channel" } EVENT_CHANNEL = proc { |event| "#{event}_channel" }
default_value_for :category, 'chat' default_value_for :category, 'chat'
prop_accessor :webhook, :username, :channel, :branches_to_be_notified prop_accessor :webhook, :username, :channel, :branches_to_be_notified, :labels_to_be_notified
# Custom serialized properties initialization # Custom serialized properties initialization
prop_accessor(*SUPPORTED_EVENTS.map { |event| EVENT_CHANNEL[event] }) prop_accessor(*SUPPORTED_EVENTS.map { |event| EVENT_CHANNEL[event] })
...@@ -62,12 +64,16 @@ class ChatNotificationService < Service ...@@ -62,12 +64,16 @@ class ChatNotificationService < Service
{ type: 'text', name: 'webhook', placeholder: "e.g. #{webhook_placeholder}", required: true }.freeze, { type: 'text', name: 'webhook', placeholder: "e.g. #{webhook_placeholder}", required: true }.freeze,
{ type: 'text', name: 'username', placeholder: 'e.g. GitLab' }.freeze, { type: 'text', name: 'username', placeholder: 'e.g. GitLab' }.freeze,
{ type: 'checkbox', name: 'notify_only_broken_pipelines' }.freeze, { type: 'checkbox', name: 'notify_only_broken_pipelines' }.freeze,
{ type: 'select', name: 'branches_to_be_notified', choices: branch_choices }.freeze { type: 'select', name: 'branches_to_be_notified', choices: branch_choices }.freeze,
{ type: 'text', name: 'labels_to_be_notified', placeholder: 'e.g. ~backend', help: 'Only supported for issue, merge request and note events.' }.freeze
].freeze ].freeze
end end
def execute(data) def execute(data)
return unless supported_events.include?(data[:object_kind]) return unless supported_events.include?(data[:object_kind])
return unless notify_label?(data)
return unless webhook.present? return unless webhook.present?
object_kind = data[:object_kind] object_kind = data[:object_kind]
...@@ -114,6 +120,22 @@ class ChatNotificationService < Service ...@@ -114,6 +120,22 @@ class ChatNotificationService < Service
private private
def labels_to_be_notified_list
return [] if labels_to_be_notified.nil?
labels_to_be_notified.delete('~').split(',').map(&:strip)
end
def notify_label?(data)
return true unless SUPPORTED_EVENTS_FOR_LABEL_FILTER.include?(data[:object_kind]) && labels_to_be_notified.present?
issue_labels = data.dig(:issue, :labels) || []
merge_request_labels = data.dig(:merge_request, :labels) || []
label_titles = (issue_labels + merge_request_labels).pluck(:title)
(labels_to_be_notified_list & label_titles).any?
end
# every notifier must implement this independently # every notifier must implement this independently
def notify(message, opts) def notify(message, opts)
raise NotImplementedError raise NotImplementedError
......
---
title: Add chat notification label support
merge_request: 52105
author:
type: added
...@@ -59,5 +59,6 @@ At the end, fill in your Mattermost details: ...@@ -59,5 +59,6 @@ At the end, fill in your Mattermost details:
| **Username** | Optional username which can be on messages sent to Mattermost. Fill this in if you want to change the username of the bot. | | **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 pipelines** | If you choose to enable the **Pipeline** event and you want to be only notified about failed pipelines. | | **Notify only broken pipelines** | If you choose to enable the **Pipeline** event and you want to be only notified about failed pipelines. |
| **Branches to be notified** | Select which types of branches to send notifications for. | | **Branches to be notified** | Select which types of branches to send notifications for. |
| **Labels to be notified** | Optional labels that the issue or merge request must have in order to trigger a notification. Leave blank to get all notifications. |
![Mattermost configuration](img/mattermost_configuration.png) ![Mattermost configuration](img/mattermost_configuration_v2.png)
...@@ -45,6 +45,7 @@ separately configured [Slack slash commands](slack_slash_commands.md). ...@@ -45,6 +45,7 @@ separately configured [Slack slash commands](slack_slash_commands.md).
1. Select the **Notify only broken pipelines** check box to only notify on failures. 1. Select the **Notify only broken pipelines** check box to only notify on failures.
1. In the **Branches to be notified** select box, choose which types of branches 1. In the **Branches to be notified** select box, choose which types of branches
to send notifications for. to send notifications for.
1. Leave the **Labels to be notified** field blank to get all notifications or add labels that the issue or merge request must have in order to trigger a notification.
1. Click **Test settings and save changes**. 1. Click **Test settings and save changes**.
Your Slack team now starts receiving GitLab event notifications as configured. Your Slack team now starts receiving GitLab event notifications as configured.
......
...@@ -75,6 +75,39 @@ RSpec.describe ChatNotificationService do ...@@ -75,6 +75,39 @@ RSpec.describe ChatNotificationService do
end end
end end
context 'when the data object has a label' do
let(:label) { create(:label, project: project, name: 'Bug')}
let(:issue) { create(:labeled_issue, project: project, labels: [label]) }
let(:note) { create(:note, noteable: issue, project: project)}
let(:data) { Gitlab::DataBuilder::Note.build(note, user) }
it 'notifies the chat service' do
expect(chat_service).to receive(:notify).with(any_args)
chat_service.execute(data)
end
context 'and the chat_service has a label filter that does not matches the label' do
subject(:chat_service) { described_class.new(labels_to_be_notified: '~some random label') }
it 'does not notify the chat service' do
expect(chat_service).not_to receive(:notify)
chat_service.execute(data)
end
end
context 'and the chat_service has a label filter that matches the label' do
subject(:chat_service) { described_class.new(labels_to_be_notified: '~Backend, ~Bug') }
it 'notifies the chat service' do
expect(chat_service).to receive(:notify).with(any_args)
chat_service.execute(data)
end
end
end
context 'with "channel" property' do context 'with "channel" property' do
before do before do
allow(chat_service).to receive(:channel).and_return(channel) allow(chat_service).to receive(:channel).and_return(channel)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment