hudson 0.5.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/Changelog.md +3 -0
- data/Gemfile.lock +11 -43
- data/README.md +3 -151
- data/Rakefile +0 -77
- data/bin/hudson +2 -10
- data/hudson.gemspec +2 -12
- data/lib/hudson.rb +1 -8
- data/lib/hudson/version.rb +1 -1
- metadata +8 -203
- data/features/default_host.feature +0 -19
- data/features/development.feature +0 -14
- data/features/launch_server.feature +0 -17
- data/features/listing_jobs.feature +0 -34
- data/features/manage_jobs.feature +0 -207
- data/features/manage_slave_nodes.feature +0 -80
- data/features/step_definitions/common_steps.rb +0 -197
- data/features/step_definitions/fixture_project_steps.rb +0 -8
- data/features/step_definitions/hudson_steps.rb +0 -104
- data/features/step_definitions/scm_steps.rb +0 -12
- data/features/support/common.rb +0 -37
- data/features/support/env.rb +0 -14
- data/features/support/hooks.rb +0 -16
- data/features/support/hudson_helpers.rb +0 -6
- data/features/support/matchers.rb +0 -10
- data/lib/hudson/api.rb +0 -219
- data/lib/hudson/cli.rb +0 -253
- data/lib/hudson/cli/formatting.rb +0 -53
- data/lib/hudson/config.rb +0 -27
- data/lib/hudson/core_ext/hash.rb +0 -9
- data/lib/hudson/core_ext/object/blank.rb +0 -77
- data/lib/hudson/hudson-cli.jar +0 -0
- data/lib/hudson/installation.rb +0 -136
- data/lib/hudson/job_config_builder.rb +0 -287
- data/lib/hudson/project_scm.rb +0 -22
- data/lib/hudson/remote.rb +0 -11
- data/spec/fixtures/ec2_global.config.xml +0 -103
- data/spec/fixtures/rails.multi.config.xml +0 -82
- data/spec/fixtures/rails.single.config.triggers.xml +0 -84
- data/spec/fixtures/rails.single.config.xml +0 -80
- data/spec/fixtures/ruby.multi-ruby-multi-labels.config.xml +0 -84
- data/spec/fixtures/ruby.multi.config.xml +0 -77
- data/spec/fixtures/ruby.single.config.xml +0 -58
- data/spec/fixtures/therubyracer.config.xml +0 -77
- data/spec/hash_key_cleaner_spec.rb +0 -25
- data/spec/job_config_builder_spec.rb +0 -137
- data/spec/spec_helper.rb +0 -15
@@ -1,8 +0,0 @@
|
|
1
|
-
Given /^I am in the "([^\"]*)" project folder$/ do |project|
|
2
|
-
project_folder = File.expand_path(File.dirname(__FILE__) + "/../../fixtures/projects/#{project}")
|
3
|
-
in_tmp_folder do
|
4
|
-
FileUtils.cp_r(project_folder, project)
|
5
|
-
setup_active_project_folder(project)
|
6
|
-
end
|
7
|
-
end
|
8
|
-
|
@@ -1,104 +0,0 @@
|
|
1
|
-
Given /^I have a Hudson server running$/ do
|
2
|
-
unless @hudson_port
|
3
|
-
port = 3010
|
4
|
-
begin
|
5
|
-
res = Net::HTTP.start("localhost", port) { |http| http.get('/api/json') }
|
6
|
-
Hudson::Api.base_uri "http://localhost:#{port}"
|
7
|
-
rescue Errno::ECONNREFUSED => e
|
8
|
-
raise Exception, "To run tests, launch hudson in test mode: 'rake hudson:server:test'"
|
9
|
-
end
|
10
|
-
@hudson_port = port.to_s
|
11
|
-
@hudson_host = 'localhost'
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
Given /^the Hudson server has no current jobs$/ do
|
16
|
-
if port = @hudson_port
|
17
|
-
Hudson::Api.summary['jobs'].each do |job|
|
18
|
-
Hudson::Api.delete_job(job['name'])
|
19
|
-
end
|
20
|
-
Hudson::Api.summary['jobs'].should == []
|
21
|
-
else
|
22
|
-
puts "WARNING: Run 'I have a Hudson server running' step first."
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
Given /^the Hudson server has no slaves$/ do
|
27
|
-
if port = @hudson_port
|
28
|
-
Hudson::Api.summary['jobs'].each do |job|
|
29
|
-
Hudson::Api.delete_job(job['name'])
|
30
|
-
end
|
31
|
-
Hudson::Api.summary['jobs'].should == []
|
32
|
-
|
33
|
-
Hudson::Api.nodes['computer'].each do |node|
|
34
|
-
name = node['displayName']
|
35
|
-
Hudson::Api.delete_node(name) unless name == "master"
|
36
|
-
end
|
37
|
-
Hudson::Api.nodes['computer'].size.should == 1
|
38
|
-
else
|
39
|
-
puts "WARNING: Run 'I have a Hudson server running' step first."
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
Given /^there is nothing listening on port (\d+)$/ do |port|
|
44
|
-
lambda {
|
45
|
-
TCPSocket.open("localhost", port) {}
|
46
|
-
}.should raise_error
|
47
|
-
end
|
48
|
-
|
49
|
-
Given /^I cleanup any hudson processes with control port (\d+)$/ do |port|
|
50
|
-
@hudson_cleanup << port
|
51
|
-
end
|
52
|
-
|
53
|
-
def try(times, interval = 1)
|
54
|
-
begin
|
55
|
-
times -= 1
|
56
|
-
return yield
|
57
|
-
rescue Exception => e
|
58
|
-
if times >= 0
|
59
|
-
sleep(interval)
|
60
|
-
retry
|
61
|
-
end
|
62
|
-
raise e
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
When /^I run hudson server with arguments "(.*)"/ do |arguments|
|
67
|
-
@stdout = File.expand_path(File.join(@tmp_root, "executable.out"))
|
68
|
-
executable = File.expand_path(File.join(File.dirname(__FILE__), "/../../bin","hudson"))
|
69
|
-
in_project_folder do
|
70
|
-
system "ruby #{executable.inspect} server #{arguments} > #{@stdout.inspect} 2> #{@stdout.inspect}"
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
|
75
|
-
Then /^I should see a hudson server on port (\d+)$/ do |port|
|
76
|
-
require 'json'
|
77
|
-
try(15, 2) do
|
78
|
-
Hudson::Api.base_uri "http://localhost:#{port}"
|
79
|
-
Hudson::Api.summary['nodeDescription'].should == "the master Hudson node"
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
When /^I (re|)create a job$/ do |override|
|
84
|
-
override = override.blank? ? "" : " --override"
|
85
|
-
steps <<-CUCUMBER
|
86
|
-
When the project uses "git" scm
|
87
|
-
When I run local executable "hudson" with arguments "create . --host localhost --port 3010#{override}"
|
88
|
-
CUCUMBER
|
89
|
-
end
|
90
|
-
|
91
|
-
Then /^the job "([^"]*)" config "([^"]*)" should be:$/ do |job_name, xpath, string|
|
92
|
-
raise "Cannot yet fetch XML config from non-localhost Hudson" unless Hudson::Api.base_uri =~ /localhost/
|
93
|
-
require "hpricot"
|
94
|
-
config = Hpricot.XML(File.read("#{test_hudson_path}/jobs/#{job_name}/config.xml"))
|
95
|
-
config.search(xpath).to_s.should == string
|
96
|
-
end
|
97
|
-
|
98
|
-
Then /^the Hudson config "([^"]*)" should be:$/ do |xpath, string|
|
99
|
-
raise "Cannot yet fetch XML config from non-localhost Hudson" unless Hudson::Api.base_uri =~ /localhost/
|
100
|
-
require "hpricot"
|
101
|
-
config = Hpricot.XML(File.read("#{test_hudson_path}/config.xml"))
|
102
|
-
config.search(xpath).to_s.should == string
|
103
|
-
end
|
104
|
-
|
@@ -1,12 +0,0 @@
|
|
1
|
-
Given /^the project uses "git" scm$/ do
|
2
|
-
repo = "git://some.host/drnic/ruby.git"
|
3
|
-
in_project_folder do
|
4
|
-
unless File.exist?(".git")
|
5
|
-
%x[ git init ]
|
6
|
-
%x[ git add . ]
|
7
|
-
%x[ git commit -m "initial commit" ]
|
8
|
-
%x[ git remote add origin #{repo} ]
|
9
|
-
end
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
data/features/support/common.rb
DELETED
@@ -1,37 +0,0 @@
|
|
1
|
-
module CommonHelpers
|
2
|
-
def get_command_output
|
3
|
-
strip_color_codes(File.read(@stdout)).chomp
|
4
|
-
end
|
5
|
-
|
6
|
-
def strip_color_codes(text)
|
7
|
-
text.gsub(/\e\[\d+m/, '')
|
8
|
-
end
|
9
|
-
|
10
|
-
def in_tmp_folder(&block)
|
11
|
-
FileUtils.chdir(@tmp_root, &block)
|
12
|
-
end
|
13
|
-
|
14
|
-
def in_project_folder(&block)
|
15
|
-
project_folder = @active_project_folder || @tmp_root
|
16
|
-
FileUtils.chdir(project_folder, &block)
|
17
|
-
end
|
18
|
-
|
19
|
-
def in_home_folder(&block)
|
20
|
-
FileUtils.chdir(@home_path, &block)
|
21
|
-
end
|
22
|
-
|
23
|
-
def force_local_lib_override(project_name = @project_name)
|
24
|
-
rakefile = File.read(File.join(project_name, 'Rakefile'))
|
25
|
-
File.open(File.join(project_name, 'Rakefile'), "w+") do |f|
|
26
|
-
f << "$:.unshift('#{@lib_path}')\n"
|
27
|
-
f << rakefile
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
def setup_active_project_folder project_name
|
32
|
-
@active_project_folder = File.join(@tmp_root, project_name)
|
33
|
-
@project_name = project_name
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
World(CommonHelpers)
|
data/features/support/env.rb
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
$:.unshift(File.expand_path(File.dirname(__FILE__) + "/../../lib"))
|
2
|
-
require 'hudson.rb'
|
3
|
-
require 'bundler/setup'
|
4
|
-
require 'ap'
|
5
|
-
|
6
|
-
Before do
|
7
|
-
@tmp_root = File.dirname(__FILE__) + "/../../tmp"
|
8
|
-
@home_path = File.expand_path(File.join(@tmp_root, "home"))
|
9
|
-
@lib_path = File.expand_path(File.dirname(__FILE__) + "/../../lib")
|
10
|
-
FileUtils.rm_rf @tmp_root
|
11
|
-
FileUtils.mkdir_p @home_path
|
12
|
-
ENV['HOME'] = @home_path
|
13
|
-
ENV['CUCUMBER_RUNNING'] = 'oooh yes'
|
14
|
-
end
|
data/features/support/hooks.rb
DELETED
data/lib/hudson/api.rb
DELETED
@@ -1,219 +0,0 @@
|
|
1
|
-
require 'httparty'
|
2
|
-
require 'cgi'
|
3
|
-
require 'uri'
|
4
|
-
require 'json'
|
5
|
-
|
6
|
-
require 'hudson/core_ext/hash'
|
7
|
-
require 'hudson/config'
|
8
|
-
|
9
|
-
module Hudson
|
10
|
-
module Api
|
11
|
-
include HTTParty
|
12
|
-
|
13
|
-
headers 'content-type' => 'application/json'
|
14
|
-
format :json
|
15
|
-
# http_proxy 'localhost', '8888'
|
16
|
-
|
17
|
-
JobAlreadyExistsError = Class.new(Exception)
|
18
|
-
|
19
|
-
def self.setup_base_url(options)
|
20
|
-
options = options.with_clean_keys
|
21
|
-
# Thor's HashWithIndifferentAccess is based on string keys which URI::HTTP.build ignores
|
22
|
-
options = options.inject({}) { |mem, (key, val)| mem[key.to_sym] = val; mem }
|
23
|
-
options[:host] ||= ENV['HUDSON_HOST']
|
24
|
-
options[:port] ||= ENV['HUDSON_PORT']
|
25
|
-
options[:port] &&= options[:port].to_i
|
26
|
-
return false unless options[:host] || Hudson::Config.config["base_uri"]
|
27
|
-
uri = options[:host] ? URI::HTTP.build(options) : Hudson::Config.config["base_uri"]
|
28
|
-
base_uri uri.to_s
|
29
|
-
uri
|
30
|
-
end
|
31
|
-
|
32
|
-
# returns true if successfully create a new job on Hudson
|
33
|
-
# +job_config+ is a Hudson::JobConfigBuilder instance
|
34
|
-
# +options+ are:
|
35
|
-
# :override - true, will delete any existing job with same name, else error
|
36
|
-
#
|
37
|
-
# returns true if successful, else false
|
38
|
-
#
|
39
|
-
# TODO Exceptions?
|
40
|
-
def self.create_job(name, job_config, options = {})
|
41
|
-
options = options.with_clean_keys
|
42
|
-
delete_job(name) if options[:override]
|
43
|
-
begin
|
44
|
-
res = post "/createItem/api/xml?name=#{CGI.escape(name)}", {
|
45
|
-
:body => job_config.to_xml, :format => :xml, :headers => { 'content-type' => 'application/xml' }
|
46
|
-
}
|
47
|
-
if res.code.to_i == 200
|
48
|
-
cache_base_uri
|
49
|
-
true
|
50
|
-
else
|
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
|
62
|
-
false
|
63
|
-
end
|
64
|
-
rescue REXML::ParseException => e
|
65
|
-
# For some reason, if the job exists we get back half a page of HTML
|
66
|
-
raise JobAlreadyExistsError.new(name)
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
# Attempts to delete a job +name+
|
71
|
-
def self.delete_job(name)
|
72
|
-
res = post_plain "#{job_url name}/doDelete"
|
73
|
-
res.code.to_i == 302
|
74
|
-
end
|
75
|
-
|
76
|
-
def self.build_job(name)
|
77
|
-
res = get_plain "/job/#{name}/build"
|
78
|
-
res.code.to_i == 302
|
79
|
-
end
|
80
|
-
|
81
|
-
def self.summary
|
82
|
-
json = get "/api/json"
|
83
|
-
cache_base_uri
|
84
|
-
json
|
85
|
-
end
|
86
|
-
|
87
|
-
def self.job_names
|
88
|
-
summary["jobs"].map {|job| job["name"]}
|
89
|
-
end
|
90
|
-
|
91
|
-
# Return hash of job statuses
|
92
|
-
def self.job(name)
|
93
|
-
begin
|
94
|
-
json = get "/job/#{name}/api/json"
|
95
|
-
cache_base_uri
|
96
|
-
json
|
97
|
-
rescue Crack::ParseError
|
98
|
-
false
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
def self.nodes
|
103
|
-
json = get "/computer/api/json"
|
104
|
-
cache_base_uri
|
105
|
-
json
|
106
|
-
end
|
107
|
-
|
108
|
-
# Adds SSH nodes only, for now
|
109
|
-
def self.add_node(options = {})
|
110
|
-
options = options.with_clean_keys
|
111
|
-
default_options = Hash.new
|
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
|
-
|
135
|
-
slave_host = options[:slave_host]
|
136
|
-
name = options[:name] || slave_host
|
137
|
-
labels = options[:labels].split(/\s*,\s*/).join(' ') if options[:labels]
|
138
|
-
|
139
|
-
type = "hudson.slaves.DumbSlave$DescriptorImpl"
|
140
|
-
|
141
|
-
fields = {
|
142
|
-
"name" => name,
|
143
|
-
"type" => type,
|
144
|
-
|
145
|
-
"json" => {
|
146
|
-
"name" => name,
|
147
|
-
"nodeDescription" => options[:description],
|
148
|
-
"numExecutors" => options[:executors],
|
149
|
-
"remoteFS" => options[:slave_fs],
|
150
|
-
"labelString" => labels,
|
151
|
-
"mode" => options[:exclusive] ? "EXCLUSIVE" : "NORMAL",
|
152
|
-
"type" => type,
|
153
|
-
"retentionStrategy" => { "stapler-class" => "hudson.slaves.RetentionStrategy$Always" },
|
154
|
-
"nodeProperties" => { "stapler-class-bag" => "true" },
|
155
|
-
"launcher" => {
|
156
|
-
"stapler-class" => "hudson.plugins.sshslaves.SSHLauncher",
|
157
|
-
"host" => slave_host,
|
158
|
-
"port" => options[:slave_port],
|
159
|
-
"username" => options[:slave_user],
|
160
|
-
"privatekey" => options[:master_key],
|
161
|
-
}
|
162
|
-
}.to_json
|
163
|
-
}
|
164
|
-
|
165
|
-
url = URI.parse("#{base_uri}/computer/doCreateItem")
|
166
|
-
|
167
|
-
req = Net::HTTP::Post.new(url.path)
|
168
|
-
req.set_form_data(fields)
|
169
|
-
|
170
|
-
http = Net::HTTP.new(url.host, url.port)
|
171
|
-
|
172
|
-
response = http.request(req)
|
173
|
-
case response
|
174
|
-
when Net::HTTPFound
|
175
|
-
{ :name => name, :slave_host => slave_host }
|
176
|
-
else
|
177
|
-
# error message looks like:
|
178
|
-
# <td id="main-panel">
|
179
|
-
# <h1>Error</h1><p>Slave called 'localhost' already exists</p>
|
180
|
-
require "hpricot"
|
181
|
-
error = Hpricot(response.body).search("td#main-panel p").text
|
182
|
-
unless error.blank?
|
183
|
-
puts error
|
184
|
-
else
|
185
|
-
puts response.body # so we can find other errors
|
186
|
-
end
|
187
|
-
false
|
188
|
-
end
|
189
|
-
end
|
190
|
-
|
191
|
-
def self.delete_node(name)
|
192
|
-
post_plain("#{base_uri}/computer/#{CGI::escape(name).gsub('+', '%20')}/doDelete/api/json")
|
193
|
-
end
|
194
|
-
|
195
|
-
# Helper for POST that don't barf at Hudson's crappy API responses
|
196
|
-
def self.post_plain(path, options = {})
|
197
|
-
options = options.with_clean_keys
|
198
|
-
uri = URI.parse base_uri
|
199
|
-
res = Net::HTTP.start(uri.host, uri.port) { |http| http.post(path, options) }
|
200
|
-
end
|
201
|
-
|
202
|
-
# Helper for GET that don't barf at Hudson's crappy API responses
|
203
|
-
def self.get_plain(path, options = {})
|
204
|
-
options = options.with_clean_keys
|
205
|
-
uri = URI.parse base_uri
|
206
|
-
res = Net::HTTP.start(uri.host, uri.port) { |http| http.get(path, options) }
|
207
|
-
end
|
208
|
-
|
209
|
-
private
|
210
|
-
def self.cache_base_uri
|
211
|
-
Hudson::Config.config["base_uri"] = base_uri
|
212
|
-
Hudson::Config.store!
|
213
|
-
end
|
214
|
-
|
215
|
-
def self.job_url(name)
|
216
|
-
"#{base_uri}/job/#{name}"
|
217
|
-
end
|
218
|
-
end
|
219
|
-
end
|
data/lib/hudson/cli.rb
DELETED
@@ -1,253 +0,0 @@
|
|
1
|
-
require 'thor'
|
2
|
-
require 'hudson/core_ext/object/blank'
|
3
|
-
require 'hudson/core_ext/hash'
|
4
|
-
require 'hudson/cli/formatting'
|
5
|
-
require 'hudson/remote'
|
6
|
-
|
7
|
-
module Hudson
|
8
|
-
class CLI < Thor
|
9
|
-
include CLI::Formatting
|
10
|
-
|
11
|
-
map "-v" => :version, "--version" => :version, "-h" => :help, "--help" => :help
|
12
|
-
|
13
|
-
def self.common_options
|
14
|
-
method_option :host, :desc => 'connect to hudson server on this host'
|
15
|
-
method_option :port, :desc => 'connect to hudson server on this port'
|
16
|
-
end
|
17
|
-
|
18
|
-
desc "server [options]", "run a hudson server"
|
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
|
26
|
-
def server
|
27
|
-
installation = Hudson::Installation.new(shell, options)
|
28
|
-
if options[:kill]
|
29
|
-
installation.kill!
|
30
|
-
exit(0)
|
31
|
-
elsif options[:upgrade]
|
32
|
-
installation.upgrade!
|
33
|
-
exit(0)
|
34
|
-
else
|
35
|
-
installation.launch!
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
desc "create project_path [options]", "create a build for your project"
|
40
|
-
common_options
|
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
|
51
|
-
def create(project_path)
|
52
|
-
select_hudson_server(options)
|
53
|
-
FileUtils.chdir(project_path) do
|
54
|
-
unless scm = Hudson::ProjectScm.discover(options[:scm])
|
55
|
-
error "Cannot determine project SCM. Currently supported: #{Hudson::ProjectScm.supported}"
|
56
|
-
end
|
57
|
-
unless (options[:template] == "none" || options[:"no-template"]) || File.exists?("Gemfile")
|
58
|
-
error "Ruby/Rails projects without a Gemfile are currently unsupported."
|
59
|
-
end
|
60
|
-
begin
|
61
|
-
template = options[:"no-template"] ? 'none' : options[:template]
|
62
|
-
job_config = Hudson::JobConfigBuilder.new(template) do |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*/)
|
67
|
-
c.assigned_node = options[:"assigned-node"] if options[:"assigned-node"]
|
68
|
-
c.public_scm = options[:"public-scm"]
|
69
|
-
end
|
70
|
-
name = File.basename(FileUtils.pwd)
|
71
|
-
if Hudson::Api.create_job(name, job_config, options)
|
72
|
-
build_url = "#{@uri}/job/#{name.gsub(/\s/,'%20')}/build"
|
73
|
-
shell.say "Added#{' ' + template unless template == 'none'} project '#{name}' to Hudson.", :green
|
74
|
-
unless options[:"no-build"]
|
75
|
-
shell.say "Triggering initial build..."
|
76
|
-
Hudson::Api.build_job(name)
|
77
|
-
shell.say "Trigger additional builds via:"
|
78
|
-
else
|
79
|
-
shell.say "Trigger builds via:"
|
80
|
-
end
|
81
|
-
shell.say " URL: "; shell.say "#{build_url}", :yellow
|
82
|
-
shell.say " CLI: "; shell.say "#{cmd} build #{name}", :yellow
|
83
|
-
else
|
84
|
-
error "Failed to create project '#{name}'"
|
85
|
-
end
|
86
|
-
rescue Hudson::JobConfigBuilder::InvalidTemplate
|
87
|
-
error "Invalid job template '#{template}'."
|
88
|
-
rescue Hudson::Api::JobAlreadyExistsError
|
89
|
-
error "Job '#{name}' already exists."
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
desc "build [PROJECT_PATH]", "trigger build of this project's build job"
|
95
|
-
common_options
|
96
|
-
def build(project_path = ".")
|
97
|
-
select_hudson_server(options)
|
98
|
-
FileUtils.chdir(project_path) do
|
99
|
-
name = File.basename(FileUtils.pwd)
|
100
|
-
if Hudson::Api.build_job(name)
|
101
|
-
shell.say "Build for '#{name}' running now..."
|
102
|
-
else
|
103
|
-
error "No job '#{name}' on server."
|
104
|
-
end
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
desc "remove PROJECT_PATH", "remove this project's build job from Hudson"
|
109
|
-
common_options
|
110
|
-
def remove(project_path)
|
111
|
-
select_hudson_server(options)
|
112
|
-
FileUtils.chdir(project_path) do
|
113
|
-
name = File.basename(FileUtils.pwd)
|
114
|
-
if Hudson::Api.delete_job(name)
|
115
|
-
shell.say "Removed project '#{name}' from Hudson."
|
116
|
-
else
|
117
|
-
error "Failed to delete project '#{name}'."
|
118
|
-
end
|
119
|
-
end
|
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
|
145
|
-
|
146
|
-
desc "list [options]", "list jobs on a hudson server"
|
147
|
-
common_options
|
148
|
-
def list
|
149
|
-
select_hudson_server(options)
|
150
|
-
summary = Hudson::Api.summary
|
151
|
-
unless summary["jobs"].blank?
|
152
|
-
shell.say "#{@uri}:", :bold
|
153
|
-
summary["jobs"].each do |job|
|
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'
|
158
|
-
shell.say "* "; shell.say(shell.set_color(job['name'], color.to_sym, bold), nil, true)
|
159
|
-
end
|
160
|
-
shell.say ""
|
161
|
-
else
|
162
|
-
shell.say "#{@uri}: "; shell.say "no jobs", :yellow
|
163
|
-
end
|
164
|
-
end
|
165
|
-
|
166
|
-
desc "nodes", "list hudson server nodes"
|
167
|
-
common_options
|
168
|
-
def nodes
|
169
|
-
select_hudson_server(options)
|
170
|
-
nodes = Hudson::Api.nodes
|
171
|
-
nodes["computer"].each do |node|
|
172
|
-
color = node["offline"] ? :red : :green
|
173
|
-
shell.say node["displayName"], color
|
174
|
-
end
|
175
|
-
end
|
176
|
-
|
177
|
-
desc "add_node SLAVE_HOST", "add a URI (user@host:port) server as a 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)'
|
181
|
-
method_option :"master-key", :desc => 'Location of master public key or identity file'
|
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
|
185
|
-
common_options
|
186
|
-
def add_node(slave_host)
|
187
|
-
select_hudson_server(options)
|
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
|
190
|
-
else
|
191
|
-
error "Failed to add slave node #{slave_host}"
|
192
|
-
end
|
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
|
203
|
-
|
204
|
-
desc "help [command]", "show help for hudson or for a specific command"
|
205
|
-
def help(*args)
|
206
|
-
super(*args)
|
207
|
-
end
|
208
|
-
|
209
|
-
desc "version", "show version information"
|
210
|
-
def version
|
211
|
-
shell.say "#{Hudson::VERSION}"
|
212
|
-
end
|
213
|
-
|
214
|
-
def self.help(shell, *)
|
215
|
-
list = printable_tasks
|
216
|
-
shell.say <<-USEAGE
|
217
|
-
Hudson.rb is a smart set of utilities for making
|
218
|
-
continuous integration as simple as possible
|
219
|
-
|
220
|
-
Usage: hudson command [arguments] [options]
|
221
|
-
|
222
|
-
USEAGE
|
223
|
-
|
224
|
-
shell.say "Commands:"
|
225
|
-
shell.print_table(list, :ident => 2, :truncate => true)
|
226
|
-
shell.say
|
227
|
-
class_options_help(shell)
|
228
|
-
end
|
229
|
-
|
230
|
-
private
|
231
|
-
|
232
|
-
def select_hudson_server(options)
|
233
|
-
unless @uri = Hudson::Api.setup_base_url(options)
|
234
|
-
error "Either use --host or add remote servers."
|
235
|
-
end
|
236
|
-
@uri
|
237
|
-
end
|
238
|
-
|
239
|
-
def display(text)
|
240
|
-
shell.say text
|
241
|
-
exit
|
242
|
-
end
|
243
|
-
|
244
|
-
def error(text)
|
245
|
-
shell.say "ERROR: #{text}", :red
|
246
|
-
exit
|
247
|
-
end
|
248
|
-
|
249
|
-
def cmd
|
250
|
-
ENV['CUCUMBER_RUNNING'] ? 'hudson' : $0
|
251
|
-
end
|
252
|
-
end
|
253
|
-
end
|