jenkins-capistrano 0.0.7 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/.gitignore +73 -16
  2. data/Gemfile.lock +80 -0
  3. data/README.md +169 -56
  4. data/Vagrantfile +23 -0
  5. data/example/Gemfile +3 -1
  6. data/example/README.md +13 -17
  7. data/example/config/deploy.rb +8 -12
  8. data/example/config/deploy/develop.rb +5 -3
  9. data/example/config/deploy/production.rb +13 -3
  10. data/example/config/deploy/staging.rb +13 -4
  11. data/example/config/jenkins/nodes/develop/dev-slave01.xml.erb +33 -0
  12. data/example/config/jenkins/nodes/production/prod-slave01.xml.erb +33 -0
  13. data/example/config/jenkins/nodes/production/prod-slave02.xml.erb +33 -0
  14. data/example/config/jenkins/nodes/production/prod-slave03.xml.erb +33 -0
  15. data/example/config/jenkins/nodes/staging/stg-slave01.xml.erb +33 -0
  16. data/example/config/jenkins/nodes/staging/stg-slave02.xml.erb +33 -0
  17. data/example/config/jenkins/nodes/staging/stg-slave03.xml.erb +33 -0
  18. data/example/script/bootstrap +1 -2
  19. data/features/config_jobs.feature +162 -0
  20. data/features/config_nodes.feature +121 -0
  21. data/features/config_views.feature +136 -0
  22. data/features/help.feature +83 -0
  23. data/features/step_definitions/jenkins_steps.rb +19 -0
  24. data/features/support/env.rb +5 -0
  25. data/features/support/jenkins_helper.rb +113 -0
  26. data/jenkins-capistrano.gemspec +4 -3
  27. data/lib/jenkins-capistrano.rb +2 -215
  28. data/lib/jenkins-capistrano/configurator.rb +87 -0
  29. data/lib/jenkins-capistrano/tasks.rb +112 -0
  30. data/lib/jenkins-capistrano/template.rb +20 -0
  31. data/lib/jenkins-capistrano/version.rb +1 -1
  32. metadata +87 -41
  33. checksums.yaml +0 -7
  34. data/example/config/jenkins/jobs/.gitkeep +0 -0
  35. data/example/config/jenkins/nodes/develop/dev-slave01.json +0 -17
  36. data/example/config/jenkins/nodes/production/prod-slave01.json +0 -17
  37. data/example/config/jenkins/nodes/production/prod-slave02.json +0 -17
  38. data/example/config/jenkins/nodes/production/prod-slave03.json +0 -17
  39. data/example/config/jenkins/nodes/staging/stg-slave01.json +0 -17
  40. data/example/config/jenkins/nodes/staging/stg-slave02.json +0 -17
  41. data/example/config/jenkins/nodes/staging/stg-slave03.json +0 -17
  42. data/lib/jenkins-capistrano/client.rb +0 -66
  43. data/lib/jenkins-capistrano/client/job.rb +0 -47
  44. data/lib/jenkins-capistrano/client/node.rb +0 -103
  45. data/lib/jenkins-capistrano/client/plugin_manager.rb +0 -51
  46. data/lib/jenkins-capistrano/client/update_center.rb +0 -43
  47. data/lib/jenkins-capistrano/client/view.rb +0 -40
@@ -15,10 +15,11 @@ Gem::Specification.new do |gem|
15
15
  gem.require_paths = ["lib"]
16
16
  gem.version = Jenkins::Capistrano::VERSION
17
17
 
18
- gem.add_dependency 'capistrano'
19
- gem.add_dependency 'httparty', '~> 0.8.3'
20
- gem.add_dependency 'hpricot'
18
+ gem.add_dependency 'capistrano', '< 3.0.0'
19
+ gem.add_dependency 'jenkins_api_client', '>= 1.0.0'
21
20
 
22
21
  gem.add_development_dependency 'rake'
23
22
  gem.add_development_dependency 'pry'
