jenkins-capistrano 0.0.4 → 0.0.5
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/README.rst +11 -0
- data/lib/jenkins-capistrano.rb +30 -11
- data/lib/jenkins-capistrano/client.rb +5 -125
- data/lib/jenkins-capistrano/client/job.rb +47 -0
- data/lib/jenkins-capistrano/client/node.rb +103 -0
- data/lib/jenkins-capistrano/version.rb +1 -1
- metadata +5 -8
data/README.rst
CHANGED
@@ -51,6 +51,17 @@ deploy.rb::
|
|
51
51
|
|
52
52
|
before 'deploy', 'jenkins:deploy_jobs'
|
53
53
|
|
54
|
+
Want to disabling some jobs for specific environment?
|
55
|
+
-----------------------------------------------------
|
56
|
+
|
57
|
+
Since 0.0.5, you can disabling jobs using `disabled_jobs` option.
|
58
|
+
Use this option with `multistage-extension <https://github.com/capistrano/capistrano/wiki/2.x-Multistage-Extension>`_.
|
59
|
+
|
60
|
+
Put the following line into `config/deploy/<env>.rb`::
|
61
|
+
|
62
|
+
set :disabled_jobs, %w(job1 job2)
|
63
|
+
|
64
|
+
|
54
65
|
Node Configuration
|
55
66
|
~~~~~~~~~~~~~~~~~~
|
56
67
|
|
data/lib/jenkins-capistrano.rb
CHANGED
@@ -9,7 +9,7 @@ end
|
|
9
9
|
|
10
10
|
# Capistrano task for Jenkins.
|
11
11
|
#
|
12
|
-
# Just add "require 'jenkins-capistrano'" in your Capistrano deploy.rb
|
12
|
+
# Just add "require 'jenkins-capistrano'" in your Capistrano deploy.rb
|
13
13
|
Capistrano::Configuration.instance(:must_exist).load do
|
14
14
|
|
15
15
|
_cset(:jenkins_host) { abort "Please specify the host of your jenkins server, set :jenkins_host, 'http://localhost:8080'" }
|
@@ -20,6 +20,8 @@ Capistrano::Configuration.instance(:must_exist).load do
|
|
20
20
|
_cset(:jenkins_job_config_dir) { 'config/jenkins/jobs' }
|
21
21
|
_cset(:jenkins_node_config_dir) { 'config/jenkins/nodes' }
|
22
22
|
|
23
|
+
_cset(:disabled_jobs) { [] }
|
24
|
+
|
23
25
|
def client
|
24
26
|
@client ||= Jenkins::Client.new(jenkins_host, { :username => jenkins_username, :password => jenkins_password})
|
25
27
|
end
|
@@ -40,31 +42,48 @@ Capistrano::Configuration.instance(:must_exist).load do
|
|
40
42
|
namespace :jenkins do
|
41
43
|
|
42
44
|
desc <<-DESC
|
43
|
-
|
45
|
+
Deploy the jobs to Jenkins server -- meaning create or update --
|
46
|
+
|
47
|
+
Configuration
|
48
|
+
-------------
|
49
|
+
jenkins_job_config_dir
|
50
|
+
the directory path where the config.xml stored.
|
51
|
+
default: 'config/jenkins/jobs'
|
52
|
+
|
53
|
+
disabled_jobs
|
54
|
+
job names array which should be disabled after deployment.
|
55
|
+
default: []
|
44
56
|
|
45
|
-
set :jenkins_job_config_dir, 'config/jenkins/jobs'
|
46
|
-
set :jenkins_job_deploy_strategy, :clean | :merge
|
47
57
|
DESC
|
48
58
|
task :deploy_jobs do
|
49
|
-
strategy = fetch(:jenkins_job_deploy_strategy, :clean)
|
50
59
|
logger.info "deploying jenkins jobs to #{jenkins_host}"
|
51
60
|
logger.important "no job configs found." if job_configs.empty?
|
52
61
|
job_configs.each do |file|
|
53
62
|
name = File.basename(file, '.xml')
|
63
|
+
msg = StringIO.new
|
64
|
+
|
54
65
|
client.create_or_update_job(name, File.read(file))
|
55
|
-
|
66
|
+
msg << "job #{name} created"
|
67
|
+
|
68
|
+
if disabled_jobs.include? name
|
69
|
+
client.disable_job(name)
|
70
|
+
msg << ", but was set to disabled"
|
71
|
+
end
|
72
|
+
msg << "."
|
73
|
+
logger.trace msg.string
|
56
74
|
end
|
57
|
-
|
58
75
|
end
|
59
76
|
|
60
77
|
desc <<-DESC
|
61
|
-
|
78
|
+
Configure the nodes to Jenkins server -- meaning create or update --
|
62
79
|
|
63
|
-
|
64
|
-
|
80
|
+
Configuration
|
81
|
+
-------------
|
82
|
+
jenkins_node_config_dir
|
83
|
+
the directory path where the node's configuration stored.
|
84
|
+
default: 'config/jenkins/nodes'
|
65
85
|
DESC
|
66
86
|
task :config_nodes do
|
67
|
-
strategy = fetch(:jenkins_node_deploy_strategy, :clean)
|
68
87
|
logger.info "configuring jenkins nodes to #{jenkins_host}"
|
69
88
|
logger.important "no node configs found." if node_configs.empty?
|
70
89
|
node_configs.each do |file|
|
@@ -1,6 +1,8 @@
|
|
1
1
|
require 'httparty'
|
2
2
|
require 'cgi/util'
|
3
3
|
require 'json'
|
4
|
+
require 'jenkins-capistrano/client/node'
|
5
|
+
require 'jenkins-capistrano/client/job'
|
4
6
|
|
5
7
|
module Jenkins
|
6
8
|
class Client
|
@@ -16,137 +18,15 @@ module Jenkins
|
|
16
18
|
self.class.basic_auth opts[:username], opts[:password] if opts[:username] and opts[:password]
|
17
19
|
end
|
18
20
|
|
19
|
-
def create_job(name, config)
|
20
|
-
res = self.class.post("/createItem/api/xml?name=#{CGI.escape(name)}", xml_body(config))
|
21
|
-
raise ServerError, parse_error_message(res) unless res.code.to_i == 200
|
22
|
-
rescue => e
|
23
|
-
raise ServerError, "Failed to create job: #{name}, make sure you have specified auth info properly"
|
24
|
-
end
|
25
|
-
|
26
|
-
def update_job(name, config)
|
27
|
-
res = self.class.post("/job/#{CGI.escape(name)}/config.xml", xml_body(config))
|
28
|
-
raise ServerError, parse_error_message(res) unless res.code.to_i == 200
|
29
|
-
rescue => e
|
30
|
-
raise ServerError, "Failed to create job: #{name}, make sure you have specified auth info properly"
|
31
|
-
end
|
32
|
-
|
33
|
-
def create_or_update_job(name, config)
|
34
|
-
begin
|
35
|
-
create_job(name, config)
|
36
|
-
rescue ServerError => e
|
37
|
-
update_job(name, config)
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
def add_node(name, opts = {})
|
42
|
-
options = default_node_options.merge(opts)
|
43
|
-
options[:name] = name
|
44
|
-
options[:labels] = options[:labels].split(/\s*,\s*/).join(' ') if options[:labels]
|
45
|
-
options[:env_vars] = options[:env_vars].map { |k, v| { :key => k, :value => v } }
|
46
|
-
|
47
|
-
response = post_form("/computer/doCreateItem", node_form_fields(options))
|
48
|
-
case response
|
49
|
-
when Net::HTTPFound
|
50
|
-
{ :name => name, :slave_host => options[:slave_host] }
|
51
|
-
else
|
52
|
-
raise ServerError, parse_error_message(response)
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
def update_node(name, opts = {})
|
57
|
-
options = default_node_options.merge(opts)
|
58
|
-
options[:name] = name
|
59
|
-
options[:labels] = options[:labels].split(/\s*,\s*/).join(' ') if options[:labels]
|
60
|
-
options[:env_vars] = options[:env_vars].map { |k, v| { :key => k, :value => v } }
|
61
|
-
|
62
|
-
response = post_form("/computer/#{CGI::escape(name)}/configSubmit", node_form_fields(options))
|
63
|
-
case response
|
64
|
-
when Net::HTTPFound
|
65
|
-
{ :name => name, :slave_host => options[:slave_host] }
|
66
|
-
else
|
67
|
-
raise ServerError, parse_error_message(response)
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
def config_node(name, opts = {})
|
72
|
-
begin
|
73
|
-
add_node(name, opts)
|
74
|
-
rescue ServerError => e
|
75
|
-
update_node(name, opts)
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
private
|
80
|
-
def xml_body(xml_str)
|
81
|
-
{
|
82
|
-
:body => xml_str,
|
83
|
-
:format => :xml,
|
84
|
-
:headers => { 'content-type' => 'application/xml' }
|
85
|
-
}
|
86
|
-
end
|
87
|
-
|
88
21
|
def parse_error_message(response)
|
89
22
|
require "hpricot"
|
90
23
|
doc = Hpricot(response.body)
|
91
24
|
error_msg = doc.search("td#main-panel p")
|
92
|
-
error_msg.inner_text.empty? ? "
|
25
|
+
error_msg.inner_text.empty? ? doc.search("body").text : error_msg
|
93
26
|
end
|
94
27
|
|
95
|
-
|
96
|
-
|
97
|
-
req = Net::HTTP::Post.new(url.path)
|
98
|
-
|
99
|
-
basic_auth = self.class.default_options[:basic_auth]
|
100
|
-
req.basic_auth basic_auth[:username], basic_auth[:password] if basic_auth
|
101
|
-
|
102
|
-
req.set_form_data(fields)
|
103
|
-
http = Net::HTTP.new(url.host, url.port)
|
104
|
-
http.request(req)
|
105
|
-
end
|
106
|
-
|
107
|
-
def default_node_options
|
108
|
-
{
|
109
|
-
:slave_port => 22,
|
110
|
-
:slave_user => 'jenkins',
|
111
|
-
:master_key => "/var/lib/jenkins/.ssh/id_rsa",
|
112
|
-
:slave_fs => "/data/jenkins-slave/",
|
113
|
-
:description => "Automatically created by capistrano-jenkins",
|
114
|
-
:executors => 2,
|
115
|
-
:exclusive => true
|
116
|
-
}
|
117
|
-
end
|
118
|
-
|
119
|
-
def node_form_fields(options = {})
|
120
|
-
{
|
121
|
-
"name" => options[:name],
|
122
|
-
"type" => "hudson.slaves.DumbSlave$DescriptorImpl",
|
123
|
-
"json" => {
|
124
|
-
"name" => options[:name],
|
125
|
-
"type" => "hudson.slaves.DumbSlave$DescriptorImpl",
|
126
|
-
"nodeDescription" => options[:description],
|
127
|
-
"numExecutors" => options[:executors],
|
128
|
-
"remoteFS" => options[:slave_fs],
|
129
|
-
"labelString" => options[:labels],
|
130
|
-
"mode" => options[:exclusive] ? "EXCLUSIVE" : "NORMAL",
|
131
|
-
"retentionStrategy" => { "stapler-class" => "hudson.slaves.RetentionStrategy$Always" },
|
132
|
-
"launcher" => {
|
133
|
-
"stapler-class" => "hudson.plugins.sshslaves.SSHLauncher",
|
134
|
-
"host" => options[:slave_host],
|
135
|
-
"port" => options[:slave_port],
|
136
|
-
"username" => options[:slave_user],
|
137
|
-
"privatekey" => options[:master_key],
|
138
|
-
"javaPath" => options[:java_path],
|
139
|
-
"jvmOptions" => options[:jvm_options]
|
140
|
-
},
|
141
|
-
"nodeProperties" => {
|
142
|
-
"stapler-class-bag" => "true",
|
143
|
-
"hudson-slaves-EnvironmentVariablesNodeProperty" => {
|
144
|
-
"env" => options[:env_vars]
|
145
|
-
}
|
146
|
-
}
|
147
|
-
}.to_json
|
148
|
-
}
|
149
|
-
end
|
28
|
+
include Node
|
29
|
+
include Job
|
150
30
|
|
151
31
|
end
|
152
32
|
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
|
2
|
+
module Jenkins
|
3
|
+
class Client
|
4
|
+
module Job
|
5
|
+
|
6
|
+
def job_names
|
7
|
+
self.class.get("/api/json")['jobs'].map {|job| job['name'] }
|
8
|
+
end
|
9
|
+
|
10
|
+
def create_job(name, config)
|
11
|
+
res = self.class.post("/createItem/api/xml?name=#{CGI.escape(name)}", xml_body(config))
|
12
|
+
raise ServerError, parse_error_message(res) unless res.code.to_i == 200
|
13
|
+
rescue => e
|
14
|
+
raise ServerError, "Failed to create job: #{name}, make sure you have specified auth info properly"
|
15
|
+
end
|
16
|
+
|
17
|
+
def update_job(name, config)
|
18
|
+
res = self.class.post("/job/#{CGI.escape(name)}/config.xml", xml_body(config))
|
19
|
+
raise ServerError, parse_error_message(res) unless res.code.to_i == 200
|
20
|
+
rescue => e
|
21
|
+
raise ServerError, "Failed to create job: #{name}, make sure you have specified auth info properly"
|
22
|
+
end
|
23
|
+
|
24
|
+
def create_or_update_job(name, config)
|
25
|
+
job_names.include?(name) ? update_job(name, config) : create_job(name, config)
|
26
|
+
end
|
27
|
+
|
28
|
+
def disable_job(name)
|
29
|
+
res = self.class.post("/job/#{CGI.escape(name)}/disable")
|
30
|
+
raise ServerError, parse_error_message(res) unless res.code.to_i == 200
|
31
|
+
rescue => e
|
32
|
+
raise ServerError, "Failed to create job: #{name}, make sure you have specified auth info properly"
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
def xml_body(xml_str)
|
37
|
+
{
|
38
|
+
:body => xml_str,
|
39
|
+
:format => :xml,
|
40
|
+
:headers => { 'content-type' => 'application/xml' }
|
41
|
+
}
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
@@ -0,0 +1,103 @@
|
|
1
|
+
|
2
|
+
module Jenkins
|
3
|
+
class Client
|
4
|
+
module Node
|
5
|
+
|
6
|
+
def node_names
|
7
|
+
self.class.get("/computer/api/json")['computer'].map {|computer| computer['displayName'] }
|
8
|
+
end
|
9
|
+
|
10
|
+
def add_node(name, opts = {})
|
11
|
+
options = default_node_options.merge(opts)
|
12
|
+
options[:name] = name
|
13
|
+
options[:labels] = options[:labels].split(/\s*,\s*/).join(' ') if options[:labels]
|
14
|
+
options[:env_vars] = options[:env_vars].map { |k, v| { :key => k, :value => v } }
|
15
|
+
|
16
|
+
response = post_form("/computer/doCreateItem", node_form_fields(options))
|
17
|
+
case response
|
18
|
+
when Net::HTTPFound
|
19
|
+
{ :name => name, :slave_host => options[:slave_host] }
|
20
|
+
else
|
21
|
+
raise ServerError, parse_error_message(response)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def update_node(name, opts = {})
|
26
|
+
options = default_node_options.merge(opts)
|
27
|
+
options[:name] = name
|
28
|
+
options[:labels] = options[:labels].split(/\s*,\s*/).join(' ') if options[:labels]
|
29
|
+
options[:env_vars] = options[:env_vars].map { |k, v| { :key => k, :value => v } }
|
30
|
+
|
31
|
+
response = post_form("/computer/#{CGI::escape(name)}/configSubmit", node_form_fields(options))
|
32
|
+
case response
|
33
|
+
when Net::HTTPFound
|
34
|
+
{ :name => name, :slave_host => options[:slave_host] }
|
35
|
+
else
|
36
|
+
raise ServerError, parse_error_message(response)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def config_node(name, opts = {})
|
41
|
+
node_names.include?(name) ? update_node(name, config) : add_node(name, config)
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
def post_form(path, fields)
|
46
|
+
url = URI.parse("#{self.class.base_uri}/#{path}")
|
47
|
+
req = Net::HTTP::Post.new(url.path)
|
48
|
+
|
49
|
+
basic_auth = self.class.default_options[:basic_auth]
|
50
|
+
req.basic_auth basic_auth[:username], basic_auth[:password] if basic_auth
|
51
|
+
|
52
|
+
req.set_form_data(fields)
|
53
|
+
http = Net::HTTP.new(url.host, url.port)
|
54
|
+
http.request(req)
|
55
|
+
end
|
56
|
+
|
57
|
+
def default_node_options
|
58
|
+
{
|
59
|
+
:slave_port => 22,
|
60
|
+
:slave_user => 'jenkins',
|
61
|
+
:master_key => "/var/lib/jenkins/.ssh/id_rsa",
|
62
|
+
:slave_fs => "/data/jenkins-slave/",
|
63
|
+
:description => "Automatically created by capistrano-jenkins",
|
64
|
+
:executors => 2,
|
65
|
+
:exclusive => true
|
66
|
+
}
|
67
|
+
end
|
68
|
+
|
69
|
+
def node_form_fields(options = {})
|
70
|
+
{
|
71
|
+
"name" => options[:name],
|
72
|
+
"type" => "hudson.slaves.DumbSlave$DescriptorImpl",
|
73
|
+
"json" => {
|
74
|
+
"name" => options[:name],
|
75
|
+
"type" => "hudson.slaves.DumbSlave$DescriptorImpl",
|
76
|
+
"nodeDescription" => options[:description],
|
77
|
+
"numExecutors" => options[:executors],
|
78
|
+
"remoteFS" => options[:slave_fs],
|
79
|
+
"labelString" => options[:labels],
|
80
|
+
"mode" => options[:exclusive] ? "EXCLUSIVE" : "NORMAL",
|
81
|
+
"retentionStrategy" => { "stapler-class" => "hudson.slaves.RetentionStrategy$Always" },
|
82
|
+
"launcher" => {
|
83
|
+
"stapler-class" => "hudson.plugins.sshslaves.SSHLauncher",
|
84
|
+
"host" => options[:slave_host],
|
85
|
+
"port" => options[:slave_port],
|
86
|
+
"username" => options[:slave_user],
|
87
|
+
"privatekey" => options[:master_key],
|
88
|
+
"javaPath" => options[:java_path],
|
89
|
+
"jvmOptions" => options[:jvm_options]
|
90
|
+
},
|
91
|
+
"nodeProperties" => {
|
92
|
+
"stapler-class-bag" => "true",
|
93
|
+
"hudson-slaves-EnvironmentVariablesNodeProperty" => {
|
94
|
+
"env" => options[:env_vars]
|
95
|
+
}
|
96
|
+
}
|
97
|
+
}.to_json
|
98
|
+
}
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jenkins-capistrano
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-10-24 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: capistrano
|
@@ -106,6 +106,8 @@ files:
|
|
106
106
|
- jenkins-capistrano.gemspec
|
107
107
|
- lib/jenkins-capistrano.rb
|
108
108
|
- lib/jenkins-capistrano/client.rb
|
109
|
+
- lib/jenkins-capistrano/client/job.rb
|
110
|
+
- lib/jenkins-capistrano/client/node.rb
|
109
111
|
- lib/jenkins-capistrano/version.rb
|
110
112
|
homepage: https://github.com/cynipe/jenkins-capistrano
|
111
113
|
licenses: []
|
@@ -119,18 +121,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
119
121
|
- - ! '>='
|
120
122
|
- !ruby/object:Gem::Version
|
121
123
|
version: '0'
|
122
|
-
segments:
|
123
|
-
- 0
|
124
|
-
hash: 2200036594680116764
|
125
124
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
126
125
|
none: false
|
127
126
|
requirements:
|
128
127
|
- - ! '>='
|
129
128
|
- !ruby/object:Gem::Version
|
130
129
|
version: '0'
|
131
|
-
segments:
|
132
|
-
- 0
|
133
|
-
hash: 2200036594680116764
|
134
130
|
requirements: []
|
135
131
|
rubyforge_project:
|
136
132
|
rubygems_version: 1.8.24
|
@@ -138,3 +134,4 @@ signing_key:
|
|
138
134
|
specification_version: 3
|
139
135
|
summary: ''
|
140
136
|
test_files: []
|
137
|
+
has_rdoc:
|