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.
Files changed (58) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +4 -0
  3. data/Gemfile +9 -0
  4. data/Gemfile.lock +20 -0
  5. data/README.md +11 -9
  6. data/Rakefile +10 -0
  7. data/fixtures/vcr_cassettes/TestHudsonBuildQueue_test_list.yml +38 -0
  8. data/fixtures/vcr_cassettes/TestHudsonBuild_setup.yml +407 -0
  9. data/fixtures/vcr_cassettes/TestHudsonBuild_test_build_info.yml +222 -0
  10. data/fixtures/vcr_cassettes/TestHudsonClient_test_build_job_.yml +52 -0
  11. data/fixtures/vcr_cassettes/TestHudsonClient_test_build_job_with_parameters_.yml +52 -0
  12. data/fixtures/vcr_cassettes/TestHudsonClient_test_build_queue_info.yml +38 -0
  13. data/fixtures/vcr_cassettes/TestHudsonClient_test_create_item_.yml +52 -0
  14. data/fixtures/vcr_cassettes/TestHudsonClient_test_delete_job_.yml +52 -0
  15. data/fixtures/vcr_cassettes/TestHudsonClient_test_job_build_info.yml +39 -0
  16. data/fixtures/vcr_cassettes/TestHudsonClient_test_job_config_info.yml +48 -0
  17. data/fixtures/vcr_cassettes/TestHudsonJob_test_build.yml +409 -0
  18. data/fixtures/vcr_cassettes/TestHudsonJob_test_build_with_params.yml +189 -0
  19. data/fixtures/vcr_cassettes/TestHudsonJob_test_builds_list.yml +192 -0
  20. data/fixtures/vcr_cassettes/TestHudsonJob_test_copy.yml +410 -0
  21. data/fixtures/vcr_cassettes/TestHudsonJob_test_create.yml +257 -0
  22. data/fixtures/vcr_cassettes/TestHudsonJob_test_desc_update.yml +281 -0
  23. data/fixtures/vcr_cassettes/TestHudsonJob_test_get.yml +191 -0
  24. data/fixtures/vcr_cassettes/TestHudsonJob_test_job_with_spaces.yml +260 -0
  25. data/fixtures/vcr_cassettes/TestHudsonJob_test_list.yml +39 -0
  26. data/fixtures/vcr_cassettes/TestHudsonJob_test_list_active.yml +39 -0
  27. data/fixtures/vcr_cassettes/TestHudsonJob_test_new.yml +561 -0
  28. data/fixtures/vcr_cassettes/TestHudsonJob_test_scm_url.yml +728 -0
  29. data/fixtures/vcr_cassettes/TestHudsonJob_test_triggers_delete.yml +588 -0
  30. data/fixtures/vcr_cassettes/TestHudsonJob_test_triggers_set.yml +346 -0
  31. data/fixtures/vcr_cassettes/TestHudsonJob_test_triggers_set_using_shortcut.yml +346 -0
  32. data/fixtures/vcr_cassettes/TestHudsonJob_test_url.yml +156 -0
  33. data/fixtures/vcr_cassettes/TestHudsonJob_test_wipe_out_workspace.yml +685 -0
  34. data/hudson-remote-api.gemspec +23 -0
  35. data/lib/hudson-remote-api.rb +3 -128
  36. data/lib/hudson-remote-api/build.rb +18 -35
  37. data/lib/hudson-remote-api/build_queue.rb +13 -20
  38. data/lib/hudson-remote-api/client.rb +179 -0
  39. data/lib/hudson-remote-api/hudson_xml_api.rb +61 -0
  40. data/lib/hudson-remote-api/job.rb +207 -345
  41. data/lib/hudson-remote-api/parser/build_info.rb +37 -0
  42. data/lib/hudson-remote-api/parser/build_queue_info.rb +19 -0
  43. data/lib/hudson-remote-api/parser/job_config_info.rb +99 -0
  44. data/lib/hudson-remote-api/parser/job_info.rb +62 -0
  45. data/lib/hudson-remote-api/parser/multicast.rb +28 -0
  46. data/lib/hudson-remote-api/parser/server_info.rb +49 -0
  47. data/lib/hudson-remote-api/settings.rb +31 -0
  48. data/lib/hudson-remote-api/version.rb +3 -0
  49. data/lib/hudson-remote-api/xml_writer/job_config_info.rb +113 -0
  50. data/test/test_helper.rb +10 -0
  51. data/test/test_hudson_build.rb +28 -0
  52. data/test/test_hudson_build_queue.rb +11 -0
  53. data/test/test_hudson_client.rb +65 -0
  54. data/test/test_hudson_job.rb +162 -0
  55. data/test/test_hudson_multicast.rb +9 -0
  56. data/test/test_hudson_settings.rb +70 -0
  57. metadata +71 -53
  58. 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,3 @@
1
+ module Hudson
2
+ VERSION = "1.0.0"
3
+ 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