Skip to content
Snippets Groups Projects
Commit e3fc01b3 authored by Federico Ravasio's avatar Federico Ravasio
Browse files

Added Slack service integration.

parent acaf2978
No related branches found
No related tags found
1 merge request!6550Added Slack service integration.
Loading
Loading
@@ -24,6 +24,7 @@ v 6.7.0
- Faster authorized_keys rebuilding in `rake gitlab:shell:setup` (requires gitlab-shell 1.8.5)
- Create and Update MR calls now support the description parameter (Greg Messner)
- Markdown relative links in the wiki link to wiki pages, markdown relative links in repositories link to files in the repository
- Added Slack service integration (Federico Ravasio)
 
v 6.6.5
- Added option to remove issue assignee on project issue page and issue edit page (Jason Blanchard)
Loading
Loading
Loading
Loading
@@ -132,6 +132,9 @@ gem "gitlab-flowdock-git-hook", "~> 0.4.2"
# Gemnasium integration
gem "gemnasium-gitlab-service", "~> 0.2"
 
# Slack integration
gem "slack-notifier", "~> 0.2.0"
# d3
gem "d3_rails", "~> 3.1.4"
 
Loading
Loading
Loading
Loading
@@ -468,6 +468,7 @@ GEM
rack-protection (~> 1.4)
tilt (~> 1.3, >= 1.3.4)
six (0.2.0)
slack-notifier (0.2.0)
slim (2.0.2)
temple (~> 0.6.6)
tilt (>= 1.3.3, < 2.1)
Loading
Loading
@@ -652,6 +653,7 @@ DEPENDENCIES
simplecov
sinatra
six
slack-notifier (~> 0.2.0)
slim
spinach-rails
spork (~> 1.0rc)
Loading
Loading
Loading
Loading
@@ -56,6 +56,7 @@ class Project < ActiveRecord::Base
has_one :flowdock_service, dependent: :destroy
has_one :assembla_service, dependent: :destroy
has_one :gemnasium_service, dependent: :destroy
has_one :slack_service, dependent: :destroy
has_one :forked_project_link, dependent: :destroy, foreign_key: "forked_to_project_id"
has_one :forked_from_project, through: :forked_project_link
# Merge Requests for target project should be removed with it
Loading
Loading
@@ -304,7 +305,7 @@ class Project < ActiveRecord::Base
end
 
def available_services_names
%w(gitlab_ci campfire hipchat pivotaltracker flowdock assembla emails_on_push gemnasium)
%w(gitlab_ci campfire hipchat pivotaltracker flowdock assembla emails_on_push gemnasium slack)
end
 
def gitlab_ci?
Loading
Loading
require 'slack-notifier'
class SlackMessage
def initialize(params)
@after = params.fetch(:after)
@before = params.fetch(:before)
@commits = params.fetch(:commits, [])
@project_name = params.fetch(:project_name)
@project_url = params.fetch(:project_url)
@ref = params.fetch(:ref).gsub('refs/heads/', '')
@username = params.fetch(:user_name)
end
def compose
format(message)
end
private
attr_reader :after
attr_reader :before
attr_reader :commits
attr_reader :project_name
attr_reader :project_url
attr_reader :ref
attr_reader :username
def message
if new_branch?
new_branch_message
elsif removed_branch?
removed_branch_message
else
push_message << commit_messages
end
end
def format(string)
Slack::Notifier::LinkFormatter.format(string)
end
def new_branch_message
"#{username} pushed new branch #{branch_link} to #{project_link}"
end
def removed_branch_message
"#{username} removed branch #{ref} from #{project_link}"
end
def push_message
"#{username} pushed to branch #{branch_link} of #{project_link} (#{compare_link})"
end
def commit_messages
commits.each_with_object('') do |commit, str|
str << compose_commit_message(commit)
end
end
def compose_commit_message(commit)
id = commit.fetch(:id)[0..5]
message = commit.fetch(:message)
url = commit.fetch(:url)
"\n - #{message} ([#{id}](#{url}))"
end
def new_branch?
before =~ /000000/
end
def removed_branch?
after =~ /000000/
end
def branch_url
"#{project_url}/commits/#{ref}"
end
def compare_url
"#{project_url}/compare/#{before}...#{after}"
end
def branch_link
"[#{ref}](#{branch_url})"
end
def project_link
"[#{project_name}](#{project_url})"
end
def compare_link
"[Compare changes](#{compare_url})"
end
end
# == Schema Information
#
# Table name: services
#
# id :integer not null, primary key
# type :string(255)
# title :string(255)
# token :string(255)
# project_id :integer not null
# created_at :datetime not null
# updated_at :datetime not null
# active :boolean default(FALSE), not null
# project_url :string(255)
# subdomain :string(255)
# room :string(255)
# api_key :string(255)
#
class SlackService < Service
attr_accessible :room
attr_accessible :subdomain
validates :room, presence: true, if: :activated?
validates :subdomain, presence: true, if: :activated?
validates :token, presence: true, if: :activated?
def title
'Slack'
end
def description
'A team communication tool for the 21st century'
end
def to_param
'slack'
end
def fields
[
{ type: 'text', name: 'subdomain', placeholder: '' },
{ type: 'text', name: 'token', placeholder: '' },
{ type: 'text', name: 'room', placeholder: '' },
]
end
def execute(push_data)
message = SlackMessage.new(push_data.merge(
project_url: project_url,
project_name: project_name
))
notifier = Slack::Notifier.new(subdomain, token)
notifier.channel = room
notifier.ping(message.compose)
end
private
def project_name
project.name_with_namespace.gsub(/\s/, '')
end
def project_url
project.web_url
end
end
Loading
Loading
@@ -37,6 +37,12 @@ Feature: Project Services
And I fill Assembla settings
Then I should see Assembla service settings saved
 
