mirror of
https://github.com/wahyd4/gitlabhq.git
synced 2026-08-15 23:56:09 +10:00
Merge branch 'master' of github.com:gitlabhq/gitlabhq
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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)
|
||||
@@ -652,6 +653,7 @@ DEPENDENCIES
|
||||
simplecov
|
||||
sinatra
|
||||
six
|
||||
slack-notifier (~> 0.2.0)
|
||||
slim
|
||||
spinach-rails
|
||||
spork (~> 1.0rc)
|
||||
|
||||
@@ -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
|
||||
@@ -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?
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
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
|
||||
@@ -0,0 +1,67 @@
|
||||
# == 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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -66,6 +66,7 @@ namespace :gitlab do
|
||||
puts "no".green
|
||||
else
|
||||
puts "yes".red
|
||||
puts "Please fix this by removing the SQLite entry from the database.yml".blue
|
||||
for_more_information(
|
||||
"https://github.com/gitlabhq/gitlabhq/wiki/Migrate-from-SQLite-to-MySQL",
|
||||
see_database_guide
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
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
|
||||
@@ -0,0 +1,69 @@
|
||||
# == 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
|
||||
Reference in New Issue
Block a user