hudson-remote-api 0.7.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +4 -0
- data/Gemfile +9 -0
- data/Gemfile.lock +20 -0
- data/README.md +11 -9
- data/Rakefile +10 -0
- data/fixtures/vcr_cassettes/TestHudsonBuildQueue_test_list.yml +38 -0
- data/fixtures/vcr_cassettes/TestHudsonBuild_setup.yml +407 -0
- data/fixtures/vcr_cassettes/TestHudsonBuild_test_build_info.yml +222 -0
- data/fixtures/vcr_cassettes/TestHudsonClient_test_build_job_.yml +52 -0
- data/fixtures/vcr_cassettes/TestHudsonClient_test_build_job_with_parameters_.yml +52 -0
- data/fixtures/vcr_cassettes/TestHudsonClient_test_build_queue_info.yml +38 -0
- data/fixtures/vcr_cassettes/TestHudsonClient_test_create_item_.yml +52 -0
- data/fixtures/vcr_cassettes/TestHudsonClient_test_delete_job_.yml +52 -0
- data/fixtures/vcr_cassettes/TestHudsonClient_test_job_build_info.yml +39 -0
- data/fixtures/vcr_cassettes/TestHudsonClient_test_job_config_info.yml +48 -0
- data/fixtures/vcr_cassettes/TestHudsonJob_test_build.yml +409 -0
- data/fixtures/vcr_cassettes/TestHudsonJob_test_build_with_params.yml +189 -0
- data/fixtures/vcr_cassettes/TestHudsonJob_test_builds_list.yml +192 -0
- data/fixtures/vcr_cassettes/TestHudsonJob_test_copy.yml +410 -0
- data/fixtures/vcr_cassettes/TestHudsonJob_test_create.yml +257 -0
- data/fixtures/vcr_cassettes/TestHudsonJob_test_desc_update.yml +281 -0
- data/fixtures/vcr_cassettes/TestHudsonJob_test_get.yml +191 -0
- data/fixtures/vcr_cassettes/TestHudsonJob_test_job_with_spaces.yml +260 -0
- data/fixtures/vcr_cassettes/TestHudsonJob_test_list.yml +39 -0
- data/fixtures/vcr_cassettes/TestHudsonJob_test_list_active.yml +39 -0
- data/fixtures/vcr_cassettes/TestHudsonJob_test_new.yml +561 -0
- data/fixtures/vcr_cassettes/TestHudsonJob_test_scm_url.yml +728 -0
- data/fixtures/vcr_cassettes/TestHudsonJob_test_triggers_delete.yml +588 -0
- data/fixtures/vcr_cassettes/TestHudsonJob_test_triggers_set.yml +346 -0
- data/fixtures/vcr_cassettes/TestHudsonJob_test_triggers_set_using_shortcut.yml +346 -0
- data/fixtures/vcr_cassettes/TestHudsonJob_test_url.yml +156 -0
- data/fixtures/vcr_cassettes/TestHudsonJob_test_wipe_out_workspace.yml +685 -0
- data/hudson-remote-api.gemspec +23 -0
- data/lib/hudson-remote-api.rb +3 -128
- data/lib/hudson-remote-api/build.rb +18 -35
- data/lib/hudson-remote-api/build_queue.rb +13 -20
- data/lib/hudson-remote-api/client.rb +179 -0
- data/lib/hudson-remote-api/hudson_xml_api.rb +61 -0
- data/lib/hudson-remote-api/job.rb +207 -345
- data/lib/hudson-remote-api/parser/build_info.rb +37 -0
- data/lib/hudson-remote-api/parser/build_queue_info.rb +19 -0
- data/lib/hudson-remote-api/parser/job_config_info.rb +99 -0
- data/lib/hudson-remote-api/parser/job_info.rb +62 -0
- data/lib/hudson-remote-api/parser/multicast.rb +28 -0
- data/lib/hudson-remote-api/parser/server_info.rb +49 -0
- data/lib/hudson-remote-api/settings.rb +31 -0
- data/lib/hudson-remote-api/version.rb +3 -0
- data/lib/hudson-remote-api/xml_writer/job_config_info.rb +113 -0
- data/test/test_helper.rb +10 -0
- data/test/test_hudson_build.rb +28 -0
- data/test/test_hudson_build_queue.rb +11 -0
- data/test/test_hudson_client.rb +65 -0
- data/test/test_hudson_job.rb +162 -0
- data/test/test_hudson_multicast.rb +9 -0
- data/test/test_hudson_settings.rb +70 -0
- metadata +71 -53
- data/lib/hudson-remote-api/config.rb +0 -46
@@ -0,0 +1,37 @@
|
|
1
|
+
module Hudson
|
2
|
+
module Parser
|
3
|
+
|
4
|
+
class BuildInfo
|
5
|
+
attr_accessor :xml, :xml_doc
|
6
|
+
|
7
|
+
def initialize(raw_xml)
|
8
|
+
@xml = raw_xml
|
9
|
+
@xml_doc = REXML::Document.new(raw_xml)
|
10
|
+
end
|
11
|
+
|
12
|
+
def result
|
13
|
+
build_result_element = self.xml_doc.elements["/freeStyleBuild/result"]
|
14
|
+
|
15
|
+
build_result_element.respond_to?(:text) ? build_result_element.text : nil
|
16
|
+
end
|
17
|
+
|
18
|
+
def revisions
|
19
|
+
return nil unless self.xml_doc.elements["/freeStyleBuild/changeSet"]
|
20
|
+
|
21
|
+
Hash.new().tap do |h|
|
22
|
+
self.xml_doc.elements.each("/freeStyleBuild/changeSet/revision") do |revision|
|
23
|
+
h[revision.elements["module"].text] = revision.elements["revision"].text
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def culprit
|
29
|
+
culprit_element = self.xml_doc.elements['/freeStyleBuild/culprit/fullName']
|
30
|
+
|
31
|
+
if culprit_element.respond_to?(:text) ? culprit_element.text : nil
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Hudson
|
2
|
+
module Parser
|
3
|
+
class BuildQueueInfo
|
4
|
+
attr_accessor :xml, :xml_doc
|
5
|
+
|
6
|
+
def initialize(raw_xml)
|
7
|
+
@xml = raw_xml
|
8
|
+
@xml_doc = REXML::Document.new(raw_xml)
|
9
|
+
end
|
10
|
+
|
11
|
+
def items
|
12
|
+
return [] if self.xml_doc.elements["/queue/item"].nil? # there's nothing in the queue
|
13
|
+
|
14
|
+
self.xml_doc.each_element("/queue/item/task").collect{ |job| job.elements["name"].text }
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
module Hudson
|
2
|
+
module Parser
|
3
|
+
|
4
|
+
class JobConfigInfo
|
5
|
+
attr_accessor :xml, :xml_doc
|
6
|
+
|
7
|
+
def initialize(raw_xml)
|
8
|
+
@xml = raw_xml
|
9
|
+
@xml_doc = REXML::Document.new(raw_xml)
|
10
|
+
end
|
11
|
+
|
12
|
+
def description
|
13
|
+
description_elem = self.xml_doc.elements["/project/description"]
|
14
|
+
description_elem ? description_elem.text : ""
|
15
|
+
end
|
16
|
+
|
17
|
+
def disabled?
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
def block_build_when_downstream_building?
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
def block_build_when_upstream_building?
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
def concurrent_build?
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
def git_repo?
|
34
|
+
self.xml_doc.elements["/project/scm"].attributes['class'] == "hudson.plugins.git.GitSCM"
|
35
|
+
end
|
36
|
+
|
37
|
+
def git_url
|
38
|
+
git_url_elem = self.xml_doc.elements["/project/scm/userRemoteConfigs/hudson.plugins.git.UserRemoteConfig/url"]
|
39
|
+
git_url_elem ? git_url_elem.text : nil
|
40
|
+
end
|
41
|
+
|
42
|
+
def git_branch
|
43
|
+
git_branch_elem = self.xml_doc.elements['/project/scm/branches/hudson.plugins.git.BranchSpec/name']
|
44
|
+
git_branch_elem ? git_branch_elem.text : nil
|
45
|
+
end
|
46
|
+
|
47
|
+
def parameterized?
|
48
|
+
!self.xml_doc.elements["/project/properties/hudson.model.ParametersDefinitionProperty"].nil?
|
49
|
+
end
|
50
|
+
|
51
|
+
def triggers
|
52
|
+
Hash.new.tap do |h|
|
53
|
+
if triggers_elem = self.xml_doc.elements["/project/triggers"] || self.xml_doc.elements["/project/triggers[@class='vector']"]
|
54
|
+
triggers_elem.elements.to_a.each do |trigger|
|
55
|
+
spec_text = trigger.elements['spec'].text
|
56
|
+
h[trigger.name.to_s] = spec_text.to_s
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def scm_browser_url
|
63
|
+
scm_browser_url_elem = self.xml_doc.elements['/project/scm/browser/url']
|
64
|
+
scm_browser_url_elem ? scm_browser_url_elem.text : ""
|
65
|
+
end
|
66
|
+
|
67
|
+
def scm_broswer_location
|
68
|
+
if !self.xml_doc.elements["/project/scm/browser/location"].nil?
|
69
|
+
self.xml_doc.elements["/project/scm/browser/location"].text
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def svn_repo?
|
74
|
+
!self.xml_doc.elements["/project/scm/locations/hudson.scm.SubversionSCM_-ModuleLocation/remote"].nil?
|
75
|
+
end
|
76
|
+
|
77
|
+
def svn_repository_urls
|
78
|
+
if !self.xml_doc.elements["/project/scm/locations"].nil?
|
79
|
+
Array.new.tap do |a|
|
80
|
+
self.xml_doc.elements.each("/project/scm/locations/hudson.scm.SubversionSCM_-ModuleLocation"){|e| a << e.elements["remote"].text }
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def git_repository
|
86
|
+
Hash.new.tap do |h|
|
87
|
+
h[:url] = self.git_url
|
88
|
+
h[:branch] = self.git_branch
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def svn_repository
|
93
|
+
repo_elem = self.xml_doc.elements["/project/scm/locations/hudson.scm.SubversionSCM_-ModuleLocation/remote"]
|
94
|
+
repo_elem ? repo_elem.text : ""
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Hudson
|
2
|
+
module Parser
|
3
|
+
class JobInfo
|
4
|
+
attr_accessor :xml, :xml_doc
|
5
|
+
|
6
|
+
def initialize(raw_xml)
|
7
|
+
@xml = raw_xml
|
8
|
+
@xml_doc = REXML::Document.new(raw_xml)
|
9
|
+
end
|
10
|
+
|
11
|
+
def builds
|
12
|
+
Array.new().tap do |a|
|
13
|
+
self.xml_doc.elements.each("/freeStyleProject/build"){|e| a << e.elements["number"].text } unless self.xml_doc.elements["/freeStyleProject/build"].nil?
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def color
|
18
|
+
color_elem = self.xml_doc.elements["/freeStyleProject/color"]
|
19
|
+
color_elem.text if free_style_project? && color_elem
|
20
|
+
end
|
21
|
+
|
22
|
+
def free_style_project?
|
23
|
+
!self.xml_doc.elements["/freeStyleProject"].nil?
|
24
|
+
end
|
25
|
+
|
26
|
+
def last_build
|
27
|
+
read_elem_text("/freeStyleProject/lastBuild/number") if free_style_project?
|
28
|
+
end
|
29
|
+
|
30
|
+
def last_completed_build
|
31
|
+
read_elem_text("/freeStyleProject/lastCompletedBuild/number") if free_style_project?
|
32
|
+
end
|
33
|
+
|
34
|
+
def last_failed_build
|
35
|
+
read_elem_text("/freeStyleProject/lastFailedBuild/number") if free_style_project?
|
36
|
+
end
|
37
|
+
|
38
|
+
def last_stable_build
|
39
|
+
read_elem_text("/freeStyleProject/lastStableBuild/number") if free_style_project?
|
40
|
+
end
|
41
|
+
|
42
|
+
def last_successful_build
|
43
|
+
read_elem_text("/freeStyleProject/lastSuccessfulBuild/number") if free_style_project?
|
44
|
+
end
|
45
|
+
|
46
|
+
def last_unsuccessful_build
|
47
|
+
read_elem_text("/freeStyleProject/lastUnsuccessfulBuild/number") if free_style_project?
|
48
|
+
end
|
49
|
+
|
50
|
+
def next_build_number
|
51
|
+
read_elem_text("/freeStyleProject/nextBuildNumber") if free_style_project?
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
def read_elem_text(elem_path)
|
56
|
+
elem = self.xml_doc.elements[elem_path]
|
57
|
+
elem.text if elem
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Hudson
|
2
|
+
module Parser
|
3
|
+
class Multicast
|
4
|
+
attr_accessor :xml, :xml_doc
|
5
|
+
|
6
|
+
def initialize(raw_xml)
|
7
|
+
@xml = raw_xml
|
8
|
+
@xml_doc = REXML::Document.new(raw_xml)
|
9
|
+
end
|
10
|
+
|
11
|
+
def version
|
12
|
+
version_element = self.xml_doc.elements["/hudson/version"]
|
13
|
+
version_element.respond_to?(:text) ? version_element.text : nil
|
14
|
+
end
|
15
|
+
|
16
|
+
def url
|
17
|
+
url_element = self.xml_doc.elements["/hudson/url"]
|
18
|
+
url_element.respond_to?(:text) ? url_element.text : nil
|
19
|
+
end
|
20
|
+
|
21
|
+
def slave_port
|
22
|
+
slave_port_element = self.xml_doc.elements["/hudson/slave-port"]
|
23
|
+
slave_port_element.respond_to?(:text) ? slave_port_element.text : nil
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Hudson
|
2
|
+
module Parser
|
3
|
+
class ServerInfo
|
4
|
+
attr_accessor :xml, :xml_doc
|
5
|
+
|
6
|
+
def initialize(raw_xml)
|
7
|
+
@xml = raw_xml
|
8
|
+
@xml_doc = REXML::Document.new(raw_xml)
|
9
|
+
end
|
10
|
+
|
11
|
+
def active_jobs
|
12
|
+
Array.new().tap do |active_jobs|
|
13
|
+
self.xml_doc.each_element("hudson/job") do |job|
|
14
|
+
active_jobs << job.elements["name"].text if job.elements["color"].text.include?("anime")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def mode
|
20
|
+
self.xml_doc.elements["/hudson/mode"].text
|
21
|
+
end
|
22
|
+
|
23
|
+
def node_description
|
24
|
+
self.xml_doc.elements["/hudson/nodeDescription"].text
|
25
|
+
end
|
26
|
+
|
27
|
+
def node_name
|
28
|
+
self.xml_doc.elements["/hudson/nodeName"].text
|
29
|
+
end
|
30
|
+
|
31
|
+
def jobs
|
32
|
+
Array.new.tap do |j|
|
33
|
+
self.xml_doc.each_element("hudson/job") do |job|
|
34
|
+
j << job.elements["name"].text
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def use_crumbs?
|
40
|
+
self.xml_doc.elements["/hudson/useCrumbs"].text == "true"
|
41
|
+
end
|
42
|
+
|
43
|
+
def use_security?
|
44
|
+
self.xml_doc.elements["/hudson/useSecurity"].text == "true"
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Hudson
|
2
|
+
class Settings
|
3
|
+
|
4
|
+
Configuration = Struct.new(:host, :user, :password, :version, :crumb, :proxy_host, :proxy_port)
|
5
|
+
attr_accessor :configuration
|
6
|
+
|
7
|
+
DEFAULTS = {
|
8
|
+
:host => 'http://localhost:8080',
|
9
|
+
:user => nil,
|
10
|
+
:password => nil,
|
11
|
+
:version => nil,
|
12
|
+
:crumb => true,
|
13
|
+
:proxy_host => nil,
|
14
|
+
:proxy_port => nil
|
15
|
+
}
|
16
|
+
|
17
|
+
def initialize(settings_hash={})
|
18
|
+
settings_hash = DEFAULTS.merge(settings_hash)
|
19
|
+
self.configuration = Configuration.new
|
20
|
+
|
21
|
+
self.configuration.host = settings_hash[:host]
|
22
|
+
self.configuration.user = settings_hash[:user]
|
23
|
+
self.configuration.password = settings_hash[:password]
|
24
|
+
self.configuration.version = settings_hash[:version]
|
25
|
+
self.configuration.crumb = settings_hash[:crumb]
|
26
|
+
self.configuration.proxy_host = settings_hash[:proxy_host]
|
27
|
+
self.configuration.proxy_port = settings_hash[:proxy_port]
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
module Hudson
|
2
|
+
module XmlWriter
|
3
|
+
|
4
|
+
class JobConfigInfo
|
5
|
+
attr_accessor :job_name, :xml_doc
|
6
|
+
|
7
|
+
SVN_SCM_CONF = <<-SVN_SCM_STRING
|
8
|
+
<scm class="hudson.scm.SubversionSCM">
|
9
|
+
<locations>
|
10
|
+
<hudson.scm.SubversionSCM_-ModuleLocation>
|
11
|
+
<remote>%s</remote>
|
12
|
+
<local>.</local>
|
13
|
+
</hudson.scm.SubversionSCM_-ModuleLocation>
|
14
|
+
</locations>
|
15
|
+
<excludedRegions/>
|
16
|
+
<includedRegions/>
|
17
|
+
<excludedUsers/>
|
18
|
+
<excludedRevprop/>
|
19
|
+
<excludedCommitMessages/>
|
20
|
+
<workspaceUpdater class="hudson.scm.subversion.UpdateUpdater"/>
|
21
|
+
</scm>
|
22
|
+
SVN_SCM_STRING
|
23
|
+
|
24
|
+
def initialize(job_name, raw_xml)
|
25
|
+
@job_name = job_name
|
26
|
+
@xml_doc = REXML::Document.new(raw_xml)
|
27
|
+
end
|
28
|
+
|
29
|
+
def git_repository_url=(repository_url)
|
30
|
+
if repository_url[:url]
|
31
|
+
self.xml_doc.elements['/project/scm/userRemoteConfigs/hudson.plugins.git.UserRemoteConfig/url'].text = repository_url[:url]
|
32
|
+
end
|
33
|
+
if repository_url[:branch]
|
34
|
+
self.xml_doc.elements['/project/scm/branches/hudson.plugins.git.BranchSpec/name'].text = repository_url[:branch]
|
35
|
+
end
|
36
|
+
update
|
37
|
+
end
|
38
|
+
|
39
|
+
def svn_repository_url=(repository_url)
|
40
|
+
if self.xml_doc.elements["/project/scm"].attributes['class'] == "hudson.scm.NullSCM"
|
41
|
+
self.xml_doc.elements["/project/scm"].replace_with REXML::Document.new(SVN_SCM_CONF % repository_url)
|
42
|
+
else
|
43
|
+
self.xml_doc.elements["/project/scm/locations/hudson.scm.SubversionSCM_-ModuleLocation/remote"].text = repository_url
|
44
|
+
end
|
45
|
+
update
|
46
|
+
end
|
47
|
+
|
48
|
+
def repository_urls=(repository_urls)
|
49
|
+
return false if !repository_urls.class == Array
|
50
|
+
|
51
|
+
i = 0
|
52
|
+
self.xml_doc.elements.each("/project/scm/locations/hudson.scm.SubversionSCM_-ModuleLocation") do |location|
|
53
|
+
location.elements["remote"].text = repository_urls[i]
|
54
|
+
i += 1
|
55
|
+
end
|
56
|
+
update
|
57
|
+
end
|
58
|
+
|
59
|
+
def git_repository_browser_location=(repository_browser_location)
|
60
|
+
self.xml_doc.elements['/project/scm/browser/url'].text = repository_browser_location
|
61
|
+
update
|
62
|
+
end
|
63
|
+
|
64
|
+
def svn_repository_browser_location=(repository_browser_location)
|
65
|
+
self.xml_doc.elements["/project/scm/browser/location"].text = repository_browser_location
|
66
|
+
update
|
67
|
+
end
|
68
|
+
|
69
|
+
def description=(description)
|
70
|
+
self.xml_doc.elements["/project"] << REXML::Element.new("description") if self.xml_doc.elements["/project/description"].nil?
|
71
|
+
self.xml_doc.elements["/project/description"].text = description
|
72
|
+
update
|
73
|
+
end
|
74
|
+
|
75
|
+
def triggers= opts={}
|
76
|
+
opts = {} if opts.nil?
|
77
|
+
if triggers = self.xml_doc.elements["/project/triggers"] || self.xml_doc.elements["/project/triggers[@class='vector']"]
|
78
|
+
triggers.elements.delete_all '*'
|
79
|
+
opts.each do |key, value|
|
80
|
+
trigger_name = key.to_s
|
81
|
+
trigger_name = 'hudson.triggers.' + trigger_name unless Regexp.new(/^hudson\.triggers\./).match(trigger_name)
|
82
|
+
if trigger = triggers.elements[trigger_name]
|
83
|
+
if spec = trigger.elements['spec']
|
84
|
+
spec.text = value.to_s
|
85
|
+
else
|
86
|
+
triggers.elements << generate_trigger(trigger, value)
|
87
|
+
end
|
88
|
+
else
|
89
|
+
triggers.elements << generate_trigger(REXML::Element.new(trigger_name), value)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
update
|
93
|
+
else
|
94
|
+
$stderr.puts "triggers not found in configuration, triggers assignment ignored."
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
private
|
99
|
+
def update
|
100
|
+
response = Hudson.client.update_job_config!(self.job_name, self.xml_doc.to_s)
|
101
|
+
response.is_a?(Net::HTTPSuccess) or response.is_a?(Net::HTTPRedirection)
|
102
|
+
end
|
103
|
+
|
104
|
+
def generate_trigger trigger, spec_text
|
105
|
+
spec = REXML::Element.new("spec")
|
106
|
+
spec.text = spec_text.to_s
|
107
|
+
trigger.elements << spec
|
108
|
+
trigger
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
end
|