hudson 0.3.1 → 0.5.0
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/.gitignore +4 -0
- data/Changelog.md +24 -0
- data/Gemfile.lock +1 -1
- data/Rakefile +4 -50
- data/features/default_host.feature +19 -0
- data/features/development.feature +2 -2
- data/features/launch_server.feature +1 -0
- data/features/manage_jobs.feature +109 -1
- data/features/manage_slave_nodes.feature +39 -4
- data/features/step_definitions/common_steps.rb +6 -0
- data/features/step_definitions/hudson_steps.rb +13 -2
- data/features/support/hudson_helpers.rb +6 -0
- data/hudson.gemspec +26 -56
- data/lib/hudson.rb +1 -1
- data/lib/hudson/api.rb +38 -24
- data/lib/hudson/cli.rb +81 -49
- data/lib/hudson/installation.rb +136 -0
- data/lib/hudson/job_config_builder.rb +68 -21
- data/lib/hudson/project_scm.rb +3 -3
- data/lib/hudson/version.rb +1 -1
- data/spec/fixtures/rails.single.config.xml +1 -0
- data/spec/fixtures/ruby.multi-ruby-multi-labels.config.xml +84 -0
- data/spec/fixtures/{rubygem.config.xml → ruby.multi.config.xml} +18 -1
- data/spec/job_config_builder_spec.rb +47 -11
- metadata +41 -93
- data/fixtures/projects/non-bundler/Rakefile +0 -4
- data/fixtures/projects/rails-3/Gemfile +0 -30
- data/fixtures/projects/rails-3/Gemfile.lock +0 -74
- data/fixtures/projects/rails-3/README +0 -256
- data/fixtures/projects/rails-3/Rakefile +0 -7
- data/fixtures/projects/rails-3/app/controllers/application_controller.rb +0 -3
- data/fixtures/projects/rails-3/app/helpers/application_helper.rb +0 -2
- data/fixtures/projects/rails-3/app/views/layouts/application.html.erb +0 -14
- data/fixtures/projects/rails-3/config.ru +0 -4
- data/fixtures/projects/rails-3/config/application.rb +0 -42
- data/fixtures/projects/rails-3/config/boot.rb +0 -13
- data/fixtures/projects/rails-3/config/database.yml +0 -22
- data/fixtures/projects/rails-3/config/environment.rb +0 -5
- data/fixtures/projects/rails-3/config/environments/development.rb +0 -26
- data/fixtures/projects/rails-3/config/environments/production.rb +0 -49
- data/fixtures/projects/rails-3/config/environments/test.rb +0 -35
- data/fixtures/projects/rails-3/config/initializers/backtrace_silencers.rb +0 -7
- data/fixtures/projects/rails-3/config/initializers/inflections.rb +0 -10
- data/fixtures/projects/rails-3/config/initializers/mime_types.rb +0 -5
- data/fixtures/projects/rails-3/config/initializers/secret_token.rb +0 -7
- data/fixtures/projects/rails-3/config/initializers/session_store.rb +0 -8
- data/fixtures/projects/rails-3/config/locales/en.yml +0 -5
- data/fixtures/projects/rails-3/config/routes.rb +0 -58
- data/fixtures/projects/rails-3/db/seeds.rb +0 -7
- data/fixtures/projects/rails-3/doc/README_FOR_APP +0 -2
- data/fixtures/projects/rails-3/log/development.log +0 -0
- data/fixtures/projects/rails-3/log/production.log +0 -0
- data/fixtures/projects/rails-3/log/server.log +0 -0
- data/fixtures/projects/rails-3/log/test.log +0 -0
- data/fixtures/projects/rails-3/public/404.html +0 -26
- data/fixtures/projects/rails-3/public/422.html +0 -26
- data/fixtures/projects/rails-3/public/500.html +0 -26
- data/fixtures/projects/rails-3/public/favicon.ico +0 -0
- data/fixtures/projects/rails-3/public/images/rails.png +0 -0
- data/fixtures/projects/rails-3/public/index.html +0 -239
- data/fixtures/projects/rails-3/public/javascripts/application.js +0 -2
- data/fixtures/projects/rails-3/public/javascripts/controls.js +0 -965
- data/fixtures/projects/rails-3/public/javascripts/dragdrop.js +0 -974
- data/fixtures/projects/rails-3/public/javascripts/effects.js +0 -1123
- data/fixtures/projects/rails-3/public/javascripts/prototype.js +0 -6001
- data/fixtures/projects/rails-3/public/javascripts/rails.js +0 -175
- data/fixtures/projects/rails-3/public/robots.txt +0 -5
- data/fixtures/projects/rails-3/script/rails +0 -6
- data/fixtures/projects/rails-3/test/performance/browsing_test.rb +0 -9
- data/fixtures/projects/rails-3/test/test_helper.rb +0 -13
- data/fixtures/projects/ruby/Gemfile +0 -3
- data/fixtures/projects/ruby/Gemfile.lock +0 -10
- data/fixtures/projects/ruby/Rakefile +0 -4
- data/lib/hudson/hudson.war +0 -0
- data/lib/hudson/hudson_version.rb +0 -4
- data/lib/hudson/plugins/envfile.hpi +0 -0
- data/lib/hudson/plugins/git.hpi +0 -0
- data/lib/hudson/plugins/github.hpi +0 -0
- data/lib/hudson/plugins/greenballs.hpi +0 -0
- data/lib/hudson/plugins/rake.hpi +0 -0
- data/lib/hudson/plugins/ruby.hpi +0 -0
- data/tasks/upgrade.rake +0 -83
data/lib/hudson.rb
CHANGED
data/lib/hudson/api.rb
CHANGED
@@ -48,10 +48,17 @@ module Hudson
|
|
48
48
|
cache_base_uri
|
49
49
|
true
|
50
50
|
else
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
51
|
+
require "hpricot"
|
52
|
+
doc = Hpricot(res.body)
|
53
|
+
error_msg = doc.search("td#main-panel p")
|
54
|
+
unless error_msg.inner_text.blank?
|
55
|
+
$stderr.puts error_msg.inner_text
|
56
|
+
else
|
57
|
+
# TODO - what are the errors we get?
|
58
|
+
puts "Server error:"
|
59
|
+
p res.code
|
60
|
+
puts res.body
|
61
|
+
end
|
55
62
|
false
|
56
63
|
end
|
57
64
|
rescue REXML::ParseException => e
|
@@ -87,9 +94,7 @@ module Hudson
|
|
87
94
|
json = get "/job/#{name}/api/json"
|
88
95
|
cache_base_uri
|
89
96
|
json
|
90
|
-
rescue
|
91
|
-
false
|
92
|
-
rescue Errno::EAFNOSUPPORT
|
97
|
+
rescue Crack::ParseError
|
93
98
|
false
|
94
99
|
end
|
95
100
|
end
|
@@ -98,30 +103,39 @@ module Hudson
|
|
98
103
|
json = get "/computer/api/json"
|
99
104
|
cache_base_uri
|
100
105
|
json
|
101
|
-
rescue Errno::ECONNREFUSED => e
|
102
|
-
false
|
103
|
-
rescue Errno::EAFNOSUPPORT
|
104
|
-
false
|
105
106
|
end
|
106
107
|
|
107
108
|
# Adds SSH nodes only, for now
|
108
109
|
def self.add_node(options = {})
|
109
110
|
options = options.with_clean_keys
|
110
111
|
default_options = Hash.new
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
112
|
+
if options[:vagrant]
|
113
|
+
default_options.merge!(
|
114
|
+
:slave_port => 2222,
|
115
|
+
:slave_user => 'vagrant',
|
116
|
+
:master_key => "/Library/Ruby/Gems/1.8/gems/vagrant-0.6.7/keys/vagrant", # FIXME - hardcoded master username assumption
|
117
|
+
:slave_fs => "/vagrant/tmp/hudson-slave/",
|
118
|
+
:description => "Automatically created by Hudson.rb",
|
119
|
+
:executors => 2,
|
120
|
+
:exclusive => true
|
121
|
+
)
|
122
|
+
else
|
123
|
+
default_options.merge!(
|
124
|
+
:slave_port => 22,
|
125
|
+
:slave_user => 'deploy',
|
126
|
+
:master_key => "/home/deploy/.ssh/id_rsa", # FIXME - hardcoded master username assumption
|
127
|
+
:slave_fs => "/data/hudson-slave/",
|
128
|
+
:description => "Automatically created by Hudson.rb",
|
129
|
+
:executors => 2,
|
130
|
+
:exclusive => true
|
131
|
+
)
|
132
|
+
end
|
133
|
+
options = default_options.merge(options)
|
134
|
+
|
120
135
|
slave_host = options[:slave_host]
|
121
136
|
name = options[:name] || slave_host
|
137
|
+
labels = options[:labels].split(/\s*,\s*/).join(' ') if options[:labels]
|
122
138
|
|
123
|
-
options = default_options.merge(options)
|
124
|
-
|
125
139
|
type = "hudson.slaves.DumbSlave$DescriptorImpl"
|
126
140
|
|
127
141
|
fields = {
|
@@ -133,7 +147,7 @@ module Hudson
|
|
133
147
|
"nodeDescription" => options[:description],
|
134
148
|
"numExecutors" => options[:executors],
|
135
149
|
"remoteFS" => options[:slave_fs],
|
136
|
-
"labelString" =>
|
150
|
+
"labelString" => labels,
|
137
151
|
"mode" => options[:exclusive] ? "EXCLUSIVE" : "NORMAL",
|
138
152
|
"type" => type,
|
139
153
|
"retentionStrategy" => { "stapler-class" => "hudson.slaves.RetentionStrategy$Always" },
|
@@ -158,7 +172,7 @@ module Hudson
|
|
158
172
|
response = http.request(req)
|
159
173
|
case response
|
160
174
|
when Net::HTTPFound
|
161
|
-
|
175
|
+
{ :name => name, :slave_host => slave_host }
|
162
176
|
else
|
163
177
|
# error message looks like:
|
164
178
|
# <td id="main-panel">
|
data/lib/hudson/cli.rb
CHANGED
@@ -16,63 +16,61 @@ module Hudson
|
|
16
16
|
end
|
17
17
|
|
18
18
|
desc "server [options]", "run a hudson server"
|
19
|
-
method_option :home, :type => :string, :default => File.join(ENV['HOME'], ".hudson", "server"), :banner => "PATH"
|
20
|
-
method_option :port, :
|
21
|
-
method_option :control, :
|
22
|
-
method_option :daemon, :
|
23
|
-
method_option :kill, :
|
24
|
-
method_option :logfile, :
|
19
|
+
method_option :home, :desc => "use this directory to store server data", :type => :string, :default => File.join(ENV['HOME'], ".hudson", "server"), :banner => "PATH"
|
20
|
+
method_option :port, :desc => "run hudson server on this port", :type => :numeric, :default => 3001, :aliases => "-p"
|
21
|
+
method_option :control, :desc => "set the shutdown/control port", :type => :numeric, :default => 3002, :aliases => "-c"
|
22
|
+
method_option :daemon, :desc => "fork into background and run as a daemon", :type => :boolean, :default => false
|
23
|
+
method_option :kill, :desc => "send shutdown signal to control port", :type => :boolean, :aliases => "-k"
|
24
|
+
method_option :logfile, :desc => "redirect log messages to this file", :type => :string, :banner => "PATH"
|
25
|
+
method_option :upgrade, :desc => "upgrade hudson server and plugins to latest version", :type => :boolean
|
25
26
|
def server
|
27
|
+
installation = Hudson::Installation.new(shell, options)
|
26
28
|
if options[:kill]
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
exit
|
29
|
+
installation.kill!
|
30
|
+
exit(0)
|
31
|
+
elsif options[:upgrade]
|
32
|
+
installation.upgrade!
|
33
|
+
exit(0)
|
34
|
+
else
|
35
|
+
installation.launch!
|
32
36
|
end
|
33
|
-
|
34
|
-
serverhome = File.join(options[:home])
|
35
|
-
javatmp = File.join(serverhome, "javatmp")
|
36
|
-
FileUtils.mkdir_p serverhome
|
37
|
-
FileUtils.mkdir_p javatmp
|
38
|
-
FileUtils.cp_r Hudson::PLUGINS, serverhome
|
39
|
-
ENV['HUDSON_HOME'] = serverhome
|
40
|
-
cmd = ["java", "-Djava.io.tmpdir=#{javatmp}", "-jar", Hudson::WAR]
|
41
|
-
cmd << "--daemon" if options[:daemon]
|
42
|
-
cmd << "--logfile=#{File.expand_path(options[:logfile])}" if options[:logfile]
|
43
|
-
cmd << "--httpPort=#{options[:port]}"
|
44
|
-
cmd << "--controlPort=#{options[:control]}"
|
45
|
-
shell.say cmd.join(" ")
|
46
|
-
exec(*cmd)
|
47
37
|
end
|
48
38
|
|
49
39
|
desc "create project_path [options]", "create a build for your project"
|
50
40
|
common_options
|
51
|
-
method_option :
|
52
|
-
method_option :
|
53
|
-
method_option :"
|
54
|
-
method_option :"
|
55
|
-
method_option :
|
41
|
+
method_option :rubies, :desc => "run tests against multiple explicit rubies via RVM", :type => :string
|
42
|
+
method_option :"node-labels", :desc => "run tests against multiple slave nodes by their label (comma separated)"
|
43
|
+
method_option :"assigned-node", :desc => "only use slave nodes with this label (similar to --node-labels)"
|
44
|
+
method_option :"no-build", :desc => "create job without initial build", :type => :boolean, :default => false
|
45
|
+
method_option :override, :desc => "override if job exists", :type => :boolean, :default => false
|
46
|
+
method_option :"scm", :desc => "specific SCM URI", :type => :string
|
47
|
+
method_option :"scm-branches", :desc => "list of branches to build from (comma separated)", :type => :string, :default => "master"
|
48
|
+
method_option :"public-scm", :desc => "use public scm URL", :type => :boolean, :default => false
|
49
|
+
method_option :template, :desc => "template of job steps (available: #{JobConfigBuilder::VALID_JOB_TEMPLATES.join ','})", :default => 'ruby'
|
50
|
+
method_option :"no-template", :desc => "do not use a template of default steps; avoids Gemfile requirement", :type => :boolean, :default => false
|
56
51
|
def create(project_path)
|
57
52
|
select_hudson_server(options)
|
58
53
|
FileUtils.chdir(project_path) do
|
59
|
-
unless scm = Hudson::ProjectScm.discover
|
54
|
+
unless scm = Hudson::ProjectScm.discover(options[:scm])
|
60
55
|
error "Cannot determine project SCM. Currently supported: #{Hudson::ProjectScm.supported}"
|
61
56
|
end
|
62
|
-
unless File.exists?("Gemfile")
|
57
|
+
unless (options[:template] == "none" || options[:"no-template"]) || File.exists?("Gemfile")
|
63
58
|
error "Ruby/Rails projects without a Gemfile are currently unsupported."
|
64
59
|
end
|
65
60
|
begin
|
66
|
-
template = options[:template]
|
61
|
+
template = options[:"no-template"] ? 'none' : options[:template]
|
67
62
|
job_config = Hudson::JobConfigBuilder.new(template) do |c|
|
68
|
-
c.
|
63
|
+
c.rubies = options[:rubies].split(/\s*,\s*/) if options[:rubies]
|
64
|
+
c.node_labels = options[:"node-labels"].split(/\s*,\s*/) if options[:"node-labels"]
|
65
|
+
c.scm = scm.url
|
66
|
+
c.scm_branches = options[:"scm-branches"].split(/\s*,\s*/)
|
69
67
|
c.assigned_node = options[:"assigned-node"] if options[:"assigned-node"]
|
70
|
-
c.public_scm
|
68
|
+
c.public_scm = options[:"public-scm"]
|
71
69
|
end
|
72
70
|
name = File.basename(FileUtils.pwd)
|
73
71
|
if Hudson::Api.create_job(name, job_config, options)
|
74
72
|
build_url = "#{@uri}/job/#{name.gsub(/\s/,'%20')}/build"
|
75
|
-
shell.say "Added
|
73
|
+
shell.say "Added#{' ' + template unless template == 'none'} project '#{name}' to Hudson.", :green
|
76
74
|
unless options[:"no-build"]
|
77
75
|
shell.say "Triggering initial build..."
|
78
76
|
Hudson::Api.build_job(name)
|
@@ -120,6 +118,30 @@ module Hudson
|
|
120
118
|
end
|
121
119
|
end
|
122
120
|
end
|
121
|
+
|
122
|
+
desc "job NAME", "Display job details"
|
123
|
+
method_option :hash, :desc => 'Dump as formatted Ruby hash format'
|
124
|
+
method_option :json, :desc => 'Dump as JSON format'
|
125
|
+
method_option :yaml, :desc => 'Dump as YAML format'
|
126
|
+
common_options
|
127
|
+
def job(name)
|
128
|
+
select_hudson_server(options)
|
129
|
+
if job = Hudson::Api.job(name)
|
130
|
+
if options[:hash]
|
131
|
+
require "ap"
|
132
|
+
ap job.parsed_response
|
133
|
+
elsif options[:json]
|
134
|
+
puts job.parsed_response.to_json
|
135
|
+
elsif options[:yaml]
|
136
|
+
require "yaml"
|
137
|
+
puts job.parsed_response.to_yaml
|
138
|
+
else
|
139
|
+
error "Select an output format: --json, --xml, --yaml, --hash"
|
140
|
+
end
|
141
|
+
else
|
142
|
+
error "Cannot find project '#{name}'."
|
143
|
+
end
|
144
|
+
end
|
123
145
|
|
124
146
|
desc "list [options]", "list jobs on a hudson server"
|
125
147
|
common_options
|
@@ -129,11 +151,10 @@ module Hudson
|
|
129
151
|
unless summary["jobs"].blank?
|
130
152
|
shell.say "#{@uri}:", :bold
|
131
153
|
summary["jobs"].each do |job|
|
132
|
-
|
133
|
-
|
134
|
-
color = '
|
135
|
-
color
|
136
|
-
color = 'yellow' if color == 'grey' || color == 'disabled'
|
154
|
+
bold = job['color'] =~ /anime/
|
155
|
+
color = 'red' if job['color'] =~ /red/
|
156
|
+
color = 'green' if job['color'] =~ /(blue|green)/
|
157
|
+
color ||= 'yellow' # if color =~ /grey/ || color == 'disabled'
|
137
158
|
shell.say "* "; shell.say(shell.set_color(job['name'], color.to_sym, bold), nil, true)
|
138
159
|
end
|
139
160
|
shell.say ""
|
@@ -154,21 +175,31 @@ module Hudson
|
|
154
175
|
end
|
155
176
|
|
156
177
|
desc "add_node SLAVE_HOST", "add a URI (user@host:port) server as a slave node"
|
157
|
-
method_option :
|
158
|
-
method_option :"slave-user", :desc => 'SSH user for Hudson to connect to slave node
|
159
|
-
method_option :"slave-port", :desc => 'SSH port for Hudson to connect to slave node
|
178
|
+
method_option :labels, :desc => 'Labels for a job --assigned_node to match against to select a slave (comma separated)'
|
179
|
+
method_option :"slave-user", :desc => 'SSH user for Hudson to connect to slave node (default: deploy)'
|
180
|
+
method_option :"slave-port", :desc => 'SSH port for Hudson to connect to slave node (default: 22)'
|
160
181
|
method_option :"master-key", :desc => 'Location of master public key or identity file'
|
161
|
-
method_option :"slave-fs", :desc
|
162
|
-
method_option :name, :desc
|
182
|
+
method_option :"slave-fs", :desc => 'Location of file system on slave for Hudson to use'
|
183
|
+
method_option :name, :desc => 'Name of slave node (default SLAVE_HOST)'
|
184
|
+
method_option :vagrant, :desc => 'Use settings for a Vagrant VM', :type => :boolean, :default => false
|
163
185
|
common_options
|
164
186
|
def add_node(slave_host)
|
165
187
|
select_hudson_server(options)
|
166
|
-
if Hudson::Api.add_node({:slave_host => slave_host}.merge(options))
|
167
|
-
shell.say "Added slave node #{slave_host}", :green
|
188
|
+
if results = Hudson::Api.add_node({:slave_host => slave_host}.merge(options))
|
189
|
+
shell.say "Added slave node '#{results[:name]}' to #{results[:slave_host]}", :green
|
168
190
|
else
|
169
191
|
error "Failed to add slave node #{slave_host}"
|
170
192
|
end
|
171
193
|
end
|
194
|
+
|
195
|
+
desc "default_host", "display current default host:port URI"
|
196
|
+
def default_host
|
197
|
+
if select_hudson_server({})
|
198
|
+
display Hudson::Api.base_uri
|
199
|
+
else
|
200
|
+
display "No default host yet. Use '--host host --port port' on your first request."
|
201
|
+
end
|
202
|
+
end
|
172
203
|
|
173
204
|
desc "help [command]", "show help for hudson or for a specific command"
|
174
205
|
def help(*args)
|
@@ -177,7 +208,7 @@ module Hudson
|
|
177
208
|
|
178
209
|
desc "version", "show version information"
|
179
210
|
def version
|
180
|
-
shell.say "#{Hudson::VERSION}
|
211
|
+
shell.say "#{Hudson::VERSION}"
|
181
212
|
end
|
182
213
|
|
183
214
|
def self.help(shell, *)
|
@@ -202,6 +233,7 @@ USEAGE
|
|
202
233
|
unless @uri = Hudson::Api.setup_base_url(options)
|
203
234
|
error "Either use --host or add remote servers."
|
204
235
|
end
|
236
|
+
@uri
|
205
237
|
end
|
206
238
|
|
207
239
|
def display(text)
|
@@ -0,0 +1,136 @@
|
|
1
|
+
module Hudson
|
2
|
+
class Installation
|
3
|
+
attr_reader :directory
|
4
|
+
|
5
|
+
def initialize(shell, opts = {})
|
6
|
+
@shell = shell
|
7
|
+
@options = opts
|
8
|
+
@serverhome = File.expand_path(@options[:home])
|
9
|
+
@warfile = File.join(File.dirname(@serverhome), "hudson.war")
|
10
|
+
@versionfile = "#{@serverhome}/version.txt"
|
11
|
+
@control_port = opts[:control]
|
12
|
+
end
|
13
|
+
|
14
|
+
def launch!
|
15
|
+
unless warfile?
|
16
|
+
@shell.say "no server currently installed."
|
17
|
+
upgrade!
|
18
|
+
end
|
19
|
+
javatmp = File.join(@serverhome, "javatmp")
|
20
|
+
FileUtils.mkdir_p javatmp
|
21
|
+
ENV['HUDSON_HOME'] = @serverhome
|
22
|
+
cmd = ["java", "-Djava.io.tmpdir=#{javatmp}", "-jar", @warfile]
|
23
|
+
cmd << "--daemon" if @options[:daemon]
|
24
|
+
cmd << "--logfile=#{File.expand_path(@options[:logfile])}" if @options[:logfile]
|
25
|
+
cmd << "--httpPort=#{@options[:port]}"
|
26
|
+
cmd << "--controlPort=#{@control_port}"
|
27
|
+
@shell.say cmd.join(" ")
|
28
|
+
exec(*cmd)
|
29
|
+
end
|
30
|
+
|
31
|
+
def kill!
|
32
|
+
require 'socket'
|
33
|
+
TCPSocket.open("localhost", @control_port) do |sock|
|
34
|
+
sock.write("0")
|
35
|
+
end
|
36
|
+
exit
|
37
|
+
end
|
38
|
+
|
39
|
+
def upgrade!
|
40
|
+
FileUtils.mkdir_p @serverhome
|
41
|
+
hudson_stock ? upgrade_from_fixture_stock : upgrade_from_network_stock
|
42
|
+
end
|
43
|
+
|
44
|
+
def hudson_stock
|
45
|
+
ENV['HUDSON_STOCK']
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def warfile?
|
51
|
+
File.exists?(@warfile) && system("unzip -l #{@warfile} > /dev/null 2>/dev/null")
|
52
|
+
end
|
53
|
+
|
54
|
+
def upgrade_from_fixture_stock
|
55
|
+
FileUtils.cp File.join(hudson_stock, "hudson.war"), @warfile
|
56
|
+
FileUtils.cp_r File.join(hudson_stock, "plugins"), @serverhome
|
57
|
+
end
|
58
|
+
|
59
|
+
def upgrade_from_network_stock
|
60
|
+
require 'ostruct'
|
61
|
+
progress = Progress.new
|
62
|
+
latest = progress.means "grabbing the latest metadata from hudson-ci.org" do |step|
|
63
|
+
JSON.parse(HTTParty.get("http://hudson-ci.org/update-center.json").lines.to_a[1..-2].join("\n"))
|
64
|
+
end
|
65
|
+
progress.means "downloading hudson server" do |step|
|
66
|
+
latest_version = latest["core"]["version"]
|
67
|
+
if latest_version > current_server_version
|
68
|
+
puts
|
69
|
+
`curl -L --progress-bar #{latest["core"]["url"]} -o #{@warfile}`
|
70
|
+
self.current_server_version = latest_version
|
71
|
+
step.ok("#{current_server_version} -> #{latest_version}")
|
72
|
+
else
|
73
|
+
step.ok("Up-to-date at #{current_server_version}")
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
plugins_dir = File.join(@serverhome, 'plugins')
|
78
|
+
plugins = if File.exists?(plugins_dir)
|
79
|
+
Dir.chdir(plugins_dir) do
|
80
|
+
Dir['*.hpi'].map {|entry| File.basename(entry,".hpi")}
|
81
|
+
end
|
82
|
+
else
|
83
|
+
%w(envfile git github greenballs rake ruby)
|
84
|
+
end
|
85
|
+
FileUtils.mkdir_p(plugins_dir)
|
86
|
+
for plugin in plugins do
|
87
|
+
metadata = OpenStruct.new(latest['plugins'][plugin])
|
88
|
+
progress.means "downloading #{plugin} plugin" do |step|
|
89
|
+
system("curl -L --silent #{metadata.url} > #{plugins_dir}/#{plugin}.hpi")
|
90
|
+
step.ok(metadata.version)
|
91
|
+
end
|
92
|
+
end unless progress.aborted
|
93
|
+
end
|
94
|
+
|
95
|
+
def current_server_version
|
96
|
+
File.exists?(@versionfile) ? File.read(@versionfile) : "0"
|
97
|
+
end
|
98
|
+
|
99
|
+
def current_server_version=(version)
|
100
|
+
File.open(@versionfile, "w") do |f|
|
101
|
+
f.write(version)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
class Progress
|
106
|
+
attr_reader :aborted
|
107
|
+
def initialize
|
108
|
+
@shell = Thor::Shell::Color.new
|
109
|
+
@aborted = false
|
110
|
+
end
|
111
|
+
|
112
|
+
def means(step)
|
113
|
+
return if @aborted
|
114
|
+
begin
|
115
|
+
@shell.say(step + "... ")
|
116
|
+
yield(self).tap do
|
117
|
+
@shell.say("[OK]", :green)
|
118
|
+
end
|
119
|
+
rescue Ok => ok
|
120
|
+
@shell.say("[OK#{ok.message ? " - #{ok.message}" : ''}]", :green)
|
121
|
+
rescue StandardError => e
|
122
|
+
@shell.say("[FAIL - #{e.message}]", :red)
|
123
|
+
@aborted = true
|
124
|
+
false
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def ok(msg = nil)
|
129
|
+
raise Ok.new(msg)
|
130
|
+
end
|
131
|
+
|
132
|
+
class Ok < StandardError
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
@@ -2,29 +2,31 @@ require "builder"
|
|
2
2
|
|
3
3
|
module Hudson
|
4
4
|
class JobConfigBuilder
|
5
|
-
attr_accessor :job_type
|
6
|
-
attr_accessor :steps
|
5
|
+
attr_accessor :job_type
|
6
|
+
attr_accessor :steps, :rubies
|
7
|
+
attr_accessor :scm, :public_scm, :scm_branches
|
7
8
|
attr_accessor :scm, :public_scm, :git_branches
|
8
|
-
attr_accessor :assigned_node
|
9
|
+
attr_accessor :assigned_node, :node_labels # TODO just one of these
|
9
10
|
attr_accessor :envfile
|
10
11
|
|
11
12
|
InvalidTemplate = Class.new(StandardError)
|
12
13
|
|
13
|
-
VALID_JOB_TEMPLATES = %w[rails rails3 ruby rubygem]
|
14
|
+
VALID_JOB_TEMPLATES = %w[none rails rails3 ruby rubygem]
|
14
15
|
|
15
16
|
# +job_type+ - template of default steps to create with the job
|
16
17
|
# +steps+ - array of [:method, cmd], e.g. [:build_shell_step, "bundle initial"]
|
17
18
|
# - Default is based on +job_type+.
|
18
19
|
# +scm+ - URL to the repository. Currently only support git URLs.
|
19
20
|
# +public_scm+ - convert the +scm+ URL to a publicly accessible URL for the Hudson job config.
|
20
|
-
# +
|
21
|
+
# +scm_branches+ - array of branches to run builds. Default: ['master']
|
22
|
+
# +rubies+ - list of RVM rubies to run tests (via Hudson Axes).
|
21
23
|
# +assigned_node+ - restrict this job to running on slaves with these labels (space separated)
|
22
24
|
def initialize(job_type = :ruby, &block)
|
23
25
|
self.job_type = job_type.to_s if job_type
|
24
26
|
|
25
27
|
yield self
|
26
28
|
|
27
|
-
self.
|
29
|
+
self.scm_branches ||= ["master"]
|
28
30
|
raise InvalidTemplate unless VALID_JOB_TEMPLATES.include?(job_type.to_s)
|
29
31
|
end
|
30
32
|
|
@@ -41,7 +43,7 @@ module Hudson
|
|
41
43
|
b.canRoam !assigned_node
|
42
44
|
b.disabled false
|
43
45
|
b.blockBuildWhenUpstreamBuilding false
|
44
|
-
|
46
|
+
b.triggers :class => "vector"
|
45
47
|
b.concurrentBuild false
|
46
48
|
build_axes b if matrix_project?
|
47
49
|
build_steps b
|
@@ -57,11 +59,6 @@ module Hudson
|
|
57
59
|
|
58
60
|
protected
|
59
61
|
|
60
|
-
def matrix_project?
|
61
|
-
matrix_project ||
|
62
|
-
%w[rubygem].include?(job_type)
|
63
|
-
end
|
64
|
-
|
65
62
|
# <scm class="hudson.plugins.git.GitSCM"> ... </scm>
|
66
63
|
def build_scm(b)
|
67
64
|
if scm && scm =~ /git/
|
@@ -85,9 +82,9 @@ module Hudson
|
|
85
82
|
end
|
86
83
|
end
|
87
84
|
|
88
|
-
if
|
85
|
+
if scm_branches
|
89
86
|
b.branches do
|
90
|
-
|
87
|
+
scm_branches.each do |branch|
|
91
88
|
b.tag! "hudson.plugins.git.BranchSpec" do
|
92
89
|
b.name branch
|
93
90
|
end
|
@@ -112,9 +109,49 @@ module Hudson
|
|
112
109
|
end
|
113
110
|
end
|
114
111
|
|
115
|
-
|
112
|
+
def matrix_project?
|
113
|
+
!(rubies.blank? && node_labels.blank?)
|
114
|
+
end
|
115
|
+
|
116
|
+
# <hudson.matrix.TextAxis>
|
117
|
+
# <name>RUBY_VERSION</name>
|
118
|
+
# <values>
|
119
|
+
# <string>1.8.7</string>
|
120
|
+
# <string>1.9.2</string>
|
121
|
+
# <string>rbx-head</string>
|
122
|
+
# <string>jruby</string>
|
123
|
+
# </values>
|
124
|
+
# </hudson.matrix.TextAxis>
|
125
|
+
# <hudson.matrix.LabelAxis>
|
126
|
+
# <name>label</name>
|
127
|
+
# <values>
|
128
|
+
# <string>1.8.7</string>
|
129
|
+
# <string>ubuntu</string>
|
130
|
+
# </values>
|
131
|
+
# </hudson.matrix.LabelAxis>
|
116
132
|
def build_axes(b)
|
117
|
-
b.axes
|
133
|
+
b.axes do
|
134
|
+
unless rubies.blank?
|
135
|
+
b.tag! "hudson.matrix.TextAxis" do
|
136
|
+
b.name "RUBY_VERSION"
|
137
|
+
b.values do
|
138
|
+
rubies.each do |rvm_name|
|
139
|
+
b.string rvm_name
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
unless node_labels.blank?
|
145
|
+
b.tag! "hudson.matrix.LabelAxis" do
|
146
|
+
b.name "label"
|
147
|
+
b.values do
|
148
|
+
node_labels.each do |label|
|
149
|
+
b.string label
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
118
155
|
end
|
119
156
|
|
120
157
|
# Example:
|
@@ -152,7 +189,7 @@ module Hudson
|
|
152
189
|
end
|
153
190
|
|
154
191
|
def default_steps(job_type)
|
155
|
-
case job_type.to_sym
|
192
|
+
steps = case job_type.to_sym
|
156
193
|
when :rails, :rails3
|
157
194
|
[
|
158
195
|
[:build_shell_step, "bundle install"],
|
@@ -174,20 +211,30 @@ module Hudson
|
|
174
211
|
RUBY
|
175
212
|
[:build_shell_step, "bundle exec rake"]
|
176
213
|
]
|
177
|
-
|
214
|
+
when :ruby, :rubygems
|
178
215
|
[
|
179
216
|
[:build_shell_step, "bundle install"],
|
180
217
|
[:build_shell_step, "bundle exec rake"]
|
181
218
|
]
|
219
|
+
else
|
220
|
+
[ [:build_shell_step, 'echo "THERE ARE NO STEPS! Except this one..."'] ]
|
182
221
|
end
|
222
|
+
rubies.blank? ? steps : default_rvm_steps + steps
|
183
223
|
end
|
184
|
-
|
224
|
+
|
225
|
+
def default_rvm_steps
|
226
|
+
[
|
227
|
+
[:build_shell_step, "rvm $RUBY_VERSION"],
|
228
|
+
[:build_shell_step, "rvm gemset create ruby-$RUBY_VERSION && rvm gemset use ruby-$RUBY_VERSION"]
|
229
|
+
]
|
230
|
+
end
|
231
|
+
|
185
232
|
# <hudson.tasks.Shell>
|
186
|
-
# <command>
|
233
|
+
# <command>echo 'THERE ARE NO STEPS! Except this one...'</command>
|
187
234
|
# </hudson.tasks.Shell>
|
188
235
|
def build_shell_step(b, command)
|
189
236
|
b.tag! "hudson.tasks.Shell" do
|
190
|
-
b.command command.to_xs.gsub(%r{"}, '"').gsub(%r{'}, ''')
|
237
|
+
b.command command.to_xs.gsub("&", '&') #.gsub(%r{"}, '"').gsub(%r{'}, ''')
|
191
238
|
end
|
192
239
|
end
|
193
240
|
|