bamboo-client 0.0.1
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/.gitignore +4 -0
- data/.rspec +1 -0
- data/Gemfile +4 -0
- data/LICENSE +20 -0
- data/README +4 -0
- data/Rakefile +12 -0
- data/bamboo-client.gemspec +29 -0
- data/cucumber.yml +2 -0
- data/features/remote.feature +17 -0
- data/features/step_definitions/remote_steps.rb +33 -0
- data/features/support/env.rb +30 -0
- data/lib/bamboo-client.rb +27 -0
- data/lib/bamboo-client/abstract.rb +11 -0
- data/lib/bamboo-client/http.rb +11 -0
- data/lib/bamboo-client/http/abstract.rb +13 -0
- data/lib/bamboo-client/http/json.rb +11 -0
- data/lib/bamboo-client/http/xml.rb +48 -0
- data/lib/bamboo-client/remote.rb +197 -0
- data/lib/bamboo-client/rest.rb +14 -0
- data/lib/bamboo-client/version.rb +5 -0
- data/spec/bamboo-client/client_spec.rb +22 -0
- data/spec/bamboo-client/http/xml_spec.rb +52 -0
- data/spec/bamboo-client/remote_spec.rb +233 -0
- data/spec/bamboo-client/rest_spec.rb +11 -0
- data/spec/fixtures/build.xml +4 -0
- data/spec/fixtures/build_result.xml +21 -0
- data/spec/spec_helper.rb +36 -0
- metadata +177 -0
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010-2011 Jari Bakken
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "bamboo-client/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "bamboo-client"
|
7
|
+
s.version = Bamboo::Client::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Jari Bakken"]
|
10
|
+
s.email = ["jari.bakken@gmail.com"]
|
11
|
+
s.homepage = ""
|
12
|
+
s.summary = %q{Ruby client for Atlassian Bamboo's REST APIs}
|
13
|
+
s.description = %q{Ruby client for Atlassian Bamboo's REST APIs}
|
14
|
+
|
15
|
+
s.rubyforge_project = "bamboo-client"
|
16
|
+
|
17
|
+
s.add_development_dependency "rspec"
|
18
|
+
s.add_development_dependency "cucumber"
|
19
|
+
s.add_development_dependency "simplecov"
|
20
|
+
|
21
|
+
s.add_dependency "rest-client"
|
22
|
+
s.add_dependency "json"
|
23
|
+
s.add_dependency "nokogiri"
|
24
|
+
|
25
|
+
s.files = `git ls-files`.split("\n")
|
26
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
27
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
28
|
+
s.require_paths = ["lib"]
|
29
|
+
end
|
data/cucumber.yml
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
Feature: Bamboo Remote client
|
2
|
+
In order to know more about our build pipeline
|
3
|
+
As a Bamboo user
|
4
|
+
I want to use Bamboo's Remote API
|
5
|
+
|
6
|
+
Background:
|
7
|
+
Given I am using the Remote client
|
8
|
+
And I am logged in
|
9
|
+
|
10
|
+
Scenario: Fetch build names
|
11
|
+
When I fetch all build names
|
12
|
+
Then I should get a list of builds
|
13
|
+
|
14
|
+
Scenario: Fetch a build result
|
15
|
+
When I fetch a build result
|
16
|
+
Then the build result should have a key
|
17
|
+
And the build result should have a state
|
@@ -0,0 +1,33 @@
|
|
1
|
+
Given /^I am using the (Remote|REST) client$/ do |api|
|
2
|
+
use api.downcase
|
3
|
+
end
|
4
|
+
|
5
|
+
Given /^I am logged in$/ do
|
6
|
+
client.login user, password
|
7
|
+
end
|
8
|
+
|
9
|
+
When /^I fetch all build names$/ do
|
10
|
+
@builds = client.builds
|
11
|
+
end
|
12
|
+
|
13
|
+
Then /^I should get a list of builds$/ do
|
14
|
+
@builds.should_not be_empty
|
15
|
+
@builds.each { |e| e.should be_kind_of(Bamboo::Client::Remote::Build) }
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
When /^I fetch a build result$/ do
|
20
|
+
builds = client.builds
|
21
|
+
build_key = builds.first.key
|
22
|
+
|
23
|
+
@build_result = client.latest_build_results(build_key)
|
24
|
+
end
|
25
|
+
|
26
|
+
Then /^the build result should have a key$/ do
|
27
|
+
@build_result.key.should be_kind_of(String)
|
28
|
+
end
|
29
|
+
|
30
|
+
Then /^the build result should have a state$/ do
|
31
|
+
@build_result.state.should be_kind_of(Symbol)
|
32
|
+
end
|
33
|
+
|
@@ -0,0 +1,30 @@
|
|
1
|
+
$:.unshift File.expand_path("../../../lib", __FILE__)
|
2
|
+
require "bamboo-client"
|
3
|
+
|
4
|
+
module BambooClientHelper
|
5
|
+
attr_reader :client
|
6
|
+
|
7
|
+
def use(what)
|
8
|
+
@client = Bamboo::Client.for what, url
|
9
|
+
end
|
10
|
+
|
11
|
+
def url
|
12
|
+
fetch_env 'BAMBOO_URL'
|
13
|
+
end
|
14
|
+
|
15
|
+
def user
|
16
|
+
fetch_env 'BAMBOO_USER'
|
17
|
+
end
|
18
|
+
|
19
|
+
def password
|
20
|
+
fetch_env 'BAMBOO_PASSWORD'
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def fetch_env(var)
|
26
|
+
ENV[var] or raise "#{var} must be set for cucumber tests"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
World(BambooClientHelper)
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require "uri"
|
2
|
+
require "restclient"
|
3
|
+
|
4
|
+
require "bamboo-client/version"
|
5
|
+
require "bamboo-client/http"
|
6
|
+
require "bamboo-client/abstract"
|
7
|
+
require "bamboo-client/rest"
|
8
|
+
require "bamboo-client/remote"
|
9
|
+
|
10
|
+
|
11
|
+
module Bamboo
|
12
|
+
module Client
|
13
|
+
class Error < StandardError; end
|
14
|
+
|
15
|
+
def self.for(sym, url)
|
16
|
+
case sym.to_sym
|
17
|
+
when :rest
|
18
|
+
Rest.new Http::Json.new(url)
|
19
|
+
when :remote, :legacy
|
20
|
+
Remote.new Http::Xml.new(url)
|
21
|
+
else
|
22
|
+
raise ArgumentError, "unknown client #{sym.inspect}"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end # Client
|
27
|
+
end # Bamboo
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
|
3
|
+
module Bamboo
|
4
|
+
module Client
|
5
|
+
module Http
|
6
|
+
class Xml < Abstract
|
7
|
+
class Doc
|
8
|
+
def self.from(str)
|
9
|
+
new(Nokogiri::XML(str))
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(doc)
|
13
|
+
@doc = doc
|
14
|
+
puts doc.to_s if $DEBUG
|
15
|
+
end
|
16
|
+
|
17
|
+
def text_for(css)
|
18
|
+
@doc.css(css).text
|
19
|
+
end
|
20
|
+
|
21
|
+
def objects_for(selector, klass)
|
22
|
+
@doc.css(selector).map { |e| klass.new(e) }
|
23
|
+
end
|
24
|
+
|
25
|
+
def object_for(selector, klass)
|
26
|
+
node = @doc.css(selector).first
|
27
|
+
node or raise Error, "no node matches selector #{selector.inspect}"
|
28
|
+
|
29
|
+
klass.new node
|
30
|
+
end
|
31
|
+
end # Doc
|
32
|
+
|
33
|
+
def post(path, data = {})
|
34
|
+
Doc.from RestClient.post(uri_for(path), data)
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def uri_for(path)
|
40
|
+
u = uri.dup
|
41
|
+
u.path = path
|
42
|
+
|
43
|
+
u.to_s
|
44
|
+
end
|
45
|
+
end # Xml
|
46
|
+
end # Http
|
47
|
+
end # Client
|
48
|
+
end # Bamboo
|
@@ -0,0 +1,197 @@
|
|
1
|
+
module Bamboo
|
2
|
+
module Client
|
3
|
+
|
4
|
+
#
|
5
|
+
# Client for the legacy Bamboo Remote API
|
6
|
+
#
|
7
|
+
# http://confluence.atlassian.com/display/BAMBOO/Bamboo+Remote+API
|
8
|
+
#
|
9
|
+
|
10
|
+
class Remote < Abstract
|
11
|
+
attr_reader :token
|
12
|
+
|
13
|
+
def initialize(http)
|
14
|
+
super
|
15
|
+
@service = "/api/rest"
|
16
|
+
end
|
17
|
+
|
18
|
+
def login(user, pass)
|
19
|
+
doc = post :login,
|
20
|
+
:username => user,
|
21
|
+
:password => pass
|
22
|
+
|
23
|
+
@token = doc.text_for("response auth")
|
24
|
+
end
|
25
|
+
|
26
|
+
def logout
|
27
|
+
post :logout, :token => token
|
28
|
+
@token = nil
|
29
|
+
end
|
30
|
+
|
31
|
+
def update_and_build(build_name)
|
32
|
+
doc = post :updateAndBuild, :buildName => build_name
|
33
|
+
|
34
|
+
doc.text_for "response success"
|
35
|
+
end
|
36
|
+
|
37
|
+
def execute_build(build_key)
|
38
|
+
doc = post :executeBuild,
|
39
|
+
:auth => token,
|
40
|
+
:buildKey => build_key
|
41
|
+
|
42
|
+
doc.text_for "response string"
|
43
|
+
end
|
44
|
+
|
45
|
+
def builds
|
46
|
+
doc = post :listBuildNames, :auth => token
|
47
|
+
|
48
|
+
doc.objects_for "build", Remote::Build
|
49
|
+
end
|
50
|
+
|
51
|
+
def latest_builds_for(user)
|
52
|
+
doc = post :getLatestUserBuilds,
|
53
|
+
:auth => token,
|
54
|
+
:user => user
|
55
|
+
|
56
|
+
doc.objects_for "build", Remote::Build
|
57
|
+
end
|
58
|
+
|
59
|
+
def latest_build_results(build_key)
|
60
|
+
doc = post :getLatestBuildResults,
|
61
|
+
:auth => token,
|
62
|
+
:buildKey => build_key
|
63
|
+
|
64
|
+
doc.object_for "response", Remote::BuildResult
|
65
|
+
end
|
66
|
+
|
67
|
+
def recently_completed_results_for_project(project_key)
|
68
|
+
doc = post :getRecentlyCompletedBuildResultsForProject,
|
69
|
+
:auth => token,
|
70
|
+
:projectKey => project_key
|
71
|
+
|
72
|
+
doc.objects_for "build", Remote::BuildResult
|
73
|
+
end
|
74
|
+
|
75
|
+
def recently_completed_results_for_build(build_key)
|
76
|
+
doc = post :getRecentlyCompletedBuildResultsForBuild,
|
77
|
+
:auth => token,
|
78
|
+
:buildKey => build_key
|
79
|
+
|
80
|
+
doc.objects_for "build", Remote::BuildResult
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
def post(action, data = {})
|
86
|
+
@http.post "#{@service}/#{action}.action", data
|
87
|
+
end
|
88
|
+
|
89
|
+
#
|
90
|
+
# types
|
91
|
+
#
|
92
|
+
|
93
|
+
class Build
|
94
|
+
def initialize(doc)
|
95
|
+
@doc = doc
|
96
|
+
end
|
97
|
+
|
98
|
+
def enabled?
|
99
|
+
@doc['enabled'] == 'true'
|
100
|
+
end
|
101
|
+
|
102
|
+
def name
|
103
|
+
@doc.css("name").text
|
104
|
+
end
|
105
|
+
|
106
|
+
def key
|
107
|
+
@doc.css("key").text
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
class BuildResult
|
112
|
+
def initialize(doc)
|
113
|
+
@doc = doc
|
114
|
+
end
|
115
|
+
|
116
|
+
def key
|
117
|
+
@doc.css("buildKey").text
|
118
|
+
end
|
119
|
+
|
120
|
+
def state
|
121
|
+
@doc.css("buildState").text.downcase.gsub(/ /, '_').to_sym
|
122
|
+
end
|
123
|
+
|
124
|
+
def successful?
|
125
|
+
state == :successful
|
126
|
+
end
|
127
|
+
|
128
|
+
def project_name
|
129
|
+
@doc.css("projectName").text
|
130
|
+
end
|
131
|
+
|
132
|
+
def name
|
133
|
+
@doc.css("buildName").text
|
134
|
+
end
|
135
|
+
|
136
|
+
def number
|
137
|
+
@doc.css("buildNumber").text.to_i
|
138
|
+
end
|
139
|
+
|
140
|
+
def failed_test_count
|
141
|
+
@doc.css("failedTestCount").text.to_i
|
142
|
+
end
|
143
|
+
|
144
|
+
def successful_test_count
|
145
|
+
@doc.css("successfulTestCount").text.to_i
|
146
|
+
end
|
147
|
+
|
148
|
+
def start_time
|
149
|
+
Time.parse @doc.css("buildTime").text
|
150
|
+
rescue ArgumentError
|
151
|
+
nil
|
152
|
+
end
|
153
|
+
|
154
|
+
def end_time
|
155
|
+
Time.parse @doc.css("buildCompletedDate").text
|
156
|
+
rescue ArgumentError
|
157
|
+
nil
|
158
|
+
end
|
159
|
+
|
160
|
+
def duration
|
161
|
+
@doc.css("buildDurationInSeconds").text.to_i
|
162
|
+
end
|
163
|
+
|
164
|
+
def duration_description
|
165
|
+
@doc.css("buildDurationDescription").text
|
166
|
+
end
|
167
|
+
|
168
|
+
def relative_date
|
169
|
+
@doc.css("buildRelativeBuildDate").text
|
170
|
+
end
|
171
|
+
|
172
|
+
def test_summary
|
173
|
+
@doc.css("buildTestSummary").text
|
174
|
+
end
|
175
|
+
|
176
|
+
def reason
|
177
|
+
@doc.css("buildReason").text
|
178
|
+
end
|
179
|
+
|
180
|
+
def commits
|
181
|
+
@doc.css('commits commit').map { |e| Commit.new(e) }
|
182
|
+
end
|
183
|
+
|
184
|
+
class Commit
|
185
|
+
def initialize(doc)
|
186
|
+
@doc = doc
|
187
|
+
end
|
188
|
+
|
189
|
+
def author
|
190
|
+
@doc['author']
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
end
|
195
|
+
end # Remote
|
196
|
+
end # Client
|
197
|
+
end # Bamboo
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require File.expand_path("../../spec_helper", __FILE__)
|
2
|
+
|
3
|
+
module Bamboo
|
4
|
+
describe Client do
|
5
|
+
it "returns a client for the REST API" do
|
6
|
+
client = Client.for :rest, "http://bamboo.com"
|
7
|
+
|
8
|
+
client.should be_kind_of(Client::Rest)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "returns a client for the Remote API" do
|
12
|
+
client = Client.for :remote, "http://bamboo.com"
|
13
|
+
|
14
|
+
client.should be_kind_of(Client::Remote)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "raises ArgumentError if the client is unknown" do
|
18
|
+
lambda { Client.for :foo, "http://foo.com" }.should raise_error(ArgumentError)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require File.expand_path("../../../spec_helper", __FILE__)
|
2
|
+
|
3
|
+
module Bamboo
|
4
|
+
module Client
|
5
|
+
module Http
|
6
|
+
describe Xml do
|
7
|
+
let(:url) { "http://example.com" }
|
8
|
+
let(:xml) { Xml.new(url) }
|
9
|
+
|
10
|
+
|
11
|
+
it "does a POST" do
|
12
|
+
RestClient.should_receive(:post).
|
13
|
+
with("#{url}/", :some => "data").
|
14
|
+
and_return("<foo><bar></bar></foo>")
|
15
|
+
|
16
|
+
doc = xml.post("/", :some => "data")
|
17
|
+
doc.should be_kind_of(Xml::Doc)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe Xml::Doc do
|
22
|
+
let(:wrapped) { mock("nokogiri document") }
|
23
|
+
let(:doc) { Xml::Doc.new(wrapped)}
|
24
|
+
|
25
|
+
it "returns the text of the given CSS selector" do
|
26
|
+
wrapped.should_receive(:css).
|
27
|
+
with("some selector").
|
28
|
+
and_return(mock("node", :text => "bar"))
|
29
|
+
|
30
|
+
doc.text_for("some selector").should == "bar"
|
31
|
+
end
|
32
|
+
|
33
|
+
it "returns an instance of the given class for each node matching the selector" do
|
34
|
+
wrapped.should_receive(:css).with("selector").and_return(['node1', 'node2'])
|
35
|
+
|
36
|
+
objs = doc.objects_for("selector", SpecHelper::Wrapper)
|
37
|
+
|
38
|
+
objs.size.should == 2
|
39
|
+
objs.each { |e| e.should be_instance_of(SpecHelper::Wrapper) }
|
40
|
+
objs.map { |e| e.obj }.should == ['node1', 'node2']
|
41
|
+
end
|
42
|
+
|
43
|
+
it "returns an instance of the given class for the first node matching the selector" do
|
44
|
+
wrapped.should_receive(:css).with("selector").and_return(['node1', 'node2'])
|
45
|
+
obj = doc.object_for("selector", SpecHelper::Wrapper)
|
46
|
+
obj.should be_instance_of(SpecHelper::Wrapper)
|
47
|
+
obj.obj.should == "node1"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,233 @@
|
|
1
|
+
require File.expand_path("../../spec_helper", __FILE__)
|
2
|
+
|
3
|
+
module Bamboo
|
4
|
+
module Client
|
5
|
+
describe Remote do
|
6
|
+
let(:url) { "http://bamboo.example.com" }
|
7
|
+
let(:http) { mock(Http::Xml) }
|
8
|
+
let(:client) { Remote.new(http) }
|
9
|
+
let(:document) { mock(Http::Xml::Doc) }
|
10
|
+
|
11
|
+
context "authorization" do
|
12
|
+
it "logs in" do
|
13
|
+
document.should_receive(:text_for).with("response auth").and_return "token"
|
14
|
+
|
15
|
+
http.should_receive(:post).with(
|
16
|
+
"/api/rest/login.action",
|
17
|
+
:username => "user",
|
18
|
+
:password => "pass"
|
19
|
+
).and_return(document)
|
20
|
+
|
21
|
+
client.login "user", "pass"
|
22
|
+
client.token.should == "token"
|
23
|
+
end
|
24
|
+
|
25
|
+
it "raises an error if no token is set" do
|
26
|
+
lambda { client.builds }.should raise_error
|
27
|
+
end
|
28
|
+
|
29
|
+
it "logs out" do
|
30
|
+
http.should_receive(:post).with(
|
31
|
+
"/api/rest/logout.action",
|
32
|
+
:token => "foo"
|
33
|
+
)
|
34
|
+
|
35
|
+
client.instance_variable_set "@token", "foo"
|
36
|
+
client.logout
|
37
|
+
client.token.should be_nil
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context "API calls" do
|
42
|
+
before { client.stub(:token => "fake-token") }
|
43
|
+
|
44
|
+
it "updates and builds" do
|
45
|
+
document.should_receive(:text_for).with("response success").and_return "true"
|
46
|
+
|
47
|
+
http.should_receive(:post).
|
48
|
+
with("/api/rest/updateAndBuild.action", :buildName => "fake-name").
|
49
|
+
and_return(document)
|
50
|
+
|
51
|
+
client.update_and_build("fake-name").should == "true"
|
52
|
+
end
|
53
|
+
|
54
|
+
it "executes a build" do
|
55
|
+
document.should_receive(:text_for).with("response string").and_return "true"
|
56
|
+
|
57
|
+
http.should_receive(:post).with(
|
58
|
+
"/api/rest/executeBuild.action",
|
59
|
+
:auth => "fake-token",
|
60
|
+
:buildKey => "fake-build-key"
|
61
|
+
).and_return(document)
|
62
|
+
|
63
|
+
client.execute_build("fake-build-key").should == "true"
|
64
|
+
end
|
65
|
+
|
66
|
+
it "fetches a list of builds" do
|
67
|
+
document.should_receive(:objects_for).with("build", Remote::Build).
|
68
|
+
and_return(["some", "objects"])
|
69
|
+
|
70
|
+
http.should_receive(:post).with(
|
71
|
+
"/api/rest/listBuildNames.action",
|
72
|
+
:auth => "fake-token"
|
73
|
+
).and_return(document)
|
74
|
+
|
75
|
+
client.builds.should == ["some", "objects"]
|
76
|
+
end
|
77
|
+
|
78
|
+
it "fetches a list of the latest builds for the given user" do
|
79
|
+
document.should_receive(:objects_for).with("build", Remote::Build).
|
80
|
+
and_return(["some", "objects"])
|
81
|
+
|
82
|
+
user = "fake-user"
|
83
|
+
|
84
|
+
http.should_receive(:post).with(
|
85
|
+
"/api/rest/getLatestUserBuilds.action",
|
86
|
+
:auth => "fake-token",
|
87
|
+
:user => user
|
88
|
+
).and_return(document)
|
89
|
+
|
90
|
+
client.latest_builds_for(user).should == ["some", "objects"]
|
91
|
+
end
|
92
|
+
|
93
|
+
it "fetches the latest build results for a given key" do
|
94
|
+
document.should_receive(:object_for).with("response", Remote::BuildResult).
|
95
|
+
and_return(["some objects"])
|
96
|
+
|
97
|
+
http.should_receive(:post).with(
|
98
|
+
"/api/rest/getLatestBuildResults.action",
|
99
|
+
:auth => "fake-token",
|
100
|
+
:buildKey => "fake-key"
|
101
|
+
).and_return(document)
|
102
|
+
|
103
|
+
client.latest_build_results("fake-key").should == ["some objects"]
|
104
|
+
end
|
105
|
+
|
106
|
+
it "fetches the recently completed build results for a given project" do
|
107
|
+
document.should_receive(:objects_for).with("build", Remote::BuildResult).
|
108
|
+
and_return(%w[some results])
|
109
|
+
|
110
|
+
http.should_receive(:post).with(
|
111
|
+
"/api/rest/getRecentlyCompletedBuildResultsForProject.action",
|
112
|
+
:auth => "fake-token",
|
113
|
+
:projectKey => "fake-project"
|
114
|
+
).and_return(document)
|
115
|
+
|
116
|
+
client.recently_completed_results_for_project("fake-project").should == %w[some results]
|
117
|
+
end
|
118
|
+
|
119
|
+
it "fetches the recently completed build results for a given build key" do
|
120
|
+
document.should_receive(:objects_for).with("build", Remote::BuildResult).
|
121
|
+
and_return(%w[some results])
|
122
|
+
|
123
|
+
http.should_receive(:post).with(
|
124
|
+
"/api/rest/getRecentlyCompletedBuildResultsForBuild.action",
|
125
|
+
:auth => "fake-token",
|
126
|
+
:buildKey => "fake-key"
|
127
|
+
).and_return(document)
|
128
|
+
|
129
|
+
client.recently_completed_results_for_build("fake-key").should == %w[some results]
|
130
|
+
end
|
131
|
+
end # API calls
|
132
|
+
|
133
|
+
describe Remote::Build do
|
134
|
+
let(:build) { Remote::Build.new(xml_fixture("build").css("build").first) }
|
135
|
+
|
136
|
+
it "should know if the build is enabled" do
|
137
|
+
build.should be_enabled
|
138
|
+
end
|
139
|
+
|
140
|
+
it "should know the name of the build" do
|
141
|
+
build.name.should == "Thrift - Default"
|
142
|
+
end
|
143
|
+
|
144
|
+
it "should know the key of the build" do
|
145
|
+
build.key.should == "THRIFT-DEFAULT"
|
146
|
+
end
|
147
|
+
end # Remote::Build
|
148
|
+
|
149
|
+
describe Remote::BuildResult do
|
150
|
+
let(:doc) { xml_fixture("build_result").css("response").first }
|
151
|
+
let(:result) { Remote::BuildResult.new(doc) }
|
152
|
+
|
153
|
+
it "should have a key" do
|
154
|
+
result.key.should == "ADS-DEFAULT"
|
155
|
+
end
|
156
|
+
|
157
|
+
it "should have a state" do
|
158
|
+
result.state.should == :successful
|
159
|
+
end
|
160
|
+
|
161
|
+
it "should know if the build was successful" do
|
162
|
+
result.should be_successful
|
163
|
+
end
|
164
|
+
|
165
|
+
it "should have a project name" do
|
166
|
+
result.project_name.should == "Advert Selection"
|
167
|
+
end
|
168
|
+
|
169
|
+
it "should have a build name" do
|
170
|
+
result.name.should == "DEFAULT"
|
171
|
+
end
|
172
|
+
|
173
|
+
it "should have a build number" do
|
174
|
+
result.number.should == 28
|
175
|
+
end
|
176
|
+
|
177
|
+
it "should have a failed test count" do
|
178
|
+
result.failed_test_count.should == 0
|
179
|
+
end
|
180
|
+
|
181
|
+
it "should have a successful test count" do
|
182
|
+
result.successful_test_count.should == 13
|
183
|
+
end
|
184
|
+
|
185
|
+
it "should have a start time" do
|
186
|
+
result.start_time.should == Time.parse("2011-01-18 09:55:54")
|
187
|
+
end
|
188
|
+
|
189
|
+
it "returns nil if start time can not be parsed" do
|
190
|
+
doc.stub(:css).and_return mock(:text => "foo")
|
191
|
+
result.start_time.should be_nil
|
192
|
+
end
|
193
|
+
|
194
|
+
it "returns nil if start time can not be parsed" do
|
195
|
+
doc.stub(:css).and_return mock(:text => "foo")
|
196
|
+
result.end_time.should be_nil
|
197
|
+
end
|
198
|
+
|
199
|
+
it "should have an end time" do
|
200
|
+
result.end_time.should == Time.parse("2011-01-18T09:56:40+0100")
|
201
|
+
end
|
202
|
+
|
203
|
+
it "should have duration" do
|
204
|
+
result.duration.should == 46
|
205
|
+
end
|
206
|
+
|
207
|
+
it "should have a duration description" do
|
208
|
+
result.duration_description.should == "46 seconds"
|
209
|
+
end
|
210
|
+
|
211
|
+
it "should have a relative date" do
|
212
|
+
result.relative_date.should == "1 day ago"
|
213
|
+
end
|
214
|
+
|
215
|
+
it "should have a test summary" do
|
216
|
+
result.test_summary.should == "13 passed"
|
217
|
+
end
|
218
|
+
|
219
|
+
it "should have a reason" do
|
220
|
+
result.reason.should == "Code has changed"
|
221
|
+
end
|
222
|
+
|
223
|
+
it "should have commits" do
|
224
|
+
commits = result.commits
|
225
|
+
commits.size.should == 2
|
226
|
+
commits.each { |c| c.should be_kind_of Remote::BuildResult::Commit }
|
227
|
+
commits.map { |c| c.author }.should == %w[foo bar]
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
end # describe Remote
|
232
|
+
end # Client
|
233
|
+
end # Bamboo
|
@@ -0,0 +1,21 @@
|
|
1
|
+
<?xml version="1.0"?>
|
2
|
+
<response>
|
3
|
+
<projectName>Advert Selection</projectName>
|
4
|
+
<buildName>DEFAULT</buildName>
|
5
|
+
<buildKey>ADS-DEFAULT</buildKey>
|
6
|
+
<buildState>Successful</buildState>
|
7
|
+
<buildNumber>28</buildNumber>
|
8
|
+
<failedTestCount>0</failedTestCount>
|
9
|
+
<successfulTestCount>13</successfulTestCount>
|
10
|
+
<buildTime>2011-01-18 09:55:54</buildTime>
|
11
|
+
<buildCompletedDate>2011-01-18T09:56:40+0100</buildCompletedDate>
|
12
|
+
<buildDurationInSeconds>46</buildDurationInSeconds>
|
13
|
+
<buildDurationDescription>46 seconds</buildDurationDescription>
|
14
|
+
<buildRelativeBuildDate>1 day ago</buildRelativeBuildDate>
|
15
|
+
<buildTestSummary>13 passed</buildTestSummary>
|
16
|
+
<buildReason>Code has changed</buildReason>
|
17
|
+
<commits>
|
18
|
+
<commit author="foo"/>
|
19
|
+
<commit author="bar"/>
|
20
|
+
</commits>
|
21
|
+
</response>
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
if ENV['COVERAGE']
|
2
|
+
raise "simplecov only works on 1.9" unless RUBY_PLATFORM >= "1.9"
|
3
|
+
require 'simplecov'
|
4
|
+
SimpleCov.start {
|
5
|
+
add_filter "spec/"
|
6
|
+
}
|
7
|
+
end
|
8
|
+
|
9
|
+
$:.unshift File.expand_path("../../lib", __FILE__)
|
10
|
+
require "bamboo-client"
|
11
|
+
|
12
|
+
module Bamboo::Client::SpecHelper
|
13
|
+
def xml_fixture(name)
|
14
|
+
path = File.join fixture_path("#{name}.xml")
|
15
|
+
|
16
|
+
Nokogiri.XML File.read(path)
|
17
|
+
end
|
18
|
+
|
19
|
+
def fixture_path(file)
|
20
|
+
dir = File.expand_path("../fixtures", __FILE__)
|
21
|
+
|
22
|
+
File.join dir, file
|
23
|
+
end
|
24
|
+
|
25
|
+
class Wrapper
|
26
|
+
attr_reader :obj
|
27
|
+
|
28
|
+
def initialize(obj)
|
29
|
+
@obj = obj
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
RSpec.configure do |c|
|
35
|
+
c.include Bamboo::Client::SpecHelper
|
36
|
+
end
|
metadata
ADDED
@@ -0,0 +1,177 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bamboo-client
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
version: 0.0.1
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Jari Bakken
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2011-01-19 00:00:00 +01:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: rspec
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
segments:
|
29
|
+
- 0
|
30
|
+
version: "0"
|
31
|
+
type: :development
|
32
|
+
version_requirements: *id001
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: cucumber
|
35
|
+
prerelease: false
|
36
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
37
|
+
none: false
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
segments:
|
42
|
+
- 0
|
43
|
+
version: "0"
|
44
|
+
type: :development
|
45
|
+
version_requirements: *id002
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: simplecov
|
48
|
+
prerelease: false
|
49
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
segments:
|
55
|
+
- 0
|
56
|
+
version: "0"
|
57
|
+
type: :development
|
58
|
+
version_requirements: *id003
|
59
|
+
- !ruby/object:Gem::Dependency
|
60
|
+
name: rest-client
|
61
|
+
prerelease: false
|
62
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
63
|
+
none: false
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
segments:
|
68
|
+
- 0
|
69
|
+
version: "0"
|
70
|
+
type: :runtime
|
71
|
+
version_requirements: *id004
|
72
|
+
- !ruby/object:Gem::Dependency
|
73
|
+
name: json
|
74
|
+
prerelease: false
|
75
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
76
|
+
none: false
|
77
|
+
requirements:
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
segments:
|
81
|
+
- 0
|
82
|
+
version: "0"
|
83
|
+
type: :runtime
|
84
|
+
version_requirements: *id005
|
85
|
+
- !ruby/object:Gem::Dependency
|
86
|
+
name: nokogiri
|
87
|
+
prerelease: false
|
88
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ">="
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
segments:
|
94
|
+
- 0
|
95
|
+
version: "0"
|
96
|
+
type: :runtime
|
97
|
+
version_requirements: *id006
|
98
|
+
description: Ruby client for Atlassian Bamboo's REST APIs
|
99
|
+
email:
|
100
|
+
- jari.bakken@gmail.com
|
101
|
+
executables: []
|
102
|
+
|
103
|
+
extensions: []
|
104
|
+
|
105
|
+
extra_rdoc_files: []
|
106
|
+
|
107
|
+
files:
|
108
|
+
- .gitignore
|
109
|
+
- .rspec
|
110
|
+
- Gemfile
|
111
|
+
- LICENSE
|
112
|
+
- README
|
113
|
+
- Rakefile
|
114
|
+
- bamboo-client.gemspec
|
115
|
+
- cucumber.yml
|
116
|
+
- features/remote.feature
|
117
|
+
- features/step_definitions/remote_steps.rb
|
118
|
+
- features/support/env.rb
|
119
|
+
- lib/bamboo-client.rb
|
120
|
+
- lib/bamboo-client/abstract.rb
|
121
|
+
- lib/bamboo-client/http.rb
|
122
|
+
- lib/bamboo-client/http/abstract.rb
|
123
|
+
- lib/bamboo-client/http/json.rb
|
124
|
+
- lib/bamboo-client/http/xml.rb
|
125
|
+
- lib/bamboo-client/remote.rb
|
126
|
+
- lib/bamboo-client/rest.rb
|
127
|
+
- lib/bamboo-client/version.rb
|
128
|
+
- spec/bamboo-client/client_spec.rb
|
129
|
+
- spec/bamboo-client/http/xml_spec.rb
|
130
|
+
- spec/bamboo-client/remote_spec.rb
|
131
|
+
- spec/bamboo-client/rest_spec.rb
|
132
|
+
- spec/fixtures/build.xml
|
133
|
+
- spec/fixtures/build_result.xml
|
134
|
+
- spec/spec_helper.rb
|
135
|
+
has_rdoc: true
|
136
|
+
homepage: ""
|
137
|
+
licenses: []
|
138
|
+
|
139
|
+
post_install_message:
|
140
|
+
rdoc_options: []
|
141
|
+
|
142
|
+
require_paths:
|
143
|
+
- lib
|
144
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
145
|
+
none: false
|
146
|
+
requirements:
|
147
|
+
- - ">="
|
148
|
+
- !ruby/object:Gem::Version
|
149
|
+
segments:
|
150
|
+
- 0
|
151
|
+
version: "0"
|
152
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
153
|
+
none: false
|
154
|
+
requirements:
|
155
|
+
- - ">="
|
156
|
+
- !ruby/object:Gem::Version
|
157
|
+
segments:
|
158
|
+
- 0
|
159
|
+
version: "0"
|
160
|
+
requirements: []
|
161
|
+
|
162
|
+
rubyforge_project: bamboo-client
|
163
|
+
rubygems_version: 1.3.7
|
164
|
+
signing_key:
|
165
|
+
specification_version: 3
|
166
|
+
summary: Ruby client for Atlassian Bamboo's REST APIs
|
167
|
+
test_files:
|
168
|
+
- features/remote.feature
|
169
|
+
- features/step_definitions/remote_steps.rb
|
170
|
+
- features/support/env.rb
|
171
|
+
- spec/bamboo-client/client_spec.rb
|
172
|
+
- spec/bamboo-client/http/xml_spec.rb
|
173
|
+
- spec/bamboo-client/remote_spec.rb
|
174
|
+
- spec/bamboo-client/rest_spec.rb
|
175
|
+
- spec/fixtures/build.xml
|
176
|
+
- spec/fixtures/build_result.xml
|
177
|
+
- spec/spec_helper.rb
|