Commit 8bd520d7 authored by Felipe Artur's avatar Felipe Artur

Allow slack service to send messages on different channels

parent b9ed9d65
...@@ -101,6 +101,7 @@ v 8.10.0 (unreleased) ...@@ -101,6 +101,7 @@ v 8.10.0 (unreleased)
- Don't render discussion notes when requesting diff tab through AJAX - Don't render discussion notes when requesting diff tab through AJAX
- Add basic system information like memory and disk usage to the admin panel - Add basic system information like memory and disk usage to the admin panel
- Don't garbage collect commits that have related DB records like comments - Don't garbage collect commits that have related DB records like comments
- Allow to setup event by channel on slack service
- More descriptive message for git hooks and file locks - More descriptive message for git hooks and file locks
- Aliases of award emoji should be stored as original name. !5060 (dixpac) - Aliases of award emoji should be stored as original name. !5060 (dixpac)
- Handle custom Git hook result in GitLab UI - Handle custom Git hook result in GitLab UI
......
...@@ -39,11 +39,14 @@ class Admin::ServicesController < Admin::ApplicationController ...@@ -39,11 +39,14 @@ class Admin::ServicesController < Admin::ApplicationController
end end
def application_services_params def application_services_params
dynamic_params = []
dynamic_params.concat(@service.event_channel_names) if @service.is_a?(SlackService)
application_services_params = params.permit(:id, application_services_params = params.permit(:id,
service: Projects::ServicesController::ALLOWED_PARAMS) service: Projects::ServicesController::ALLOWED_PARAMS + dynamic_params)
if application_services_params[:service].is_a?(Hash) if application_services_params[:service].is_a?(Hash)
Projects::ServicesController::FILTER_BLANK_PARAMS.each do |param| Projects::ServicesController::FILTER_BLANK_PARAMS.each do |param|
application_services_params[:service].delete(param) if application_services_params[:service][param].blank? application_services_params[:service].delete(param) if application_services_params[:service][param].blank?
end end
end end
application_services_params application_services_params
......
...@@ -66,10 +66,15 @@ class Projects::ServicesController < Projects::ApplicationController ...@@ -66,10 +66,15 @@ class Projects::ServicesController < Projects::ApplicationController
end end
def service_params def service_params
service_params = params.require(:service).permit(ALLOWED_PARAMS) dynamic_params = []
dynamic_params.concat(@service.event_channel_names) if @service.is_a?(SlackService)
service_params = params.require(:service).permit(ALLOWED_PARAMS + dynamic_params)
FILTER_BLANK_PARAMS.each do |param| FILTER_BLANK_PARAMS.each do |param|
service_params.delete(param) if service_params[param].blank? service_params.delete(param) if service_params[param].blank?
end end
service_params service_params
end end
end end
module ServicesHelper
def service_event_description(event)
case event
when "push"
"Webhook will triggered by a push to the repository"
when "tag_push"
"Webhook will be triggered when a new tag is pushed to the repository"
when "note"
"Webhook will be triggered when someone adds a comment"
when "issue"
"Webhook will be triggered when an issue is created/updated/merged"
when "merge_request"
"Webhook will be triggered when a merge request is created/updated/merged"
when "build"
"Webhook will be triggered when a build status changes"
when "wiki_page"
"Webhook will be triggered when a wiki page is created/updated"
end
end
def service_event_field_name(event)
event = event.pluralize if %w(merge_request issue).include?(event)
"#{event}_events"
end
end
...@@ -4,6 +4,9 @@ class SlackService < Service ...@@ -4,6 +4,9 @@ class SlackService < Service
validates :webhook, presence: true, url: true, if: :activated? validates :webhook, presence: true, url: true, if: :activated?
def initialize_properties def initialize_properties
# Custom serialized properties initialization
self.supported_events.each { |event| self.class.prop_accessor event_channel_name(event) }
if properties.nil? if properties.nil?
self.properties = {} self.properties = {}
self.notify_only_broken_builds = true self.notify_only_broken_builds = true
...@@ -29,13 +32,15 @@ class SlackService < Service ...@@ -29,13 +32,15 @@ class SlackService < Service
end end
def fields def fields
[ default_fields =
{ type: 'text', name: 'webhook', [
placeholder: 'https://hooks.slack.com/services/...' }, { type: 'text', name: 'webhook', placeholder: 'https://hooks.slack.com/services/...' },
{ type: 'text', name: 'username', placeholder: 'username' }, { type: 'text', name: 'username', placeholder: 'username' },
{ type: 'text', name: 'channel', placeholder: '#channel' }, { type: 'text', name: 'channel', placeholder: "#General" },
{ type: 'checkbox', name: 'notify_only_broken_builds' }, { type: 'checkbox', name: 'notify_only_broken_builds' },
] ]
default_fields + build_event_channels
end end
def supported_events def supported_events
...@@ -74,7 +79,10 @@ class SlackService < Service ...@@ -74,7 +79,10 @@ class SlackService < Service
end end
opt = {} opt = {}
opt[:channel] = channel if channel
event_channel = get_channel_field(object_kind) || channel
opt[:channel] = event_channel if event_channel
opt[:username] = username if username opt[:username] = username if username
if message if message
...@@ -83,8 +91,32 @@ class SlackService < Service ...@@ -83,8 +91,32 @@ class SlackService < Service
end end
end end
def event_channel_names
supported_events.map { |event| event_channel_name(event) }
end
private private
def get_channel_field(event)
field_name = event_channel_name(event)
self.send(field_name)
end
def build_event_channels
channels = []
supported_events.each do |event|
channel_name = event_channel_name(event)
channels << { type: 'text', name: channel_name, placeholder: "#General" }
end
channels
end
def event_channel_name(event)
"#{event}_channel"
end
def project_name def project_name
project.name_with_namespace.gsub(/\s/, '') project.name_with_namespace.gsub(/\s/, '')
end end
......
...@@ -4,7 +4,10 @@ ...@@ -4,7 +4,10 @@
%p #{@service.description} template %p #{@service.description} template
= form_for :service, url: admin_application_settings_service_path, method: :put, html: { class: 'form-horizontal fieldset-form' } do |form| = form_for :service, url: admin_application_settings_service_path, method: :put, html: { class: 'form-horizontal fieldset-form' } do |form|
= render 'shared/service_settings', form: form - if @service.is_a?(SlackService)
= render 'projects/services/slack/service_settings', form: form
- else
= render 'shared/service_settings', form: form
.form-actions .form-actions
= form.submit 'Save', class: 'btn btn-save' = form.submit 'Save', class: 'btn btn-save'
...@@ -7,7 +7,11 @@ ...@@ -7,7 +7,11 @@
%p= @service.description %p= @service.description
.col-lg-9 .col-lg-9
= form_for(@service, as: :service, url: namespace_project_service_path(@project.namespace, @project, @service.to_param), method: :put, html: { class: 'form-horizontal' }) do |form| = form_for(@service, as: :service, url: namespace_project_service_path(@project.namespace, @project, @service.to_param), method: :put, html: { class: 'form-horizontal' }) do |form|
= render 'shared/service_settings', form: form - if @service.is_a?(SlackService)
= render 'projects/services/slack/service_settings', form: form
- else
= render 'shared/service_settings', form: form
= form.submit 'Save changes', class: 'btn btn-save' = form.submit 'Save changes', class: 'btn btn-save'
&nbsp; &nbsp;
- if @service.valid? && @service.activated? - if @service.valid? && @service.activated?
......
= form_errors(@service)
- if @service.help.present?
.well
= preserve do
= markdown @service.help
.form-group
= form.label :active, "Active", class: "control-label"
.col-sm-10
= form.check_box :active
.form-group
= form.label :url, "Trigger", class: 'control-label'
.col-sm-10
- @service.supported_events.each do |event|
%div
= form.check_box service_event_field_name(event), class: 'pull-left'
.prepend-left-20
= form.label service_event_field_name(event), class: 'list-label' do
%strong
= event.humanize
%p
- field = @service.fields.select{ |field| field[:name] == "#{event}_channel"}.first
= form.text_field field[:name], class: "form-control", placeholder: field[:placeholder]
%p.light
= service_event_description(event)
- @service.fields.each do |field|
- if %w(webhook username notify_only_broken_builds).include?(field[:name])
= render 'shared/field', form: form, field: field
...@@ -27,19 +27,19 @@ class Spinach::Features::AdminSettings < Spinach::FeatureSteps ...@@ -27,19 +27,19 @@ class Spinach::Features::AdminSettings < Spinach::FeatureSteps
step 'I check all events and submit form' do step 'I check all events and submit form' do
page.check('Active') page.check('Active')
page.check('Push events') page.check('Push')
page.check('Tag push events') page.check('Tag push')
page.check('Comments') page.check('Note')
page.check('Issues events') page.check('Issue')
page.check('Merge Request events') page.check('Merge request')
page.check('Build events') page.check('Build')
click_on 'Save' click_on 'Save'
end end
step 'I fill out Slack settings' do step 'I fill out Slack settings' do
fill_in 'Webhook', with: 'http://localhost' fill_in 'Webhook', with: 'http://localhost'
fill_in 'Username', with: 'test_user' fill_in 'Username', with: 'test_user'
fill_in 'Channel', with: '#test_channel' fill_in 'service_push_channel', with: '#test_channel'
page.check('Notify only broken builds') page.check('Notify only broken builds')
end end
...@@ -56,6 +56,6 @@ class Spinach::Features::AdminSettings < Spinach::FeatureSteps ...@@ -56,6 +56,6 @@ class Spinach::Features::AdminSettings < Spinach::FeatureSteps
step 'I should see Slack settings saved' do step 'I should see Slack settings saved' do
expect(find_field('Webhook').value).to eq 'http://localhost' expect(find_field('Webhook').value).to eq 'http://localhost'
expect(find_field('Username').value).to eq 'test_user' expect(find_field('Username').value).to eq 'test_user'
expect(find_field('Channel').value).to eq '#test_channel' expect(find('#service_push_channel').value).to eq '#test_channel'
end end
end end
...@@ -124,6 +124,7 @@ describe SlackService, models: true do ...@@ -124,6 +124,7 @@ describe SlackService, models: true do
and_return( and_return(
double(:slack_service).as_null_object double(:slack_service).as_null_object
) )
slack.execute(push_sample_data) slack.execute(push_sample_data)
end end
...@@ -136,6 +137,76 @@ describe SlackService, models: true do ...@@ -136,6 +137,76 @@ describe SlackService, models: true do
) )
slack.execute(push_sample_data) slack.execute(push_sample_data)
end end
context "event channels" do
it "should user 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 "should use 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 "should use 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 "should use 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 "should use the right channel" do
slack.update_attributes(note_channel: "random")
note_data = Gitlab::NoteDataBuilder.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 end
describe "Note events" do describe "Note events" do
......
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