hudson 0.5.0 → 0.6.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 +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
|