build_eval 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/lib/build_eval/http.rb +16 -0
  3. data/lib/build_eval/monitor/base.rb +13 -0
  4. data/lib/build_eval/monitor/composite.rb +17 -0
  5. data/lib/build_eval/monitor/server.rb +18 -0
  6. data/lib/build_eval/result/build_result.rb +41 -0
  7. data/lib/build_eval/result/composite_result.rb +25 -0
  8. data/lib/build_eval/result/server_result.rb +26 -0
  9. data/lib/build_eval/result/status.rb +54 -0
  10. data/lib/build_eval/{ci_server → server}/decorator.rb +3 -3
  11. data/lib/build_eval/server/team_city.rb +28 -0
  12. data/lib/build_eval/server/travis.rb +26 -0
  13. data/lib/build_eval/version.rb +1 -1
  14. data/lib/build_eval.rb +13 -8
  15. data/spec/lib/build_eval/http_spec.rb +82 -0
  16. data/spec/lib/build_eval/monitor/base_spec.rb +29 -0
  17. data/spec/lib/build_eval/monitor/composite_spec.rb +38 -0
  18. data/spec/lib/build_eval/monitor/server_spec.rb +43 -0
  19. data/spec/lib/build_eval/{build_result_spec.rb → result/build_result_spec.rb} +9 -9
  20. data/spec/lib/build_eval/result/composite_result_spec.rb +84 -0
  21. data/spec/lib/build_eval/result/server_result_spec.rb +92 -0
  22. data/spec/lib/build_eval/{status_spec.rb → result/status_spec.rb} +36 -15
  23. data/spec/lib/build_eval/server/decorator_spec.rb +97 -0
  24. data/spec/lib/build_eval/server/team_city_spec.rb +119 -0
  25. data/spec/lib/build_eval/server/travis_spec.rb +92 -0
  26. data/spec/lib/build_eval_spec.rb +8 -8
  27. metadata +35 -20
  28. data/lib/build_eval/build_result.rb +0 -39
  29. data/lib/build_eval/build_results.rb +0 -23
  30. data/lib/build_eval/ci_server/team_city.rb +0 -33
  31. data/lib/build_eval/monitor.rb +0 -15
  32. data/lib/build_eval/status.rb +0 -51
  33. data/spec/lib/build_eval/build_results_spec.rb +0 -82
  34. data/spec/lib/build_eval/ci_server/decorator_spec.rb +0 -97
  35. data/spec/lib/build_eval/ci_server/team_city_spec.rb +0 -111
  36. data/spec/lib/build_eval/monitor_spec.rb +0 -37
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: build_eval
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matthew Ueckerman
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-08-13 00:00:00.000000000 Z
12
+ date: 2015-08-17 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: nokogiri
@@ -117,19 +117,29 @@ extensions: []
117
117
  extra_rdoc_files: []
118
118
  files:
119
119
  - "./lib/build_eval.rb"
120
- - "./lib/build_eval/build_result.rb"
121
- - "./lib/build_eval/build_results.rb"
122
- - "./lib/build_eval/ci_server/decorator.rb"
123
- - "./lib/build_eval/ci_server/team_city.rb"
124
- - "./lib/build_eval/monitor.rb"
125
- - "./lib/build_eval/status.rb"
120
+ - "./lib/build_eval/http.rb"
121
+ - "./lib/build_eval/monitor/base.rb"
122
+ - "./lib/build_eval/monitor/composite.rb"
123
+ - "./lib/build_eval/monitor/server.rb"
124
+ - "./lib/build_eval/result/build_result.rb"
125
+ - "./lib/build_eval/result/composite_result.rb"
126
+ - "./lib/build_eval/result/server_result.rb"
127
+ - "./lib/build_eval/result/status.rb"
128
+ - "./lib/build_eval/server/decorator.rb"
129
+ - "./lib/build_eval/server/team_city.rb"
130
+ - "./lib/build_eval/server/travis.rb"
126
131
  - "./lib/build_eval/version.rb"
