ampel_extase 0.1.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.utilsrc +21 -0
- data/Rakefile +5 -4
- data/VERSION +1 -1
- data/ampel_extase.gemspec +13 -10
- data/bin/ampel_control +8 -7
- data/lib/ampel_extase/controller.rb +60 -38
- data/lib/ampel_extase/jenkins_client.rb +5 -19
- data/lib/ampel_extase/jenkins_state_observer.rb +48 -0
- data/lib/ampel_extase/light_switcher.rb +11 -4
- data/lib/ampel_extase/version.rb +1 -1
- data/spec/ampel_extase/build_state_spec.rb +80 -0
- data/spec/ampel_extase/controller_spec.rb +226 -0
- data/spec/ampel_extase/jekins_state_observer_spec.rb +115 -0
- data/spec/ampel_extase/jenkins_client_spec.rb +43 -1
- data/spec/ampel_extase/light_switcher_spec.rb +36 -1
- metadata +28 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 185c3c458af6b31e6b267f17af22fbceefef5447
|
4
|
+
data.tar.gz: 279c80d9fa98fb8878d9a0299789903fd607f810
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8ac46db41479a33a543bf87735d633a9efa49952cceaf6a8bcf9b5c6b0fd33b32485b4be2615ea422d56406d5f0fc5884882ceec8daa4c3350d5beb6c9c5331c
|
7
|
+
data.tar.gz: efe0863f59b6af56b2e4d4eb792fa4d34af22cf1328af1dc77bd543f1781de8f5723e96bd3fc30474dab704990dd9a4e00adb5f6a1f2ce2a17815931d7fa1897
|
data/.gitignore
CHANGED
data/.utilsrc
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# vim: set ft=ruby:
|
2
|
+
|
3
|
+
search do
|
4
|
+
prune_dirs /\A(\.svn|\.git|CVS|tmp|tags|coverage)\z/
|
5
|
+
skip_files /(\A\.|\.sw[pon]\z|\.(log|fnm|jpg|jpeg|png|pdf|svg)\z|tags|brakeman.ignore|errors\.lst|~\z)/i
|
6
|
+
end
|
7
|
+
|
8
|
+
discover do
|
9
|
+
prune_dirs /\A(\.svn|\.git|CVS|tmp|tags|coverage)\z/
|
10
|
+
skip_files /(\A\.|\.sw[pon]\z|\.log\z|~\z)/
|
11
|
+
binary false
|
12
|
+
end
|
13
|
+
|
14
|
+
strip_spaces do
|
15
|
+
prune_dirs /\A(\..*|CVS)\z/
|
16
|
+
skip_files /(\A\.|\.sw[pon]\z|\.log\z|~\z)/
|
17
|
+
end
|
18
|
+
|
19
|
+
probe do
|
20
|
+
test_framework :'rspec'
|
21
|
+
end
|
data/Rakefile
CHANGED
@@ -12,15 +12,16 @@ GemHadar do
|
|
12
12
|
licenses << 'GPL-2'
|
13
13
|
test_dir 'spec'
|
14
14
|
ignore '.*.sw[pon]', 'pkg', 'Gemfile.lock', '.rvmrc', 'coverage',
|
15
|
-
'tags', '.bundle', '.DS_Store', '.build'
|
15
|
+
'tags', '.bundle', '.DS_Store', '.build', 'errors.lst'
|
16
16
|
|
17
17
|
readme 'README.md'
|
18
18
|
executables.merge Dir['bin/*'].map { |x| File.basename(x) }
|
19
19
|
|
20
|
-
dependency 'tins',
|
20
|
+
dependency 'tins', '~>1.0'
|
21
|
+
dependency 'term-ansicolor', '~>1.0'
|
21
22
|
dependency 'socket_switcher'
|
22
|
-
development_dependency 'simplecov',
|
23
|
-
development_dependency 'rspec',
|
23
|
+
development_dependency 'simplecov', '~>0.9'
|
24
|
+
development_dependency 'rspec', '~>3.0'
|
24
25
|
development_dependency 'byebug'
|
25
26
|
|
26
27
|
default_task_dependencies :spec
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.3.0
|
data/ampel_extase.gemspec
CHANGED
@@ -1,50 +1,53 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
# stub: ampel_extase 0.
|
2
|
+
# stub: ampel_extase 0.3.0 ruby lib
|
3
3
|
|
4
4
|
Gem::Specification.new do |s|
|
5
5
|
s.name = "ampel_extase"
|
6
|
-
s.version = "0.
|
6
|
+
s.version = "0.3.0"
|
7
7
|
|
8
8
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
9
9
|
s.require_paths = ["lib"]
|
10
10
|
s.authors = ["Florian Frank"]
|
11
|
-
s.date = "2015-
|
11
|
+
s.date = "2015-08-25"
|
12
12
|
s.description = "Library to control the build traffic light. Yes, we can\u{2026}"
|
13
13
|
s.email = "flori@ping.de"
|
14
14
|
s.executables = ["ampel_control"]
|
15
|
-
s.extra_rdoc_files = ["README.md", "lib/ampel_extase.rb", "lib/ampel_extase/build_state.rb", "lib/ampel_extase/controller.rb", "lib/ampel_extase/jenkins_client.rb", "lib/ampel_extase/light_switcher.rb", "lib/ampel_extase/version.rb"]
|
16
|
-
s.files = [".gitignore", "Gemfile", "README.md", "Rakefile", "VERSION", "ampel_extase.gemspec", "bin/ampel_control", "lib/ampel_extase.rb", "lib/ampel_extase/build_state.rb", "lib/ampel_extase/controller.rb", "lib/ampel_extase/jenkins_client.rb", "lib/ampel_extase/light_switcher.rb", "lib/ampel_extase/version.rb", "spec/ampel_extase/jenkins_client_spec.rb", "spec/ampel_extase/light_switcher_spec.rb", "spec/spec_helper.rb"]
|
15
|
+
s.extra_rdoc_files = ["README.md", "lib/ampel_extase.rb", "lib/ampel_extase/build_state.rb", "lib/ampel_extase/controller.rb", "lib/ampel_extase/jenkins_client.rb", "lib/ampel_extase/jenkins_state_observer.rb", "lib/ampel_extase/light_switcher.rb", "lib/ampel_extase/version.rb"]
|
16
|
+
s.files = [".gitignore", ".utilsrc", "Gemfile", "README.md", "Rakefile", "VERSION", "ampel_extase.gemspec", "bin/ampel_control", "lib/ampel_extase.rb", "lib/ampel_extase/build_state.rb", "lib/ampel_extase/controller.rb", "lib/ampel_extase/jenkins_client.rb", "lib/ampel_extase/jenkins_state_observer.rb", "lib/ampel_extase/light_switcher.rb", "lib/ampel_extase/version.rb", "spec/ampel_extase/build_state_spec.rb", "spec/ampel_extase/controller_spec.rb", "spec/ampel_extase/jekins_state_observer_spec.rb", "spec/ampel_extase/jenkins_client_spec.rb", "spec/ampel_extase/light_switcher_spec.rb", "spec/spec_helper.rb"]
|
17
17
|
s.homepage = "http://github.com/flori/ampel_extase"
|
18
18
|
s.licenses = ["GPL-2"]
|
19
19
|
s.rdoc_options = ["--title", "AmpelExtase - Library to control the build traffic light", "--main", "README.md"]
|
20
|
-
s.rubygems_version = "2.
|
20
|
+
s.rubygems_version = "2.4.5.1"
|
21
21
|
s.summary = "Library to control the build traffic light"
|
22
|
-
s.test_files = ["spec/ampel_extase/jenkins_client_spec.rb", "spec/ampel_extase/light_switcher_spec.rb", "spec/spec_helper.rb"]
|
22
|
+
s.test_files = ["spec/ampel_extase/build_state_spec.rb", "spec/ampel_extase/controller_spec.rb", "spec/ampel_extase/jekins_state_observer_spec.rb", "spec/ampel_extase/jenkins_client_spec.rb", "spec/ampel_extase/light_switcher_spec.rb", "spec/spec_helper.rb"]
|
23
23
|
|
24
24
|
if s.respond_to? :specification_version then
|
25
25
|
s.specification_version = 4
|
26
26
|
|
27
27
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
28
|
-
s.add_development_dependency(%q<gem_hadar>, ["~> 1.
|
28
|
+
s.add_development_dependency(%q<gem_hadar>, ["~> 1.3.1"])
|
29
29
|
s.add_development_dependency(%q<simplecov>, ["~> 0.9"])
|
30
30
|
s.add_development_dependency(%q<rspec>, ["~> 3.0"])
|
31
31
|
s.add_development_dependency(%q<byebug>, [">= 0"])
|
32
32
|
s.add_runtime_dependency(%q<tins>, ["~> 1.0"])
|
33
|
+
s.add_runtime_dependency(%q<term-ansicolor>, ["~> 1.0"])
|
33
34
|
s.add_runtime_dependency(%q<socket_switcher>, [">= 0"])
|
34
35
|
else
|
35
|
-
s.add_dependency(%q<gem_hadar>, ["~> 1.
|
36
|
+
s.add_dependency(%q<gem_hadar>, ["~> 1.3.1"])
|
36
37
|
s.add_dependency(%q<simplecov>, ["~> 0.9"])
|
37
38
|
s.add_dependency(%q<rspec>, ["~> 3.0"])
|
38
39
|
s.add_dependency(%q<byebug>, [">= 0"])
|
39
40
|
s.add_dependency(%q<tins>, ["~> 1.0"])
|
41
|
+
s.add_dependency(%q<term-ansicolor>, ["~> 1.0"])
|
40
42
|
s.add_dependency(%q<socket_switcher>, [">= 0"])
|
41
43
|
end
|
42
44
|
else
|
43
|
-
s.add_dependency(%q<gem_hadar>, ["~> 1.
|
45
|
+
s.add_dependency(%q<gem_hadar>, ["~> 1.3.1"])
|
44
46
|
s.add_dependency(%q<simplecov>, ["~> 0.9"])
|
45
47
|
s.add_dependency(%q<rspec>, ["~> 3.0"])
|
46
48
|
s.add_dependency(%q<byebug>, [">= 0"])
|
47
49
|
s.add_dependency(%q<tins>, ["~> 1.0"])
|
50
|
+
s.add_dependency(%q<term-ansicolor>, ["~> 1.0"])
|
48
51
|
s.add_dependency(%q<socket_switcher>, [">= 0"])
|
49
52
|
end
|
50
53
|
end
|
data/bin/ampel_control
CHANGED
@@ -2,15 +2,16 @@
|
|
2
2
|
|
3
3
|
require 'ampel_extase'
|
4
4
|
|
5
|
-
serial = ENV['SERIAL'] or
|
5
|
+
serial = ENV['SERIAL'].full? or
|
6
6
|
fail 'need env var SERIAL for path to serial port'
|
7
|
-
jenkins_url = ENV['JENKINS_URL'] or
|
7
|
+
jenkins_url = ENV['JENKINS_URL'].full? or
|
8
8
|
fail 'need env var JENKINS_URL of the form http://test2.local:8080/job/foo'
|
9
|
+
warning_jenkins_url = ENV['WARNING_JENKINS_URL'].full?
|
9
10
|
sleep_duration = (ENV['SLEEP'] || 10).to_i
|
10
11
|
|
11
|
-
AmpelExtase::Controller.
|
12
|
-
serial,
|
13
|
-
jenkins_url,
|
14
|
-
|
15
|
-
sleep: sleep_duration
|
12
|
+
AmpelExtase::Controller.for(
|
13
|
+
serial: serial,
|
14
|
+
jenkins_url: jenkins_url,
|
15
|
+
warning_jenkins_url: warning_jenkins_url,
|
16
|
+
sleep: sleep_duration
|
16
17
|
).start
|
@@ -1,17 +1,33 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
require '
|
3
|
+
require 'term/ansicolor'
|
4
4
|
require 'ampel_extase/light_switcher'
|
5
|
-
require 'ampel_extase/
|
5
|
+
require 'ampel_extase/jenkins_state_observer'
|
6
6
|
|
7
7
|
class AmpelExtase::Controller
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
8
|
+
include Term::ANSIColor
|
9
|
+
|
10
|
+
def self.for(
|
11
|
+
serial:,
|
12
|
+
jenkins_url:,
|
13
|
+
warning_jenkins_url: nil,
|
14
|
+
sleep: 10
|
15
|
+
)
|
16
|
+
ampel_jenkins = AmpelExtase::JenkinsStateObserver.for_url(jenkins_url)
|
17
|
+
warning_jenkins = AmpelExtase::JenkinsStateObserver.for_url(warning_jenkins_url)
|
18
|
+
lights = AmpelExtase::LightSwitcher.for(serial: serial)
|
19
|
+
new(ampel_jenkins, warning_jenkins, lights, sleep: sleep)
|
20
|
+
end
|
21
|
+
|
22
|
+
def initialize(
|
23
|
+
ampel_jenkins,
|
24
|
+
warning_jenkins,
|
25
|
+
lights,
|
26
|
+
sleep: 10
|
27
|
+
)
|
28
|
+
@ampel_jenkins, @warning_jenkins, @lights, @sleep =
|
29
|
+
ampel_jenkins, warning_jenkins, lights, sleep
|
12
30
|
check_lights
|
13
|
-
@sleep = sleep
|
14
|
-
@build_state = AmpelExtase::BuildState.for
|
15
31
|
end
|
16
32
|
|
17
33
|
def start
|
@@ -41,50 +57,65 @@ class AmpelExtase::Controller
|
|
41
57
|
|
42
58
|
def perform
|
43
59
|
@crashed = false
|
44
|
-
on_state_change do |state|
|
45
|
-
|
60
|
+
@ampel_jenkins.on_state_change do |state|
|
61
|
+
perform_lights_switch state
|
62
|
+
end
|
63
|
+
@warning_jenkins.on_state_change do |state|
|
64
|
+
perform_warning state
|
46
65
|
end
|
47
66
|
end
|
48
67
|
|
49
|
-
def
|
68
|
+
def perform_lights_switch(state)
|
50
69
|
case state.last_result
|
51
70
|
when 'SUCCESS'
|
52
71
|
@lights.green.on
|
53
72
|
@lights.red.off
|
73
|
+
puts success('LIGHTS SUCCESS')
|
54
74
|
when 'FAILURE', 'ABORTED'
|
55
75
|
@lights.red.on
|
56
76
|
if state.building?
|
57
77
|
@lights.green.on
|
78
|
+
puts failure_building('LIGHTS FAILURE BUILDING')
|
58
79
|
else
|
59
80
|
@lights.green.off
|
81
|
+
puts failure('LIGHTS FAILURE')
|
60
82
|
end
|
61
83
|
end
|
62
84
|
end
|
63
85
|
|
64
|
-
def
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
86
|
+
def perform_warning(state)
|
87
|
+
case state.last_result
|
88
|
+
when 'SUCCESS'
|
89
|
+
@lights.aux.off
|
90
|
+
puts success('WARNING SUCCESS')
|
91
|
+
when 'FAILURE', 'ABORTED'
|
92
|
+
if state.building?
|
93
|
+
puts failure_building('WARNING FAILURE BUILDING')
|
94
|
+
else
|
95
|
+
@lights.aux.on
|
96
|
+
puts failure('WARNING FAILURE')
|
97
|
+
end
|
71
98
|
end
|
72
|
-
ensure
|
73
|
-
@build_state = new_state
|
74
99
|
end
|
75
100
|
|
76
|
-
def
|
77
|
-
|
101
|
+
def success(message)
|
102
|
+
green message
|
78
103
|
end
|
79
104
|
|
80
|
-
def
|
81
|
-
|
105
|
+
def failure(message)
|
106
|
+
red message
|
107
|
+
end
|
108
|
+
|
109
|
+
def failure_building(message)
|
110
|
+
green on_red message
|
82
111
|
end
|
83
112
|
|
84
113
|
def switch_all_lights_off
|
85
|
-
|
86
|
-
|
87
|
-
|
114
|
+
@lights.each(&:off)
|
115
|
+
end
|
116
|
+
|
117
|
+
def switch_all_lights_on
|
118
|
+
@lights.each(&:on)
|
88
119
|
end
|
89
120
|
|
90
121
|
def handle_crash(exception)
|
@@ -98,19 +129,10 @@ class AmpelExtase::Controller
|
|
98
129
|
|
99
130
|
def check_lights
|
100
131
|
puts "checking lights configuration"
|
101
|
-
|
102
|
-
light.on
|
103
|
-
end
|
132
|
+
switch_all_lights_on
|
104
133
|
sleep 1
|
105
|
-
|
106
|
-
light.off
|
107
|
-
end
|
134
|
+
switch_all_lights_off
|
108
135
|
sleep 1
|
109
136
|
puts "OK"
|
110
137
|
end
|
111
|
-
|
112
|
-
def check_jenkins
|
113
|
-
puts "checking jenkins configuration"
|
114
|
-
@jenkins.fetch and puts "OK"
|
115
|
-
end
|
116
138
|
end
|
@@ -5,21 +5,19 @@ require 'uri'
|
|
5
5
|
|
6
6
|
module AmpelExtase
|
7
7
|
class JenkinsClient
|
8
|
-
def initialize(url
|
8
|
+
def initialize(url)
|
9
9
|
url = URI.parse(url.to_s) unless URI::HTTP === url
|
10
|
-
@url
|
10
|
+
@url = url
|
11
11
|
end
|
12
12
|
|
13
|
+
attr_reader :url
|
14
|
+
|
13
15
|
def api_url(*path)
|
14
16
|
[ @url, *path, 'api', 'json' ].compact * '/'
|
15
17
|
end
|
16
18
|
|
17
|
-
def console_url(number)
|
18
|
-
[ @url, number, 'consoleText' ] * '/'
|
19
|
-
end
|
20
|
-
|
21
19
|
def fetch(url = api_url)
|
22
|
-
|
20
|
+
puts "Fetching #{url.to_s.inspect}."
|
23
21
|
JSON open(url).read
|
24
22
|
rescue => e
|
25
23
|
e.message << " for #{url.inspect}"
|
@@ -36,17 +34,5 @@ module AmpelExtase
|
|
36
34
|
end
|
37
35
|
fetch url
|
38
36
|
end
|
39
|
-
|
40
|
-
def fetch_build_revision(type)
|
41
|
-
data = fetch_build(type)
|
42
|
-
data['actions'].find { |x| x.keys.include?('lastBuiltRevision') }['lastBuiltRevision']['SHA1']
|
43
|
-
rescue
|
44
|
-
nil
|
45
|
-
end
|
46
|
-
|
47
|
-
def fetch_console_text(type)
|
48
|
-
build = fetch_build(type)
|
49
|
-
open(console_url(build['number'])).read
|
50
|
-
end
|
51
37
|
end
|
52
38
|
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'ampel_extase/build_state'
|
2
|
+
require 'ampel_extase/jenkins_client'
|
3
|
+
|
4
|
+
class AmpelExtase::JenkinsStateObserver
|
5
|
+
def self.for_url(jenkins_url)
|
6
|
+
if jenkins_url
|
7
|
+
jenkins = AmpelExtase::JenkinsClient.new(jenkins_url)
|
8
|
+
new(jenkins)
|
9
|
+
else
|
10
|
+
Tins::NULL
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(jenkins)
|
15
|
+
@jenkins = jenkins
|
16
|
+
@build_state = AmpelExtase::BuildState.for
|
17
|
+
check
|
18
|
+
end
|
19
|
+
|
20
|
+
def check
|
21
|
+
puts "checking jenkins configuration for #{@jenkins.url.to_s.inspect}"
|
22
|
+
@jenkins.fetch and puts "OK"
|
23
|
+
end
|
24
|
+
|
25
|
+
def last_result
|
26
|
+
@jenkins.fetch_build(:last_completed_build)['result']
|
27
|
+
end
|
28
|
+
|
29
|
+
def building?
|
30
|
+
@jenkins.fetch_build(:last_build)['building']
|
31
|
+
end
|
32
|
+
|
33
|
+
def state_changed?(new_state)
|
34
|
+
new_state != @build_state
|
35
|
+
end
|
36
|
+
|
37
|
+
def on_state_change
|
38
|
+
new_state = AmpelExtase::BuildState.for [ last_result, building? ]
|
39
|
+
if state_changed?(new_state)
|
40
|
+
puts "state changed from #@build_state to #{new_state} => taking action"
|
41
|
+
yield new_state
|
42
|
+
else
|
43
|
+
puts "state did not change, is still #@build_state => do nothing"
|
44
|
+
end
|
45
|
+
ensure
|
46
|
+
@build_state = new_state
|
47
|
+
end
|
48
|
+
end
|
@@ -2,8 +2,16 @@ require 'socket_switcher'
|
|
2
2
|
|
3
3
|
module AmpelExtase
|
4
4
|
class LightSwitcher
|
5
|
-
def
|
6
|
-
|
5
|
+
def self.for(serial:)
|
6
|
+
if serial
|
7
|
+
new SocketSwitcher::Port.new(serial)
|
8
|
+
else
|
9
|
+
Tins::NULL
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(port)
|
14
|
+
@port = port
|
7
15
|
end
|
8
16
|
|
9
17
|
attr_reader :port
|
@@ -24,9 +32,8 @@ module AmpelExtase
|
|
24
32
|
[
|
25
33
|
:green,
|
26
34
|
:red,
|
27
|
-
|
35
|
+
:aux,
|
28
36
|
].map { |color| __send__(color) }.each(&block)
|
29
37
|
end
|
30
38
|
end
|
31
39
|
end
|
32
|
-
|
data/lib/ampel_extase/version.rb
CHANGED
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe AmpelExtase::BuildState do
|
4
|
+
describe 'initial state' do
|
5
|
+
let :bs do
|
6
|
+
described_class.for
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'has a to_a' do
|
10
|
+
expect(bs.to_a).to eq [ 'N/A', nil ]
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'has N/A as the last result' do
|
14
|
+
expect(bs.last_result).to eq 'N/A'
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'does not build atm' do
|
18
|
+
expect(bs.building?).to eq false
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'reads N/A as a string' do
|
22
|
+
expect(bs.to_s).to eq 'N/A'
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe 'an intermediate state' do
|
27
|
+
let :bs do
|
28
|
+
described_class.for [ 'SUCCESS', true ]
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
it 'has SUCCESS as the last result' do
|
33
|
+
expect(bs.last_result).to eq 'SUCCESS'
|
34
|
+
end
|
35
|
+
|
36
|
+
describe 'building' do
|
37
|
+
it 'has a to_a' do
|
38
|
+
expect(bs.to_a).to eq [ 'SUCCESS', true ]
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'can be building' do
|
42
|
+
expect(bs.building?).to eq true
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'reads SUCCESS (building) as a string' do
|
46
|
+
expect(bs.to_s).to eq 'SUCCESS (building)'
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe 'not building' do
|
51
|
+
let :bs do
|
52
|
+
described_class.for [ 'SUCCESS', false ]
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'has a to_a' do
|
56
|
+
expect(bs.to_a).to eq [ 'SUCCESS', false ]
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'can not be building' do
|
60
|
+
expect(bs.building?).to eq false
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'reads SUCCESS (building) as a string' do
|
64
|
+
expect(bs.to_s).to eq 'SUCCESS'
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe 'equality' do
|
70
|
+
it 'can be equal or unequal' do
|
71
|
+
foo_true = described_class.for([ 'FOO', true ])
|
72
|
+
foo_false = described_class.for([ 'FOO', false ])
|
73
|
+
bar_true = described_class.for([ 'BAR', true ])
|
74
|
+
expect(foo_true).to eq described_class.for([ 'FOO', true ])
|
75
|
+
expect(foo_true).not_to eq foo_false
|
76
|
+
expect(foo_true).not_to eq bar_true
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,226 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe AmpelExtase::Controller do
|
4
|
+
before do
|
5
|
+
allow_any_instance_of(AmpelExtase::JenkinsClient).to receive(:puts)
|
6
|
+
allow_any_instance_of(AmpelExtase::Controller).to receive(:puts)
|
7
|
+
allow_any_instance_of(AmpelExtase::JenkinsStateObserver).to receive(:puts)
|
8
|
+
allow_any_instance_of(described_class).to receive(:sleep)
|
9
|
+
end
|
10
|
+
|
11
|
+
let :ampel_client do
|
12
|
+
double('AmpelExtase::JenkinsClient', url: 'http://foo/bar')
|
13
|
+
end
|
14
|
+
|
15
|
+
let :warning_client do
|
16
|
+
double('AmpelExtase::JenkinsClient', url: 'http://foo/bar')
|
17
|
+
end
|
18
|
+
|
19
|
+
let :ampel_jenkins do
|
20
|
+
AmpelExtase::JenkinsStateObserver.new ampel_client
|
21
|
+
end
|
22
|
+
|
23
|
+
let :warning_jenkins do
|
24
|
+
AmpelExtase::JenkinsStateObserver.new warning_client
|
25
|
+
end
|
26
|
+
|
27
|
+
let :lights do
|
28
|
+
double('AmpelExtase::LightSwitcher')
|
29
|
+
end
|
30
|
+
|
31
|
+
let :controller do
|
32
|
+
described_class.new(
|
33
|
+
ampel_jenkins,
|
34
|
+
warning_jenkins,
|
35
|
+
lights
|
36
|
+
)
|
37
|
+
end
|
38
|
+
|
39
|
+
before do
|
40
|
+
for client in [ ampel_client, warning_client ]
|
41
|
+
allow(client).to receive(:fetch).and_return true
|
42
|
+
allow(client).to receive(:fetch_build).and_return('result' => 'N/A')
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
before do
|
47
|
+
allow(lights).to receive(:each)
|
48
|
+
end
|
49
|
+
|
50
|
+
describe '.for' do
|
51
|
+
it 'can create a demo object that does not really do anything' do
|
52
|
+
demo_object = described_class.for(
|
53
|
+
serial: nil,
|
54
|
+
jenkins_url: nil
|
55
|
+
)
|
56
|
+
expect(demo_object.instance_eval { @ampel_jenkins }).to be_nil
|
57
|
+
expect(demo_object.instance_eval { @warning_jenkins }).to be_nil
|
58
|
+
expect(demo_object.instance_eval { @lights }).to be_nil
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe '#start' do
|
63
|
+
it 'performs and then sleeps' do
|
64
|
+
allow(controller).to receive(:sleep).and_raise(
|
65
|
+
sleep_error = StandardError.new
|
66
|
+
)
|
67
|
+
allow(controller).to receive(:at_exit)
|
68
|
+
expect(controller).to receive(:perform)
|
69
|
+
expect { controller.start }.to raise_error sleep_error
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'can handle crashes' do
|
73
|
+
allow(controller).to receive(:sleep).and_raise(
|
74
|
+
sleep_error = StandardError.new
|
75
|
+
)
|
76
|
+
allow(controller).to receive(:at_exit)
|
77
|
+
expect(controller).to receive(:perform).and_raise(e = StandardError.new)
|
78
|
+
expect(controller).to receive(:handle_crash).with(e)
|
79
|
+
expect { controller.start }.to raise_error sleep_error
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
describe '#stop' do
|
85
|
+
before do
|
86
|
+
controller
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'iterates over all lights' do
|
90
|
+
expect(lights).to receive(:each).once
|
91
|
+
controller.stop
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
describe '#perform' do
|
96
|
+
let :perform do
|
97
|
+
controller.instance_eval { perform }
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'reacts to state changes' do
|
101
|
+
state = AmpelExtase::BuildState.for
|
102
|
+
allow(ampel_jenkins).to receive(:state_changed?).and_return true
|
103
|
+
expect { |b| ampel_jenkins.on_state_change(&b) }.to yield_with_args(state)
|
104
|
+
allow(warning_jenkins).to receive(:state_changed?).and_return true
|
105
|
+
expect { |b| warning_jenkins.on_state_change(&b) }.to yield_with_args(state)
|
106
|
+
perform
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
|
111
|
+
describe '#handle_crash' do
|
112
|
+
let :exception do
|
113
|
+
raise StandardError rescue $!
|
114
|
+
end
|
115
|
+
|
116
|
+
let :handle_crash do
|
117
|
+
my_exception = exception
|
118
|
+
controller.instance_eval { handle_crash(my_exception) }
|
119
|
+
end
|
120
|
+
|
121
|
+
before do
|
122
|
+
controller
|
123
|
+
allow(controller).to receive(:warn)
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'warns on crash' do
|
127
|
+
expect(controller).to receive(:warn).with(/^Caught/)
|
128
|
+
handle_crash
|
129
|
+
end
|
130
|
+
|
131
|
+
it 'switches the lights of once' do
|
132
|
+
expect(controller).to receive(:switch_all_lights_off)
|
133
|
+
handle_crash
|
134
|
+
expect(controller).not_to receive(:switch_all_lights_off)
|
135
|
+
handle_crash
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
describe '#perform_lights_switch' do
|
140
|
+
before do
|
141
|
+
controller.instance_variable_set :@lights, Tins::NULL
|
142
|
+
end
|
143
|
+
|
144
|
+
let :perform_lights_switch do
|
145
|
+
my_state = state
|
146
|
+
controller.instance_eval { perform_lights_switch(my_state) }
|
147
|
+
end
|
148
|
+
|
149
|
+
context 'success' do
|
150
|
+
let :state do
|
151
|
+
AmpelExtase::BuildState.for [ 'SUCCESS', false ]
|
152
|
+
end
|
153
|
+
|
154
|
+
it 'goes green on success' do
|
155
|
+
expect(controller).to receive(:success).and_call_original
|
156
|
+
perform_lights_switch
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
context 'failure' do
|
161
|
+
let :state do
|
162
|
+
AmpelExtase::BuildState.for [ 'FAILURE', false ]
|
163
|
+
end
|
164
|
+
|
165
|
+
it 'goes red on failure' do
|
166
|
+
expect(controller).to receive(:failure).and_call_original
|
167
|
+
perform_lights_switch
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
context 'failure building' do
|
172
|
+
let :state do
|
173
|
+
AmpelExtase::BuildState.for [ 'FAILURE', true ]
|
174
|
+
end
|
175
|
+
|
176
|
+
it 'goes green on red on failure and building' do
|
177
|
+
expect(controller).to receive(:failure_building).and_call_original
|
178
|
+
perform_lights_switch
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
describe '#perform_warning' do
|
184
|
+
before do
|
185
|
+
controller.instance_variable_set :@lights, Tins::NULL
|
186
|
+
end
|
187
|
+
|
188
|
+
let :perform_warning do
|
189
|
+
my_state = state
|
190
|
+
controller.instance_eval { perform_warning(my_state) }
|
191
|
+
end
|
192
|
+
|
193
|
+
context 'success' do
|
194
|
+
let :state do
|
195
|
+
AmpelExtase::BuildState.for [ 'SUCCESS', false ]
|
196
|
+
end
|
197
|
+
|
198
|
+
it 'goes green on success' do
|
199
|
+
expect(controller).to receive(:success).and_call_original
|
200
|
+
perform_warning
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
context 'failure' do
|
205
|
+
let :state do
|
206
|
+
AmpelExtase::BuildState.for [ 'FAILURE', false ]
|
207
|
+
end
|
208
|
+
|
209
|
+
it 'goes red on failure' do
|
210
|
+
expect(controller).to receive(:failure).and_call_original
|
211
|
+
perform_warning
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
context 'failure building' do
|
216
|
+
let :state do
|
217
|
+
AmpelExtase::BuildState.for [ 'FAILURE', true ]
|
218
|
+
end
|
219
|
+
|
220
|
+
it 'goes green on red on failure and building' do
|
221
|
+
expect(controller).to receive(:failure_building).and_call_original
|
222
|
+
perform_warning
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe AmpelExtase::JenkinsStateObserver do
|
4
|
+
let :client do
|
5
|
+
double('AmpelExtase::JenkinsClient', url: 'http://foo/bar')
|
6
|
+
end
|
7
|
+
|
8
|
+
before do
|
9
|
+
allow(client).to receive(:fetch).and_return true
|
10
|
+
end
|
11
|
+
|
12
|
+
let :jso do
|
13
|
+
described_class.new client
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '.for_url' do
|
17
|
+
it 'creates a state observer for an URL' do
|
18
|
+
url = 'http://foo/bar'
|
19
|
+
expect(AmpelExtase::JenkinsClient).to\
|
20
|
+
receive(:new).with(url).and_return client
|
21
|
+
expect(described_class).to\
|
22
|
+
receive(:new).with(client)
|
23
|
+
described_class.for_url url
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'returns a null object if url was nil' do
|
27
|
+
expect(described_class.for_url(nil)).to be_nil
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe '#check' do
|
32
|
+
it 'outputs "OK" if it can fetch data from CI' do
|
33
|
+
allow(jso).to receive(:puts)
|
34
|
+
expect(jso).to receive(:puts).with('OK')
|
35
|
+
jso.check
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'lets an exception pass if raised by the client' do
|
39
|
+
allow(client).to receive(:fetch).and_raise e = StandardError.new
|
40
|
+
expect { jso.check }.to raise_error e
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe '#last_result' do
|
45
|
+
it 'uses client to fetch last_completed_build' do
|
46
|
+
allow(client).to receive(:fetch_build).with(:last_completed_build).
|
47
|
+
and_return('result' => :foo)
|
48
|
+
expect(jso.last_result).to eq :foo
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe '#building?' do
|
53
|
+
it 'uses client to fetch last_build' do
|
54
|
+
allow(client).to receive(:fetch_build).with(:last_build).
|
55
|
+
and_return('building' => :foo)
|
56
|
+
expect(jso.building?).to eq :foo
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe '#on_state_change' do
|
61
|
+
let :bs_initial do
|
62
|
+
AmpelExtase::BuildState.for [ 'N/A', nil ]
|
63
|
+
end
|
64
|
+
|
65
|
+
let :bs_success do
|
66
|
+
AmpelExtase::BuildState.for [ 'SUCCESS', true ]
|
67
|
+
end
|
68
|
+
|
69
|
+
let :bs_failure do
|
70
|
+
AmpelExtase::BuildState.for [ 'FAILURE', true ]
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'tracks changes in build state' do
|
74
|
+
expect(jso.instance_variable_get(:@build_state)).to eq bs_initial
|
75
|
+
allow(client).to receive(:fetch_build).with(:last_completed_build).
|
76
|
+
and_return('result' => 'SUCCESS')
|
77
|
+
allow(client).to receive(:fetch_build).with(:last_build).
|
78
|
+
and_return('building' => true)
|
79
|
+
expect(jso).to receive(:puts).with(
|
80
|
+
"state changed from N/A to SUCCESS (building) => "\
|
81
|
+
"taking action"
|
82
|
+
)
|
83
|
+
expect { |b| jso.on_state_change(&b) }.to yield_with_args(bs_success)
|
84
|
+
expect(jso.instance_variable_get(:@build_state)).to eq bs_success
|
85
|
+
allow(client).to receive(:fetch_build).with(:last_completed_build).
|
86
|
+
and_return('result' => 'FAILURE')
|
87
|
+
allow(client).to receive(:fetch_build).with(:last_build).
|
88
|
+
and_return('building' => true)
|
89
|
+
expect(jso).to receive(:puts).with(
|
90
|
+
"state changed from SUCCESS (building) to FAILURE (building) => "\
|
91
|
+
"taking action"
|
92
|
+
)
|
93
|
+
expect { |b| jso.on_state_change(&b) }.to yield_with_args(bs_failure)
|
94
|
+
expect(jso.instance_variable_get(:@build_state)).to eq bs_failure
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'notices if nothing has changed' do
|
98
|
+
allow(client).to receive(:fetch_build).twice.with(:last_completed_build).
|
99
|
+
and_return('result' => 'SUCCESS')
|
100
|
+
allow(client).to receive(:fetch_build).twice.with(:last_build).
|
101
|
+
and_return('building' => true)
|
102
|
+
expect(jso).to receive(:puts).with(
|
103
|
+
"state changed from N/A to SUCCESS (building) => "\
|
104
|
+
"taking action"
|
105
|
+
)
|
106
|
+
expect { |b| jso.on_state_change(&b) }.to yield_with_args(bs_success)
|
107
|
+
expect(jso.instance_variable_get(:@build_state)).to eq bs_success
|
108
|
+
expect(jso).to receive(:puts).with(
|
109
|
+
"state did not change, is still SUCCESS (building) => do nothing"
|
110
|
+
)
|
111
|
+
expect(jso.instance_variable_get(:@build_state)).to eq bs_success
|
112
|
+
expect { |b| jso.on_state_change(&b) }.not_to yield_with_args(bs_success)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -1,5 +1,47 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe AmpelExtase::JenkinsClient do
|
4
|
-
|
4
|
+
let :client do
|
5
|
+
AmpelExtase::JenkinsClient.new 'http://foo/bar'
|
6
|
+
end
|
7
|
+
|
8
|
+
let :opened_uri do
|
9
|
+
double('URI', read: '{"hello":"world"}')
|
10
|
+
end
|
11
|
+
|
12
|
+
describe '#fetch' do
|
13
|
+
let :api_url do
|
14
|
+
'http://foo/bar/api/json'
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'can fetch JSON data from CI' do
|
18
|
+
expect(client).to receive(:open).with(api_url).
|
19
|
+
and_return opened_uri
|
20
|
+
expect(client.fetch).to eq("hello" => "world")
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'modifies exception messages and reraises' do
|
24
|
+
expect(client).to receive(:open).with(api_url).
|
25
|
+
and_raise e = StandardError.new('foo')
|
26
|
+
expect { client.fetch }.to raise_error(
|
27
|
+
StandardError, /for #{api_url.inspect}/
|
28
|
+
)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe '#fetch_build' do
|
33
|
+
let :api_url do
|
34
|
+
'http://foo/bar/buildType/api/json'
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'can can fetch a build type responding to #to_s' do
|
38
|
+
expect(client).to receive(:open).with(api_url).and_return opened_uri
|
39
|
+
client.fetch_build double(to_s: 'buildType')
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'can interpret a build type symbol correctly' do
|
43
|
+
expect(client).to receive(:open).with(api_url).and_return opened_uri
|
44
|
+
client.fetch_build :build_type
|
45
|
+
end
|
46
|
+
end
|
5
47
|
end
|
@@ -1,5 +1,40 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe AmpelExtase::LightSwitcher do
|
4
|
-
|
4
|
+
let :port do
|
5
|
+
double('SocketSwitcher::Port')
|
6
|
+
end
|
7
|
+
|
8
|
+
let :switcher do
|
9
|
+
allow(SocketSwitcher::Port).to receive(:new).and_return port
|
10
|
+
described_class.for serial: 'foo/bar'
|
11
|
+
end
|
12
|
+
|
13
|
+
describe '#green' do
|
14
|
+
it 'returns device 0' do
|
15
|
+
expect(port).to receive(:device).with(0)
|
16
|
+
switcher.green
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '#red' do
|
21
|
+
it 'returns device 1' do
|
22
|
+
expect(port).to receive(:device).with(1)
|
23
|
+
switcher.red
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '#aux' do
|
28
|
+
it 'returns device 3' do
|
29
|
+
expect(port).to receive(:device).with(2)
|
30
|
+
switcher.aux
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe '#each' do
|
35
|
+
it 'iterates over all port devices' do
|
36
|
+
expect(port).to receive(:device).thrice.and_return :ok
|
37
|
+
expect(switcher.each.to_a).to eq %i[ ok ] * 3
|
38
|
+
end
|
39
|
+
end
|
5
40
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ampel_extase
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Florian Frank
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-08-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: gem_hadar
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 1.
|
19
|
+
version: 1.3.1
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 1.
|
26
|
+
version: 1.3.1
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: simplecov
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -80,6 +80,20 @@ dependencies:
|
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '1.0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: term-ansicolor
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '1.0'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '1.0'
|
83
97
|
- !ruby/object:Gem::Dependency
|
84
98
|
name: socket_switcher
|
85
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -105,10 +119,12 @@ extra_rdoc_files:
|
|
105
119
|
- lib/ampel_extase/build_state.rb
|
106
120
|
- lib/ampel_extase/controller.rb
|
107
121
|
- lib/ampel_extase/jenkins_client.rb
|
122
|
+
- lib/ampel_extase/jenkins_state_observer.rb
|
108
123
|
- lib/ampel_extase/light_switcher.rb
|
109
124
|
- lib/ampel_extase/version.rb
|
110
125
|
files:
|
111
126
|
- ".gitignore"
|
127
|
+
- ".utilsrc"
|
112
128
|
- Gemfile
|
113
129
|
- README.md
|
114
130
|
- Rakefile
|
@@ -119,8 +135,12 @@ files:
|
|
119
135
|
- lib/ampel_extase/build_state.rb
|
120
136
|
- lib/ampel_extase/controller.rb
|
121
137
|
- lib/ampel_extase/jenkins_client.rb
|
138
|
+
- lib/ampel_extase/jenkins_state_observer.rb
|
122
139
|
- lib/ampel_extase/light_switcher.rb
|
123
140
|
- lib/ampel_extase/version.rb
|
141
|
+
- spec/ampel_extase/build_state_spec.rb
|
142
|
+
- spec/ampel_extase/controller_spec.rb
|
143
|
+
- spec/ampel_extase/jekins_state_observer_spec.rb
|
124
144
|
- spec/ampel_extase/jenkins_client_spec.rb
|
125
145
|
- spec/ampel_extase/light_switcher_spec.rb
|
126
146
|
- spec/spec_helper.rb
|
@@ -148,11 +168,14 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
148
168
|
version: '0'
|
149
169
|
requirements: []
|
150
170
|
rubyforge_project:
|
151
|
-
rubygems_version: 2.
|
171
|
+
rubygems_version: 2.4.5.1
|
152
172
|
signing_key:
|
153
173
|
specification_version: 4
|
154
174
|
summary: Library to control the build traffic light
|
155
175
|
test_files:
|
176
|
+
- spec/ampel_extase/build_state_spec.rb
|
177
|
+
- spec/ampel_extase/controller_spec.rb
|
178
|
+
- spec/ampel_extase/jekins_state_observer_spec.rb
|
156
179
|
- spec/ampel_extase/jenkins_client_spec.rb
|
157
180
|
- spec/ampel_extase/light_switcher_spec.rb
|
158
181
|
- spec/spec_helper.rb
|