23
+ gem.add_development_dependency 'tapp'
24
+ gem.add_development_dependency 'aruba'
24
25
  end
@@ -1,216 +1,3 @@
1
1
  require 'jenkins-capistrano/version'
2
- require 'jenkins-capistrano/client'
3
-
4
- def _cset(name, *args, &block)
5
- unless exists?(name)
6
- set(name, *args, &block)
7
- end
8
- end
9
-
10
- # Capistrano task for Jenkins.
11
- #
12
- # Just add "require 'jenkins-capistrano'" in your Capistrano deploy.rb
13
- Capistrano::Configuration.instance(:must_exist).load do
14
-
15
- _cset(:jenkins_host) { abort "Please specify the host of your jenkins server, set :jenkins_host, 'http://localhost:8080'" }
16
-
17
- _cset(:jenkins_username) { '' }
18
- _cset(:jenkins_password) { '' }
19
-
20
- _cset(:jenkins_job_config_dir) { 'config/jenkins/jobs' }
21
- _cset(:jenkins_node_config_dir) { 'config/jenkins/nodes' }
22
- _cset(:jenkins_view_config_dir) { 'config/jenkins/views' }
23
-
24
- _cset(:jenkins_plugins) { [] }
25
- _cset(:jenkins_install_timeout) { 60 * 5 }
26
- _cset(:jenkins_plugin_enable_update) { false }
27
- _cset(:jenkins_plugin_enable_restart) { false }
28
-
29
- _cset(:disabled_jobs) { [] }
30
-
31
- def client
32
- @client ||= Jenkins::Client.new(jenkins_host, { :username => jenkins_username, :password => jenkins_password})
33
- end
34
-
35
- def job_configs
36
- abort "Please create the jenkins_job_config_dir first: #{jenkins_job_config_dir}" unless Dir.exists? jenkins_job_config_dir
37
- Dir.glob("#{jenkins_job_config_dir}/*.xml")
38
- end
39
-
40
- def node_configs
41
- abort "Please create the jenkins_node_config_dir first: #{jenkins_node_config_dir}" unless Dir.exists? jenkins_node_config_dir
42
- Dir.glob("#{jenkins_node_config_dir}/*.json")
43
- end
44
-
45
- def view_configs
46
- abort "Please create the jenkins_view_config_dir first: #{jenkins_node_config_dir}" unless Dir.exists? jenkins_node_config_dir
47
- Dir.glob("#{jenkins_view_config_dir}/*.xml")
48
- end
49
-
50
- def missing_plugins
51
- installed = client.plugin_names
52
- jenkins_plugins.select do |plugin|
53
- missing = !installed.include?(plugin.split('@'))
54
- logger.info "#{plugin} is already installed." unless missing
55
- missing
56
- end
57
- end
58
-
59
- # minimum configurations
60
- #
61
- # role :jenkins, 'localhost:8080'
62
- namespace :jenkins do
63
-
64
- desc <<-DESC
65
- Deploy the jobs to Jenkins server -- meaning create or update --
66
-
67
- Configuration
68
- -------------
69
- jenkins_job_config_dir
70
- the directory path where the config.xml stored.
71
- default: 'config/jenkins/jobs'
72
-
73
- disabled_jobs
74
- job names array which should be disabled after deployment.
75
- default: []
76
-
77
- DESC
78
- task :deploy_jobs do
79
- logger.info "deploying jenkins jobs to #{jenkins_host}"
80
- logger.important "no job configs found." if job_configs.empty?
81
- job_configs.each do |file|
82
- name = File.basename(file, '.xml')
83
- msg = StringIO.new
84
-
85
- client.create_or_update_job(name, File.read(file))
86
- msg << "job #{name} created"
87
-
88
- if disabled_jobs.include? name
89
- client.disable_job(name)
90
- msg << ", but was set to disabled"
91
- end
92
- msg << "."
93
- logger.trace msg.string
94
- end
95
- end
96
-
97
- desc <<-DESC
98
- Configure the nodes to Jenkins server -- meaning create or update --
99
-
100
- Configuration
101
- -------------
102
- jenkins_node_config_dir
103
- the directory path where the node's configuration stored.
104
- default: 'config/jenkins/nodes'
105
- DESC
106
- task :config_nodes do
107
- logger.info "configuring jenkins nodes to #{jenkins_host}"
108
- logger.important "no node configs found." if node_configs.empty?
109
- node_configs.each do |file|
110
- name = File.basename(file, '.json')
111
- opts = JSON.parse(File.read(file)).to_hash.
112
- inject({}) { |mem, (key, val)| mem[key.to_sym] = val; mem }
113
- client.config_node(name, opts)
114
- logger.trace "node #{name} created."
115
- end
116
- end
117
-
118
- desc <<-DESC
119
- Configure the views to Jenkins server -- meaning create or update --
120
-
121
- Configuration
122
- -------------
123
- jenkins_view_config_dir
124
- the directory path where the view's configuration stored.
125
- default: 'config/jenkins/views'
126
- DESC
127
- task :config_views do
128
- logger.info "configuring jenkins views to #{jenkins_host}"
129
- logger.important "no view configs found." if view_configs.empty?
130
- view_configs.each do |file|
131
- name = File.basename(file, '.xml')
132
- msg = StringIO.new
133
- client.create_or_update_view(name, File.read(file))
134
- logger.trace "view #{name} created."
135
- end
136
- end
137
-
138
- desc <<-DESC
139
- Install plugins to Jenkins server
140
-
141
- Configuration
142
- -------------
143
- jenkins_plugins
144
- the hash array contains plugin's name and version.
145
-
146
- jenkins_install_timeout
147
- a timeout seconds to wait for plugin installation.
148
- default: 5 min
149
-
150
- jenkins_plugin_enable_update
151
- whether to update or ignore when the plugin already installed.
152
- default: false
153
-
154
- jenkins_plugin_enable_restart
155
- whether to restart or ignore when the plugin installation requires restarting.
156
- default: false
157
- DESC
158
- task :install_plugins do
159
- logger.important "installing plugins to #{jenkins_host}"
160
- if jenkins_plugins.empty?
161
- logger.info "no plugin config found."
162
- next
163
- end
164
-
165
- logger.info "calcurating plugins to install..."
166
- candidates = client.prevalidate_plugin_config(missing_plugins)
167
- plugins_to_install = candidates.reduce([]) do |mem, candidate|
168
- plugin = "#{candidate['name']}@#{candidate['version']}"
169
- mode = candidate['mode']
170
- case
171
- when mode == 'missing'
172
- logger.debug "#{plugin} marked to be installed."
173
- mem << candidate
174
- when mode == 'old'
175
- if jenkins_plugin_enable_update
176
- logger.debug "#{plugin} marked to be updated."
177
- mem << candidate
178
- end
179
- end
180
- mem
181
- end
182
- if plugins_to_install.empty?
183
- logger.info "all plugins already installed."
184
- next
185
- end
186
-
187
- logger.info "installing the plugins, this could be take a while..."
188
- client.install_plugin(plugins_to_install)
189
-
190
- names = plugins_to_install.map {|v| v['name'] }
191
- client.wait_for_complete(jenkins_install_timeout) do |job|
192
- result = job['status'] == true
193
- # skip unknown jobs
194
- if result and names.include?(job['name'])
195
- names.delete job['name']
196
- logger.debug "#{job['name']}@#{job['version']} installed."
197
- end
198
- result
199
- end
200
- logger.info "all plugins successfully installed."
201
-
202
- if client.restart_required?
203
- if jenkins_plugin_enable_restart
204
- logger.important "restarting jenkins."
205
- client.safe_restart! do
206
- logger.debug "waiting for Jenkins to restart..."
207
- end
208
- logger.info "Jenkins is successfully restarted."
209
- else
210
- logger.important "restarting is disabled, please restart the jenkins manually for complete the installation."
211
- end
212
- end
213
- end
214
- end
215
-
216
- end
2
+ require 'jenkins-capistrano/configurator'
3
+ require 'jenkins-capistrano/tasks'
@@ -0,0 +1,87 @@
1
+ require 'jenkins-capistrano/template'
2
+ require 'jenkins_api_client'
3
+
4
+ module Jenkins
5
+ module Capistrano
6
+ class Configurator
7
+
8
+ attr_reader :logger, :client, :job_config_dir, :node_config_dir, :view_config_dir, :template_vars
9
+
10
+ def initialize(options = {})
11
+ opts = {:log_location => '/dev/null'}.merge(options)
12
+ @logger = opts.delete(:logger)
13
+ @template_vars = opts.delete(:template_vars)
14
+ @client = JenkinsApi::Client.new(opts)
15
+ end
16
+
17
+ def configure_jobs(config_files, disabled_jobs)
18
+ if config_files.empty?
19
+ logger.important "no node configs found."
20
+ return
21
+ end
22
+
23
+ config_files.each do |file|
24
+ name = name_for(file)
25
+ client.job.create_or_update(name, config_xml_for(file))
26
+ logger.trace "job #{name} created."
27
+ if disabled_jobs.include? name
28
+ client.job.disable(name)
29
+ logger.trace " -> disabled"
30
+ end
31
+ end
32
+ end
33
+
34
+ def configure_nodes(config_files)
35
+ if config_files.empty?
36
+ logger.important "no node configs found."
37
+ return
38
+ end
39
+
40
+ config_files.each do |file|
41
+ name = name_for(file)
42
+ unless client.node.list.include? name
43
+ params = { :name => name, :slave_host => 'dummy-by-jenkins-capistrano', :private_key_file => 'dummy' }
44
+ client.node.create_dumb_slave(params)
45
+ end
46
+ client.node.post_config(name, config_xml_for(file))
47
+ logger.trace "node #{name} created."
48
+ end
49
+ end
50
+
51
+ def configure_views(config_files)
52
+ if config_files.empty?
53
+ logger.important "no view configs found."
54
+ return
55
+ end
56
+
57
+ config_files.each do |file|
58
+ name = name_for(file)
59
+ unless client.view.exists? name
60
+ client.view.create name
61
+ end
62
+ client.view.post_config(name, config_xml_for(file))
63
+ logger.trace "view #{name} created."
64
+ end
65
+ end
66
+
67
+ private
68
+ def name_for(file_path)
69
+ file_path.basename.to_s.split('.').first
70
+ end
71
+
72
+ def config_xml_for(file)
73
+ config_xml = if file.extname == '.erb'
74
+ Jenkins::Template.new(file, template_vars).evaluate
75
+ else
76
+ file.read
77
+ end
78
+ Nokogiri::XML(config_xml) do |config|
79
+ config.options = Nokogiri::XML::ParseOptions::STRICT
80
+ end.to_xml
81
+ rescue => e
82
+ abort "`#{file}` is not well-formed, put `.erb` as extname if it's erb template: #{e.message}"
83
+ end
84
+
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,112 @@
1
+ Capistrano::Configuration.instance(:must_exist).load do
2
+
3
+ def _cset(name, *args, &block)
4
+ unless exists?(name)
5
+ set(name, *args, &block)
6
+ end
7
+ end
8
+
9
+ _cset(:jenkins_host) { abort "Please specify the host of your jenkins server, set :jenkins_host, 'http://localhost:8080'" }
10
+
11
+ _cset(:jenkins_username) { '' }
12
+ _cset(:jenkins_password) { '' }
13
+
14
+ _cset(:jenkins_job_config_dir) { 'config/jenkins/jobs' }
15
+ _cset(:jenkins_node_config_dir) { 'config/jenkins/nodes' }
16
+ _cset(:jenkins_view_config_dir) { 'config/jenkins/views' }
17
+
18
+ _cset(:disabled_jobs) { [] }
19
+
20
+ _cset(:jenkins_template_vars) { {} }
21
+
22
+ def configurator
23
+ @configurator ||= Jenkins::Capistrano::Configurator.new(
24
+ :logger => logger,
25
+ :server_url => jenkins_host,
26
+ :username => jenkins_username,
27
+ :password => jenkins_password,
28
+ :template_vars => jenkins_template_vars
29
+ )
30
+ end
31
+
32
+ %w(job node view).each do |name|
33
+ instance_eval <<-RUBY, __FILE__, __LINE__ + 1
34
+ def #{name}_configs
35
+ config_dir = fetch('jenkins_#{name}_config_dir'.to_sym)
36
+ abort "Please create the jenkins_#{name}_config_dir first: \#{config_dir}" unless Dir.exists? config_dir
37
+ Pathname.glob(File.join(config_dir, '/*.{xml,erb}'))
38
+ end
39
+ RUBY
40
+ end
41
+
42
+ # minimum configurations
43
+ #
44
+ # role :jenkins, 'localhost:8080'
45
+ namespace :jenkins do
46
+
47
+ desc <<-DESC
48
+ Configure the jobs to Jenkins server.
49
+
50
+ Configuration
51
+ -------------
52
+ jenkins_job_config_dir
53
+ the directory path where the config.xml stored.
54
+ default: 'config/jenkins/jobs'
55
+
56
+ disabled_jobs
57
+ job names array which should be disabled after deployment.
58
+ default: []
59
+ DESC
60
+ task :config_jobs do
61
+ logger.info "deploying jenkins jobs to #{jenkins_host}"
62
+ configurator.configure_jobs(job_configs, disabled_jobs)
63
+ end
64
+
65
+
66
+ desc <<-DESC
67
+ [DEPRECATED] Use jenkins:config_jobs instead.
68
+ DESC
69
+ task :deploy_jobs do
70
+ logger.important '[DEPRECATED] Use jenkins:config_jobs instead.'
71
+ config_jobs
72
+ end
73
+
74
+ desc <<-DESC
75
+
76
+ DESC
77
+ task :reverse_jobs do
78
+ logger.important '[DEPRECATED] Use jenkins:config_jobs instead.'
79
+ config_jobs
80
+ end
81
+
82
+ desc <<-DESC
83
+ Configure the nodes to Jenkins server.
84
+
85
+ Configuration
86
+ -------------
87
+ jenkins_node_config_dir
88
+ the directory path where the node's configuration stored.
89
+ default: 'config/jenkins/nodes'
90
+ DESC
91
+ task :config_nodes do
92
+ logger.info "configuring jenkins nodes to #{jenkins_host}"
93
+ configurator.configure_nodes(node_configs)
94
+ end
95
+
96
+ desc <<-DESC
97
+ Configure the views to Jenkins server.
98
+
99
+ Configuration
100
+ -------------
101
+ jenkins_view_config_dir
102
+ the directory path where the view's configuration stored.
103
+ default: 'config/jenkins/views'
104
+ DESC
105
+ task :config_views do
106
+ logger.info "configuring jenkins views to #{jenkins_host}"
107
+ configurator.configure_views(view_configs)
108
+ end
109
+
110
+ end
111
+
112
+ end
@@ -0,0 +1,20 @@
1
+
2
+ module Jenkins
3
+ class Template
4
+
5
+ def initialize(template, variables)
6
+ raise ArgumentError, "Template #{template} does not exist." unless File.exists? template
7
+ raise ArgumentError, "variables must be a Hash, but was #{variables.class}" unless variables.is_a? Hash
8
+ @template = template
9
+ @variables = variables
10
+ end
11
+
12
+ def evaluate
13
+ @variables.each do |param, value|
14
+ var = "@#{param.to_s}"
15
+ instance_variable_set(var, value)
16
+ end
17
+ ERB.new(File.read(@template), 0, '-').result(binding)
18
+ end
19
+ end
20
+ end