127
- - "./spec/lib/build_eval/build_result_spec.rb"
128
- - "./spec/lib/build_eval/build_results_spec.rb"
129
- - "./spec/lib/build_eval/ci_server/decorator_spec.rb"
130
- - "./spec/lib/build_eval/ci_server/team_city_spec.rb"
131
- - "./spec/lib/build_eval/monitor_spec.rb"
132
- - "./spec/lib/build_eval/status_spec.rb"
132
+ - "./spec/lib/build_eval/http_spec.rb"
133
+ - "./spec/lib/build_eval/monitor/base_spec.rb"
134
+ - "./spec/lib/build_eval/monitor/composite_spec.rb"
135
+ - "./spec/lib/build_eval/monitor/server_spec.rb"
136
+ - "./spec/lib/build_eval/result/build_result_spec.rb"
137
+ - "./spec/lib/build_eval/result/composite_result_spec.rb"
138
+ - "./spec/lib/build_eval/result/server_result_spec.rb"
139
+ - "./spec/lib/build_eval/result/status_spec.rb"
140
+ - "./spec/lib/build_eval/server/decorator_spec.rb"
141
+ - "./spec/lib/build_eval/server/team_city_spec.rb"
142
+ - "./spec/lib/build_eval/server/travis_spec.rb"
133
143
  - "./spec/lib/build_eval_spec.rb"
134
144
  - "./spec/spec_helper.rb"
135
145
  homepage: http://github.com/MYOB-Technology/build_eval
@@ -157,11 +167,16 @@ signing_key:
157
167
  specification_version: 4
158
168
  summary: Evaluates the effective status of continuous integration builds
159
169
  test_files:
160
- - "./spec/lib/build_eval/build_result_spec.rb"
161
- - "./spec/lib/build_eval/build_results_spec.rb"
162
- - "./spec/lib/build_eval/ci_server/decorator_spec.rb"
163
- - "./spec/lib/build_eval/ci_server/team_city_spec.rb"
164
- - "./spec/lib/build_eval/monitor_spec.rb"
165
- - "./spec/lib/build_eval/status_spec.rb"
170
+ - "./spec/lib/build_eval/http_spec.rb"
171
+ - "./spec/lib/build_eval/monitor/base_spec.rb"
172
+ - "./spec/lib/build_eval/monitor/composite_spec.rb"
173
+ - "./spec/lib/build_eval/monitor/server_spec.rb"
174
+ - "./spec/lib/build_eval/result/build_result_spec.rb"
175
+ - "./spec/lib/build_eval/result/composite_result_spec.rb"
176
+ - "./spec/lib/build_eval/result/server_result_spec.rb"
177
+ - "./spec/lib/build_eval/result/status_spec.rb"
178
+ - "./spec/lib/build_eval/server/decorator_spec.rb"
179
+ - "./spec/lib/build_eval/server/team_city_spec.rb"
180
+ - "./spec/lib/build_eval/server/travis_spec.rb"
166
181
  - "./spec/lib/build_eval_spec.rb"
167
182
  - "./spec/spec_helper.rb"
