teamcity-rest-client 0.1.1 → 0.2.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.
- data/VERSION +1 -1
- data/lib/teamcity-rest-client.rb +112 -24
- data/spec/teamcity-rest-client_spec.rb +348 -62
- data/teamcity-rest-client.gemspec +2 -2
- metadata +11 -11
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.0
|
data/lib/teamcity-rest-client.rb
CHANGED
@@ -4,9 +4,76 @@ require 'set'
|
|
4
4
|
|
5
5
|
module TeamcityRestClient
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
7
|
+
class Filter
|
8
|
+
end
|
9
|
+
|
10
|
+
class IncludeAllFilter
|
11
|
+
def retain? thing
|
12
|
+
true
|
13
|
+
end
|
14
|
+
def misses
|
15
|
+
[]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class ExcludeNoneFilter
|
20
|
+
def retain? thing
|
21
|
+
true
|
22
|
+
end
|
23
|
+
def misses
|
24
|
+
[]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class IncludeFilter
|
29
|
+
def initialize to_retain
|
30
|
+
@misses = [to_retain].flatten
|
31
|
+
end
|
32
|
+
|
33
|
+
def retain? build_type
|
34
|
+
@misses.delete(build_type.id) || @misses.delete(build_type.name) ? true : false
|
35
|
+
end
|
36
|
+
|
37
|
+
def misses
|
38
|
+
@misses
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class ExcludeFilter
|
43
|
+
def initialize to_exclude
|
44
|
+
@misses = [to_exclude].flatten
|
45
|
+
end
|
46
|
+
|
47
|
+
def retain? build_type
|
48
|
+
@misses.delete(build_type.id) || @misses.delete(build_type.name) ? false : true
|
49
|
+
end
|
50
|
+
|
51
|
+
def misses
|
52
|
+
@misses
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
class Project
|
57
|
+
|
58
|
+
attr_reader :teamcity, :name, :id, :href
|
59
|
+
|
60
|
+
def initialize teamcity, name, id, href
|
61
|
+
@teamcity, @name, @id, @href = teamcity, name, id, href
|
62
|
+
end
|
63
|
+
|
64
|
+
def build_types filter = {}
|
65
|
+
including = filter.has_key?(:include) ? IncludeFilter.new(filter.delete(:include)) : IncludeAllFilter.new
|
66
|
+
excluding = filter.has_key?(:exclude) ? ExcludeFilter.new(filter.delete(:exclude)) : ExcludeNoneFilter.new
|
67
|
+
raise "Unsupported filter options #{filter}" unless filter.empty?
|
68
|
+
build_types_for_project = teamcity.build_types.find_all { |bt| bt.project_id == id }
|
69
|
+
filtered_build_types = build_types_for_project.find_all { |bt| including.retain?(bt) && excluding.retain?(bt) }
|
70
|
+
raise "Failed to find a match for build type(s) #{including.misses}" if not including.misses.empty?
|
71
|
+
raise "Failed to find a match for build type(s) #{excluding.misses}" if not excluding.misses.empty?
|
72
|
+
filtered_build_types
|
73
|
+
end
|
74
|
+
|
75
|
+
def latest_builds filter = {}
|
76
|
+
build_types(filter).collect(&:latest_build)
|
10
77
|
end
|
11
78
|
|
12
79
|
def builds
|
@@ -15,25 +82,40 @@ module TeamcityRestClient
|
|
15
82
|
end
|
16
83
|
end
|
17
84
|
|
18
|
-
BuildType = Struct.new(:id, :name, :href, :project_name, :project_id, :web_url)
|
85
|
+
BuildType = Struct.new(:teamcity, :id, :name, :href, :project_name, :project_id, :web_url) do
|
86
|
+
# httpAuth/app/rest/builds?buildType=id:bt107&count=1
|
87
|
+
def latest_build
|
88
|
+
teamcity.builds(:buildType => "id:#{id}", :count => 1)[0]
|
89
|
+
end
|
90
|
+
end
|
19
91
|
|
20
|
-
Build = Struct.new(:id, :number, :status, :build_type_id, :start_date, :href, :web_url) do
|
92
|
+
Build = Struct.new(:teamcity, :id, :number, :status, :build_type_id, :start_date, :href, :web_url) do
|
21
93
|
def success?
|
22
94
|
status == :SUCCESS
|
23
95
|
end
|
24
96
|
end
|
97
|
+
|
98
|
+
class Authentication
|
99
|
+
def query_string_for params
|
100
|
+
pairs = []
|
101
|
+
params.each_pair { |k,v| pairs << "#{k}=#{v}" }
|
102
|
+
pairs.join("&")
|
103
|
+
end
|
104
|
+
end
|
25
105
|
|
26
|
-
class HttpBasicAuthentication
|
106
|
+
class HttpBasicAuthentication < Authentication
|
27
107
|
def initialize host, port, user, password
|
28
108
|
@host, @port, @user, @password = host, port, user, password
|
29
109
|
end
|
30
110
|
|
31
|
-
def get path
|
32
|
-
open(url(path), :http_basic_authentication => [@user, @password]).read
|
111
|
+
def get path, params = {}
|
112
|
+
open(url(path, params), :http_basic_authentication => [@user, @password]).read
|
33
113
|
end
|
34
114
|
|
35
|
-
def url path
|
36
|
-
"
|
115
|
+
def url path, params = {}
|
116
|
+
auth_path = path.start_with?("/httpAuth/") ? path : "/httpAuth#{path}"
|
117
|
+
query_string = !params.empty? ? "?#{query_string_for(params)}" : ""
|
118
|
+
"http://#{@host}:#{@port}#{auth_path}#{query_string}"
|
37
119
|
end
|
38
120
|
|
39
121
|
def to_s
|
@@ -41,17 +123,18 @@ module TeamcityRestClient
|
|
41
123
|
end
|
42
124
|
end
|
43
125
|
|
44
|
-
class Open
|
126
|
+
class Open < Authentication
|
45
127
|
def initialize host, port
|
46
128
|
@host, @port = host, port
|
47
129
|
end
|
48
130
|
|
49
|
-
def get path
|
50
|
-
open(url(path)).read
|
131
|
+
def get path, params = {}
|
132
|
+
open(url(path, params)).read
|
51
133
|
end
|
52
134
|
|
53
|
-
def url path
|
54
|
-
"
|
135
|
+
def url path, params = {}
|
136
|
+
query_string = !params.empty? ? "?#{query_string_for(params)}" : ""
|
137
|
+
"http://#{@host}:#{@port}#{path}#{query_string}"
|
55
138
|
end
|
56
139
|
|
57
140
|
def to_s
|
@@ -61,9 +144,14 @@ module TeamcityRestClient
|
|
61
144
|
end
|
62
145
|
|
63
146
|
class REXML::Element
|
64
|
-
def
|
147
|
+
def av name
|
65
148
|
attribute(name).value
|
66
149
|
end
|
150
|
+
|
151
|
+
def av_or name, otherwise
|
152
|
+
att = attribute(name)
|
153
|
+
att ? att.value : otherwise
|
154
|
+
end
|
67
155
|
end
|
68
156
|
|
69
157
|
class Teamcity
|
@@ -88,24 +176,24 @@ class Teamcity
|
|
88
176
|
|
89
177
|
def projects
|
90
178
|
doc(get('/app/rest/projects')).elements.collect('//project') do |e|
|
91
|
-
TeamcityRestClient::Project.new(self, e.
|
179
|
+
TeamcityRestClient::Project.new(self, e.av("name"), e.av("id"), url(e.av("href")))
|
92
180
|
end
|
93
181
|
end
|
94
182
|
|
95
183
|
def build_types
|
96
184
|
doc(get('/app/rest/buildTypes')).elements.collect('//buildType') do |e|
|
97
|
-
TeamcityRestClient::BuildType.new(e.
|
185
|
+
TeamcityRestClient::BuildType.new(self, e.av("id"), e.av("name"), url(e.av("href")), e.av('projectName'), e.av('projectId'), e.av('webUrl'))
|
98
186
|
end
|
99
187
|
end
|
100
188
|
|
101
|
-
def builds
|
102
|
-
doc(get('/app/rest/builds').gsub(/&buildTypeId/,'&buildTypeId')).elements.collect('//build') do |e|
|
103
|
-
TeamcityRestClient::Build.new(e.
|
189
|
+
def builds options = {}
|
190
|
+
doc(get('/app/rest/builds', options).gsub(/&buildTypeId/,'&buildTypeId')).elements.collect('//build') do |e|
|
191
|
+
TeamcityRestClient::Build.new(self, e.av('id'), e.av('number'), e.av('status').to_sym, e.av('buildTypeId'), e.av_or('startDate', ''), url(e.av('href')), e.av('webUrl'))
|
104
192
|
end
|
105
193
|
end
|
106
194
|
|
107
195
|
def to_s
|
108
|
-
"Teamcity @
|
196
|
+
"Teamcity @ #{url("/")}"
|
109
197
|
end
|
110
198
|
|
111
199
|
private
|
@@ -113,8 +201,8 @@ class Teamcity
|
|
113
201
|
REXML::Document.new string
|
114
202
|
end
|
115
203
|
|
116
|
-
def get path
|
117
|
-
result = @authentication.get(path)
|
204
|
+
def get path, params = {}
|
205
|
+
result = @authentication.get(path, params)
|
118
206
|
raise "Teamcity returned html, perhaps you need to use authentication??" if result =~ /.*<html.*<\/html>.*/im
|
119
207
|
result
|
120
208
|
end
|
@@ -2,18 +2,132 @@ require_relative 'spec_helper'
|
|
2
2
|
|
3
3
|
module TeamcityRestClient
|
4
4
|
|
5
|
+
describe "filters" do
|
6
|
+
before :each do
|
7
|
+
@build_type_a = stub('build type a', :id => "bt1", :name => "a" )
|
8
|
+
@build_type_b = stub('build type b', :id => "bt2", :name => "b" )
|
9
|
+
@build_type_c = stub('build type c', :id => "bt3", :name => "c" )
|
10
|
+
end
|
11
|
+
|
12
|
+
describe IncludeAllFilter do
|
13
|
+
before :each do
|
14
|
+
@filter = IncludeAllFilter.new
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should retain everything and have no misses" do
|
18
|
+
@filter.retain?(@build_type_a).should be_true
|
19
|
+
@filter.retain?(@build_type_b).should be_true
|
20
|
+
@filter.retain?(@build_type_c).should be_true
|
21
|
+
@filter.misses.should be_empty
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe ExcludeNoneFilter do
|
26
|
+
before :each do
|
27
|
+
@filter = ExcludeNoneFilter.new
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should retain everything have no misses" do
|
31
|
+
@filter.retain?(@build_type_a).should be_true
|
32
|
+
@filter.retain?(@build_type_b).should be_true
|
33
|
+
@filter.retain?(@build_type_c).should be_true
|
34
|
+
@filter.misses.should be_empty
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe IncludeFilter do
|
39
|
+
describe "including 1 thing" do
|
40
|
+
before :each do
|
41
|
+
@filter = IncludeFilter.new "a"
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should retain when there is a match by name" do
|
45
|
+
@filter.retain?(@build_type_a).should be_true
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should not retain when there is not a match" do
|
49
|
+
@filter.retain?(@build_type_b).should be_false
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe "include many things" do
|
54
|
+
before :each do
|
55
|
+
@filter = IncludeFilter.new ["a", "bt3", "non-existant"]
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should retain when there is a match by name" do
|
59
|
+
@filter.retain?(@build_type_a).should be_true
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should retain when there is a match by id" do
|
63
|
+
@filter.retain?(@build_type_c).should be_true
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should not retain when there is not a match" do
|
67
|
+
@filter.retain?(@build_type_b).should be_false
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should be able to report things that didnt match" do
|
71
|
+
@filter.retain?(@build_type_a)
|
72
|
+
@filter.misses.should == ["bt3", "non-existant"]
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe ExcludeFilter do
|
78
|
+
describe "excluding 1 thing" do
|
79
|
+
before :each do
|
80
|
+
@filter = ExcludeFilter.new "a"
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should not retain when there is a match by name" do
|
84
|
+
@filter.retain?(@build_type_a).should be_false
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should retain when there is not a match" do
|
88
|
+
@filter.retain?(@build_type_b).should be_true
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe "exclude many things" do
|
93
|
+
before :each do
|
94
|
+
@filter = ExcludeFilter.new ["a", "bt3", "non-existant"]
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should not retain there is a match by name" do
|
98
|
+
@filter.retain?(@build_type_a).should be_false
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should not retain there is a match by id" do
|
102
|
+
@filter.retain?(@build_type_c).should be_false
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should retain when there is not a match" do
|
106
|
+
@filter.retain?(@build_type_b).should be_true
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should be able to report things that didnt match" do
|
110
|
+
@filter.retain?(@build_type_a)
|
111
|
+
@filter.misses.should == ["bt3", "non-existant"]
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
5
117
|
describe Project do
|
6
118
|
before :each do
|
7
119
|
@bt11 = stub('bt11', :id => "bt11", :name => "project1-build1", :project_id => "project1")
|
8
120
|
@bt12 = stub('bt12', :id => "bt12", :name => "project1-build2", :project_id => "project1")
|
121
|
+
@bt13 = stub('bt13', :id => "bt13", :name => "project1-build3", :project_id => "project1")
|
9
122
|
@bt21 = stub('bt21', :id => "bt21", :name => "project2-build1", :project_id => "project2")
|
10
123
|
|
11
124
|
@bt11_1 = stub('bt11_1', :id => "1", :build_type_id => "bt11")
|
12
125
|
@bt11_2 = stub('bt11_2', :id => "2", :build_type_id => "bt11")
|
13
126
|
@bt12_33 = stub('bt12_33', :id => "33", :build_type_id => "bt12")
|
127
|
+
@bt13_44 = stub('bt13_44', :id => "44", :build_type_id => "bt13")
|
14
128
|
@bt21_666 = stub('bt21_666', :id => "666", :build_type_id => "bt21")
|
15
129
|
|
16
|
-
@tc = stub('teamcity', :build_types => [@bt11, @bt12, @bt21], :builds => [@bt11_1, @bt11_2, @bt12_33, @bt21_666])
|
130
|
+
@tc = stub('teamcity', :build_types => [@bt11, @bt12, @bt13, @bt21], :builds => [@bt11_1, @bt11_2, @bt12_33, @bt13_44, @bt21_666])
|
17
131
|
@project1 = Project.new @tc, "Project 1", "project1", "http://www.example.com"
|
18
132
|
end
|
19
133
|
|
@@ -23,17 +137,99 @@ module TeamcityRestClient
|
|
23
137
|
end
|
24
138
|
|
25
139
|
it "should have only those for project 1" do
|
26
|
-
@build_types.should == [@bt11, @bt12]
|
140
|
+
@build_types.should == [@bt11, @bt12, @bt13]
|
27
141
|
end
|
28
142
|
end
|
29
|
-
|
143
|
+
|
144
|
+
describe "asking it for it's build types with filtering" do
|
145
|
+
describe "include" do
|
146
|
+
it "should match by single project name" do
|
147
|
+
@project1.build_types({ :include => "project1-build2" }).should == [@bt12]
|
148
|
+
end
|
149
|
+
it "should match by single project id" do
|
150
|
+
@project1.build_types({ :include => "bt11" }).should == [@bt11]
|
151
|
+
end
|
152
|
+
it "should match by multiple project id and name" do
|
153
|
+
@project1.build_types({ :include => ["bt11","project1-build2"] }).should == [@bt11, @bt12]
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
describe "exclude" do
|
158
|
+
it "should match by single project name" do
|
159
|
+
@project1.build_types({ :exclude => "project1-build2" }).should == [@bt11, @bt13]
|
160
|
+
end
|
161
|
+
it "should match by single project id" do
|
162
|
+
@project1.build_types({ :exclude => "bt11" }).should == [@bt12, @bt13]
|
163
|
+
end
|
164
|
+
it "should match by multiple project id and name" do
|
165
|
+
@project1.build_types({ :exclude => ["bt11","project1-build2"] }).should == [@bt13]
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
describe "include and exclude" do
|
170
|
+
it "should allow both, but its a bit pointless" do
|
171
|
+
@project1.build_types({ :include => ["bt11","project1-build2"], :exclude => ["bt11"]}).should == [@bt12]
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
describe "when an include fails to match as incorrectly typed" do
|
176
|
+
it "should raise exception" do
|
177
|
+
lambda { @project1.build_types({ :include => ["bt11", "nonsense1", "nonsense2"]}) }.should raise_error 'Failed to find a match for build type(s) ["nonsense1", "nonsense2"]'
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
describe "when an exclude fails to match as incorrectly typed" do
|
182
|
+
it "should raise exception" do
|
183
|
+
lambda { @project1.build_types({ :exclude => ["bt11", "nonsense1", "nonsense2"]}) }.should raise_error 'Failed to find a match for build type(s) ["nonsense1", "nonsense2"]'
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
30
188
|
describe "asking it for it's builds" do
|
31
189
|
before :each do
|
32
190
|
@builds = @project1.builds
|
33
191
|
end
|
34
192
|
|
35
193
|
it "should have only builds for project 1" do
|
36
|
-
@builds.should == [@bt11_1, @bt11_2, @bt12_33]
|
194
|
+
@builds.should == [@bt11_1, @bt11_2, @bt12_33, @bt13_44]
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
describe "latest_builds" do
|
199
|
+
before :each do
|
200
|
+
@bt11.stub(:latest_build).and_return(@bt11_2)
|
201
|
+
@bt12.stub(:latest_build).and_return(@bt12_33)
|
202
|
+
@bt13.stub(:latest_build).and_return(@bt13_44)
|
203
|
+
end
|
204
|
+
|
205
|
+
describe "for all builds in project" do
|
206
|
+
before :each do
|
207
|
+
@latest_builds = @project1.latest_builds
|
208
|
+
end
|
209
|
+
|
210
|
+
it "should get latest" do
|
211
|
+
@latest_builds.should == [@bt11_2, @bt12_33, @bt13_44]
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
describe "with an include filter specified" do
|
216
|
+
before :each do
|
217
|
+
@latest_builds = @project1.latest_builds :include => @bt11.id
|
218
|
+
end
|
219
|
+
|
220
|
+
it "should get latest only for that filter" do
|
221
|
+
@latest_builds.should == [@bt11_2]
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
describe "with an exclude filter specified" do
|
226
|
+
before :each do
|
227
|
+
@latest_builds = @project1.latest_builds :exclude => @bt11.id
|
228
|
+
end
|
229
|
+
|
230
|
+
it "should get latest only for that filter" do
|
231
|
+
@latest_builds.should == [@bt12_33, @bt13_44]
|
232
|
+
end
|
37
233
|
end
|
38
234
|
end
|
39
235
|
end
|
@@ -49,12 +245,23 @@ module TeamcityRestClient
|
|
49
245
|
it "should add /httpAuth to path" do
|
50
246
|
@auth.url("/something").should == "http://auth.example.com:2233/httpAuth/something"
|
51
247
|
end
|
248
|
+
|
249
|
+
it "should not add /httpAuth to path when already there" do
|
250
|
+
@auth.url("/httpAuth/something").should == "http://auth.example.com:2233/httpAuth/something"
|
251
|
+
end
|
252
|
+
|
253
|
+
it "should create query string from params" do
|
254
|
+
@auth.url("/overhere", {:id => "1", :name => 'betty'}).should == "http://auth.example.com:2233/httpAuth/overhere?id=1&name=betty"
|
255
|
+
end
|
52
256
|
end
|
53
257
|
|
54
258
|
describe "get" do
|
55
259
|
it "should call open with http basic auth options" do
|
56
|
-
|
57
|
-
|
260
|
+
path, options = "/something", {:id => 1}
|
261
|
+
url = "http://localhost:1324"
|
262
|
+
@auth.should_receive(:url).with(path, options).and_return url
|
263
|
+
@auth.should_receive(:open).with(url, :http_basic_authentication=>[@user, @password]).and_return(@io)
|
264
|
+
@auth.get(path, options)
|
58
265
|
end
|
59
266
|
end
|
60
267
|
end
|
@@ -70,16 +277,40 @@ module TeamcityRestClient
|
|
70
277
|
it "should create valid url" do
|
71
278
|
@auth.url("/something").should == "http://auth.example.com:2233/something"
|
72
279
|
end
|
280
|
+
|
281
|
+
it "should create query string from params" do
|
282
|
+
@auth.url("/overhere", {:id => "2", :name => 'boo'}).should == "http://auth.example.com:2233/overhere?id=2&name=boo"
|
283
|
+
end
|
73
284
|
end
|
74
285
|
|
75
286
|
describe "get" do
|
76
287
|
it "should call open with no auth options" do
|
77
|
-
|
78
|
-
|
288
|
+
path, options = "/something", {:id => 1}
|
289
|
+
url = "http://localhost:1324"
|
290
|
+
@auth.should_receive(:url).with(path, options).and_return url
|
291
|
+
@auth.should_receive(:open).with(url).and_return(@io)
|
292
|
+
@auth.get(path, options)
|
293
|
+
end
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
describe BuildType do
|
298
|
+
before :each do
|
299
|
+
@tc = mock('teamcity')
|
300
|
+
@id, @name, @href, @project_name, @project_id, @web_url = "bt123", "build 123", "project 1", "project1", "http://www.example.com/something"
|
301
|
+
@build_type = BuildType.new @tc, @id, @name, @href, @project_name, @project_id, @web_url
|
302
|
+
end
|
303
|
+
|
304
|
+
describe "latest_build" do
|
305
|
+
before :each do
|
306
|
+
@build = mock('build')
|
307
|
+
@tc.should_receive(:builds).with(:buildType => "id:bt123", :count => 1).and_return [@build]
|
308
|
+
end
|
309
|
+
it "should ask teamcity" do
|
310
|
+
@build_type.latest_build.should == @build
|
79
311
|
end
|
80
312
|
end
|
81
313
|
end
|
82
|
-
|
83
314
|
end
|
84
315
|
|
85
316
|
describe Teamcity do
|
@@ -97,7 +328,7 @@ describe Teamcity do
|
|
97
328
|
@tc = Teamcity.new @host, @port, @user, @password
|
98
329
|
end
|
99
330
|
|
100
|
-
it "should create
|
331
|
+
it "should create HttpBasicAuthentication" do
|
101
332
|
@tc.authentication.should === @authentication
|
102
333
|
end
|
103
334
|
end
|
@@ -162,7 +393,7 @@ describe Teamcity do
|
|
162
393
|
</html>
|
163
394
|
HTML
|
164
395
|
|
165
|
-
@authentication.
|
396
|
+
@authentication.stub(:get).and_return(fail_html)
|
166
397
|
@tc = Teamcity.new @host, @port
|
167
398
|
end
|
168
399
|
|
@@ -173,8 +404,8 @@ HTML
|
|
173
404
|
|
174
405
|
describe "parsing xml feeds" do
|
175
406
|
before :each do
|
176
|
-
@host, @port = "tc.example.com", 1234
|
177
|
-
@authentication = TeamcityRestClient::
|
407
|
+
@host, @port, @user, @password = "tc.example.com", 1234, "user", "password"
|
408
|
+
@authentication = TeamcityRestClient::HttpBasicAuthentication.new @host, @port, @user, @password
|
178
409
|
end
|
179
410
|
|
180
411
|
describe "projects" do
|
@@ -182,13 +413,13 @@ HTML
|
|
182
413
|
xml = <<XML
|
183
414
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
184
415
|
<projects>
|
185
|
-
<project name="Amazon API client" id="project54" href="/app/rest/projects/id:project54"/>
|
186
|
-
<project name="Apache Ant" id="project28" href="/app/rest/projects/id:project28"/>
|
416
|
+
<project name="Amazon API client" id="project54" href="/httpAuth/app/rest/projects/id:project54"/>
|
417
|
+
<project name="Apache Ant" id="project28" href="/httpAuth/app/rest/projects/id:project28"/>
|
187
418
|
</projects>
|
188
419
|
XML
|
189
|
-
@authentication.should_receive(:get).with("/app/rest/projects").and_return(xml)
|
190
|
-
TeamcityRestClient::
|
191
|
-
@tc = Teamcity.new @host, @port
|
420
|
+
@authentication.should_receive(:get).with("/app/rest/projects", {}).and_return(xml)
|
421
|
+
TeamcityRestClient::HttpBasicAuthentication.should_receive(:new).and_return(@authentication)
|
422
|
+
@tc = Teamcity.new @host, @port, @user, @password
|
192
423
|
@projects = @tc.projects
|
193
424
|
end
|
194
425
|
|
@@ -200,14 +431,14 @@ XML
|
|
200
431
|
amazon = @projects[0]
|
201
432
|
amazon.name.should == "Amazon API client"
|
202
433
|
amazon.id.should == "project54"
|
203
|
-
amazon.href.should == "http://tc.example.com:1234/app/rest/projects/id:project54"
|
434
|
+
amazon.href.should == "http://tc.example.com:1234/httpAuth/app/rest/projects/id:project54"
|
204
435
|
end
|
205
436
|
|
206
437
|
it "should have ant project" do
|
207
438
|
ant = @projects[1]
|
208
439
|
ant.name.should == "Apache Ant"
|
209
440
|
ant.id.should == "project28"
|
210
|
-
ant.href.should == "http://tc.example.com:1234/app/rest/projects/id:project28"
|
441
|
+
ant.href.should == "http://tc.example.com:1234/httpAuth/app/rest/projects/id:project28"
|
211
442
|
end
|
212
443
|
end
|
213
444
|
|
@@ -216,15 +447,15 @@ XML
|
|
216
447
|
xml = <<XML
|
217
448
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
218
449
|
<buildTypes>
|
219
|
-
<buildType id="bt297" name="Build" href="/app/rest/buildTypes/id:bt297"
|
450
|
+
<buildType id="bt297" name="Build" href="/httpAuth/app/rest/buildTypes/id:bt297"
|
220
451
|
projectName="Amazon API client" projectId="project54" webUrl="http://teamcity.jetbrains.com/viewType.html?buildTypeId=bt297"/>
|
221
|
-
<buildType id="bt296" name="Download missing jar" href="/app/rest/buildTypes/id:bt296"
|
452
|
+
<buildType id="bt296" name="Download missing jar" href="/httpAuth/app/rest/buildTypes/id:bt296"
|
222
453
|
projectName="Amazon API client" projectId="project54" webUrl="http://teamcity.jetbrains.com/viewType.html?buildTypeId=bt296"/>
|
223
454
|
</buildTypes>
|
224
455
|
XML
|
225
|
-
@authentication.should_receive(:get).with("/app/rest/buildTypes").and_return(xml)
|
226
|
-
TeamcityRestClient::
|
227
|
-
@tc = Teamcity.new @host, @port
|
456
|
+
@authentication.should_receive(:get).with("/app/rest/buildTypes", {}).and_return(xml)
|
457
|
+
TeamcityRestClient::HttpBasicAuthentication.should_receive(:new).and_return(@authentication)
|
458
|
+
@tc = Teamcity.new @host, @port, @user, @password
|
228
459
|
@build_types = @tc.build_types
|
229
460
|
end
|
230
461
|
|
@@ -236,7 +467,7 @@ XML
|
|
236
467
|
bt297 = @build_types[0]
|
237
468
|
bt297.id.should == "bt297"
|
238
469
|
bt297.name.should == "Build"
|
239
|
-
bt297.href.should == "http://tc.example.com:1234/app/rest/buildTypes/id:bt297"
|
470
|
+
bt297.href.should == "http://tc.example.com:1234/httpAuth/app/rest/buildTypes/id:bt297"
|
240
471
|
bt297.project_name.should == "Amazon API client"
|
241
472
|
bt297.project_id.should == "project54"
|
242
473
|
bt297.web_url.should == "http://teamcity.jetbrains.com/viewType.html?buildTypeId=bt297"
|
@@ -246,7 +477,7 @@ XML
|
|
246
477
|
bt296 = @build_types[1]
|
247
478
|
bt296.id.should == "bt296"
|
248
479
|
bt296.name.should == "Download missing jar"
|
249
|
-
bt296.href.should == "http://tc.example.com:1234/app/rest/buildTypes/id:bt296"
|
480
|
+
bt296.href.should == "http://tc.example.com:1234/httpAuth/app/rest/buildTypes/id:bt296"
|
250
481
|
bt296.project_name.should == "Amazon API client"
|
251
482
|
bt296.project_id.should == "project54"
|
252
483
|
bt296.web_url.should == "http://teamcity.jetbrains.com/viewType.html?buildTypeId=bt296"
|
@@ -254,49 +485,104 @@ XML
|
|
254
485
|
end
|
255
486
|
|
256
487
|
describe "builds" do
|
257
|
-
|
258
|
-
|
488
|
+
describe "with options specified" do
|
489
|
+
before :each do
|
490
|
+
xml = <<XML
|
259
491
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
260
492
|
<builds nextHref="/app/rest/builds?count=100&start=100" count="100">
|
261
|
-
|
262
|
-
|
263
|
-
<build id="56262" number="568" status="SUCCESS" buildTypeId="bt213" startDate="20111021T120639+0400" href="/app/rest/builds/id:56262"
|
264
|
-
webUrl="http://teamcity.jetbrains.com/viewLog.html?buildId=56262&buildTypeId=bt213"/>
|
493
|
+
<build id="56264" number="126" status="FAILURE" buildTypeId="bt212" href="/httpAuth/app/rest/builds/id:56264"
|
494
|
+
webUrl="http://teamcity.jetbrains.com/viewLog.html?buildId=56264&buildTypeId=bt212"/>
|
265
495
|
</builds>
|
266
496
|
XML
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
497
|
+
@options = {:buildType => "id:bt212", :count => 1}
|
498
|
+
@authentication.should_receive(:get).with("/app/rest/builds", @options).and_return(xml)
|
499
|
+
TeamcityRestClient::HttpBasicAuthentication.should_receive(:new).and_return(@authentication)
|
500
|
+
@tc = Teamcity.new @host, @port, @user, @password
|
501
|
+
@builds = @tc.builds @options
|
502
|
+
end
|
503
|
+
|
504
|
+
it "should have only 1 build as a result" do
|
505
|
+
@builds.length.should == 1
|
506
|
+
end
|
275
507
|
end
|
276
508
|
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
509
|
+
describe "TeamCity Enterprise 5.1.2" do
|
510
|
+
before :each do
|
511
|
+
xml = <<XML
|
512
|
+
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
513
|
+
<builds nextHref="/app/rest/builds?count=100&start=100" count="100">
|
514
|
+
<build id="56264" number="126" status="FAILURE" buildTypeId="bt212" href="/httpAuth/app/rest/builds/id:56264"
|
515
|
+
webUrl="http://teamcity.jetbrains.com/viewLog.html?buildId=56264&buildTypeId=bt212"/>
|
516
|
+
</builds>
|
517
|
+
XML
|
518
|
+
@authentication.should_receive(:get).with("/app/rest/builds", {}).and_return(xml)
|
519
|
+
TeamcityRestClient::HttpBasicAuthentication.should_receive(:new).and_return(@authentication)
|
520
|
+
@tc = Teamcity.new @host, @port, @user, @password
|
521
|
+
@builds = @tc.builds
|
522
|
+
end
|
523
|
+
|
524
|
+
it "should have 1" do
|
525
|
+
@builds.length.should == 1
|
526
|
+
end
|
527
|
+
|
528
|
+
it "should have build 56264" do
|
529
|
+
build = @builds[0]
|
530
|
+
build.id.should == "56264"
|
531
|
+
build.number.should == "126"
|
532
|
+
build.status.should == :FAILURE
|
533
|
+
build.success?.should == false
|
534
|
+
build.build_type_id.should == "bt212"
|
535
|
+
build.start_date.should == ""
|
536
|
+
build.href.should == "http://tc.example.com:1234/httpAuth/app/rest/builds/id:56264"
|
537
|
+
build.web_url.should == "http://teamcity.jetbrains.com/viewLog.html?buildId=56264&buildTypeId=bt212"
|
538
|
+
end
|
287
539
|
end
|
288
540
|
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
541
|
+
describe "TeamCity Enterprise 6.5.4" do
|
542
|
+
before :each do
|
543
|
+
xml = <<XML
|
544
|
+
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
545
|
+
<builds nextHref="/app/rest/builds?count=100&start=100" count="100">
|
546
|
+
<build id="56264" number="126" status="FAILURE" buildTypeId="bt212" startDate="20111021T123714+0400" href="/app/rest/builds/id:56264"
|
547
|
+
webUrl="http://teamcity.jetbrains.com/viewLog.html?buildId=56264&buildTypeId=bt212"/>
|
548
|
+
<build id="56262" number="568" status="SUCCESS" buildTypeId="bt213" startDate="20111021T120639+0400" href="/app/rest/builds/id:56262"
|
549
|
+
webUrl="http://teamcity.jetbrains.com/viewLog.html?buildId=56262&buildTypeId=bt213"/>
|
550
|
+
</builds>
|
551
|
+
XML
|
552
|
+
@authentication.should_receive(:get).with("/app/rest/builds", {}).and_return(xml)
|
553
|
+
TeamcityRestClient::HttpBasicAuthentication.should_receive(:new).and_return(@authentication)
|
554
|
+
@tc = Teamcity.new @host, @port, @user, @password
|
555
|
+
@builds = @tc.builds
|
556
|
+
end
|
557
|
+
|
558
|
+
it "should have 2" do
|
559
|
+
@builds.length.should == 2
|
560
|
+
end
|
561
|
+
|
562
|
+
it "should have build 56264" do
|
563
|
+
build = @builds[0]
|
564
|
+
build.id.should == "56264"
|
565
|
+
build.number.should == "126"
|
566
|
+
build.status.should == :FAILURE
|
567
|
+
build.success?.should == false
|
568
|
+
build.build_type_id.should == "bt212"
|
569
|
+
build.start_date.should == "20111021T123714+0400"
|
570
|
+
build.href.should == "http://tc.example.com:1234/httpAuth/app/rest/builds/id:56264"
|
571
|
+
build.web_url.should == "http://teamcity.jetbrains.com/viewLog.html?buildId=56264&buildTypeId=bt212"
|
572
|
+
end
|
573
|
+
|
574
|
+
it "should have build 56262" do
|
575
|
+
build = @builds[1]
|
576
|
+
build.id.should == "56262"
|
577
|
+
build.number.should == "568"
|
578
|
+
build.status.should == :SUCCESS
|
579
|
+
build.success?.should == true
|
580
|
+
build.build_type_id.should == "bt213"
|
581
|
+
build.start_date.should == "20111021T120639+0400"
|
582
|
+
build.href.should == "http://tc.example.com:1234/httpAuth/app/rest/builds/id:56262"
|
583
|
+
build.web_url.should == "http://teamcity.jetbrains.com/viewLog.html?buildId=56262&buildTypeId=bt213"
|
584
|
+
end
|
585
|
+
end
|
300
586
|
end
|
301
587
|
end
|
302
588
|
end
|
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "teamcity-rest-client"
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.2.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["simon"]
|
12
|
-
s.date = "2011-10-
|
12
|
+
s.date = "2011-10-27"
|
13
13
|
s.description = "Teamcity rest api client (readonly)"
|
14
14
|
s.email = "simojenki@gmail.com"
|
15
15
|
s.extra_rdoc_files = [
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: teamcity-rest-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-10-
|
12
|
+
date: 2011-10-27 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
16
|
-
requirement: &
|
16
|
+
requirement: &2159724440 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: 2.3.0
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *2159724440
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: bundler
|
27
|
-
requirement: &
|
27
|
+
requirement: &2159723960 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ~>
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: 1.0.0
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *2159723960
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: jeweler
|
38
|
-
requirement: &
|
38
|
+
requirement: &2159723480 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ~>
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: 1.6.4
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *2159723480
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: rcov
|
49
|
-
requirement: &
|
49
|
+
requirement: &2159723000 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,7 +54,7 @@ dependencies:
|
|
54
54
|
version: '0'
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *2159723000
|
58
58
|
description: Teamcity rest api client (readonly)
|
59
59
|
email: simojenki@gmail.com
|
60
60
|
executables: []
|
@@ -94,7 +94,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
94
94
|
version: '0'
|
95
95
|
segments:
|
96
96
|
- 0
|
97
|
-
hash:
|
97
|
+
hash: -677859045905772882
|
98
98
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
99
99
|
none: false
|
100
100
|
requirements:
|