Change SlackService to SlackNotificationsService
This commit is contained in:
parent
141faaacf9
commit
a5ccaded65
19 changed files with 223 additions and 168 deletions
|
@ -95,8 +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 :mattermost_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
|
||||
|
|
147
app/models/project_services/chat_notification_service.rb
Normal file
147
app/models/project_services/chat_notification_service.rb
Normal file
|
@ -0,0 +1,147 @@
|
|||
# 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
|
||||
# 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
|
||||
|
||||
def can_test?
|
||||
valid?
|
||||
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)
|
||||
|
||||
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
|
|
@ -1,148 +1,21 @@
|
|||
# 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
|
||||
include ChatMessage
|
||||
|
||||
default_value_for :category, 'chat'
|
||||
|
||||
prop_accessor :webhook, :username, :channel
|
||||
boolean_accessor :notify_only_broken_builds, :notify_only_broken_pipelines
|
||||
has_many :chat_names, foreign_key: :service_id
|
||||
|
||||
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
|
||||
|
||||
def can_test?
|
||||
valid?
|
||||
def valid_token?(token)
|
||||
self.respond_to?(:token) &&
|
||||
self.token.present? &&
|
||||
ActiveSupport::SecurityUtils.variable_size_secure_compare(token, self.token)
|
||||
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)
|
||||
|
||||
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
|
||||
def trigger(params)
|
||||
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
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
class MattermostService < ChatService
|
||||
class MattermostNotificationService < ChatNotificationService
|
||||
def title
|
||||
'Mattermost notifications'
|
||||
end
|
||||
|
@ -8,7 +8,7 @@ class MattermostService < ChatService
|
|||
end
|
||||
|
||||
def to_param
|
||||
'mattermost'
|
||||
'mattermost_notification'
|
||||
end
|
||||
|
||||
def help
|
||||
|
@ -28,7 +28,7 @@ class MattermostService < ChatService
|
|||
|
||||
def default_fields
|
||||
[
|
||||
{ type: 'text', name: 'webhook', placeholder: 'http://mattermost_host/hooks/...' },
|
||||
{ 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' },
|
|
@ -1,18 +1,8 @@
|
|||
class MattermostSlashCommandsService < Service
|
||||
class MattermostSlashCommandsService < ChatService
|
||||
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
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
class SlackService < ChatService
|
||||
class SlackNotificationService < ChatNotificationService
|
||||
def title
|
||||
'Slack notifications'
|
||||
end
|
||||
|
@ -8,7 +8,7 @@ class SlackService < ChatService
|
|||
end
|
||||
|
||||
def to_param
|
||||
'slack'
|
||||
'slack_notification'
|
||||
end
|
||||
|
||||
def help
|
|
@ -220,8 +220,8 @@ class Service < ActiveRecord::Base
|
|||
pivotaltracker
|
||||
pushover
|
||||
redmine
|
||||
mattermost
|
||||
slack
|
||||
mattermost_notification
|
||||
slack_notification
|
||||
teamcity
|
||||
]
|
||||
end
|
||||
|
|
|
@ -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']
|
||||
|
|
|
@ -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
|
|
@ -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"
|
||||
|
|
|
@ -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,
|
||||
|
|
Binary file not shown.
|
@ -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
|
||||
|
|
|
@ -136,8 +136,8 @@ project:
|
|||
- assembla_service
|
||||
- asana_service
|
||||
- gemnasium_service
|
||||
- slack_service
|
||||
- mattermost_service
|
||||
- slack_notification_service
|
||||
- mattermost_notification_service
|
||||
- buildkite_service
|
||||
- bamboo_service
|
||||
- teamcity_service
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
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
|
|
@ -2,7 +2,14 @@ require 'spec_helper'
|
|||
|
||||
describe ChatService, models: true do
|
||||
describe "Associations" do
|
||||
before { allow(subject).to receive(:activated?).and_return(true) }
|
||||
it { is_expected.to validate_presence_of :webhook }
|
||||
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
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe SlackService, models: true do
|
||||
describe MattermostNotificationService, models: true do
|
||||
it_behaves_like "slack or mattermost"
|
||||
end
|
|
@ -1,5 +1,5 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe MattermostService, models: true do
|
||||
describe SlackNotificationService, models: true do
|
||||
it_behaves_like "slack or mattermost"
|
||||
end
|
|
@ -22,8 +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(:mattermost_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) }
|
||||
|
|
Loading…
Reference in a new issue