jenkins 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 +6 -0
- data/Changelog.md +40 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +58 -0
- data/README.md +154 -0
- data/Rakefile +82 -0
- data/bin/jenkins +10 -0
- data/features/default_host.feature +19 -0
- data/features/development.feature +14 -0
- data/features/launch_server.feature +16 -0
- data/features/listing_jobs.feature +34 -0
- data/features/manage_jobs.feature +208 -0
- data/features/manage_slave_nodes.feature +82 -0
- data/features/step_definitions/common_steps.rb +192 -0
- data/features/step_definitions/fixture_project_steps.rb +8 -0
- data/features/step_definitions/jenkins_steps.rb +104 -0
- data/features/step_definitions/scm_steps.rb +12 -0
- data/features/support/common.rb +37 -0
- data/features/support/env.rb +19 -0
- data/features/support/hooks.rb +16 -0
- data/features/support/jenkins_helpers.rb +6 -0
- data/features/support/matchers.rb +10 -0
- data/fixtures/jenkins/envfile.hpi +0 -0
- data/fixtures/jenkins/git.hpi +0 -0
- data/fixtures/jenkins/github.hpi +0 -0
- data/fixtures/jenkins/greenballs.hpi +0 -0
- data/fixtures/jenkins/rake.hpi +0 -0
- data/fixtures/jenkins/ruby.hpi +0 -0
- data/fixtures/projects/non-bundler/Rakefile +4 -0
- data/fixtures/projects/rails-3/.gitignore +4 -0
- data/fixtures/projects/rails-3/Gemfile +30 -0
- data/fixtures/projects/rails-3/Gemfile.lock +74 -0
- data/fixtures/projects/rails-3/README +256 -0
- data/fixtures/projects/rails-3/Rakefile +7 -0
- data/fixtures/projects/rails-3/app/controllers/application_controller.rb +3 -0
- data/fixtures/projects/rails-3/app/helpers/application_helper.rb +2 -0
- data/fixtures/projects/rails-3/app/views/layouts/application.html.erb +14 -0
- data/fixtures/projects/rails-3/config.ru +4 -0
- data/fixtures/projects/rails-3/config/application.rb +42 -0
- data/fixtures/projects/rails-3/config/boot.rb +13 -0
- data/fixtures/projects/rails-3/config/database.yml +22 -0
- data/fixtures/projects/rails-3/config/environment.rb +5 -0
- data/fixtures/projects/rails-3/config/environments/development.rb +26 -0
- data/fixtures/projects/rails-3/config/environments/production.rb +49 -0
- data/fixtures/projects/rails-3/config/environments/test.rb +35 -0
- data/fixtures/projects/rails-3/config/initializers/backtrace_silencers.rb +7 -0
- data/fixtures/projects/rails-3/config/initializers/inflections.rb +10 -0
- data/fixtures/projects/rails-3/config/initializers/mime_types.rb +5 -0
- data/fixtures/projects/rails-3/config/initializers/secret_token.rb +7 -0
- data/fixtures/projects/rails-3/config/initializers/session_store.rb +8 -0
- data/fixtures/projects/rails-3/config/locales/en.yml +5 -0
- data/fixtures/projects/rails-3/config/routes.rb +58 -0
- data/fixtures/projects/rails-3/db/seeds.rb +7 -0
- data/fixtures/projects/rails-3/doc/README_FOR_APP +2 -0
- data/fixtures/projects/rails-3/lib/tasks/.gitkeep +0 -0
- data/fixtures/projects/rails-3/public/404.html +26 -0
- data/fixtures/projects/rails-3/public/422.html +26 -0
- data/fixtures/projects/rails-3/public/500.html +26 -0
- 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 +239 -0
- data/fixtures/projects/rails-3/public/javascripts/application.js +2 -0
- data/fixtures/projects/rails-3/public/javascripts/controls.js +965 -0
- data/fixtures/projects/rails-3/public/javascripts/dragdrop.js +974 -0
- data/fixtures/projects/rails-3/public/javascripts/effects.js +1123 -0
- data/fixtures/projects/rails-3/public/javascripts/prototype.js +6001 -0
- data/fixtures/projects/rails-3/public/javascripts/rails.js +175 -0
- data/fixtures/projects/rails-3/public/robots.txt +5 -0
- data/fixtures/projects/rails-3/public/stylesheets/.gitkeep +0 -0
- data/fixtures/projects/rails-3/script/rails +6 -0
- data/fixtures/projects/rails-3/test/performance/browsing_test.rb +9 -0
- data/fixtures/projects/rails-3/test/test_helper.rb +13 -0
- data/fixtures/projects/rails-3/vendor/plugins/.gitkeep +0 -0
- data/fixtures/projects/ruby/Gemfile +3 -0
- data/fixtures/projects/ruby/Gemfile.lock +10 -0
- data/fixtures/projects/ruby/Rakefile +4 -0
- data/jenkins.gemspec +34 -0
- data/lib/jenkins.rb +6 -0
- data/lib/jenkins/api.rb +219 -0
- data/lib/jenkins/cli.rb +249 -0
- data/lib/jenkins/cli/formatting.rb +53 -0
- data/lib/jenkins/config.rb +27 -0
- data/lib/jenkins/core_ext/hash.rb +9 -0
- data/lib/jenkins/core_ext/object/blank.rb +77 -0
- data/lib/jenkins/hudson-cli.jar +0 -0
- data/lib/jenkins/job_config_builder.rb +287 -0
- data/lib/jenkins/project_scm.rb +22 -0
- data/lib/jenkins/remote.rb +11 -0
- data/lib/jenkins/version.rb +3 -0
- data/spec/fixtures/ec2_global.config.xml +103 -0
- data/spec/fixtures/rails.multi.config.xml +82 -0
- data/spec/fixtures/rails.single.config.triggers.xml +84 -0
- data/spec/fixtures/rails.single.config.xml +80 -0
- data/spec/fixtures/ruby.multi-ruby-multi-labels.config.xml +84 -0
- data/spec/fixtures/ruby.multi.config.xml +77 -0
- data/spec/fixtures/ruby.single.config.xml +58 -0
- data/spec/fixtures/therubyracer.config.xml +77 -0
- data/spec/hash_key_cleaner_spec.rb +25 -0
- data/spec/job_config_builder_spec.rb +137 -0
- data/spec/spec_helper.rb +15 -0
- metadata +355 -0
data/lib/jenkins/cli.rb
ADDED
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
require 'thor'
|
|
2
|
+
require 'jenkins/core_ext/object/blank'
|
|
3
|
+
require 'jenkins/core_ext/hash'
|
|
4
|
+
require 'jenkins/cli/formatting'
|
|
5
|
+
require 'jenkins/remote'
|
|
6
|
+
|
|
7
|
+
module Jenkins
|
|
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 jenkins server on this host'
|
|
15
|
+
method_option :port, :desc => 'connect to jenkins server on this port'
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
desc "server [options]", "run a jenkins server"
|
|
19
|
+
method_option :home, :desc => "use this directory to store server data", :type => :string, :default => File.join(ENV['HOME'], ".jenkins", "server"), :banner => "PATH"
|
|
20
|
+
method_option :port, :desc => "run jenkins 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
|
+
def server
|
|
26
|
+
begin
|
|
27
|
+
require 'jenkins/war'
|
|
28
|
+
Jenkins::War::server(options)
|
|
29
|
+
rescue LoadError
|
|
30
|
+
puts "To run a jenkins server, you need to install the jenkins-war gem. try:"
|
|
31
|
+
puts "gem install jenkins-war"
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
desc "create project_path [options]", "create a build for your project"
|
|
36
|
+
common_options
|
|
37
|
+
method_option :rubies, :desc => "run tests against multiple explicit rubies via RVM", :type => :string
|
|
38
|
+
method_option :"node-labels", :desc => "run tests against multiple slave nodes by their label (comma separated)"
|
|
39
|
+
method_option :"assigned-node", :desc => "only use slave nodes with this label (similar to --node-labels)"
|
|
40
|
+
method_option :"no-build", :desc => "create job without initial build", :type => :boolean, :default => false
|
|
41
|
+
method_option :override, :desc => "override if job exists", :type => :boolean, :default => false
|
|
42
|
+
method_option :"scm", :desc => "specific SCM URI", :type => :string
|
|
43
|
+
method_option :"scm-branches", :desc => "list of branches to build from (comma separated)", :type => :string, :default => "master"
|
|
44
|
+
method_option :"public-scm", :desc => "use public scm URL", :type => :boolean, :default => false
|
|
45
|
+
method_option :template, :desc => "template of job steps (available: #{JobConfigBuilder::VALID_JOB_TEMPLATES.join ','})", :default => 'ruby'
|
|
46
|
+
method_option :"no-template", :desc => "do not use a template of default steps; avoids Gemfile requirement", :type => :boolean, :default => false
|
|
47
|
+
def create(project_path)
|
|
48
|
+
select_jenkins_server(options)
|
|
49
|
+
FileUtils.chdir(project_path) do
|
|
50
|
+
unless scm = Jenkins::ProjectScm.discover(options[:scm])
|
|
51
|
+
error "Cannot determine project SCM. Currently supported: #{Jenkins::ProjectScm.supported}"
|
|
52
|
+
end
|
|
53
|
+
unless (options[:template] == "none" || options[:"no-template"]) || File.exists?("Gemfile")
|
|
54
|
+
error "Ruby/Rails projects without a Gemfile are currently unsupported."
|
|
55
|
+
end
|
|
56
|
+
begin
|
|
57
|
+
template = options[:"no-template"] ? 'none' : options[:template]
|
|
58
|
+
job_config = Jenkins::JobConfigBuilder.new(template) do |c|
|
|
59
|
+
c.rubies = options[:rubies].split(/\s*,\s*/) if options[:rubies]
|
|
60
|
+
c.node_labels = options[:"node-labels"].split(/\s*,\s*/) if options[:"node-labels"]
|
|
61
|
+
c.scm = scm.url
|
|
62
|
+
c.scm_branches = options[:"scm-branches"].split(/\s*,\s*/)
|
|
63
|
+
c.assigned_node = options[:"assigned-node"] if options[:"assigned-node"]
|
|
64
|
+
c.public_scm = options[:"public-scm"]
|
|
65
|
+
end
|
|
66
|
+
name = File.basename(FileUtils.pwd)
|
|
67
|
+
if Jenkins::Api.create_job(name, job_config, options)
|
|
68
|
+
build_url = "#{@uri}/job/#{name.gsub(/\s/,'%20')}/build"
|
|
69
|
+
shell.say "Added#{' ' + template unless template == 'none'} project '#{name}' to Jenkins.", :green
|
|
70
|
+
unless options[:"no-build"]
|
|
71
|
+
shell.say "Triggering initial build..."
|
|
72
|
+
Jenkins::Api.build_job(name)
|
|
73
|
+
shell.say "Trigger additional builds via:"
|
|
74
|
+
else
|
|
75
|
+
shell.say "Trigger builds via:"
|
|
76
|
+
end
|
|
77
|
+
shell.say " URL: "; shell.say "#{build_url}", :yellow
|
|
78
|
+
shell.say " CLI: "; shell.say "#{cmd} build #{name}", :yellow
|
|
79
|
+
else
|
|
80
|
+
error "Failed to create project '#{name}'"
|
|
81
|
+
end
|
|
82
|
+
rescue Jenkins::JobConfigBuilder::InvalidTemplate
|
|
83
|
+
error "Invalid job template '#{template}'."
|
|
84
|
+
rescue Jenkins::Api::JobAlreadyExistsError
|
|
85
|
+
error "Job '#{name}' already exists."
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
desc "build [PROJECT_PATH]", "trigger build of this project's build job"
|
|
91
|
+
common_options
|
|
92
|
+
def build(project_path = ".")
|
|
93
|
+
select_jenkins_server(options)
|
|
94
|
+
FileUtils.chdir(project_path) do
|
|
95
|
+
name = File.basename(FileUtils.pwd)
|
|
96
|
+
if Jenkins::Api.build_job(name)
|
|
97
|
+
shell.say "Build for '#{name}' running now..."
|
|
98
|
+
else
|
|
99
|
+
error "No job '#{name}' on server."
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
desc "remove PROJECT_PATH", "remove this project's build job from Jenkins"
|
|
105
|
+
common_options
|
|
106
|
+
def remove(project_path)
|
|
107
|
+
select_jenkins_server(options)
|
|
108
|
+
FileUtils.chdir(project_path) do
|
|
109
|
+
name = File.basename(FileUtils.pwd)
|
|
110
|
+
if Jenkins::Api.delete_job(name)
|
|
111
|
+
shell.say "Removed project '#{name}' from Jenkins."
|
|
112
|
+
else
|
|
113
|
+
error "Failed to delete project '#{name}'."
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
desc "job NAME", "Display job details"
|
|
119
|
+
method_option :hash, :desc => 'Dump as formatted Ruby hash format'
|
|
120
|
+
method_option :json, :desc => 'Dump as JSON format'
|
|
121
|
+
method_option :yaml, :desc => 'Dump as YAML format'
|
|
122
|
+
common_options
|
|
123
|
+
def job(name)
|
|
124
|
+
select_jenkins_server(options)
|
|
125
|
+
if job = Jenkins::Api.job(name)
|
|
126
|
+
if options[:hash]
|
|
127
|
+
require "ap"
|
|
128
|
+
ap job.parsed_response
|
|
129
|
+
elsif options[:json]
|
|
130
|
+
puts job.parsed_response.to_json
|
|
131
|
+
elsif options[:yaml]
|
|
132
|
+
require "yaml"
|
|
133
|
+
puts job.parsed_response.to_yaml
|
|
134
|
+
else
|
|
135
|
+
error "Select an output format: --json, --xml, --yaml, --hash"
|
|
136
|
+
end
|
|
137
|
+
else
|
|
138
|
+
error "Cannot find project '#{name}'."
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
desc "list [options]", "list jobs on a jenkins server"
|
|
143
|
+
common_options
|
|
144
|
+
def list
|
|
145
|
+
select_jenkins_server(options)
|
|
146
|
+
summary = Jenkins::Api.summary
|
|
147
|
+
unless summary["jobs"].blank?
|
|
148
|
+
shell.say "#{@uri}:", :bold
|
|
149
|
+
summary["jobs"].each do |job|
|
|
150
|
+
bold = job['color'] =~ /anime/
|
|
151
|
+
color = 'red' if job['color'] =~ /red/
|
|
152
|
+
color = 'green' if job['color'] =~ /(blue|green)/
|
|
153
|
+
color ||= 'yellow' # if color =~ /grey/ || color == 'disabled'
|
|
154
|
+
shell.say "* "; shell.say(shell.set_color(job['name'], color.to_sym, bold), nil, true)
|
|
155
|
+
end
|
|
156
|
+
shell.say ""
|
|
157
|
+
else
|
|
158
|
+
shell.say "#{@uri}: "; shell.say "no jobs", :yellow
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
desc "nodes", "list jenkins server nodes"
|
|
163
|
+
common_options
|
|
164
|
+
def nodes
|
|
165
|
+
select_jenkins_server(options)
|
|
166
|
+
nodes = Jenkins::Api.nodes
|
|
167
|
+
nodes["computer"].each do |node|
|
|
168
|
+
color = node["offline"] ? :red : :green
|
|
169
|
+
shell.say node["displayName"], color
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
desc "add_node SLAVE_HOST", "add a URI (user@host:port) server as a slave node"
|
|
174
|
+
method_option :labels, :desc => 'Labels for a job --assigned_node to match against to select a slave (comma separated)'
|
|
175
|
+
method_option :"slave-user", :desc => 'SSH user for Jenkins to connect to slave node (default: deploy)'
|
|
176
|
+
method_option :"slave-port", :desc => 'SSH port for Jenkins to connect to slave node (default: 22)'
|
|
177
|
+
method_option :"master-key", :desc => 'Location of master public key or identity file'
|
|
178
|
+
method_option :"slave-fs", :desc => 'Location of file system on slave for Jenkins to use'
|
|
179
|
+
method_option :name, :desc => 'Name of slave node (default SLAVE_HOST)'
|
|
180
|
+
method_option :vagrant, :desc => 'Use settings for a Vagrant VM', :type => :boolean, :default => false
|
|
181
|
+
common_options
|
|
182
|
+
def add_node(slave_host)
|
|
183
|
+
select_jenkins_server(options)
|
|
184
|
+
if results = Jenkins::Api.add_node({:slave_host => slave_host}.merge(options))
|
|
185
|
+
shell.say "Added slave node '#{results[:name]}' to #{results[:slave_host]}", :green
|
|
186
|
+
else
|
|
187
|
+
error "Failed to add slave node #{slave_host}"
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
desc "default_host", "display current default host:port URI"
|
|
192
|
+
def default_host
|
|
193
|
+
if select_jenkins_server({})
|
|
194
|
+
display Jenkins::Api.base_uri
|
|
195
|
+
else
|
|
196
|
+
display "No default host yet. Use '--host host --port port' on your first request."
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
desc "help [command]", "show help for jenkins or for a specific command"
|
|
201
|
+
def help(*args)
|
|
202
|
+
super(*args)
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
desc "version", "show version information"
|
|
206
|
+
def version
|
|
207
|
+
shell.say "#{Jenkins::VERSION}"
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
def self.help(shell, *)
|
|
211
|
+
list = printable_tasks
|
|
212
|
+
shell.say <<-USEAGE
|
|
213
|
+
Jenkins.rb is a smart set of utilities for making
|
|
214
|
+
continuous integration as simple as possible
|
|
215
|
+
|
|
216
|
+
Usage: jenkins command [arguments] [options]
|
|
217
|
+
|
|
218
|
+
USEAGE
|
|
219
|
+
|
|
220
|
+
shell.say "Commands:"
|
|
221
|
+
shell.print_table(list, :ident => 2, :truncate => true)
|
|
222
|
+
shell.say
|
|
223
|
+
class_options_help(shell)
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
private
|
|
227
|
+
|
|
228
|
+
def select_jenkins_server(options)
|
|
229
|
+
unless @uri = Jenkins::Api.setup_base_url(options)
|
|
230
|
+
error "Either use --host or add remote servers."
|
|
231
|
+
end
|
|
232
|
+
@uri
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
def display(text)
|
|
236
|
+
shell.say text
|
|
237
|
+
exit
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
def error(text)
|
|
241
|
+
shell.say "ERROR: #{text}", :red
|
|
242
|
+
exit
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
def cmd
|
|
246
|
+
ENV['CUCUMBER_RUNNING'] ? 'jenkins' : $0
|
|
247
|
+
end
|
|
248
|
+
end
|
|
249
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
require 'term/ansicolor'
|
|
2
|
+
|
|
3
|
+
module Jenkins
|
|
4
|
+
class CLI < Thor
|
|
5
|
+
module Formatting
|
|
6
|
+
module ClassMethods
|
|
7
|
+
def task_help(shell, task_name)
|
|
8
|
+
meth = normalize_task_name(task_name)
|
|
9
|
+
task = all_tasks[meth]
|
|
10
|
+
handle_no_task_error(meth) unless task
|
|
11
|
+
|
|
12
|
+
shell.say "usage: #{banner(task)}"
|
|
13
|
+
shell.say
|
|
14
|
+
class_options_help(shell, nil => task.options.map { |_, o| o })
|
|
15
|
+
# shell.say task.description
|
|
16
|
+
# shell.say
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def print_options(shell, options, grp = nil)
|
|
21
|
+
return if options.empty?
|
|
22
|
+
table = options.map do |option|
|
|
23
|
+
prototype = if option.default
|
|
24
|
+
" [#{option.default}]"
|
|
25
|
+
elsif option.boolean?
|
|
26
|
+
""
|
|
27
|
+
elsif option.required?
|
|
28
|
+
" #{option.banner}"
|
|
29
|
+
else
|
|
30
|
+
" [#{option.banner}]"
|
|
31
|
+
end
|
|
32
|
+
aliases = option.aliases.empty? ? "" : option.aliases.join(" ") + ","
|
|
33
|
+
[aliases, "--#{option.name}#{prototype}", "\t",option.description]
|
|
34
|
+
end
|
|
35
|
+
shell.print_table(table, :ident => 2)
|
|
36
|
+
shell.say
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
module InstanceMethods
|
|
41
|
+
def c
|
|
42
|
+
Term::ANSIColor
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def self.included(receiver)
|
|
47
|
+
receiver.extend ClassMethods
|
|
48
|
+
receiver.send :include, InstanceMethods
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module Jenkins
|
|
2
|
+
module Config
|
|
3
|
+
extend self
|
|
4
|
+
|
|
5
|
+
def [](key)
|
|
6
|
+
config[key]
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def config
|
|
10
|
+
@config ||= if File.exist?(config_file)
|
|
11
|
+
JSON.parse(File.read(config_file))
|
|
12
|
+
else
|
|
13
|
+
{}
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def store!
|
|
18
|
+
@config ||= {}
|
|
19
|
+
FileUtils.mkdir_p(File.dirname(config_file))
|
|
20
|
+
File.open(config_file, "w") { |file| file << @config.to_json }
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def config_file
|
|
24
|
+
@config_file ||= "#{ENV['HOME']}/.jenkins/jenkinsrb-config.json"
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Vendored from activesupport 3.0.1
|
|
2
|
+
class Object
|
|
3
|
+
# An object is blank if it's false, empty, or a whitespace string.
|
|
4
|
+
# For example, "", " ", +nil+, [], and {} are blank.
|
|
5
|
+
#
|
|
6
|
+
# This simplifies:
|
|
7
|
+
#
|
|
8
|
+
# if !address.nil? && !address.empty?
|
|
9
|
+
#
|
|
10
|
+
# ...to:
|
|
11
|
+
#
|
|
12
|
+
# if !address.blank?
|
|
13
|
+
def blank?
|
|
14
|
+
respond_to?(:empty?) ? empty? : !self
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# An object is present if it's not blank.
|
|
18
|
+
def present?
|
|
19
|
+
!blank?
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Returns object if it's #present? otherwise returns nil.
|
|
23
|
+
# object.presence is equivalent to object.present? ? object : nil.
|
|
24
|
+
#
|
|
25
|
+
# This is handy for any representation of objects where blank is the same
|
|
26
|
+
# as not present at all. For example, this simplifies a common check for
|
|
27
|
+
# HTTP POST/query parameters:
|
|
28
|
+
#
|
|
29
|
+
# state = params[:state] if params[:state].present?
|
|
30
|
+
# country = params[:country] if params[:country].present?
|
|
31
|
+
# region = state || country || 'US'
|
|
32
|
+
#
|
|
33
|
+
# ...becomes:
|
|
34
|
+
#
|
|
35
|
+
# region = params[:state].presence || params[:country].presence || 'US'
|
|
36
|
+
def presence
|
|
37
|
+
self if present?
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
class NilClass #:nodoc:
|
|
42
|
+
def blank?
|
|
43
|
+
true
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
class FalseClass #:nodoc:
|
|
48
|
+
def blank?
|
|
49
|
+
true
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
class TrueClass #:nodoc:
|
|
54
|
+
def blank?
|
|
55
|
+
false
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
class Array #:nodoc:
|
|
60
|
+
alias_method :blank?, :empty?
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
class Hash #:nodoc:
|
|
64
|
+
alias_method :blank?, :empty?
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
class String #:nodoc:
|
|
68
|
+
def blank?
|
|
69
|
+
self !~ /\S/
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
class Numeric #:nodoc:
|
|
74
|
+
def blank?
|
|
75
|
+
false
|
|
76
|
+
end
|
|
77
|
+
end
|
|
Binary file
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
require "builder"
|
|
2
|
+
|
|
3
|
+
module Jenkins
|
|
4
|
+
class JobConfigBuilder
|
|
5
|
+
attr_accessor :job_type
|
|
6
|
+
attr_accessor :steps, :rubies
|
|
7
|
+
attr_accessor :scm, :public_scm, :scm_branches
|
|
8
|
+
attr_accessor :scm, :public_scm, :git_branches
|
|
9
|
+
attr_accessor :assigned_node, :node_labels # TODO just one of these
|
|
10
|
+
attr_accessor :envfile
|
|
11
|
+
|
|
12
|
+
InvalidTemplate = Class.new(StandardError)
|
|
13
|
+
|
|
14
|
+
VALID_JOB_TEMPLATES = %w[none rails rails3 ruby rubygem]
|
|
15
|
+
|
|
16
|
+
# +job_type+ - template of default steps to create with the job
|
|
17
|
+
# +steps+ - array of [:method, cmd], e.g. [:build_shell_step, "bundle initial"]
|
|
18
|
+
# - Default is based on +job_type+.
|
|
19
|
+
# +scm+ - URL to the repository. Currently only support git URLs.
|
|
20
|
+
# +public_scm+ - convert the +scm+ URL to a publicly accessible URL for the Jenkins job config.
|
|
21
|
+
# +scm_branches+ - array of branches to run builds. Default: ['master']
|
|
22
|
+
# +rubies+ - list of RVM rubies to run tests (via Jenkins Axes).
|
|
23
|
+
# +assigned_node+ - restrict this job to running on slaves with these labels (space separated)
|
|
24
|
+
def initialize(job_type = :ruby, &block)
|
|
25
|
+
self.job_type = job_type.to_s if job_type
|
|
26
|
+
|
|
27
|
+
yield self
|
|
28
|
+
|
|
29
|
+
self.scm_branches ||= ["master"]
|
|
30
|
+
raise InvalidTemplate unless VALID_JOB_TEMPLATES.include?(job_type.to_s)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def builder
|
|
34
|
+
b = Builder::XmlMarkup.new :indent => 2
|
|
35
|
+
b.instruct!
|
|
36
|
+
b.tag!(matrix_project? ? "matrix-project" : "project") do
|
|
37
|
+
b.actions
|
|
38
|
+
b.description
|
|
39
|
+
b.keepDependencies false
|
|
40
|
+
b.properties
|
|
41
|
+
build_scm b
|
|
42
|
+
b.assignedNode assigned_node if assigned_node
|
|
43
|
+
b.canRoam !assigned_node
|
|
44
|
+
b.disabled false
|
|
45
|
+
b.blockBuildWhenUpstreamBuilding false
|
|
46
|
+
b.triggers :class => "vector"
|
|
47
|
+
b.concurrentBuild false
|
|
48
|
+
build_axes b if matrix_project?
|
|
49
|
+
build_steps b
|
|
50
|
+
b.publishers
|
|
51
|
+
build_wrappers b
|
|
52
|
+
b.runSequentially false if matrix_project?
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def to_xml
|
|
57
|
+
builder.to_s
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
protected
|
|
61
|
+
|
|
62
|
+
# <scm class="hudson.plugins.git.GitSCM"> ... </scm>
|
|
63
|
+
def build_scm(b)
|
|
64
|
+
if scm && scm =~ /git/
|
|
65
|
+
scm_url = public_scm ? public_only_git_scm(scm) : scm
|
|
66
|
+
b.scm :class => "hudson.plugins.git.GitSCM" do
|
|
67
|
+
b.configVersion 1
|
|
68
|
+
b.remoteRepositories do
|
|
69
|
+
b.tag! "org.spearce.jgit.transport.RemoteConfig" do
|
|
70
|
+
b.string "origin"
|
|
71
|
+
b.int 5
|
|
72
|
+
b.string "fetch"
|
|
73
|
+
b.string "+refs/heads/*:refs/remotes/origin/*"
|
|
74
|
+
b.string "receivepack"
|
|
75
|
+
b.string "git-upload-pack"
|
|
76
|
+
b.string "uploadpack"
|
|
77
|
+
b.string "git-upload-pack"
|
|
78
|
+
b.string "url"
|
|
79
|
+
b.string scm_url
|
|
80
|
+
b.string "tagopt"
|
|
81
|
+
b.string
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
if scm_branches
|
|
86
|
+
b.branches do
|
|
87
|
+
scm_branches.each do |branch|
|
|
88
|
+
b.tag! "hudson.plugins.git.BranchSpec" do
|
|
89
|
+
b.name branch
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
b.localBranch
|
|
96
|
+
b.mergeOptions
|
|
97
|
+
b.recursiveSubmodules false
|
|
98
|
+
b.doGenerateSubmoduleConfigurations false
|
|
99
|
+
b.authorOrCommitter false
|
|
100
|
+
b.clean false
|
|
101
|
+
b.wipeOutWorkspace false
|
|
102
|
+
b.buildChooser :class => "hudson.plugins.git.util.DefaultBuildChooser"
|
|
103
|
+
b.gitTool "Default"
|
|
104
|
+
b.submoduleCfg :class => "list"
|
|
105
|
+
b.relativeTargetDir
|
|
106
|
+
b.excludedRegions
|
|
107
|
+
b.excludedUsers
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
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>
|
|
132
|
+
def build_axes(b)
|
|
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
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# Example:
|
|
158
|
+
# <buildWrappers>
|
|
159
|
+
# <hudson.plugins.envfile.EnvFileBuildWrapper>
|
|
160
|
+
# <filePath>/path/to/env/file</filePath>
|
|
161
|
+
# </hudson.plugins.envfile.EnvFileBuildWrapper>
|
|
162
|
+
# </buildWrappers>
|
|
163
|
+
def build_wrappers(b)
|
|
164
|
+
if envfile
|
|
165
|
+
b.buildWrappers do
|
|
166
|
+
self.envfile = [envfile] unless envfile.is_a?(Array)
|
|
167
|
+
b.tag! "hudson.plugins.envfile.EnvFileBuildWrapper" do
|
|
168
|
+
envfile.each do |file|
|
|
169
|
+
b.filePath file
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
else
|
|
174
|
+
b.buildWrappers
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# The important sequence of steps that are run to process a job build.
|
|
179
|
+
# Can be defaulted by the +job_type+ using +default_steps(job_type)+,
|
|
180
|
+
# or customized via +steps+ array.
|
|
181
|
+
def build_steps(b)
|
|
182
|
+
b.builders do
|
|
183
|
+
self.steps ||= default_steps(job_type)
|
|
184
|
+
steps.each do |step|
|
|
185
|
+
method, cmd = step
|
|
186
|
+
send(method.to_sym, b, cmd) # e.g. build_shell_step(b, "bundle install")
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def default_steps(job_type)
|
|
192
|
+
steps = case job_type.to_sym
|
|
193
|
+
when :rails, :rails3
|
|
194
|
+
[
|
|
195
|
+
[:build_shell_step, "bundle install"],
|
|
196
|
+
[:build_ruby_step, <<-RUBY.gsub(/^ /, '')],
|
|
197
|
+
unless File.exist?("config/database.yml")
|
|
198
|
+
require 'fileutils'
|
|
199
|
+
example = Dir["config/database*"].first
|
|
200
|
+
puts "Using \#{example} for config/database.yml"
|
|
201
|
+
FileUtils.cp example, "config/database.yml"
|
|
202
|
+
end
|
|
203
|
+
RUBY
|
|
204
|
+
[:build_shell_step, "bundle exec rake db:create:all"],
|
|
205
|
+
[:build_shell_step, <<-RUBY.gsub(/^ /, '')],
|
|
206
|
+
if [ -f db/schema.rb ]; then
|
|
207
|
+
bundle exec rake db:schema:load
|
|
208
|
+
else
|
|
209
|
+
bundle exec rake db:migrate
|
|
210
|
+
fi
|
|
211
|
+
RUBY
|
|
212
|
+
[:build_shell_step, "bundle exec rake"]
|
|
213
|
+
]
|
|
214
|
+
when :ruby, :rubygems
|
|
215
|
+
[
|
|
216
|
+
[:build_shell_step, "bundle install"],
|
|
217
|
+
[:build_shell_step, "bundle exec rake"]
|
|
218
|
+
]
|
|
219
|
+
else
|
|
220
|
+
[ [:build_shell_step, 'echo "THERE ARE NO STEPS! Except this one..."'] ]
|
|
221
|
+
end
|
|
222
|
+
rubies.blank? ? steps : default_rvm_steps + steps
|
|
223
|
+
end
|
|
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
|
+
|
|
232
|
+
# <hudson.tasks.Shell>
|
|
233
|
+
# <command>echo 'THERE ARE NO STEPS! Except this one...'</command>
|
|
234
|
+
# </hudson.tasks.Shell>
|
|
235
|
+
def build_shell_step(b, command)
|
|
236
|
+
b.tag! "hudson.tasks.Shell" do
|
|
237
|
+
b.command command.to_xs.gsub("&", '&') #.gsub(%r{"}, '"').gsub(%r{'}, ''')
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
# <hudson.plugins.ruby.Ruby>
|
|
242
|
+
# <command>unless File.exist?("config/database.yml")
|
|
243
|
+
# require 'fileutils'
|
|
244
|
+
# example = Dir["config/database*"].first
|
|
245
|
+
# puts "Using #{example} for config/database.yml"
|
|
246
|
+
# FileUtils.cp example, "config/database.yml"
|
|
247
|
+
# end</command>
|
|
248
|
+
# </hudson.plugins.ruby.Ruby>
|
|
249
|
+
def build_ruby_step(b, command)
|
|
250
|
+
b.tag! "hudson.plugins.ruby.Ruby" do
|
|
251
|
+
b.command do
|
|
252
|
+
b << command.to_xs.gsub(%r{"}, '"').gsub(%r{'}, ''')
|
|
253
|
+
end
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
# Usage: build_ruby_step b, "db:schema:load"
|
|
258
|
+
#
|
|
259
|
+
# <hudson.plugins.rake.Rake>
|
|
260
|
+
# <rakeInstallation>(Default)</rakeInstallation>
|
|
261
|
+
# <rakeFile></rakeFile>
|
|
262
|
+
# <rakeLibDir></rakeLibDir>
|
|
263
|
+
# <rakeWorkingDir></rakeWorkingDir>
|
|
264
|
+
# <tasks>db:schema:load</tasks>
|
|
265
|
+
# <silent>false</silent>
|
|
266
|
+
# </hudson.plugins.rake.Rake>
|
|
267
|
+
def build_rake_step(b, tasks)
|
|
268
|
+
b.tag! "hudson.plugins.rake.Rake" do
|
|
269
|
+
b.rakeInstallation "(Default)"
|
|
270
|
+
b.rakeFile
|
|
271
|
+
b.rakeLibDir
|
|
272
|
+
b.rakeWorkingDir
|
|
273
|
+
b.tasks tasks
|
|
274
|
+
b.silent false
|
|
275
|
+
end
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
# Converts git@github.com:drnic/newgem.git into git://github.com/drnic/newgem.git
|
|
279
|
+
def public_only_git_scm(scm_url)
|
|
280
|
+
if scm_url =~ /git@([\w\-_.]+):(.+)\.git/
|
|
281
|
+
"git://#{$1}/#{$2}.git"
|
|
282
|
+
else
|
|
283
|
+
scm_url
|
|
284
|
+
end
|
|
285
|
+
end
|
|
286
|
+
end
|
|
287
|
+
end
|