@@ -1,39 +0,0 @@
1
- module BuildEval
2
-
3
- class BuildResult
4
-
5
- class << self
6
-
7
- def create(args)
8
- self.new(build_name: args[:build_name], status: BuildEval::Status.find(args[:status_name]))
9
- end
10
-
11
- def unknown(build_name)
12
- self.new(build_name: build_name, status: BuildEval::Status::UNKNOWN)
13
- end
14
-
15
- end
16
-
17
- attr_reader :build_name
18
- attr_reader :status
19
-
20
- private
21
-
22
- def initialize(args)
23
- @build_name = args[:build_name]
24
- @status = args[:status]
25
- end
26
-
27
- public
28
-
29
- def unsuccessful?
30
- @status.unsuccessful?
31
- end
32
-
33
- def to_s
34
- "#{@build_name}: #{@status}"
35
- end
36
-
37
- end
38
-
39
- end
@@ -1,23 +0,0 @@
1
- module BuildEval
2
-
3
- class BuildResults
4
-
5
- def initialize(build_results)
6
- @build_results = build_results
7
- end
8
-
9
- def status
10
- BuildEval::Status.effective_status(@build_results.map(&:status))
11
- end
12
-
13
- def unsuccessful
14
- @build_results.find_all(&:unsuccessful?)
15
- end
16
-
17
- def to_s
18
- @build_results.map(&:to_s).join(", ")
19
- end
20
-
21
- end
22
-
23
- end
@@ -1,33 +0,0 @@
1
- module BuildEval
2
- module CIServer
3
-
4
- class TeamCity
5
-
6
- def initialize(args)
7
- @base_uri = args[:uri]
8
- @username = args[:username]
9
- @password = args[:password]
10
- end
11
-
12
- def build_result(name)
13
- response = issue_request(name)
14
- build_element = Nokogiri::XML(response.body).xpath("//build").first
15
- raise "Unexpected build response: #{response.message}" unless build_element
16
- BuildEval::BuildResult.create(build_name: name, status_name: build_element.attribute("status").value)
17
- end
18
-
19
- private
20
-
21
- def issue_request(name)
22
- uri = URI.parse("#{@base_uri}/httpAuth/app/rest/buildTypes/id:#{name}/builds")
23
- Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == "https") do |http|
24
- request = Net::HTTP::Get.new(uri.request_uri)
25
- request.basic_auth(@username, @password)
26
- http.request(request)
27
- end
28
- end
29
-
30
- end
31
-
32
- end
33
- end
@@ -1,15 +0,0 @@
1
- module BuildEval
2
-
3
- class Monitor
4
-
5
- def initialize(args)
6
- @server = args[:server]
7
- @build_names = args[:build_names]
8
- end
9
-
10
- def evaluate
11
- BuildEval::BuildResults.new(@build_names.map { |build_name| @server.build_result(build_name) })
12
- end
13
-
14
- end
15
- end
@@ -1,51 +0,0 @@
1
- module BuildEval
2
-
3
- class Status
4
-
5
- private
6
-
7
- def initialize(args)
8
- @severity = args[:severity]
9
- @symbol = args[:symbol]
10
- @description = args[:description]
11
- end
12
-
13
- public
14
-
15
- SUCCESS = self.new(severity: 0, symbol: :success!, description: "succeeded")
16
- FAILURE = self.new(severity: 2, symbol: :failed!, description: "failed")
17
- UNKNOWN = self.new(severity: 1, symbol: :warning!, description: "unknown")
18
-
19
- class << self
20
-
21
- def find(name)
22
- begin
23
- self.const_get(name)
24
- rescue NameError
25
- raise "Build status '#{name}' is invalid"
26
- end
27
- end
28
-
29
- def effective_status(statuses)
30
- statuses.sort_by { |status| status.severity }.last
31
- end
32
-
33
- end
34
-
35
- attr_reader :severity
36
-
37
- def unsuccessful?
38
- self != SUCCESS
39
- end
40
-
41
- def to_sym
42
- @symbol
43
- end
44
-
45
- def to_s
46
- @description
47
- end
48
-
49
- end
50
-
51
- end
@@ -1,82 +0,0 @@
1
- describe BuildEval::BuildResults do
2
-
3
- let(:results) { (1..3).map { instance_double(BuildEval::BuildResult) } }
4
-
5
- let(:build_results) { described_class.new(results) }
6
-
7
- describe "#status" do
8
-
9
- let(:statuses) { results.map { instance_double(BuildEval::Status) } }
10
-
11
- subject { build_results.status }
12
-
13
- before(:example) do
14
- results.zip(statuses).each { |result, status| allow(result).to receive(:status).and_return(status) }
15
- end
16
-
17
- it "determines the effective status of the build results" do
18
- expect(BuildEval::Status).to receive(:effective_status).with(statuses)
19
-
20
- subject
21
- end
22
-
23
- it "returns the effective status" do
24
- status = instance_double(BuildEval::Status)
25
- allow(BuildEval::Status).to receive(:effective_status).and_return(status)
26
-
27
- expect(subject).to be(status)
28
- end
29
-
30
- end
31
-
32
- describe "#unsuccessful" do
33
-
34
- subject { build_results.unsuccessful }
35
-
36
- before(:example) do
37
- results.each do |build_result|
38
- allow(build_result).to receive(:unsuccessful?).and_return(unsuccessful_results.include?(build_result))
39
- end
40
- end
41
-
42
- context "when some build results are unsuccessful" do
43
-
44
- let(:unsuccessful_results) { [ results[0], results[2] ] }
45
-
46
- it "returns the unsuccessful build results" do
47
- expect(subject).to eql(unsuccessful_results)
48
- end
49
-
50
- end
51
-
52
- context "when no build results are unsuccessful" do
53
-
54
- let(:unsuccessful_results) { [] }
55
-
56
- it "returns an empty array" do
57
- expect(subject).to eql([])
58
- end
59
-
60
- end
61
-
62
- end
63
-
64
- describe "#to_s" do
65
-
66
- let(:result_string_representations) { results.each_with_index.map { |_, i| "Result description ##{i}" } }
67
-
68
- subject { build_results.to_s }
69
-
70
- before(:example) do
71
- results.zip(result_string_representations).each do |build_result, string|
72
- allow(build_result).to receive(:to_s).and_return(string)
73
- end
74
- end
75
-
76
- it "contains the string representation of each result" do
77
- result_string_representations.each { |string| expect(subject).to include(string) }
78
- end
79
-
80
- end
81
-
82
- end
@@ -1,97 +0,0 @@
1
- describe BuildEval::CIServer::Decorator do
2
-
3
- let(:decorated_server) { double("BuildEval::CIServer::Server") }
4
-
5
- let(:decorator) { described_class.new(decorated_server) }
6
-
7
- describe "#build_result" do
8
-
9
- let(:build_name) { "some build name" }
10
-
11
- subject { decorator.build_result(build_name) }
12
-
13
- it "delegates to the decorated server" do
14
- expect(decorated_server).to receive(:build_result).with(build_name)
15
-
16
- subject
17
- end
18
-
19
- context "when the decorated server returns a result" do
20
-
21
- let(:build_result) { instance_double(BuildEval::BuildResult) }
22
-
23
- before(:example) { allow(decorated_server).to receive(:build_result).and_return(build_result) }
24
-
25
- it "returns the result" do
26
- expect(subject).to eql(build_result)
27
- end
28
-
29
- end
30
-
31
- context "when the decorated server raises an error" do
32
-
33
- before(:example) { allow(decorated_server).to receive(:build_result).and_raise("Forced error") }
34
-
35
- it "creates an unknown result" do
36
- expect(BuildEval::BuildResult).to receive(:unknown).with(build_name)
37
-
38
- subject
39
- end
40
-
41
- it "returns the unknown result" do
42
- unknown_build_result = instance_double(BuildEval::BuildResult)
43
- allow(BuildEval::BuildResult).to receive(:unknown).and_return(unknown_build_result)
44
-
45
- expect(subject).to eql(unknown_build_result)
46
- end
47
-
48
- end
49
-
50
- end
51
-
52
- describe "#monitor" do
53
-
54
- let(:build_names) { (1..3).map { |i| "build##{i}" } }
55
-
56
- subject { decorator.monitor(*build_names) }
57
-
58
- it "creates a monitor for the decorated server" do
59
- expect(BuildEval::Monitor).to receive(:new).with(hash_including(server: decorated_server))
60
-
61
- subject
62
- end
63
-
64
- it "returns the monitor" do
65
- monitor = instance_double(BuildEval::Monitor)
66
- allow(BuildEval::Monitor).to receive(:new).and_return(monitor)
67
-
68
- expect(subject).to eql(monitor)
69
- end
70
-
71
- context "when an array of build names is provided" do
72
-
73
- subject { decorator.monitor(build_names) }
74
-
75
- it "creates a monitor for the provided build names" do
76
- expect(BuildEval::Monitor).to receive(:new).with(hash_including(build_names: build_names))
77
-
78
- subject
79
- end
80
-
81
- end
82
-
83
- context "when variable argument list of build names is provided" do
84
-
85
- subject { decorator.monitor(*build_names) }
86
-
87
- it "creates a monitor for the provided build names" do
88
- expect(BuildEval::Monitor).to receive(:new).with(hash_including(build_names: build_names))
89
-
90
- subject
91
- end
92
-
93
- end
94
-
95
- end
96
-
97
- end
@@ -1,111 +0,0 @@
1
- describe BuildEval::CIServer::TeamCity do
2
-
3
- let(:scheme) { "http" }
4
- let(:host) { "some.teamcity.server" }
5
- let(:uri) { "#{scheme}://#{host}" }
6
- let(:username) { "some_username" }
7
- let(:password) { "some_password" }
8
-
9
- let(:team_city) { described_class.new(uri: uri, username: username, password: password) }
10
-
11
- describe "#build_result" do
12
-
13
- let(:build_name) { "some_build_name" }
14
- let(:last_status) { "FAILED" }
15
-
16
- let(:expected_uri) do
17
- "#{scheme}://#{username}:#{password}@#{host}/httpAuth/app/rest/buildTypes/id:#{build_name}/builds"
18
- end
19
-
20
- subject { team_city.build_result(build_name) }
21
-
22
- before(:example) { FakeWeb.register_uri(:get, expected_uri, body: response_body, status: response_status) }
23
-
24
- context "when the server responds with build results" do
25
-
26
- let(:response_body) do
27
- <<-RESPONSE
28
- <builds count="3" href="/httpAuth/app/rest/buildTypes/#{build_name}/builds/" nextHref="/httpAuth/app/rest/buildTypes/#{build_name}/builds/?count=3&start=3">
29
- <build id="87735" buildTypeId="#{build_name}" number="2062" status="#{last_status}" state="finished" href="/httpAuth/app/rest/builds/id:87735" webUrl="#{uri}/viewLog.html?buildId=87735&buildTypeId=#{build_name}"/>
30
- <build id="87723" buildTypeId="#{build_name}" number="2061" status="SUCCESS" state="finished" href="/httpAuth/app/rest/builds/id:87723" webUrl="#{uri}/viewLog.html?buildId=87723&buildTypeId=#{build_name}"/>
31
- <build id="87658" buildTypeId="#{build_name}" number="2060" status="SUCCESS" state="finished" href="/httpAuth/app/rest/builds/id:87658" webUrl="#{uri}/viewLog.html?buildId=87658&buildTypeId=#{build_name}"/>
32
- </builds>
33
- RESPONSE
34
- end
35
- let(:response_status) { [ "200", "OK" ] }
36
-
37
- it "creates a build result containing the build name" do
38
- expect(BuildEval::BuildResult).to receive(:create).with(hash_including(build_name: build_name))
39
-
40
- subject
41
- end
42
-
43
- it "creates a build result containing the latest build status" do
44
- expect(BuildEval::BuildResult).to receive(:create).with(hash_including(status_name: last_status))
45
-
46
- subject
47
- end
48
-
49
- it "returns the created result" do
50
- build_result = instance_double(BuildEval::BuildResult)
51
- allow(BuildEval::BuildResult).to receive(:create).and_return(build_result)
52
-
53
- expect(subject).to eql(build_result)
54
- end
55
-
56
- context "and the uri has a https scheme" do
57
-
58
- let(:scheme) { "https" }
59
-
60
- it "creates a build result from the response" do
61
- expect(BuildEval::BuildResult).to receive(:create).with(hash_including(status_name: last_status))
62
-
63
- subject
64
- end
65
-
66
- end
67
-
68
- end
69
-
70
- context "when the server authentication request fails" do
71
-
72
- let(:response_body) { "Incorrect username or password" }
73
- let(:response_status) { [ "401", "Unauthorized" ] }
74
-
75
- it "raises an error" do
76
- expect { subject }.to raise_error(/Unauthorized/)
77
- end
78
-
79
- end
80
-
81
- context "when the build is not found" do
82
-
83
- let(:response_body) do
84
- <<-BODY
85
- Error has occurred during request processing (Not Found).
86
- Error: jetbrains.buildServer.server.rest.errors.NotFoundException: No build type nor template is found by id '#{build_name}'.
87
- BODY
88
- end
89
- let(:response_status) { [ "404", "Not Found" ] }
90
-
91
- it "raises an error" do
92
- expect { subject }.to raise_error(/Not Found/)
93
- end
94
-
95
- end
96
-
97
- context "when the server cannot be reached" do
98
-
99
- let(:expected_uri) { "http://some.invalid.uri" }
100
- let(:response_body) { nil }
101
- let(:response_status) { nil }
102
-
103
- it "raises an error" do
104
- expect { subject }.to raise_error(/Not Found/)
105
- end
106
-
107
- end
108
-
109
- end
110
-
111
- end
@@ -1,37 +0,0 @@
1
- describe BuildEval::Monitor do
2
-
3
- let(:server) { double("BuildEval::CIServer") }
4
- let(:build_names) { (1..3).map { |i| "build##{i}" } }
5
-
6
- let(:monitor) { described_class.new(server: server, build_names: build_names) }
7
-
8
- describe "#evaluate" do
9
-
10
- let(:results) { build_names.map { instance_double(BuildEval::BuildResult) } }
11
-
12
- subject { monitor.evaluate }
13
-
14
- before(:example) { allow(server).to receive(:build_result).and_return(*results) }
15
-
16
- it "determines build results for builds of interest" do
17
- build_names.each { |build_name| expect(server).to receive(:build_result).with(build_name) }
18
-
19
- subject
20
- end
21
-
22
- it "composes a build results object containing the results" do
23
- expect(BuildEval::BuildResults).to receive(:new).with(results)
24
-
25
- subject
26
- end
27
-
28
- it "returns the build results object" do
29
- build_results = instance_double(BuildEval::BuildResults)
30
- expect(BuildEval::BuildResults).to receive(:new).and_return(build_results)
31
-
32
- expect(subject).to eql(build_results)
33
- end
34
-
35
- end
36
-
37
- end