jenkins-remote-api_1 1.0.3

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.
Files changed (61) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +5 -0
  3. data/Gemfile +10 -0
  4. data/Gemfile.lock +27 -0
  5. data/LICENSE +19 -0
  6. data/README.md +177 -0
  7. data/Rakefile +10 -0
  8. data/fixtures/vcr_cassettes/TestHudsonBuildQueue_test_list.yml +38 -0
  9. data/fixtures/vcr_cassettes/TestHudsonBuild_setup.yml +407 -0
  10. data/fixtures/vcr_cassettes/TestHudsonBuild_test_build_info.yml +222 -0
  11. data/fixtures/vcr_cassettes/TestHudsonClient_test_build_job_.yml +52 -0
  12. data/fixtures/vcr_cassettes/TestHudsonClient_test_build_job_with_parameters_.yml +52 -0
  13. data/fixtures/vcr_cassettes/TestHudsonClient_test_build_queue_info.yml +38 -0
  14. data/fixtures/vcr_cassettes/TestHudsonClient_test_create_item_.yml +52 -0
  15. data/fixtures/vcr_cassettes/TestHudsonClient_test_delete_job_.yml +52 -0
  16. data/fixtures/vcr_cassettes/TestHudsonClient_test_job_build_info.yml +39 -0
  17. data/fixtures/vcr_cassettes/TestHudsonClient_test_job_config_info.yml +48 -0
  18. data/fixtures/vcr_cassettes/TestHudsonJob_test_build.yml +409 -0
  19. data/fixtures/vcr_cassettes/TestHudsonJob_test_build_with_params.yml +189 -0
  20. data/fixtures/vcr_cassettes/TestHudsonJob_test_builds_list.yml +192 -0
  21. data/fixtures/vcr_cassettes/TestHudsonJob_test_copy.yml +410 -0
  22. data/fixtures/vcr_cassettes/TestHudsonJob_test_create.yml +257 -0
  23. data/fixtures/vcr_cassettes/TestHudsonJob_test_desc_update.yml +281 -0
  24. data/fixtures/vcr_cassettes/TestHudsonJob_test_get.yml +191 -0
  25. data/fixtures/vcr_cassettes/TestHudsonJob_test_job_with_spaces.yml +260 -0
  26. data/fixtures/vcr_cassettes/TestHudsonJob_test_list.yml +39 -0
  27. data/fixtures/vcr_cassettes/TestHudsonJob_test_list_active.yml +39 -0
  28. data/fixtures/vcr_cassettes/TestHudsonJob_test_new.yml +561 -0
  29. data/fixtures/vcr_cassettes/TestHudsonJob_test_scm_url.yml +728 -0
  30. data/fixtures/vcr_cassettes/TestHudsonJob_test_triggers_delete.yml +588 -0
  31. data/fixtures/vcr_cassettes/TestHudsonJob_test_triggers_set.yml +346 -0
  32. data/fixtures/vcr_cassettes/TestHudsonJob_test_triggers_set_using_shortcut.yml +346 -0
  33. data/fixtures/vcr_cassettes/TestHudsonJob_test_url.yml +156 -0
  34. data/fixtures/vcr_cassettes/TestHudsonJob_test_wipe_out_workspace.yml +685 -0
  35. data/jenkins-remote-api_1.gemspec +23 -0
  36. data/lib/jenkins-remote-api_1.rb +5 -0
  37. data/lib/jenkins-remote-api_1/build.rb +24 -0
  38. data/lib/jenkins-remote-api_1/build_queue.rb +16 -0
  39. data/lib/jenkins-remote-api_1/client.rb +179 -0
  40. data/lib/jenkins-remote-api_1/errors.rb +3 -0
  41. data/lib/jenkins-remote-api_1/hudson_xml_api.rb +61 -0
  42. data/lib/jenkins-remote-api_1/job.rb +212 -0
  43. data/lib/jenkins-remote-api_1/multicast.rb +22 -0
  44. data/lib/jenkins-remote-api_1/new_job_config.xml +16 -0
  45. data/lib/jenkins-remote-api_1/parser/build_info.rb +37 -0
  46. data/lib/jenkins-remote-api_1/parser/build_queue_info.rb +19 -0
  47. data/lib/jenkins-remote-api_1/parser/job_config_info.rb +99 -0
  48. data/lib/jenkins-remote-api_1/parser/job_info.rb +62 -0
  49. data/lib/jenkins-remote-api_1/parser/multicast.rb +28 -0
  50. data/lib/jenkins-remote-api_1/parser/server_info.rb +49 -0
  51. data/lib/jenkins-remote-api_1/settings.rb +31 -0
  52. data/lib/jenkins-remote-api_1/version.rb +3 -0
  53. data/lib/jenkins-remote-api_1/xml_writer/job_config_info.rb +113 -0
  54. data/test/test_helper.rb +10 -0
  55. data/test/test_hudson_build.rb +28 -0
  56. data/test/test_hudson_build_queue.rb +11 -0
  57. data/test/test_hudson_client.rb +65 -0
  58. data/test/test_hudson_job.rb +162 -0
  59. data/test/test_hudson_multicast.rb +9 -0
  60. data/test/test_hudson_settings.rb +70 -0
  61. metadata +112 -0
@@ -0,0 +1,22 @@
1
+ require 'socket'
2
+ require 'timeout'
3
+ require 'rexml/document'
4
+
5
+ module Hudson
6
+ def self.discover(multicast_addr = "239.77.124.213", port=33848, timeout_limit=5)
7
+ socket = UDPSocket.open
8
+ socket.setsockopt(Socket::IPPROTO_IP, Socket::IP_TTL, [1].pack('i'))
9
+ socket.send(ARGV.join(' '), 0, multicast_addr, port)
10
+ msg = nil
11
+ #msg, info = socket.recvfrom_nonblock(1024)
12
+ Timeout.timeout(timeout_limit) do
13
+ msg, info = socket.recvfrom(1024)
14
+ end
15
+ msg
16
+ rescue Exception => e
17
+ puts e
18
+ nil
19
+ ensure
20
+ socket.close
21
+ end
22
+ end
@@ -0,0 +1,16 @@
1
+ <?xml version='1.0' encoding='UTF-8'?>
2
+ <project>
3
+ <actions/>
4
+ <description></description>
5
+ <keepDependencies>false</keepDependencies>
6
+ <properties/>
7
+ <scm class="hudson.scm.NullSCM"/>
8
+ <canRoam>true</canRoam>
9
+ <disabled>false</disabled>
10
+ <blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
11
+ <triggers class="vector"/>
12
+ <concurrentBuild>false</concurrentBuild>
13
+ <builders/>
14
+ <publishers/>
15
+ <buildWrappers/>
16
+ </project>
@@ -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.3"
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