cruisecontrolrb-to-slack 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +39 -0
- data/LICENSE.txt +22 -0
- data/README.md +79 -0
- data/Rakefile +7 -0
- data/bin/cruisecontrolrb-to-slack +22 -0
- data/cruisecontrolrb-to-slack.gemspec +32 -0
- data/lib/cruisecontrolrb-to-slack/cruisecontrolrb.rb +65 -0
- data/lib/cruisecontrolrb-to-slack/slack_client.rb +20 -0
- data/lib/cruisecontrolrb-to-slack/version.rb +3 -0
- data/lib/cruisecontrolrb-to-slack.rb +110 -0
- data/test/cruisecontrolrb_test.rb +36 -0
- data/test/data/all_projects_statuses.xml +5 -0
- data/test/data/building.xml +3 -0
- data/test/data/failure.xml +3 -0
- data/test/data/project_details.xml +23 -0
- data/test/data/success.xml +3 -0
- data/test/runner_test.rb +35 -0
- data/test/slack_client_test.rb +35 -0
- data/test/test_helper.rb +9 -0
- metadata +189 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 55685320c39a18c763c92bbcc2738381402157e0
|
4
|
+
data.tar.gz: 9de6ba1213e70141c392f8d200fe3bd7428957f9
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: cde46bedb7f576f66af5bdf5adb8432aca50c8ca492aa22eff4bae3bc7238a3edb54412fc12e43bf6e0d7475c2d3ae492d7fcd5abde8d9d30a3303cc12b231ae
|
7
|
+
data.tar.gz: 54e5ce2fe7a85ce51b54d0cf37a43cb7784a2c82a4e9fc36ac10a06ec9d6ed625a228961c65e072f5ef6134a5ba6ede2e5e1e8495f27822875cb22169a55049e
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
cruisecontrolrb-to-slack (0.0.1)
|
5
|
+
dante (~> 0.2.0)
|
6
|
+
httparty (~> 0.13.1)
|
7
|
+
nokogiri (~> 1.6.2)
|
8
|
+
rufus-scheduler
|
9
|
+
slack-notifier (~> 0.6.0)
|
10
|
+
|
11
|
+
GEM
|
12
|
+
remote: https://rubygems.org/
|
13
|
+
specs:
|
14
|
+
dante (0.2.0)
|
15
|
+
httparty (0.13.1)
|
16
|
+
json (~> 1.8)
|
17
|
+
multi_xml (>= 0.5.2)
|
18
|
+
json (1.8.1)
|
19
|
+
mini_portile (0.6.0)
|
20
|
+
minitest (4.7.5)
|
21
|
+
multi_xml (0.5.5)
|
22
|
+
nokogiri (1.6.3.1)
|
23
|
+
mini_portile (= 0.6.0)
|
24
|
+
rake (10.3.2)
|
25
|
+
rufus-scheduler (3.0.9)
|
26
|
+
tzinfo
|
27
|
+
slack-notifier (0.6.0)
|
28
|
+
thread_safe (0.3.4)
|
29
|
+
tzinfo (1.2.2)
|
30
|
+
thread_safe (~> 0.1)
|
31
|
+
|
32
|
+
PLATFORMS
|
33
|
+
ruby
|
34
|
+
|
35
|
+
DEPENDENCIES
|
36
|
+
bundler (~> 1.6)
|
37
|
+
cruisecontrolrb-to-slack!
|
38
|
+
minitest
|
39
|
+
rake
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Emmanuel Pinault
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
This is a little app notifies Slack of any changes in the build status on your CruiseControl.rb install.
|
2
|
+
It also support github as a source code repository to link to a commit. Other can easily be extended if needed
|
3
|
+
|
4
|
+
## Installation
|
5
|
+
|
6
|
+
Install as a gem
|
7
|
+
|
8
|
+
gem install cruisecontrolrb-to-slack
|
9
|
+
|
10
|
+
or add to your Gemfile
|
11
|
+
|
12
|
+
```
|
13
|
+
# Gemfile
|
14
|
+
gem "cruisecontrolrb-to-slack"
|
15
|
+
```
|
16
|
+
|
17
|
+
and run `bundle install`
|
18
|
+
|
19
|
+
or from source
|
20
|
+
|
21
|
+
```
|
22
|
+
git clone git@github.com:epinault/cruisecontrolrb-to-slack.git
|
23
|
+
cd cruisecontrolrb-to-slack
|
24
|
+
bundle install
|
25
|
+
rake build
|
26
|
+
```
|
27
|
+
|
28
|
+
## Configuration
|
29
|
+
|
30
|
+
First you will need to create an incoming webhook from Slack integration. You will need to copy the token and the team name of that URL to setup the next part.
|
31
|
+
|
32
|
+
Make sure to define the following environment variable as they are required in either
|
33
|
+
you `.profile` or `/etc/profile.d/cruisecontrolrc-to-slack.sh` (for all users)
|
34
|
+
|
35
|
+
```
|
36
|
+
SLACK_TEAM=team # the team name (first part of the host in the incoming hook url)
|
37
|
+
SLACK_HOOK_TOKEN=your_auth_token # the incoming web_hook token
|
38
|
+
CC_URL=your_cruise_control_url
|
39
|
+
```
|
40
|
+
|
41
|
+
The following are optionals
|
42
|
+
|
43
|
+
Basic auth for your CruiseControlrb install (recommended):
|
44
|
+
|
45
|
+
```
|
46
|
+
CC_USERNAME=your_username
|
47
|
+
CC_PASSWORD=your_password
|
48
|
+
```
|
49
|
+
|
50
|
+
```
|
51
|
+
SLACK_USERNAME=your_username # Name to show for the message coming in [Default: cruisecontrol]
|
52
|
+
SLACK_CHANNEL=your_channel # the channel to receive notification [Default: #general]
|
53
|
+
POLLING_INTERVAL # polling interval in minutes. defaults to 1 minute.
|
54
|
+
```
|
55
|
+
|
56
|
+
## Running
|
57
|
+
|
58
|
+
As this gem uses dante, options are best describes [here](http://github.com/nesquena/dante) but here are some very simple
|
59
|
+
setup
|
60
|
+
|
61
|
+
### Run in foreground and STDOUT output (to test most likely)
|
62
|
+
|
63
|
+
```
|
64
|
+
cruisecontrolrb-to-slack
|
65
|
+
```
|
66
|
+
|
67
|
+
### Run in foreground with logs
|
68
|
+
|
69
|
+
```
|
70
|
+
cruisecontrolrb-to-slack -l /var/log/myapp.log
|
71
|
+
```
|
72
|
+
|
73
|
+
### Run as a daemon with a pid file and logs
|
74
|
+
|
75
|
+
```
|
76
|
+
cruisecontrolrb-to-slack -d -P /var/run/myapp.pid -l /var/log/myapp.log
|
77
|
+
```
|
78
|
+
|
79
|
+
<img width="100px" src="http://1.bp.blogspot.com/-VYkLIx6dPTE/TapmnuECsJI/AAAAAAAAALY/L3c1FY4v--w/s1600/looney_tunes_thats_all_folks.jpg" />
|
data/Rakefile
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'cruisecontrolrb-to-slack'
|
4
|
+
|
5
|
+
Dante.run('myapp') do |opts|
|
6
|
+
raise 'Missing required Cruisecontrol host: export CC_HOST=<your_cc_host>' unless host = ENV["CC_HOST"]
|
7
|
+
raise 'Missing required Slack api token, export SLACK_HOOK_TOKEN=<token>' unless token = ENV["SLACK_HOOK_TOKEN"]
|
8
|
+
raise 'Missing required Slack api token, export SLACK_TEAM=<team>' unless team = ENV["SLACK_TEAM"]
|
9
|
+
user = ENV["SLACK_USERNAME"]
|
10
|
+
channel = ENV["SLACK_CHANNEL"]
|
11
|
+
|
12
|
+
options = {cc_host: host,
|
13
|
+
cc_username: ENV["CC_USERNAME"] || "",
|
14
|
+
cc_password: ENV["CC_PASSWORD"] || "",
|
15
|
+
slack_team: team,
|
16
|
+
slack_hook_token: token,
|
17
|
+
slack_channel: channel ,
|
18
|
+
slack_user: user,
|
19
|
+
polling_interval: ENV["POLLING_INTERVAL"] || 5}
|
20
|
+
|
21
|
+
CruisecontrolrbToSlack::Runner.run(options)
|
22
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'cruisecontrolrb-to-slack/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "cruisecontrolrb-to-slack"
|
8
|
+
spec.version = CruisecontrolrbToSlack::VERSION
|
9
|
+
spec.authors = ["epinault"]
|
10
|
+
spec.email = ["emmanuel.pinault@zumobi.com"]
|
11
|
+
spec.summary = %q{A simple daemon to report last build status of projects and activities from cruisecontrol into Slack}
|
12
|
+
spec.description = %q{A simple daemon to report last build status of projects and activities from cruisecontrol into the awesome Slack (http://slack.com). It support multiple projects}
|
13
|
+
spec.homepage = "http://github.com/epinault/cruisecontrolrb-to-hipchat"
|
14
|
+
spec.license = "MIT"
|
15
|
+
spec.required_ruby_version = '>= 1.9.3'
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0")
|
18
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
19
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
20
|
+
spec.require_paths = ["lib"]
|
21
|
+
|
22
|
+
spec.add_dependency "dante", "~> 0.2.0"
|
23
|
+
spec.add_dependency "slack-notifier", "~> 0.6.0"
|
24
|
+
spec.add_dependency "nokogiri", "~> 1.6.2"
|
25
|
+
spec.add_dependency "httparty", "~> 0.13.1"
|
26
|
+
spec.add_dependency "rufus-scheduler"
|
27
|
+
|
28
|
+
spec.add_development_dependency "bundler", "~> 1.6"
|
29
|
+
spec.add_development_dependency "rake"
|
30
|
+
spec.add_development_dependency "minitest"
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module CruisecontrolrbToSlack
|
2
|
+
|
3
|
+
class Cruisecontrolrb
|
4
|
+
|
5
|
+
include HTTParty
|
6
|
+
|
7
|
+
def initialize(base_url, username = nil, password = nil)
|
8
|
+
@auth = { :username => username, :password => password }
|
9
|
+
@base_url = base_url
|
10
|
+
end
|
11
|
+
|
12
|
+
def fetch_statuses
|
13
|
+
noko = Nokogiri::XML(retrieve_content("http://#{@base_url}/XmlStatusReport.aspx"))
|
14
|
+
projects = noko.search("Project")
|
15
|
+
return [] unless projects.first
|
16
|
+
|
17
|
+
projects.map do |project|
|
18
|
+
|
19
|
+
status_hash = {
|
20
|
+
status: project["lastBuildStatus"],
|
21
|
+
web_url: project["webUrl"],
|
22
|
+
build_label: project["lastBuildLabel"],
|
23
|
+
activity: project["activity"],
|
24
|
+
name: project['name'] }
|
25
|
+
status_hash
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def fetch_project_details(project)
|
30
|
+
noko = Nokogiri::XML(retrieve_content("http://#{@base_url}/projects/#{project}.rss"))
|
31
|
+
item_node = noko.search("item")
|
32
|
+
return {} unless item_node.first
|
33
|
+
|
34
|
+
item = item_node.first
|
35
|
+
|
36
|
+
commit = item.at('guid').text.split('/')[-1]
|
37
|
+
description = item.at('description').text
|
38
|
+
title = item.at('title').text
|
39
|
+
|
40
|
+
commit_details = description.match(/committed by (.+)/)[1].split(' ' )
|
41
|
+
committer = commit_details[0]
|
42
|
+
commit_time = commit_details[-2..-1].join(' ')
|
43
|
+
commit_comment = description.split("\n\n")[1]
|
44
|
+
|
45
|
+
{
|
46
|
+
commit_url: "https://github.com/zumobi/#{project}/commit/#{commit[0..10]}",
|
47
|
+
committer: committer,
|
48
|
+
commit_time: commit_time,
|
49
|
+
commit: commit[0..10],
|
50
|
+
commit_comment: commit_comment.strip,
|
51
|
+
description: description,
|
52
|
+
title: title,
|
53
|
+
}
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def retrieve_content(url)
|
59
|
+
options = { :basic_auth => @auth }
|
60
|
+
self.class.get(url, options).parsed_response
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module CruisecontrolrbToSlack
|
2
|
+
class SlackClient
|
3
|
+
attr_reader :client
|
4
|
+
|
5
|
+
def initialize(team, token, options = {})
|
6
|
+
user = options[:user] || 'cruisecontrol'
|
7
|
+
channel = options[:channel] || '#general'
|
8
|
+
|
9
|
+
@client = Slack::Notifier.new team, token, channel: channel, username: user
|
10
|
+
end
|
11
|
+
|
12
|
+
#
|
13
|
+
# options: See https://github.com/stevenosloan/slack-notifier , additional parameters
|
14
|
+
#
|
15
|
+
def send_message(mesg, options = {})
|
16
|
+
@client.ping mesg, options
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'httparty'
|
2
|
+
require 'nokogiri'
|
3
|
+
require 'slack-notifier'
|
4
|
+
require 'dante'
|
5
|
+
require 'rufus-scheduler'
|
6
|
+
require "cruisecontrolrb-to-slack/version"
|
7
|
+
require "cruisecontrolrb-to-slack/cruisecontrolrb"
|
8
|
+
require "cruisecontrolrb-to-slack/slack_client"
|
9
|
+
|
10
|
+
module CruisecontrolrbToSlack
|
11
|
+
|
12
|
+
class Runner
|
13
|
+
attr_accessor :previous_statuses , :current_activities
|
14
|
+
attr_reader :config
|
15
|
+
FAILED_EMOJIS = [':speak_no_evil:', ':see_no_evil:', ':hear_no_evil:']
|
16
|
+
|
17
|
+
def self.run(config)
|
18
|
+
new(config).execute
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize(config)
|
22
|
+
@config = config
|
23
|
+
@previous_statuses = {}
|
24
|
+
@current_activities = {}
|
25
|
+
end
|
26
|
+
|
27
|
+
def execute
|
28
|
+
scheduler = Rufus::Scheduler.new(:blocking => true, :overlap => false)
|
29
|
+
|
30
|
+
scheduler.every("#{config[:polling_interval]}s") do
|
31
|
+
check_statuses
|
32
|
+
end
|
33
|
+
|
34
|
+
scheduler.join
|
35
|
+
end
|
36
|
+
|
37
|
+
def check_statuses
|
38
|
+
statuses = cc_client.fetch_statuses
|
39
|
+
|
40
|
+
unless statuses.empty?
|
41
|
+
|
42
|
+
statuses.each do |status_hash|
|
43
|
+
name = status_hash[:name]
|
44
|
+
|
45
|
+
if status_hash[:activity] == "Building" and current_activities[name] != "Building"
|
46
|
+
message, options = build_start_message(status_hash)
|
47
|
+
submit_message(message, options)
|
48
|
+
current_activities[name] = "Building"
|
49
|
+
elsif (current_activities[name] == "Building" and status_hash[:activity] != "Building")
|
50
|
+
current_activities[name] = status_hash[:activity]
|
51
|
+
message, options = build_end_message(status_hash)
|
52
|
+
submit_message(message, options)
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def build_start_message(status_hash)
|
60
|
+
msg = "CruiseControl has started to build project #{status_hash[:name]}. <#{build_url_for_status(status_hash)}|See details>"
|
61
|
+
|
62
|
+
[msg,{icon_emoji: ':mega:'}]
|
63
|
+
end
|
64
|
+
|
65
|
+
def build_end_message(status_hash)
|
66
|
+
name = status_hash[:name]
|
67
|
+
url = build_url_for_status(status_hash)
|
68
|
+
|
69
|
+
project_details = fetch_details(name)
|
70
|
+
|
71
|
+
color = (status_hash[:status] == "Success") ? "good" : "danger"
|
72
|
+
emoji = (status_hash[:status] == "Success") ? ":tada:" : FAILED_EMOJIS[rand(3)]
|
73
|
+
|
74
|
+
message = (status_hash[:status] == "Success") ? "<#{url}|Success!> #{name} is looking good. You are a stud! :D" : "You are a failure! #{name} is broken. <a href=\"#{url}\">See details</a> and fix it now! >:-("
|
75
|
+
attachment = {
|
76
|
+
fallback: project_details[:commit_comment],
|
77
|
+
color: color,
|
78
|
+
mrkdwn_in: ["text", "title", "fields", "fallback"],
|
79
|
+
fields: [{title: 'Commit Msg:', value: project_details[:commit_comment]},
|
80
|
+
{title: 'Commit', value: "<#{project_details[:commit_url]}|#{project_details[:commit]}>", short: 'true'},
|
81
|
+
{title: 'Committer', value: project_details[:committer], short: 'true'}]
|
82
|
+
}
|
83
|
+
|
84
|
+
options = {icon_emoji: emoji, color: color, attachments: [attachment]}
|
85
|
+
[message, options]
|
86
|
+
end
|
87
|
+
|
88
|
+
def build_url_for_status(status_hash)
|
89
|
+
File.join(status_hash[:web_url].gsub("projects", "builds"), status_hash[:build_label])
|
90
|
+
end
|
91
|
+
|
92
|
+
def submit_message(message, options)
|
93
|
+
slack_client.send_message message, options
|
94
|
+
end
|
95
|
+
|
96
|
+
def fetch_details(name)
|
97
|
+
cc_client.fetch_project_details(name)
|
98
|
+
end
|
99
|
+
|
100
|
+
def slack_client
|
101
|
+
@slack_client ||= SlackClient.new(config[:slack_team], config[:slack_hook_token],
|
102
|
+
channel: config[:slack_channel], user: config[:slack_user])
|
103
|
+
end
|
104
|
+
|
105
|
+
def cc_client
|
106
|
+
@cc_client ||= Cruisecontrolrb.new(config[:cc_host], config[:cc_username], config[:cc_password])
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
describe CruisecontrolrbToSlack::Cruisecontrolrb do
|
4
|
+
subject{CruisecontrolrbToSlack::Cruisecontrolrb.new('host')}
|
5
|
+
|
6
|
+
it 'fetch the status and parse it' do
|
7
|
+
xml = load_data_file('all_projects_statuses.xml')
|
8
|
+
|
9
|
+
subject.stub :retrieve_content, xml do
|
10
|
+
resp = subject.fetch_statuses
|
11
|
+
resp.length.must_equal 3
|
12
|
+
resp[0][:web_url].must_equal 'http://host:3333/projects/project1'
|
13
|
+
resp[0][:status].must_equal 'Failure'
|
14
|
+
resp[0][:build_label].must_equal '5d1d1ed4529dfdc864129691e480990e5751981f.17'
|
15
|
+
resp[0][:activity].must_equal 'CheckingModifications'
|
16
|
+
resp[0][:name].must_equal 'project1'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'fetch the project details and parse it correctly' do
|
21
|
+
xml = load_data_file('project_details.xml')
|
22
|
+
|
23
|
+
subject.stub :retrieve_content, xml do
|
24
|
+
resp = subject.fetch_project_details('test')
|
25
|
+
resp[:committer].must_equal 'epinault'
|
26
|
+
resp[:commit_time].must_equal '2014-03-19 17:56:36'
|
27
|
+
resp[:commit].must_equal '5d1d1ed4529'
|
28
|
+
resp[:description].must_match /<pre>Build was manually requested.+<\/pre>/m
|
29
|
+
resp[:title].must_equal 'project1 build 5d1d1ed.18 failed'
|
30
|
+
resp[:commit_comment].must_equal 'Some cool commit message'
|
31
|
+
resp[:commit_url].must_equal 'https://github.com/zumobi/test/commit/5d1d1ed4529'
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,5 @@
|
|
1
|
+
<Projects>
|
2
|
+
<Project name="project1" category="" activity="CheckingModifications" lastBuildStatus="Failure" lastBuildLabel="5d1d1ed4529dfdc864129691e480990e5751981f.17" lastBuildTime="2014-06-10T23:48:02.0000000+0000" nextBuildTime="1970-01-01T00:00:00.000000-00:00" webUrl="http://host:3333/projects/project1"/>
|
3
|
+
<Project name="project2" category="" activity="CheckingModifications" lastBuildStatus="Success" lastBuildLabel="f4f1cf90acd6e535c9863bcf0dcaa526da9aebf0" lastBuildTime="2014-09-03T22:41:32.0000000+0000" nextBuildTime="1970-01-01T00:00:00.000000-00:00" webUrl="http://host:3333/projects/project2"/>
|
4
|
+
<Project name="project3" category="" activity="CheckingModifications" lastBuildStatus="Success" lastBuildLabel="2797ba93785cbe2a5dbfef52259ffdf95da9c775" lastBuildTime="2014-06-27T20:03:36.0000000+0000" nextBuildTime="1970-01-01T00:00:00.000000-00:00" webUrl="http://host:3333/projects/project3"/>
|
5
|
+
</Projects>
|
@@ -0,0 +1,3 @@
|
|
1
|
+
<Projects>
|
2
|
+
<Project name="project1" category="" activity="Building" lastBuildStatus="Building" lastBuildLabel="5d1d1ed4529dfdc864129691e480990e5751981f.17" lastBuildTime="2014-06-10T23:48:02.0000000+0000" nextBuildTime="1970-01-01T00:00:00.000000-00:00" webUrl="http://host:3333/projects/project1"/>
|
3
|
+
</Projects>
|
@@ -0,0 +1,3 @@
|
|
1
|
+
<Projects>
|
2
|
+
<Project name="project1" category="" activity="CheckingModifications" lastBuildStatus="Failure" lastBuildLabel="5d1d1ed4529dfdc864129691e480990e5751981f.17" lastBuildTime="2014-06-10T23:48:02.0000000+0000" nextBuildTime="1970-01-01T00:00:00.000000-00:00" webUrl="http://host:3333/projects/project1"/>
|
3
|
+
</Projects>
|
@@ -0,0 +1,23 @@
|
|
1
|
+
<rss version="2.0">
|
2
|
+
<channel>
|
3
|
+
<title>CruiseControl RSS feed for project1</title>
|
4
|
+
<link>http://host:3333/projects/project1</link>
|
5
|
+
<language>en-us</language>
|
6
|
+
<ttl>10</ttl>
|
7
|
+
<item>
|
8
|
+
<title>project1 build 5d1d1ed.18 failed</title>
|
9
|
+
<description><pre>Build was manually requested.
|
10
|
+
Revision ...5d1d1ed4529dfdc864129691e480990e5751981f committed by epinault <epinault@someemail.com> on 2014-03-19 17:56:36
|
11
|
+
|
12
|
+
Some cool commit message
|
13
|
+
|
14
|
+
README.rdoc | 261 -----------------------------------------------------------
|
15
|
+
1 file changed, 261 deletions(-)
|
16
|
+
|
17
|
+
</pre></description>
|
18
|
+
<pubDate>Thu, 04 Sep 2014 22:28:35 Z</pubDate>
|
19
|
+
<guid>http://host:3333/builds/project1/5d1d1ed4529dfdc864129691e480990e5751981f.18</guid>
|
20
|
+
<link>http://host:3333/builds/project1/5d1d1ed4529dfdc864129691e480990e5751981f.18</link>
|
21
|
+
</item>
|
22
|
+
</channel>
|
23
|
+
</rss>
|
@@ -0,0 +1,3 @@
|
|
1
|
+
<Projects>
|
2
|
+
<Project name="project1" category="" activity="CheckingModifications" lastBuildStatus="Success" lastBuildLabel="5d1d1ed4529dfdc864129691e480990e5751981f.17" lastBuildTime="2014-06-10T23:48:02.0000000+0000" nextBuildTime="1970-01-01T00:00:00.000000-00:00" webUrl="http://host:3333/projects/project1"/>
|
3
|
+
</Projects>
|
data/test/runner_test.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
describe CruisecontrolrbToSlack::Runner do
|
4
|
+
subject{CruisecontrolrbToSlack::Runner.new({})}
|
5
|
+
let(:slack_client){Minitest::Mock.new}
|
6
|
+
let(:cc_client){Minitest::Mock.new}
|
7
|
+
|
8
|
+
it 'check the status and have no status fetch' do
|
9
|
+
cc_client.expect :fetch_statuses, {}
|
10
|
+
subject.stub :cc_client, cc_client do
|
11
|
+
subject.check_statuses.must_be_nil
|
12
|
+
cc_client.verify
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'check the status and have a building status' do
|
17
|
+
slack_client.expect :send_message, true,
|
18
|
+
['CruiseControl has started to build project project1. <http://host:3333/builds/project1/5d1d1ed4529dfdc864129691e480990e5751981f.17|See details>',
|
19
|
+
{icon_emoji: ':mega:'}]
|
20
|
+
subject.cc_client.stub :retrieve_content, load_data_file('building.xml') do
|
21
|
+
subject.stub :slack_client, slack_client do
|
22
|
+
|
23
|
+
subject.check_statuses
|
24
|
+
slack_client.verify
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should build the url for the status' do
|
30
|
+
subject.build_url_for_status(web_url: 'host/projects/project1',
|
31
|
+
build_label: 'mylabel').must_equal 'host/builds/project1/mylabel'
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
describe CruisecontrolrbToSlack::SlackClient do
|
4
|
+
subject{CruisecontrolrbToSlack::SlackClient.new('team', 'token')}
|
5
|
+
|
6
|
+
it 'should use the default a new instance' do
|
7
|
+
subject.client.must_be_kind_of Slack::Notifier
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'should set the team properly' do
|
11
|
+
subject.client.team.must_equal 'team'
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should set the token properly' do
|
15
|
+
subject.client.token.must_equal 'token'
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should set the default channel to #general' do
|
19
|
+
subject.client.channel.must_equal '#general'
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should set the default user to cruisecontrol' do
|
23
|
+
subject.client.default_payload[:username].must_equal 'cruisecontrol'
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'should override the default channel ' do
|
27
|
+
slack_client = CruisecontrolrbToSlack::SlackClient.new('team', 'token', channel: 'channel')
|
28
|
+
slack_client.client.channel.must_equal 'channel'
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should override the default user ' do
|
32
|
+
slack_client = CruisecontrolrbToSlack::SlackClient.new('team', 'token', user: 'user')
|
33
|
+
slack_client.client.default_payload[:username].must_equal 'user'
|
34
|
+
end
|
35
|
+
end
|
data/test/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,189 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cruisecontrolrb-to-slack
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- epinault
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-09-05 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: dante
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.2.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.2.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: slack-notifier
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.6.0
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.6.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: nokogiri
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 1.6.2
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 1.6.2
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: httparty
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.13.1
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.13.1
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rufus-scheduler
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: bundler
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '1.6'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '1.6'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rake
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: minitest
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
description: A simple daemon to report last build status of projects and activities
|
126
|
+
from cruisecontrol into the awesome Slack (http://slack.com). It support multiple
|
127
|
+
projects
|
128
|
+
email:
|
129
|
+
- emmanuel.pinault@zumobi.com
|
130
|
+
executables:
|
131
|
+
- cruisecontrolrb-to-slack
|
132
|
+
extensions: []
|
133
|
+
extra_rdoc_files: []
|
134
|
+
files:
|
135
|
+
- Gemfile
|
136
|
+
- Gemfile.lock
|
137
|
+
- LICENSE.txt
|
138
|
+
- README.md
|
139
|
+
- Rakefile
|
140
|
+
- bin/cruisecontrolrb-to-slack
|
141
|
+
- cruisecontrolrb-to-slack.gemspec
|
142
|
+
- lib/cruisecontrolrb-to-slack.rb
|
143
|
+
- lib/cruisecontrolrb-to-slack/cruisecontrolrb.rb
|
144
|
+
- lib/cruisecontrolrb-to-slack/slack_client.rb
|
145
|
+
- lib/cruisecontrolrb-to-slack/version.rb
|
146
|
+
- test/cruisecontrolrb_test.rb
|
147
|
+
- test/data/all_projects_statuses.xml
|
148
|
+
- test/data/building.xml
|
149
|
+
- test/data/failure.xml
|
150
|
+
- test/data/project_details.xml
|
151
|
+
- test/data/success.xml
|
152
|
+
- test/runner_test.rb
|
153
|
+
- test/slack_client_test.rb
|
154
|
+
- test/test_helper.rb
|
155
|
+
homepage: http://github.com/epinault/cruisecontrolrb-to-hipchat
|
156
|
+
licenses:
|
157
|
+
- MIT
|
158
|
+
metadata: {}
|
159
|
+
post_install_message:
|
160
|
+
rdoc_options: []
|
161
|
+
require_paths:
|
162
|
+
- lib
|
163
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
164
|
+
requirements:
|
165
|
+
- - ">="
|
166
|
+
- !ruby/object:Gem::Version
|
167
|
+
version: 1.9.3
|
168
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
169
|
+
requirements:
|
170
|
+
- - ">="
|
171
|
+
- !ruby/object:Gem::Version
|
172
|
+
version: '0'
|
173
|
+
requirements: []
|
174
|
+
rubyforge_project:
|
175
|
+
rubygems_version: 2.2.2
|
176
|
+
signing_key:
|
177
|
+
specification_version: 4
|
178
|
+
summary: A simple daemon to report last build status of projects and activities from
|
179
|
+
cruisecontrol into Slack
|
180
|
+
test_files:
|
181
|
+
- test/cruisecontrolrb_test.rb
|
182
|
+
- test/data/all_projects_statuses.xml
|
183
|
+
- test/data/building.xml
|
184
|
+
- test/data/failure.xml
|
185
|
+
- test/data/project_details.xml
|
186
|
+
- test/data/success.xml
|
187
|
+
- test/runner_test.rb
|
188
|
+
- test/slack_client_test.rb
|
189
|
+
- test/test_helper.rb
|