build_eval 0.0.1 → 0.0.2

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.
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