Scenario: Activate Slack service
When I visit project "Shop" services page
And I click Slack service link
And I fill Slack settings
Then I should see Slack service settings saved
Scenario: Activate email on push service
When I visit project "Shop" services page
And I click email on push service link
Loading
Loading
Loading
Loading
@@ -100,4 +100,22 @@ class ProjectServices < Spinach::FeatureSteps
step 'I should see email on push service settings saved' do
find_field('Recipients').value.should == 'qa@company.name'
end
step 'I click Slack service link' do
click_link 'Slack'
end
step 'I fill Slack settings' do
check 'Active'
fill_in 'Subdomain', with: 'gitlab'
fill_in 'Room', with: '#gitlab'
fill_in 'Token', with: 'verySecret'
click_button 'Save'
end
step 'I should see Slack service settings saved' do
find_field('Subdomain').value.should == 'gitlab'
find_field('Room').value.should == '#gitlab'
find_field('Token').value.should == 'verySecret'
end
end
Loading
Loading
@@ -47,6 +47,7 @@ describe Project do
it { should have_many(:hooks).dependent(:destroy) }
it { should have_many(:protected_branches).dependent(:destroy) }
it { should have_one(:forked_project_link).dependent(:destroy) }
it { should have_one(:slack_service).dependent(:destroy) }
end
 
describe "Mass assignment" do
Loading
Loading
require_relative '../../app/models/project_services/slack_message'
describe SlackMessage do
subject { SlackMessage.new(args) }
let(:args) {
{
after: 'after',
before: 'before',
project_name: 'project_name',
ref: 'refs/heads/master',
user_name: 'user_name',
project_url: 'url'
}
}
context 'push' do
before do
args[:commits] = [
{ message: 'message1', url: 'url1', id: 'abcdefghi' },
{ message: 'message2', url: 'url2', id: '123456789' },
]
end
it 'returns a message regarding pushes' do
subject.compose.should ==
'user_name pushed to branch <url/commits/master|master> of ' <<
'<url|project_name> (<url/compare/before...after|Compare changes>)' <<
"\n - message1 (<url1|abcdef>)" <<
"\n - message2 (<url2|123456>)"
end
end
context 'new branch' do
before do
args[:before] = '000000'
end
it 'returns a message regarding a new branch' do
subject.compose.should ==
'user_name pushed new branch <url/commits/master|master> to ' <<
'<url|project_name>'
end
end
context 'removed branch' do
before do
args[:after] = '000000'
end
it 'returns a message regarding a removed branch' do
subject.compose.should ==
'user_name removed branch master from <url|project_name>'
end
end
end
# == Schema Information
#
# Table name: services
#
# id :integer not null, primary key
# type :string(255)
# title :string(255)
# token :string(255)
# project_id :integer not null
# created_at :datetime not null
# updated_at :datetime not null
# active :boolean default(FALSE), not null
# project_url :string(255)
# subdomain :string(255)
# room :string(255)
# api_key :string(255)
#
require 'spec_helper'
describe SlackService do
describe "Associations" do
it { should belong_to :project }
it { should have_one :service_hook }
end
describe "Validations" do
context "active" do
before do
subject.active = true
end
it { should validate_presence_of :room }
it { should validate_presence_of :subdomain }
it { should validate_presence_of :token }
end
end
describe "Execute" do
let(:slack) { SlackService.new }
let(:user) { create(:user) }
let(:project) { create(:project) }
let(:sample_data) { GitPushService.new.sample_data(project, user) }
let(:subdomain) { 'gitlab' }
let(:token) { 'verySecret' }
let(:api_url) {
"https://#{subdomain}.slack.com/services/hooks/incoming-webhook?token=#{token}"
}
before do
slack.stub(
project: project,
project_id: project.id,
room: '#gitlab',
service_hook: true,
subdomain: subdomain,
token: token
)
WebMock.stub_request(:post, api_url)
end
it "should call Slack API" do
slack.execute(sample_data)
WebMock.should have_requested(:post, api_url).once
end
end
end
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