Skip to content
Snippets Groups Projects
Commit a5ccaded authored by Felipe Artur's avatar Felipe Artur
Browse files

Change SlackService to SlackNotificationsService

parent 141faaac
No related branches found
No related tags found
No related merge requests found
Showing
with 223 additions and 168 deletions
Loading
Loading
@@ -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
Loading
Loading
# 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
# 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
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)) }
has_many :chat_names, foreign_key: :service_id
 
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
class MattermostService < ChatService
class MattermostNotificationService < ChatNotificationService
def title
'Mattermost notifications'
end
Loading
Loading
@@ -8,7 +8,7 @@ class MattermostService < ChatService
end
 
def to_param
'mattermost'
'mattermost_notification'
end
 
def help
Loading
Loading
@@ -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' },
Loading
Loading
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
Loading
Loading
class SlackService < ChatService
class SlackNotificationService < ChatNotificationService
def title
'Slack notifications'
end
Loading
Loading
@@ -8,7 +8,7 @@ class SlackService < ChatService
end
 
def to_param
'slack'
'slack_notification'
end
 
def help
Loading
Loading
Loading
Loading
@@ -220,8 +220,8 @@ class Service < ActiveRecord::Base
pivotaltracker
pushover
redmine
mattermost
slack
mattermost_notification
slack_notification
teamcity
]
end
Loading
Loading
# 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']
Loading
Loading
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
Loading
Loading
@@ -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"
Loading
Loading
Loading
Loading
@@ -473,7 +473,7 @@ module API
desc: 'The description of the tracker'
}
],
'slack' => [
'slack-notification' => [
{
required: true,
name: :webhook,
Loading
Loading
@@ -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,
Loading
Loading
No preview for this file type
Loading
Loading
@@ -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
Loading
Loading
Loading
Loading
@@ -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
Loading
Loading
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
Loading
Loading
@@ -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
require 'spec_helper'
 
describe SlackService, models: true do
describe MattermostNotificationService, models: true do
it_behaves_like "slack or mattermost"
end
require 'spec_helper'
 
describe MattermostService, models: true do
describe SlackNotificationService, models: true do
it_behaves_like "slack or mattermost"
end
Loading
Loading
@@ -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
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment