hudkins 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.autotest ADDED
@@ -0,0 +1,23 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'autotest/restart'
4
+
5
+ # Autotest.add_hook :initialize do |at|
6
+ # at.extra_files << "../some/external/dependency.rb"
7
+ #
8
+ # at.libs << ":../some/external"
9
+ #
10
+ # at.add_exception 'vendor'
11
+ #
12
+ # at.add_mapping(/dependency.rb/) do |f, _|
13
+ # at.files_matching(/test_.*rb$/)
14
+ # end
15
+ #
16
+ # %w(TestA TestB).each do |klass|
17
+ # at.extra_class_map[klass] = "test/test_misc.rb"
18
+ # end
19
+ # end
20
+
21
+ # Autotest.add_hook :run_command do |at|
22
+ # system "rake build"
23
+ # end
data/.gemtest ADDED
File without changes
data/History.txt ADDED
@@ -0,0 +1,6 @@
1
+ === 0.0.1 / 2011-09-16
2
+
3
+ * 1 major enhancement
4
+
5
+ * Ported hapi repo to hudkins for public release.
6
+
data/Manifest.txt ADDED
@@ -0,0 +1,29 @@
1
+ .autotest
2
+ History.txt
3
+ Manifest.txt
4
+ README.txt
5
+ Rakefile
6
+ bin/hudkins
7
+ lib/assets/config.xml
8
+ lib/assets/config_snippets/builders.xml
9
+ lib/assets/free_style_project.xml.erb
10
+ lib/assets/hudkinsrc
11
+ lib/hudkins.rb
12
+ lib/hudkins/command.rb
13
+ lib/hudkins/command/exec.rb
14
+ lib/hudkins/command/irb_start.rb
15
+ lib/hudkins/common.rb
16
+ lib/hudkins/errors.rb
17
+ lib/hudkins/job.rb
18
+ lib/hudkins/jobs.rb
19
+ lib/hudkins/mixin.rb
20
+ lib/hudkins/rake.rb
21
+ lib/hudkins/restclient.rb
22
+ lib/hudkins/sysinfo.rb
23
+ test/fixtures/config.erb
24
+ test/fixtures/jobs.erb
25
+ test/fixtures/new_project_config.erb
26
+ test/test_helper.rb
27
+ test/unit/hudkins/test_job.rb
28
+ test/unit/hudkins/test_jobs.rb
29
+ test/unit/test_hudkins.rb
data/README.txt ADDED
@@ -0,0 +1,98 @@
1
+ = hudkins
2
+
3
+ * http://github.com/bhenderson/hudkins
4
+
5
+ == DESCRIPTION:
6
+
7
+ Hudson interaction gem.
8
+
9
+ == FEATURES/PROBLEMS:
10
+
11
+ * so far this is mostly for inspection of current jobs. There are quite a few
12
+ options in hudson for creating a new job and these haven't been implemented
13
+ yet.
14
+
15
+ === Implemented:
16
+
17
+ * Create new job
18
+
19
+ === Unimplemented:
20
+
21
+ * Copy job
22
+ * Build Que
23
+
24
+ * Hudson returns incorrect mime types!!! I've hacked it by setting response.type to the :accept header. This needs to be extracted out to dry up the code
25
+
26
+ == SYNOPSIS:
27
+
28
+ See Hudkins class documentation.
29
+ hud = Hudkins.new "http://example.com"
30
+ hud.jobs # => Hudkins::Jobs
31
+
32
+ === Working with Jobs
33
+
34
+ job = hud.jobs.find_by_name "project-main"
35
+ job.scm_url # => "https://subversion/project/branches/1.1"
36
+ job.scm_url = "https://subversion/project/branches/1.2"
37
+ job.post_config! # => Hudkins::Response
38
+ job.build!
39
+
40
+ === Creating new jobs
41
+
42
+ new_job = hud.add_job new_project_name
43
+ new_job.disabled? # => true
44
+ new_job.scm_url # => nil
45
+ new_job.scm_use :git/:svn, "http://svn/my_cool_repo/new_project_name/trunk"
46
+
47
+ job = hud.jobs.find_by_name :job_name
48
+ job2 = job.copy new_name ||
49
+ hud.copy_job job, new_name
50
+ job2.scm_url = "http://svn/new/url"
51
+ job2.post_config!
52
+
53
+
54
+ == REQUIREMENTS:
55
+
56
+ * heavily built ontop of "https://github.com/archiloque/rest-client"
57
+ * see link:Rakefile
58
+
59
+ == INSTALL:
60
+
61
+ * git clone http://github.com/bhenderson/hudkins.git
62
+ * cd hudkins/
63
+ * rake package
64
+ * gem install pkg/hudkins.gem
65
+
66
+ == DEVELOPERS:
67
+
68
+ After checking out the source, run:
69
+
70
+ $ rake newb
71
+
72
+ This task will install any missing dependencies, run the tests/specs,
73
+ and generate the RDoc.
74
+
75
+ == LICENSE:
76
+
77
+ (The MIT License)
78
+
79
+ Copyright (c) 2011
80
+
81
+ Permission is hereby granted, free of charge, to any person obtaining
82
+ a copy of this software and associated documentation files (the
83
+ 'Software'), to deal in the Software without restriction, including
84
+ without limitation the rights to use, copy, modify, merge, publish,
85
+ distribute, sublicense, and/or sell copies of the Software, and to
86
+ permit persons to whom the Software is furnished to do so, subject to
87
+ the following conditions:
88
+
89
+ The above copyright notice and this permission notice shall be
90
+ included in all copies or substantial portions of the Software.
91
+
92
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
93
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
94
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
95
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
96
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
97
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
98
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,25 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'rubygems'
4
+ require 'hoe'
5
+
6
+ Hoe.plugin :isolate
7
+
8
+ $:.unshift './'
9
+
10
+ Hoe.spec 'hudkins' do
11
+ developer('Brian Henderson', 'bhenderson@attinteractive.com')
12
+ developer('Adam Avilla', 'bhenderson@attinteractive.com')
13
+
14
+ extra_deps << [ "json", "~> 1.5.0"]
15
+ extra_deps << [ "nokogiri", "~> 1.5.0"]
16
+ extra_deps << [ "rest-client", "~> 1.6.1"]
17
+
18
+ extra_dev_deps << [ "minitest", "~> 1.7.2"]
19
+ extra_dev_deps << [ "mocha", "~> 0.9.8"]
20
+ end
21
+
22
+
23
+ #require "lib/hudkins/rake"
24
+
25
+ # vim: syntax=ruby
data/bin/hudkins ADDED
@@ -0,0 +1,5 @@
1
+ #!/user/bin/env ruby
2
+
3
+ require "hudkins/command"
4
+
5
+ Hudkins::Command.run
@@ -0,0 +1,30 @@
1
+ <?xml version='1.0' encoding='UTF-8'?>
2
+ <project>
3
+ <actions/>
4
+ <description>foo bar</description>
5
+ <keepDependencies>false</keepDependencies>
6
+ <properties/>
7
+ <scm class="hudson.scm.SubversionSCM">
8
+ <locations>
9
+ <hudson.scm.SubversionSCM_-ModuleLocation>
10
+ <remote>svn://subversion.flight.yellowpages.com/search/syndication/tags/1.1.0_201008</remote>
11
+ </hudson.scm.SubversionSCM_-ModuleLocation>
12
+ </locations>
13
+ <useUpdate>true</useUpdate>
14
+ <doRevert>false</doRevert>
15
+ <excludedRegions></excludedRegions>
16
+ <includedRegions></includedRegions>
17
+ <excludedUsers></excludedUsers>
18
+ <excludedRevprop></excludedRevprop>
19
+ <excludedCommitMessages></excludedCommitMessages>
20
+ </scm>
21
+ <assignedNode>master</assignedNode>
22
+ <canRoam>false</canRoam>
23
+ <disabled>true</disabled>
24
+ <blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
25
+ <triggers class="vector"/>
26
+ <concurrentBuild>false</concurrentBuild>
27
+ <builders/>
28
+ <publishers/>
29
+ <buildWrappers/>
30
+ </project>
@@ -0,0 +1,5 @@
1
+ <builders>
2
+ <hudson.tasks.Shell>
3
+ <command></command>
4
+ </hudson.tasks.Shell>
5
+ </builders>
@@ -0,0 +1,14 @@
1
+ <?xml version='1.0' encoding='UTF-8'?>
2
+ <project>
3
+ <keepDependencies>false</keepDependencies>
4
+ <properties/>
5
+ <scm class="hudson.scm.NullSCM"/>
6
+ <canRoam>true</canRoam>
7
+ <disabled>true</disabled>
8
+ <blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
9
+ <triggers class="vector"/>
10
+ <concurrentBuild>false</concurrentBuild>
11
+ <builders/>
12
+ <publishers/>
13
+ <buildWrappers/>
14
+ </project>
@@ -0,0 +1,4 @@
1
+ # Sample rc file
2
+ ---
3
+ :host: http://example.com
4
+ :verbose: true
data/lib/hudkins.rb ADDED
@@ -0,0 +1,263 @@
1
+ require "rest_client"
2
+ require "json"
3
+ require "nokogiri"
4
+
5
+ require "hudkins/restclient"
6
+ require "hudkins/mixin"
7
+ require "hudkins/common"
8
+
9
+ ##
10
+ # === Description
11
+ # Primary class used to interact with your Hudson server
12
+ #
13
+ # === Examples
14
+ # hud = Hudkins.new "http://my-hudson.localdomain.com:8080"
15
+ # hud.jobs # => Hudkins::Jobs
16
+ # job = hud.jobs.find_by_name :job_name
17
+ #
18
+ # == Command Line
19
+ # There is an included binary for doing simple commands.
20
+ # See Hudkins::Command#run_start_irb for a powerful way to interact with your
21
+ # hudson server at an irb cmd prompt.
22
+ #
23
+ class Hudkins
24
+ include Hudkins::Common
25
+ VERSION = '0.0.1'
26
+
27
+ attr_reader :host, :resource
28
+
29
+ ##
30
+ # === Examples
31
+ # Hudkins.new <host_name> [opts]
32
+ #
33
+ # <host_name> will be URI parsed
34
+ #
35
+ # === Options
36
+ # +host_timeout+:: number of seconds to timeout trying to connect to the server. see Hudkins#host_available?
37
+ #
38
+ def initialize(host = "http://example.com", opts = {})
39
+ @host = URI.parse( ENV["hudkins_host"] || host )
40
+ @options = opts
41
+ @resource = RestClient::Resource.new @host.to_s
42
+ end
43
+
44
+ ##
45
+ # === Description
46
+ # Reset what Hudkins#host is after initialization. Also updates Hudkins#reset_resource.
47
+ def host= host_name
48
+ @host = URI.parse host_name
49
+ # reinitialize @resource
50
+ resource = @host
51
+ end
52
+
53
+ ##
54
+ # === Description
55
+ # Update Hudkins#resource with new host name.
56
+ def reset_resource= uri = host, opts = {}
57
+ @resource = RestClient::Resource.new( uri.to_s, opts)
58
+ end
59
+
60
+ ##
61
+ # === Description
62
+ # Access to internal list of jobs. see Hudkins::Jobs
63
+ #
64
+ # One inital api call is made and then cached. See Hudkins#initialize_jobs
65
+ def jobs
66
+ @jobs ||= initialize_jobs
67
+ end
68
+
69
+ ##
70
+ # === Description
71
+ # Reload jobs from the server
72
+ def update_jobs
73
+ # I might need to reinitiailze
74
+ @jobs = initialize_jobs
75
+ end
76
+
77
+ ##
78
+ # === Description
79
+ # Available to make arbitrary HTTP/get calls to the server.
80
+ # Returns an Hudkins::Response object. (see that class for reasoning.)
81
+ #
82
+ # === Parameters
83
+ # +path+:: "/path/to/resource"
84
+ # +opts+:: {:accept => "text/plain"} (default)
85
+ # +block+:: { optional return block for RestClient#get }
86
+ def get path = nil, opts = {}, &block
87
+ use_resource :get, path, nil, opts, &block
88
+ end
89
+
90
+ ##
91
+ # === Description
92
+ # Available to make arbitrary HTTP/post calls to the server.
93
+ #
94
+ # === Parameters
95
+ # +path+:: "/path/to/resource"
96
+ # +data+:: "<?xml...>" (any object that responds to to_s).
97
+ # +opts+:: {:content => "text/plain"} (default)
98
+ # +block+:: { optional return block for RestClient#get }
99
+ def post path = nil, data = "", opts = {}, &block
100
+ use_resource :post, path, data, opts, &block
101
+ end
102
+
103
+ ##
104
+ # === Description
105
+ # Same as #get but attempt to parse the response body.
106
+ # Raise unless Response#success?
107
+ def get_parsed *args
108
+ parse_response get(*args)
109
+ end
110
+
111
+ ##
112
+ # === Description
113
+ # Same as #post but attempt to parse the response body.
114
+ # Raise unless Response#success?
115
+ def post_parsed *args
116
+ parse_response post(*args)
117
+ end
118
+
119
+ # Action methods
120
+
121
+ ##
122
+ # === Description
123
+ # TODO this needs cleaned up to be more like copy_job
124
+ # Use remote api to create a new job.
125
+ # Updates internal job list (Hudkins#jobs) afterwards
126
+ #
127
+ # === Example
128
+ # hud.add_job :job_name, "<?xml..>"
129
+ #
130
+ # === Options
131
+ # +job_name+:: String or Symbol used as the name of the new job.
132
+ # +config_data+:: Uses provided template for bare-bones config, but
133
+ # optionally takes a string parameter (such as xml from
134
+ # another job's config)
135
+ #
136
+ # === Notes
137
+ # The remote api here is not fun. It uses HTTP#post instead of HTTP#create
138
+ # (which is normal) but the error messages are not very useful.
139
+ def add_job job_name, config_data = new_config
140
+ # yuck..
141
+ job = update_jobs.find_by_name( job_name )
142
+ unless job
143
+ response = post "/createItem?" + url_escape(:name => job_name), config_data, :content_type => "text/xml"
144
+ if response.success?
145
+ update_jobs.find_by_name job_name
146
+ else
147
+ case response.code
148
+ when 400
149
+ warn "the server returned an error. most likely the job name already exists."
150
+ jobs.find_by_name( job_name ) || ( raise response.errors )
151
+ else
152
+ warn "there was a problem."
153
+ raise response.errors
154
+ end
155
+ end
156
+ else
157
+ job
158
+ end
159
+ end
160
+
161
+ ##
162
+ # === Description
163
+ # Copy a job
164
+ #
165
+ # === Examples
166
+ # new_job = hud.copy_job "job-name", "new-job-name"
167
+ #
168
+ # job = hud.find_by_name "job-name"
169
+ # new_job = hud.copy_job job, "new-job-name"
170
+ def copy_job job, new_job
171
+ job = Hudkins::Job === job ? job : jobs.find_by_name( job )
172
+ job.copy( new_job ) if job # find_by_name didn't return nil
173
+ end
174
+
175
+ ##
176
+ # === Description
177
+ # Gets the hudson version the server is running
178
+ #
179
+ # === Examples
180
+ # hud.server_version # => "1.37.0"
181
+ def server_version
182
+ get.response.headers[:x_hudson]
183
+ end
184
+
185
+ def parse_string string, format
186
+ case format
187
+ when :xml then
188
+ Nokogiri::XML string
189
+ when :json then
190
+ JSON.parse string
191
+ else
192
+ raise "unsupported type #{format.inspect}"
193
+ end
194
+ end
195
+
196
+ private
197
+ def initialize_jobs
198
+ Hudkins::Jobs.new(self)
199
+ end
200
+
201
+ def get_default_options
202
+ {:accept => "text/plain"}
203
+ end
204
+
205
+ def post_default_options
206
+ {:content_type => "text/plain"}
207
+ end
208
+
209
+ def new_config
210
+ File.read( File.join( File.dirname(__FILE__), "assets", "free_style_project.xml.erb" ) )
211
+ end
212
+
213
+ def use_resource verb, path, data = nil, opts = {}, &block
214
+ check_host_availability
215
+ # allow symbals
216
+ new_resource = path.nil? ? @resource : @resource[path.to_s]
217
+ args = [ send("#{verb}_default_options").merge( opts ) ]
218
+ # not sure how else to make this generic for both get and post
219
+ # maybe something like opts.delete :data
220
+ args.unshift data.to_s if data
221
+ new_resource.send(verb, *args, &(block || resource_block))
222
+ end
223
+
224
+ def resource_block
225
+ # restclient
226
+ # |response, request, result|
227
+ Proc.new {|*args| Response.new *args}
228
+ end
229
+
230
+ # body = @response.body, format = @response.format
231
+ def parse_response response
232
+ # I debated on wether or not to push up the raise statement. But it seems like I might want to do a "get" even if it doesn't return a valid response whereas why would I want to parse an invalid response?
233
+ raise response.result unless response.success?
234
+ body, format = response.body, response.type
235
+ begin
236
+ parse_string body, format
237
+ rescue => e
238
+ raise "unparsable response for #{response.request.url}.\n#{e.message}"
239
+ end
240
+ end
241
+
242
+ #def parse_response response
243
+ #raise response.result unless response.success?
244
+ #body = response.body
245
+ #begin
246
+ #case body
247
+ #when /^\s*<\?xml/ then
248
+ #Nokogiri::XML body
249
+ #when /^\s*\{/ then
250
+ #JSON.parse body
251
+ #else
252
+ #body
253
+ #end
254
+ #rescue => e
255
+ #raise "unparsable response. #{e.message}"
256
+ #end
257
+ #end
258
+ # private
259
+ end # Hudkins
260
+
261
+ require "hudkins/jobs"
262
+ require "hudkins/job"
263
+ require "hudkins/errors"