hudson-remote-api 0.5.0 → 0.6.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/README +22 -0
- data/VERSION +1 -1
- data/hudson-remote-api.gemspec +2 -2
- data/lib/hudson-remote-api.rb +15 -14
- data/lib/hudson-remote-api/config.rb +1 -1
- data/lib/hudson-remote-api/job.rb +135 -79
- data/test/test_hudson_config.rb +8 -1
- data/test/test_hudson_job.rb +34 -0
- metadata +2 -2
data/README
CHANGED
@@ -12,6 +12,9 @@ Hudson[:url] = 'http://localhost:8080'
|
|
12
12
|
Hudson[:user] = 'hudson'
|
13
13
|
Hudson[:password] = 'password'
|
14
14
|
|
15
|
+
# To turn off checking for crumbIssuer
|
16
|
+
Hudson[:crumb] = false
|
17
|
+
|
15
18
|
# List all Hudson jobs
|
16
19
|
Hudson::Job.list
|
17
20
|
|
@@ -26,3 +29,22 @@ puts j.last_build
|
|
26
29
|
j.repository_url = { :url => 'https://github.com/beeplove/hudson-remote-api-mkhan.git', :branch => 'origin/master' }
|
27
30
|
# or, only to change branch
|
28
31
|
j.repository_url = { :branch => 'origin/master' }
|
32
|
+
|
33
|
+
# Set build trigger
|
34
|
+
j.triggers = { 'hudson.triggers.SCMTrigger' => '* * * * *'}
|
35
|
+
# or, using shortcut
|
36
|
+
j.triggers = { 'SCMTrigger' => '* * * * *', 'TimerTrigger' => '0 22 * * *'}
|
37
|
+
|
38
|
+
# To add or update a trigger in existing triggers
|
39
|
+
j.triggers = j.triggers.merge({ 'hudson.triggers.TimerTrigger' => '0 22 * * *'})
|
40
|
+
# Avoid using shortcut form when to edit a trigger in existing triggers
|
41
|
+
|
42
|
+
# To delete existing triggers
|
43
|
+
j.triggers = {}
|
44
|
+
# or,
|
45
|
+
j.triggers = nil
|
46
|
+
|
47
|
+
# To view current trigger
|
48
|
+
j.triggers
|
49
|
+
# would return hash containing trigger name in key and trigger spec in value.
|
50
|
+
# Example of returned hash: {"hudson.triggers.TimerTrigger"=>"0 22 * * *", "hudson.triggers.SCMTrigger"=>"* * * * *"}
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.6.0
|
data/hudson-remote-api.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "hudson-remote-api"
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.6.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Dru Ibarra"]
|
12
|
-
s.date = "2012-
|
12
|
+
s.date = "2012-07-14"
|
13
13
|
s.description = "Connect to Hudson's remote web API"
|
14
14
|
s.email = "Druwerd@gmail.com"
|
15
15
|
s.extra_rdoc_files = [
|
data/lib/hudson-remote-api.rb
CHANGED
@@ -105,24 +105,25 @@ module Hudson
|
|
105
105
|
end
|
106
106
|
|
107
107
|
def self.fetch_crumb
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
108
|
+
if Hudson[:crumb]
|
109
|
+
body = get_xml(url_for '/crumbIssuer/api/xml')
|
110
|
+
doc = REXML::Document.new(body)
|
111
|
+
|
112
|
+
crumbValue = doc.elements['/defaultCrumbIssuer/crumb'] or begin
|
113
|
+
$stderr.puts "Failure fetching crumb value from server"
|
114
|
+
return
|
115
|
+
end
|
116
|
+
|
117
|
+
crumbName = doc.elements['/defaultCrumbIssuer/crumbRequestField'] or begin
|
118
|
+
$stderr.puts "Failure fetching crumb field name from server"
|
119
|
+
return
|
120
|
+
end
|
121
|
+
|
122
|
+
@@apiCrumb = Struct.new(:name,:value).new(crumbName.text,crumbValue.text)
|
119
123
|
end
|
120
|
-
|
121
|
-
@@apiCrumb = Struct.new(:name,:value).new(crumbName.text,crumbValue.text)
|
122
124
|
rescue
|
123
125
|
$stderr.puts "Failure fetching crumb xml"
|
124
126
|
end
|
125
|
-
|
126
127
|
end
|
127
128
|
end
|
128
129
|
|
@@ -2,7 +2,7 @@ require File.dirname(__FILE__) + '/multicast.rb'
|
|
2
2
|
|
3
3
|
module Hudson
|
4
4
|
# set default settings
|
5
|
-
@@settings = {:url => 'http://localhost:8080', :user => nil, :password => nil, :version => nil}
|
5
|
+
@@settings = {:url => 'http://localhost:8080', :user => nil, :password => nil, :version => nil, :crumb => true}
|
6
6
|
|
7
7
|
def self.[](param)
|
8
8
|
return @@settings[param]
|
@@ -1,10 +1,7 @@
|
|
1
1
|
module Hudson
|
2
2
|
# This class provides an interface to Hudson jobs
|
3
3
|
class Job < HudsonObject
|
4
|
-
|
5
4
|
attr_accessor :name, :config, :repository_url, :repository_urls, :repository_browser_location, :description
|
6
|
-
attr_reader :color, :last_build, :last_completed_build, :last_failed_build, :last_stable_build, :last_successful_build, :last_unsuccessful_build, :next_build_number
|
7
|
-
attr_reader :builds_list
|
8
5
|
|
9
6
|
SVN_SCM_CONF = <<-SVN_SCM_STRING
|
10
7
|
<scm class="hudson.scm.SubversionSCM">
|
@@ -23,59 +20,58 @@ SVN_SCM_CONF = <<-SVN_SCM_STRING
|
|
23
20
|
</scm>
|
24
21
|
SVN_SCM_STRING
|
25
22
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
job_name
|
55
|
-
|
56
|
-
Job.new(job_name)
|
57
|
-
else
|
58
|
-
nil
|
23
|
+
# Class methods
|
24
|
+
class <<self
|
25
|
+
# List all Hudson jobs
|
26
|
+
def list()
|
27
|
+
xml = get_xml(@@hudson_xml_api_path)
|
28
|
+
|
29
|
+
jobs = []
|
30
|
+
jobs_doc = REXML::Document.new(xml)
|
31
|
+
jobs_doc.each_element("hudson/job") do |job|
|
32
|
+
jobs << job.elements["name"].text
|
33
|
+
end
|
34
|
+
jobs
|
35
|
+
end
|
36
|
+
|
37
|
+
# List all jobs in active execution
|
38
|
+
def list_active
|
39
|
+
xml = get_xml(@@hudson_xml_api_path)
|
40
|
+
|
41
|
+
active_jobs = []
|
42
|
+
jobs_doc = REXML::Document.new(xml)
|
43
|
+
jobs_doc.each_element("hudson/job") do |job|
|
44
|
+
if job.elements["color"].text.include?("anime")
|
45
|
+
active_jobs << job.elements["name"].text
|
46
|
+
end
|
47
|
+
end
|
48
|
+
active_jobs
|
49
|
+
end
|
50
|
+
|
51
|
+
def get(job_name)
|
52
|
+
job_name.strip!
|
53
|
+
list.include?(job_name) ? Job.new(job_name) : nil
|
59
54
|
end
|
55
|
+
|
56
|
+
def create(name, config=nil)
|
57
|
+
config ||= File.open(File.dirname(__FILE__) + '/new_job_config.xml').read
|
58
|
+
|
59
|
+
response = send_post_request(@@xml_api_create_item_path, {:name=>name, :mode=>"hudson.model.FreeStyleProject", :config=>config})
|
60
|
+
raise(APIError, "Error creating job #{name}: #{response.body}") if response.class != Net::HTTPFound
|
61
|
+
Job.get(name)
|
62
|
+
end
|
63
|
+
|
60
64
|
end
|
61
|
-
|
65
|
+
|
66
|
+
# Instance methods
|
62
67
|
def initialize(name, config=nil)
|
63
68
|
name.strip!
|
64
69
|
Hudson::Job.fetch_crumb
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
self
|
71
|
-
else
|
72
|
-
j = Job.create(name, config)
|
73
|
-
@name = j.name
|
74
|
-
load_xml_api
|
75
|
-
load_config
|
76
|
-
load_info
|
77
|
-
self
|
78
|
-
end
|
70
|
+
# Creates the job in Hudson if it doesn't already exist
|
71
|
+
@name = Job.list.include?(name) ? name : Job.create(name, config).name
|
72
|
+
load_xml_api
|
73
|
+
load_config
|
74
|
+
self
|
79
75
|
end
|
80
76
|
|
81
77
|
def load_xml_api
|
@@ -92,6 +88,9 @@ SVN_SCM_STRING
|
|
92
88
|
def load_config
|
93
89
|
@config = get_xml(@xml_api_config_path)
|
94
90
|
@config_doc = REXML::Document.new(@config)
|
91
|
+
|
92
|
+
@info = get_xml(@xml_api_path)
|
93
|
+
@info_doc = REXML::Document.new(@info)
|
95
94
|
|
96
95
|
@repository_urls = []
|
97
96
|
if @config_doc.elements["/project/description"]
|
@@ -123,25 +122,46 @@ SVN_SCM_STRING
|
|
123
122
|
end
|
124
123
|
end
|
125
124
|
|
126
|
-
def
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
125
|
+
def free_style_project?
|
126
|
+
!@info_doc.elements["/freeStyleProject"].nil?
|
127
|
+
end
|
128
|
+
|
129
|
+
def color
|
130
|
+
@info_doc.elements["/freeStyleProject/color"].text if free_style_project? && @info_doc.elements["/freeStyleProject/color"]
|
131
|
+
end
|
132
|
+
|
133
|
+
def last_build
|
134
|
+
@info_doc.elements["/freeStyleProject/lastBuild/number"].text if free_style_project? && @info_doc.elements["/freeStyleProject/lastBuild/number"]
|
135
|
+
end
|
136
|
+
|
137
|
+
def last_completed_build
|
138
|
+
@info_doc.elements["/freeStyleProject/lastCompletedBuild/number"].text if free_style_project? && @info_doc.elements["/freeStyleProject/lastCompletedBuild/number"]
|
139
|
+
end
|
140
|
+
|
141
|
+
def last_failed_build
|
142
|
+
@info_doc.elements["/freeStyleProject/lastFailedBuild/number"].text if free_style_project? && @info_doc.elements["/freeStyleProject/lastFailedBuild/number"]
|
143
|
+
end
|
144
|
+
|
145
|
+
def last_stable_build
|
146
|
+
@info_doc.elements["/freeStyleProject/lastStableBuild/number"].text if free_style_project? && @info_doc.elements["/freeStyleProject/lastStableBuild/number"]
|
147
|
+
end
|
148
|
+
|
149
|
+
def last_successful_build
|
150
|
+
@info_doc.elements["/freeStyleProject/lastSuccessfulBuild/number"].text if free_style_project? && @info_doc.elements["/freeStyleProject/lastSuccessfulBuild/number"]
|
151
|
+
end
|
152
|
+
|
153
|
+
def last_unsuccessful_build
|
154
|
+
@info_doc.elements["/freeStyleProject/lastUnsuccessfulBuild/number"].text if free_style_project? && @info_doc.elements["/freeStyleProject/lastUnsuccessfulBuild/number"]
|
155
|
+
end
|
156
|
+
|
157
|
+
def next_build_number
|
158
|
+
@info_doc.elements["/freeStyleProject/nextBuildNumber"].text if free_style_project? && @info_doc.elements["/freeStyleProject/nextBuildNumber"]
|
159
|
+
end
|
160
|
+
|
161
|
+
def builds_list
|
162
|
+
builds_list = []
|
163
|
+
@info_doc.elements.each("/freeStyleProject/build"){|e| builds_list << e.elements["number"].text } unless @info_doc.elements["/freeStyleProject/build"].nil?
|
164
|
+
builds_list
|
145
165
|
end
|
146
166
|
|
147
167
|
def active?
|
@@ -156,14 +176,6 @@ SVN_SCM_STRING
|
|
156
176
|
end
|
157
177
|
end
|
158
178
|
|
159
|
-
def self.create(name, config=nil)
|
160
|
-
config = File.open(File.dirname(__FILE__) + '/new_job_config.xml').read if config.nil?
|
161
|
-
|
162
|
-
response = send_post_request(@@xml_api_create_item_path, {:name=>name, :mode=>"hudson.model.FreeStyleProject", :config=>config})
|
163
|
-
raise(APIError, "Error creating job #{name}: #{response.body}") if response.class != Net::HTTPFound
|
164
|
-
Job.get(name)
|
165
|
-
end
|
166
|
-
|
167
179
|
# Create a new job on Hudson server based on the current job object
|
168
180
|
def copy(new_job=nil)
|
169
181
|
new_job = "copy_of_#{@name}" if new_job.nil?
|
@@ -202,7 +214,6 @@ SVN_SCM_STRING
|
|
202
214
|
end
|
203
215
|
|
204
216
|
@config = @config_doc.to_s
|
205
|
-
|
206
217
|
update
|
207
218
|
end
|
208
219
|
|
@@ -242,6 +253,51 @@ SVN_SCM_STRING
|
|
242
253
|
update
|
243
254
|
end
|
244
255
|
|
256
|
+
def generate_trigger trigger, spec_text
|
257
|
+
spec = REXML::Element.new("spec")
|
258
|
+
spec.text = spec_text.to_s
|
259
|
+
trigger.elements << spec
|
260
|
+
trigger
|
261
|
+
end
|
262
|
+
private :generate_trigger
|
263
|
+
|
264
|
+
def triggers= opts={}
|
265
|
+
opts = {} if opts.nil?
|
266
|
+
if triggers = @config_doc.elements["/project/triggers[@class='vector']"]
|
267
|
+
triggers.elements.delete_all '*'
|
268
|
+
opts.each do |key, value|
|
269
|
+
trigger_name = key.to_s
|
270
|
+
trigger_name = 'hudson.triggers.' + trigger_name unless Regexp.new(/^hudson\.triggers\./).match(trigger_name)
|
271
|
+
if trigger = triggers.elements[trigger_name]
|
272
|
+
if spec = trigger.elements['spec']
|
273
|
+
spec.text = value.to_s
|
274
|
+
else
|
275
|
+
triggers.elements << generate_trigger(trigger, value)
|
276
|
+
end
|
277
|
+
else
|
278
|
+
triggers.elements << generate_trigger(REXML::Element.new(trigger_name), value)
|
279
|
+
end
|
280
|
+
end
|
281
|
+
# Todo: before calling update, @config need to be assigned with @config_doc.to_s,
|
282
|
+
# let it be done by update.
|
283
|
+
@config = @config_doc.to_s
|
284
|
+
update
|
285
|
+
else
|
286
|
+
$stderr.puts "triggers not found in configuration, triggers assignment ignored."
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
def triggers
|
291
|
+
results = {}
|
292
|
+
if triggers = @config_doc.elements["/project/triggers[@class='vector']"]
|
293
|
+
triggers.elements.to_a.each do |trigger|
|
294
|
+
spec_text = trigger.elements['spec'].text
|
295
|
+
results[trigger.name.to_s] = spec_text.to_s
|
296
|
+
end
|
297
|
+
end
|
298
|
+
results
|
299
|
+
end
|
300
|
+
|
245
301
|
def url
|
246
302
|
File.join( Hudson[:url], 'job', name) + '/'
|
247
303
|
end
|
data/test/test_hudson_config.rb
CHANGED
@@ -21,10 +21,17 @@ class TestHudsonConfig < Test::Unit::TestCase
|
|
21
21
|
assert_equal(Hudson[:user], "test")
|
22
22
|
assert_equal(Hudson[:password], "test")
|
23
23
|
assert_equal(Hudson[:version], "1.00")
|
24
|
+
assert_equal(Hudson[:crumb], true)
|
24
25
|
end
|
25
26
|
|
26
27
|
def test_auto_config
|
27
28
|
assert_nothing_thrown{ Hudson.auto_config }
|
28
29
|
end
|
30
|
+
|
31
|
+
def test_when_crumb_is_false
|
32
|
+
new_settings = {:url => 'test.com', :user => 'test', :password => 'test', :version => '1.00', :crumb => false}
|
33
|
+
Hudson.settings = new_settings
|
34
|
+
assert_equal(Hudson[:crumb], false)
|
35
|
+
end
|
29
36
|
|
30
|
-
end
|
37
|
+
end
|
data/test/test_hudson_job.rb
CHANGED
@@ -22,6 +22,7 @@ class TestHudsonJob < Test::Unit::TestCase
|
|
22
22
|
new_job = Hudson::Job.create(new_job_name)
|
23
23
|
assert new_job
|
24
24
|
assert_equal(new_job.name, new_job_name)
|
25
|
+
assert_equal(true, new_job.triggers.empty?, "New job should have empty triggers")
|
25
26
|
assert new_job.delete
|
26
27
|
end
|
27
28
|
|
@@ -81,4 +82,37 @@ class TestHudsonJob < Test::Unit::TestCase
|
|
81
82
|
job = Hudson::Job.get("test_job")
|
82
83
|
assert job.builds_list.kind_of?(Array)
|
83
84
|
end
|
85
|
+
|
86
|
+
def test_triggers_set
|
87
|
+
job_name = 'build_triggers'
|
88
|
+
job = Hudson::Job.create(job_name)
|
89
|
+
|
90
|
+
job.triggers = { "hudson.triggers.SCMTrigger" => '* * * * *' }
|
91
|
+
assert_equal(1, job.triggers.size, "Failed to set triggers with 1 trigger.")
|
92
|
+
assert_equal({"hudson.triggers.SCMTrigger" => '* * * * *'}, job.triggers, "Failed to set triggers with 1 trigger.")
|
93
|
+
|
94
|
+
assert job.delete
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_triggers_set_using_shortcut
|
98
|
+
job_name = 'build_triggers'
|
99
|
+
job = Hudson::Job.create(job_name)
|
100
|
+
|
101
|
+
job.triggers = { "SCMTrigger" => '* * * * *', 'TimerTrigger' => '0 22 * * *' }
|
102
|
+
assert_equal(2, job.triggers.size, "Failed to set triggers using shortcut.")
|
103
|
+
assert_equal({"hudson.triggers.SCMTrigger"=>"* * * * *", "hudson.triggers.TimerTrigger"=>"0 22 * * *"}, job.triggers, "Failed to set triggers using shortcut.")
|
104
|
+
|
105
|
+
assert job.delete
|
106
|
+
end
|
107
|
+
|
108
|
+
def test_triggers_delete
|
109
|
+
job_name = 'build_triggers'
|
110
|
+
job = Hudson::Job.create(job_name)
|
111
|
+
|
112
|
+
job.triggers = { "SCMTrigger" => '* * * * *', 'TimerTrigger' => '0 22 * * *' }
|
113
|
+
job.triggers = {}
|
114
|
+
assert_equal(true, job.triggers.empty?, "Failed to delete triggers.")
|
115
|
+
|
116
|
+
assert job.delete
|
117
|
+
end
|
84
118
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hudson-remote-api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-07-14 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: Connect to Hudson's remote web API
|
15
15
|
email: Druwerd@gmail.com
|