roxanne 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +5 -0
- data/.ruby-version +1 -0
- data/.travis.yml +9 -0
- data/Gemfile +4 -0
- data/Guardfile +7 -0
- data/LICENSE.txt +22 -0
- data/README.md +131 -0
- data/Rakefile +9 -0
- data/bin/roxanne +16 -0
- data/config/config.yml +6 -0
- data/lib/roxanne/configuration/yaml.rb +46 -0
- data/lib/roxanne/configuration.rb +26 -0
- data/lib/roxanne/consumers.rb +19 -0
- data/lib/roxanne/gpio/publisher.rb +24 -0
- data/lib/roxanne/http/consumer.rb +33 -0
- data/lib/roxanne/http_support.rb +43 -0
- data/lib/roxanne/jenkins/consumer.rb +34 -0
- data/lib/roxanne/loop.rb +35 -0
- data/lib/roxanne/publishers.rb +2 -0
- data/lib/roxanne/server.rb +24 -0
- data/lib/roxanne/test/consumer.rb +17 -0
- data/lib/roxanne/test/publisher.rb +18 -0
- data/lib/roxanne/travis/consumer.rb +32 -0
- data/lib/roxanne/version.rb +3 -0
- data/lib/roxanne.rb +10 -0
- data/roxanne.gemspec +37 -0
- data/service/etc_init.d_roxanne +21 -0
- data/service/roxanne.sh +5 -0
- data/spec/roxanne/configuration/yaml_spec.rb +48 -0
- data/spec/roxanne/configuration_spec.rb +37 -0
- data/spec/roxanne/gpio/publisher_spec.rb +54 -0
- data/spec/roxanne/jenkins/consumer_spec.rb +31 -0
- data/spec/roxanne/loop_spec.rb +80 -0
- data/spec/roxanne/server_spec.rb +62 -0
- data/spec/roxanne/travis/consumer_spec.rb +46 -0
- data/spec/spec_helper.rb +20 -0
- data/spec/yaml/defaults.yml +8 -0
- data/spec/yaml/full_blown.yml +12 -0
- metadata +280 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c5d851cce33eec10554348917d888de2850376f4
|
4
|
+
data.tar.gz: 8170b18990fa9ad11befe6a0da395acdf487cda8
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ea7d837226ee30baa49c0efec2b78242803de3190d173abc2b2c1ffc4cf9db4321549dff008e6b9b56fb8f6ee5f10328f2424b73a49d08937ea4c4fa49e0ba86
|
7
|
+
data.tar.gz: cc624af0b25c3717e0a8c4a247d3c18110308e2700c1c2fa538f634311e0d6a39e851db05d19eb2dd2a270fd7c3ffc696c00b75656c352a9d956590390383f36
|
data/.gitignore
ADDED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.1.1
|
data/.travis.yml
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
language: ruby
|
2
|
+
rvm:
|
3
|
+
- 1.9.3
|
4
|
+
- 2.0.0
|
5
|
+
- 2.1.1
|
6
|
+
notifications:
|
7
|
+
hipchat:
|
8
|
+
rooms:
|
9
|
+
secure: B+SptkYk6J9+PPJnqzA8S4hce6veT/bHciATE5MEA6fBd4gZQ2YMACgdaPqqzv1TU2Lr725uKFRpMQkE/E5B6oLGBcck7tAzZccKKSLiXyKMxgpyEcw+WC2laGhqqnfzd83iYjQujMy6kwksTknmgLV34HIuMUcyREYovEIxPgA=
|
data/Gemfile
ADDED
data/Guardfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Jef Mathiot
|
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,131 @@
|
|
1
|
+
# Roxanne
|
2
|
+
|
3
|
+
Roxanne allows you to aggregate the status of Continuous Integration jobs or other sources and to
|
4
|
+
publish the results on a BigVisibleThing™ (traffic light, lava lamp, whatever).
|
5
|
+
|
6
|
+
[](https://travis-ci.org/servebox/roxanne)
|
7
|
+
|
8
|
+
## Installation
|
9
|
+
|
10
|
+
Add this line to your application's Gemfile:
|
11
|
+
|
12
|
+
gem 'roxanne'
|
13
|
+
|
14
|
+
And then execute:
|
15
|
+
|
16
|
+
$ bundle
|
17
|
+
|
18
|
+
Or install it yourself as:
|
19
|
+
|
20
|
+
$ gem install roxanne
|
21
|
+
|
22
|
+
## Usage
|
23
|
+
|
24
|
+
### Configuration
|
25
|
+
|
26
|
+
Configuration is stored in a YAML file. By default, Roxanne will search for a `config/config.yml`
|
27
|
+
file.
|
28
|
+
|
29
|
+
#### Activation
|
30
|
+
|
31
|
+
Roxanne is configured by default to only be active between 9am and 20pm during working days. You
|
32
|
+
may use the `activation` section to change the default behavior:
|
33
|
+
|
34
|
+
```yaml
|
35
|
+
roxanne:
|
36
|
+
activation:
|
37
|
+
# Active from monday to wednesday
|
38
|
+
days: !ruby/range 1..3
|
39
|
+
# 07:00 to 14:59
|
40
|
+
timerange: !ruby/range 7...15
|
41
|
+
```
|
42
|
+
|
43
|
+
#### Consumers
|
44
|
+
|
45
|
+
Use the `consumers` section to specify consumers configuration:
|
46
|
+
|
47
|
+
```yaml
|
48
|
+
roxanne:
|
49
|
+
consumers:
|
50
|
+
jenkins:
|
51
|
+
class: "Roxanne::Jenkins::Consumer"
|
52
|
+
host: "192.168.20.30"
|
53
|
+
port: 8080
|
54
|
+
use_ssl: false
|
55
|
+
path: "/api/json"
|
56
|
+
```
|
57
|
+
|
58
|
+
#### Publisher
|
59
|
+
|
60
|
+
Use the `publisher` section to specify consumers configuration:
|
61
|
+
|
62
|
+
```yaml
|
63
|
+
roxanne:
|
64
|
+
publisher:
|
65
|
+
class: "Roxanne::GPIO::Publisher"
|
66
|
+
green_pin: 25
|
67
|
+
orange_pin: 17
|
68
|
+
red_pin: 27
|
69
|
+
```
|
70
|
+
|
71
|
+
### Start the daemon
|
72
|
+
|
73
|
+
Start the daemon using the `start` command:
|
74
|
+
|
75
|
+
```
|
76
|
+
bundle exec roxanne start
|
77
|
+
```
|
78
|
+
|
79
|
+
If you want to specify a configuration file pass its path as the first argument:
|
80
|
+
|
81
|
+
```
|
82
|
+
bundle exec roxanne start /etc/roxanne/config.yml
|
83
|
+
```
|
84
|
+
|
85
|
+
Other available commands are obviously `stop`, `status` and `restart`.
|
86
|
+
|
87
|
+
### Available Consumers
|
88
|
+
|
89
|
+
#### Jenkins
|
90
|
+
|
91
|
+
Use the `Roxanne::Jenkins::Consumer` class. Available options:
|
92
|
+
|
93
|
+
* **host**: the Jenkins host name or IP address
|
94
|
+
* **port**: the TCP port the Jenkins service can be reached on
|
95
|
+
* **path**: the relative path to the JSON API (`/jenkins/api/json`)
|
96
|
+
* **username**: the username to use for HTTP Basic Auth
|
97
|
+
* **password**: the password to use for HTTP Basic Auth
|
98
|
+
* **disable_certificate_verification** : set to true if you use a self-signed SSL certificate
|
99
|
+
|
100
|
+
#### Travis CI
|
101
|
+
|
102
|
+
Use the `Roxanne::Travis::Consumer` class. Available options:
|
103
|
+
|
104
|
+
* **organization_or_user**: the Github organization or user to pull build states from
|
105
|
+
|
106
|
+
### Available Publishers
|
107
|
+
|
108
|
+
#### GPIO
|
109
|
+
|
110
|
+
Use the `Roxanne::GPIO::Consumer` class. Available options:
|
111
|
+
|
112
|
+
* **green_pin**: the GPIO pin to turn on when status changes to green
|
113
|
+
* **orange_pin**: the GPIO pin to turn on when status changes to orange
|
114
|
+
* **red_pin**: the GPIO pin to turn on when status changes to red
|
115
|
+
|
116
|
+
## Statuses
|
117
|
+
|
118
|
+
Every 5 seconds, Roxanne will loop to check the status of the consumers:
|
119
|
+
|
120
|
+
* if any of the consumers returns `red` the publisher receive `red`
|
121
|
+
* if all of the consumers return `green` the publisher receive `green`
|
122
|
+
* if the previous state **was not** `green` and one of the consumer returns `orange` the publisher
|
123
|
+
receive `orange`
|
124
|
+
|
125
|
+
## Contributing
|
126
|
+
|
127
|
+
1. Fork it
|
128
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
129
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
130
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
131
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/bin/roxanne
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'roxanne'
|
4
|
+
require 'fileutils'
|
5
|
+
|
6
|
+
basedir = File.expand_path(File.join( File.dirname(__FILE__) , '..'))
|
7
|
+
%w(log pids).each do |dir|
|
8
|
+
dir = File.join(basedir, dir)
|
9
|
+
FileUtils.mkdir_p dir unless File.directory?(dir)
|
10
|
+
end
|
11
|
+
Roxanne::Server.spawn!(
|
12
|
+
log_file: File.join(basedir, 'log/roxanne.log'),
|
13
|
+
pid_file: File.join(basedir, 'pids/roxanne.pid'),
|
14
|
+
sync_log: true,
|
15
|
+
working_dir: basedir
|
16
|
+
)
|
data/config/config.yml
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'active_support/core_ext'
|
3
|
+
|
4
|
+
module Roxanne
|
5
|
+
|
6
|
+
module Configuration
|
7
|
+
|
8
|
+
class YAML < Base
|
9
|
+
|
10
|
+
def initialize(path)
|
11
|
+
super
|
12
|
+
yaml = ::YAML.load( File.open( path ) ).with_indifferent_access[:roxanne]
|
13
|
+
override_activation(yaml[:activation])
|
14
|
+
build_consumers(yaml[:consumers])
|
15
|
+
build_publisher(yaml[:publisher])
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
def override_activation(settings)
|
20
|
+
if settings
|
21
|
+
@active_days = settings[:days] if settings.has_key?(:days)
|
22
|
+
@timerange = settings[:timerange] if settings.has_key?(:timerange)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def build_consumers(hash)
|
27
|
+
(hash||{}).each do |id, hash|
|
28
|
+
@consumers << assign_properties( hash.delete(:class).constantize.new, hash )
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def build_publisher(hash)
|
33
|
+
@publisher = assign_properties( hash.delete(:class).constantize.new, hash)
|
34
|
+
end
|
35
|
+
|
36
|
+
def assign_properties(object, hash)
|
37
|
+
hash.each do |prop, value|
|
38
|
+
object.send "#{prop}=", value
|
39
|
+
end
|
40
|
+
object
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Roxanne
|
2
|
+
module Configuration
|
3
|
+
class Base
|
4
|
+
|
5
|
+
attr_reader :consumers, :publisher, :active_days, :timerange
|
6
|
+
|
7
|
+
def initialize(*args)
|
8
|
+
@consumers = []
|
9
|
+
@publisher = nil
|
10
|
+
@active_days = 1..5
|
11
|
+
@timerange=8..19
|
12
|
+
end
|
13
|
+
|
14
|
+
def activated
|
15
|
+
will_activate(DateTime.now)
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
def will_activate( dt )
|
20
|
+
@active_days.include?(dt.wday) && @timerange.cover?(dt.hour)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require 'roxanne/configuration/yaml'
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Roxanne
|
2
|
+
module Consumers
|
3
|
+
module Priority
|
4
|
+
|
5
|
+
def prioritize(current_status, former_status)
|
6
|
+
[:red, :orange].each do |status|
|
7
|
+
return status if status == former_status
|
8
|
+
end
|
9
|
+
current_status
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
require 'roxanne/jenkins/consumer'
|
17
|
+
require 'roxanne/test/consumer'
|
18
|
+
require 'roxanne/travis/consumer'
|
19
|
+
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'taopaipai'
|
2
|
+
|
3
|
+
module Roxanne
|
4
|
+
module GPIO
|
5
|
+
class Publisher
|
6
|
+
attr_accessor :green_pin, :orange_pin, :red_pin
|
7
|
+
|
8
|
+
def disable
|
9
|
+
[green_pin, orange_pin, red_pin].each do |num|
|
10
|
+
Taopaipai.gpio.pin(num, direction: :out).value 0
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def push(previous, status)
|
15
|
+
return disable unless status
|
16
|
+
[:green, :orange, :red].each do |color|
|
17
|
+
Taopaipai.gpio.pin(send("#{color}_pin"), direction: :out).
|
18
|
+
value(color == status ? 1 : 0)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'roxanne/http_support'
|
2
|
+
|
3
|
+
module Roxanne
|
4
|
+
module HTTP
|
5
|
+
class Consumer
|
6
|
+
include Consumers::Priority
|
7
|
+
include Roxanne::HTTPSupport
|
8
|
+
|
9
|
+
def pull
|
10
|
+
response = fetch_response
|
11
|
+
case response
|
12
|
+
when Net::HTTPSuccess
|
13
|
+
handle_response(response.body)
|
14
|
+
when Net::HTTPRedirection
|
15
|
+
puts "The request has been redirected to #{response['location']}"
|
16
|
+
:red
|
17
|
+
else
|
18
|
+
puts "The request has failed #{response.error}"
|
19
|
+
:red
|
20
|
+
end
|
21
|
+
rescue Exception => e
|
22
|
+
puts "Unable to fetch data : #{e.message}"
|
23
|
+
:red
|
24
|
+
end
|
25
|
+
|
26
|
+
def handle_response(body)
|
27
|
+
puts "Does nothing, HTTP consumer should be overriden."
|
28
|
+
:green
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
|
3
|
+
module Roxanne
|
4
|
+
module HTTPSupport
|
5
|
+
attr_accessor :host
|
6
|
+
attr_accessor :use_ssl
|
7
|
+
attr_accessor :disable_certificate_verification
|
8
|
+
attr_accessor :path
|
9
|
+
attr_accessor :port
|
10
|
+
attr_accessor :username
|
11
|
+
attr_accessor :password
|
12
|
+
|
13
|
+
private
|
14
|
+
def fetch_response
|
15
|
+
connection = ::Net::HTTP.new(@host, @port)
|
16
|
+
connection.use_ssl=@use_ssl
|
17
|
+
if @disable_certificate_verification
|
18
|
+
# TODO retrieve the certificate from the remote system, see http://redcorundum.blogspot.com/2008/03/ssl-certificates-and-nethttps.html
|
19
|
+
# Avoid issues with autosigned certificates
|
20
|
+
connection.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
21
|
+
end
|
22
|
+
request = Net::HTTP::Get.new(complete_path, {'Accept'=>accept})
|
23
|
+
|
24
|
+
# TODO Authentication
|
25
|
+
unless (username.nil? && password.nil?)
|
26
|
+
request.basic_auth username, password
|
27
|
+
else
|
28
|
+
end
|
29
|
+
connection.request(request)
|
30
|
+
end
|
31
|
+
|
32
|
+
def complete_path
|
33
|
+
@path
|
34
|
+
end
|
35
|
+
|
36
|
+
# Override if needed to force a particular format : application/json, text/xml, etc
|
37
|
+
protected
|
38
|
+
def accept
|
39
|
+
'*'
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'roxanne/http/consumer'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module Roxanne
|
5
|
+
module Jenkins
|
6
|
+
class Consumer < Roxanne::HTTP::Consumer
|
7
|
+
|
8
|
+
def handle_response(body)
|
9
|
+
json = JSON.parse(body)
|
10
|
+
status = :green
|
11
|
+
json['jobs'].each do |job|
|
12
|
+
if COLORS.keys.include?(job['color'])
|
13
|
+
status = prioritize(to_status(job['color']), status)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
status
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
COLORS = {
|
21
|
+
'blue'=>:green,
|
22
|
+
'yellow'=>:green,
|
23
|
+
'red'=>:red,
|
24
|
+
'blue_anime'=>:orange,
|
25
|
+
'yellow_anime'=>:orange,
|
26
|
+
'red_anime'=>:orange
|
27
|
+
}
|
28
|
+
|
29
|
+
def to_status(hudson_color)
|
30
|
+
COLORS[hudson_color]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/roxanne/loop.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
module Roxanne
|
2
|
+
class Loop
|
3
|
+
def initialize(config)
|
4
|
+
@config = config
|
5
|
+
end
|
6
|
+
|
7
|
+
def cycle
|
8
|
+
if @config.activated
|
9
|
+
status = :green
|
10
|
+
@config.consumers.each do |consumer|
|
11
|
+
actual = consumer.pull
|
12
|
+
if actual == :red
|
13
|
+
status = :red
|
14
|
+
break
|
15
|
+
elsif actual == :orange && @previous != :green
|
16
|
+
status = :orange
|
17
|
+
end
|
18
|
+
end
|
19
|
+
publish( @previous, status )
|
20
|
+
@previous = status
|
21
|
+
else
|
22
|
+
@config.publisher.disable
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def reset
|
27
|
+
@config.publisher.push(nil, nil)
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
def publish(previous, current)
|
32
|
+
@config.publisher.push(previous, current)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'daemon_spawn'
|
2
|
+
|
3
|
+
module Roxanne
|
4
|
+
class Server < DaemonSpawn::Base
|
5
|
+
|
6
|
+
def start(args)
|
7
|
+
puts "Roxanne starting in #{self.working_dir}"
|
8
|
+
@controller = Loop.new(config(args))
|
9
|
+
loop do
|
10
|
+
@controller.cycle
|
11
|
+
sleep 5
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def stop
|
16
|
+
@controller.reset
|
17
|
+
end
|
18
|
+
|
19
|
+
def config(args)
|
20
|
+
@config ||= Configuration::YAML.new(args.first || 'config/config.yml')
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Roxanne
|
2
|
+
module Test
|
3
|
+
class Publisher
|
4
|
+
def disable
|
5
|
+
puts "Publisher is now disabled"
|
6
|
+
end
|
7
|
+
|
8
|
+
def push(previous, status)
|
9
|
+
puts "Publisher switching from status #{default(previous)} to #{default(status)}"
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
def default(status)
|
14
|
+
status.nil? ? 'none' : status
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'travis'
|
2
|
+
|
3
|
+
module Roxanne
|
4
|
+
module Travis
|
5
|
+
class Consumer
|
6
|
+
include Consumers::Priority
|
7
|
+
|
8
|
+
attr_accessor :organization_or_user
|
9
|
+
|
10
|
+
def pull
|
11
|
+
repos = ::Travis::Repository.find_all(owner_name: organization_or_user)
|
12
|
+
status = :green
|
13
|
+
repos.select{|repo| repo.active? }.each do |repo|
|
14
|
+
status = prioritize(to_status(repo.last_build_state), status)
|
15
|
+
end
|
16
|
+
status
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
STATES = {
|
21
|
+
'failed' => :red,
|
22
|
+
'started' => :orange,
|
23
|
+
'passed' => :green
|
24
|
+
}
|
25
|
+
|
26
|
+
def to_status(travis_build_state)
|
27
|
+
STATES[travis_build_state]
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/roxanne.rb
ADDED
data/roxanne.gemspec
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'roxanne/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "roxanne"
|
8
|
+
spec.version = Roxanne::VERSION
|
9
|
+
spec.authors = ["Jef Mathiot", "Patrice Izzo", "Fabrice Nourisson",
|
10
|
+
"Benjamin Severac", "Eric Hartmann"]
|
11
|
+
spec.email = ["foss@servebox.com"]
|
12
|
+
spec.description = %q{Roxanne: publish your CI status to your device of choice}
|
13
|
+
spec.summary = %q{Aggregate the status of Continuous Integration jobs or other sources and
|
14
|
+
publish them}
|
15
|
+
spec.homepage = "http://github.com/servebox/roxanne"
|
16
|
+
spec.license = "MIT"
|
17
|
+
|
18
|
+
spec.files = `git ls-files`.split($/)
|
19
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
20
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
21
|
+
spec.require_paths = ["lib"]
|
22
|
+
|
23
|
+
spec.add_dependency 'json'
|
24
|
+
spec.add_dependency 'daemon-spawn'
|
25
|
+
spec.add_dependency 'activesupport', '>= 3.0.0'
|
26
|
+
spec.add_dependency 'taopaipai', '~> 0.1.1'
|
27
|
+
spec.add_dependency 'travis', '~> 1.6.8'
|
28
|
+
|
29
|
+
spec.add_development_dependency "bundler", "~> 1.6"
|
30
|
+
spec.add_development_dependency "rake"
|
31
|
+
spec.add_development_dependency "minitest", "~> 5.0.7"
|
32
|
+
spec.add_development_dependency "minitest-implicit-subject", "~> 1.4.0"
|
33
|
+
spec.add_development_dependency "rb-readline", "~> 0.5.0"
|
34
|
+
spec.add_development_dependency "guard-minitest", "~> 2.1.3"
|
35
|
+
spec.add_development_dependency "timecop"
|
36
|
+
spec.add_development_dependency "mocha"
|
37
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
#! /bin/sh
|
2
|
+
|
3
|
+
case "$1" in
|
4
|
+
start)
|
5
|
+
su roxanne -c "bash /var/lib/roxanne/roxanne/service/roxanne.sh start" ; exit
|
6
|
+
;;
|
7
|
+
stop)
|
8
|
+
su roxanne -c "bash /var/lib/roxanne/roxanne/service/roxanne.sh stop" ; exit
|
9
|
+
;;
|
10
|
+
status)
|
11
|
+
;;
|
12
|
+
restart|force-reload)
|
13
|
+
su roxanne -c "bash /var/lib/roxanne/roxanne/service/roxanne.sh restart" ; exit
|
14
|
+
;;
|
15
|
+
*)
|
16
|
+
#echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
|
17
|
+
echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2
|
18
|
+
exit 3
|
19
|
+
;;
|
20
|
+
esac
|
21
|
+
|