hudkins 0.0.1
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/.autotest +23 -0
- data/.gemtest +0 -0
- data/History.txt +6 -0
- data/Manifest.txt +29 -0
- data/README.txt +98 -0
- data/Rakefile +25 -0
- data/bin/hudkins +5 -0
- data/lib/assets/config.xml +30 -0
- data/lib/assets/config_snippets/builders.xml +5 -0
- data/lib/assets/free_style_project.xml.erb +14 -0
- data/lib/assets/hudkinsrc +4 -0
- data/lib/hudkins.rb +263 -0
- data/lib/hudkins/command.rb +127 -0
- data/lib/hudkins/command/exec.rb +113 -0
- data/lib/hudkins/command/irb_start.rb +86 -0
- data/lib/hudkins/common.rb +69 -0
- data/lib/hudkins/errors.rb +7 -0
- data/lib/hudkins/job.rb +168 -0
- data/lib/hudkins/jobs.rb +86 -0
- data/lib/hudkins/mixin.rb +103 -0
- data/lib/hudkins/rake.rb +20 -0
- data/lib/hudkins/restclient.rb +130 -0
- data/lib/hudkins/sysinfo.rb +11 -0
- data/test/fixtures/config.erb +30 -0
- data/test/fixtures/jobs.erb +22 -0
- data/test/fixtures/new_project_config.erb +14 -0
- data/test/test_helper.rb +50 -0
- data/test/unit/hudkins/test_job.rb +65 -0
- data/test/unit/hudkins/test_jobs.rb +27 -0
- data/test/unit/test_hudkins.rb +74 -0
- metadata +153 -0
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
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,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,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>
|
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"
|