jenkins_pipeline_builder 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (29) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +3 -11
  3. data/README.md +19 -29
  4. data/commit_build.sh +1 -4
  5. data/lib/jenkins_pipeline_builder.rb +9 -13
  6. data/lib/jenkins_pipeline_builder/cli/describe.rb +14 -5
  7. data/lib/jenkins_pipeline_builder/cli/helper.rb +2 -0
  8. data/lib/jenkins_pipeline_builder/cli/list.rb +11 -4
  9. data/lib/jenkins_pipeline_builder/extensions.rb +151 -40
  10. data/lib/jenkins_pipeline_builder/{builders.rb → extensions/builders.rb} +22 -15
  11. data/lib/jenkins_pipeline_builder/{job_builder.rb → extensions/job_attributes.rb} +37 -27
  12. data/lib/jenkins_pipeline_builder/{publishers.rb → extensions/publishers.rb} +55 -20
  13. data/lib/jenkins_pipeline_builder/{triggers.rb → extensions/triggers.rb} +18 -8
  14. data/lib/jenkins_pipeline_builder/{wrappers.rb → extensions/wrappers.rb} +23 -36
  15. data/lib/jenkins_pipeline_builder/generator.rb +29 -62
  16. data/lib/jenkins_pipeline_builder/module_registry.rb +21 -9
  17. data/lib/jenkins_pipeline_builder/pull_request.rb +1 -1
  18. data/lib/jenkins_pipeline_builder/version.rb +1 -1
  19. data/pipeline/Jenkins-Pipeline-Builder.yaml +3 -7
  20. data/pipeline/project.yaml +10 -0
  21. data/spec/lib/jenkins_pipeline_builder/compiler_spec.rb +9 -1
  22. data/spec/lib/jenkins_pipeline_builder/extensions/builders_spec.rb +53 -0
  23. data/spec/lib/jenkins_pipeline_builder/extensions/publishers_spec.rb +140 -0
  24. data/spec/lib/jenkins_pipeline_builder/extensions_spec.rb +113 -31
  25. data/spec/lib/jenkins_pipeline_builder/generator_spec.rb +12 -4
  26. data/spec/lib/jenkins_pipeline_builder/module_registry_spec.rb +202 -44
  27. data/spec/lib/jenkins_pipeline_builder/spec_helper.rb +5 -5
  28. data/spec/requests/pipeline_spec.rb +20 -0
  29. metadata +16 -7
@@ -66,36 +66,34 @@ module JenkinsPipelineBuilder
66
66
  JenkinsPipelineBuilder::View.new(self)
67
67
  end
68
68
 
69
- def bootstrap(path, project_name)
70
- @logger.info "Bootstrapping pipeline from path #{path}"
69
+ def bootstrap(path, project_name = nil)
70
+ logger.info "Bootstrapping pipeline from path #{path}"
71
71
  load_collection_from_path(path)
72
- # @logger.info @job_collection
73
72
  cleanup_temp_remote
74
73
  load_extensions(path)
75
74
  errors = {}
76
- # Publish all the jobs if the projects are not found
77
- if projects.count == 0
78
- errors = publish_jobs(jobs)
79
- else
75
+ if projects.any?
80
76
  errors = publish_project(project_name)
77
+ else
78
+ errors = publish_jobs(jobs)
81
79
  end
82
80
  errors.each do |k, v|
83
- @logger.error "Encountered errors compiling: #{k}:"
84
- @logger.error v
81
+ logger.error "Encountered errors compiling: #{k}:"
82
+ logger.error v
85
83
  end
86
84
  errors
87
85
  end
88
86
 
89
87
  def pull_request(path, project_name)
90
88
  success = false
91
- @logger.info "Pull Request Generator Running from path #{path}"
89
+ logger.info "Pull Request Generator Running from path #{path}"
92
90
  load_collection_from_path(path)
93
91
  cleanup_temp_remote
94
92
  load_extensions(path)
95
- @logger.info "Project: #{projects}"
93
+ logger.info "Project: #{projects}"
96
94
  projects.each do |project|
97
95
  next unless project[:name] == project_name || project_name.nil?
98
- @logger.info "Using Project #{project}"
96
+ logger.info "Using Project #{project}"
99
97
  pull_job = find_pull_request_generator(project)
100
98
  p_success, p_payload = compile_pull_request_generator(pull_job[:name], project)
101
99
  next unless p_success
@@ -223,49 +221,13 @@ module JenkinsPipelineBuilder
223
221
  def load_extensions(path)
224
222
  path = "#{path}/extensions"
225
223
  path = File.expand_path(path, Dir.getwd)
226
- unless File.directory?(path)
227
- logger.info "Loading extensions from folder #{path}"
228
- logger.info Dir.glob("#{path}/*.rb").inspect
229
- Dir.glob("#{path}/*.rb").each do |file|
230
- logger.info "Loaded #{file}"
231
- require file
232
- end
233
- end
234
- match_extension_versions
235
- end
236
-
237
- def match_extension_versions
238
- registry = @module_registry.registry[:job]
239
- installed_plugins = @debug ? nil : list_plugins # Only get plugins if not in debug mode
240
- @logger.debug 'Loading newest version of all plugins since we are in debug mode.'
241
- registry.each do |registry_key, registry_value|
242
- if registry_value.count > 1
243
- registry_value.each_key do |extension_key|
244
- registry[registry_key][extension_key] = newest_compatible(extension_key, installed_plugins, registry_key)
245
- end
246
- else
247
- registry[registry_key] = newest_compatible(registry_key, installed_plugins)
248
- end
249
- end
250
- end
251
-
252
- def newest_compatible(extension, installed_plugins, key = nil)
253
- # Fetch the registrered_modules for the extension
254
- registry = @module_registry.registry[:job]
255
- registry = registry[key] unless key.nil?
256
- registry = registry[extension]
257
- keep = nil
258
- keep_version = ''
259
- registry.each do |ex|
260
- is_available = @debug ? true : ex.min_version.to_s <= installed_plugins[ex.plugin_id.to_s].to_s
261
- is_newer = ex.min_version.to_s >= keep_version
262
-
263
- next unless keep.nil? || (is_available && is_newer)
264
-
265
- keep = ex
266
- keep_version = ex.min_version
224
+ return unless File.directory?(path)
225
+ logger.info "Loading extensions from folder #{path}"
226
+ logger.info Dir.glob("#{path}/*.rb").inspect
227
+ Dir.glob("#{path}/*.rb").each do |file|
228
+ logger.info "Loaded #{file}"
229
+ require file
267
230
  end
268
- keep
269
231
  end
270
232
 
271
233
  def load_template(path, template)
@@ -423,7 +385,7 @@ module JenkinsPipelineBuilder
423
385
  logger.info project
424
386
  process_job_changes(jobs)
425
387
  errors = process_jobs(jobs, project)
426
- errors = process_views(project_body[:views], project, errors) if project_body[:views]
388
+ errors = process_views(project_body[:views], project, errors) if project_body[:views]
427
389
  errors.each do |k, v|
428
390
  puts "Encountered errors processing: #{k}:"
429
391
  v.each do |key, error|
@@ -466,7 +428,7 @@ module JenkinsPipelineBuilder
466
428
  next unless project_name.nil? || project[:name] == project_name
467
429
  success, payload = resolve_project(project)
468
430
  if success
469
- @logger.info 'successfully resolved project'
431
+ logger.info 'successfully resolved project'
470
432
  compiled_project = payload
471
433
  else
472
434
  return false
@@ -484,7 +446,7 @@ module JenkinsPipelineBuilder
484
446
 
485
447
  def publish_jobs(jobs, errors = {})
486
448
  jobs.each do |i|
487
- @logger.info "Processing #{i}"
449
+ logger.info "Processing #{i}"
488
450
  job = i[:result]
489
451
  fail "Result is empty for #{i}" if job.nil?
490
452
  success, payload = compile_job_to_xml(job)
@@ -502,7 +464,8 @@ module JenkinsPipelineBuilder
502
464
  if @debug
503
465
  logger.info "Will create job #{job}"
504
466
  logger.info "#{xml}"
505
- File.open(job_name + '.xml', 'w') { |f| f.write xml }
467
+ FileUtils.mkdir_p(out_dir) unless File.exist?(out_dir)
468
+ File.open("#{out_dir}/#{job_name}.xml", 'w') { |f| f.write xml }
506
469
  return
507
470
  end
508
471
 
@@ -555,7 +518,7 @@ module JenkinsPipelineBuilder
555
518
  puts "Template merged: #{template}"
556
519
  end
557
520
 
558
- xml = client.job.build_freestyle_config(params)
521
+ xml = client.job.build_freestyle_config(params)
559
522
  n_xml = Nokogiri::XML(xml)
560
523
 
561
524
  logger.debug 'Loading the required modules'
@@ -576,7 +539,7 @@ module JenkinsPipelineBuilder
576
539
 
577
540
  # TODO: make sure this is tested
578
541
  def update_job_dsl(job, xml)
579
- n_xml = Nokogiri::XML(xml)
542
+ n_xml = Nokogiri::XML(xml)
580
543
  n_builders = n_xml.xpath('//builders').first
581
544
  Nokogiri::XML::Builder.with(n_builders) do |b_xml|
582
545
  build_job_dsl(job, b_xml)
@@ -591,11 +554,11 @@ module JenkinsPipelineBuilder
591
554
 
592
555
  n_xml = Nokogiri::XML(xml)
593
556
  if n_xml.xpath('//javaposse.jobdsl.plugin.ExecuteDslScripts').empty?
594
- p_xml = Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |b_xml|
557
+ p_xml = Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |b_xml|
595
558
  build_job_dsl(params, b_xml)
596
559
  end
597
560
 
598
- n_xml.xpath('//builders').first.add_child("\r\n" + p_xml.doc.root.to_xml(indent: 4) + "\r\n")
561
+ n_xml.xpath('//builders').first.add_child("\r\n" + p_xml.doc.root.to_xml(indent: 4) + "\r\n")
599
562
  xml = n_xml.to_xml
600
563
  end
601
564
  xml
@@ -614,5 +577,9 @@ module JenkinsPipelineBuilder
614
577
  xml.removedJobAction 'IGNORE'
615
578
  end
616
579
  end
580
+
581
+ def out_dir
582
+ 'out/xml'
583
+ end
617
584
  end
618
585
  end
@@ -27,6 +27,16 @@ module JenkinsPipelineBuilder
27
27
  @registry = { job: {} }
28
28
  end
29
29
 
30
+ def versions
31
+ # Return a hash with a default of 1000 so that we'll get the newest in debug
32
+ return Hash.new { |_| '1000.0' } if JenkinsPipelineBuilder.generator.debug
33
+ @versions ||= JenkinsPipelineBuilder.client.plugin.list_installed
34
+ end
35
+
36
+ def clear_versions
37
+ @versions = nil
38
+ end
39
+
30
40
  def logger
31
41
  JenkinsPipelineBuilder.logger
32
42
  end
@@ -42,13 +52,17 @@ module JenkinsPipelineBuilder
42
52
  }
43
53
  end
44
54
 
45
- def register(prefix, extension)
55
+ def register(prefix, set)
46
56
  name = prefix.pop
47
57
  root = prefix.inject(@registry, :[])
48
58
  root[name] = {} unless root[name]
59
+ # TODO: Set installed version here
49
60
 
50
- root[name][extension.name] = [] unless root[name][extension.name]
51
- root[name][extension.name] << extension
61
+ if root[name][set.name]
62
+ root[name][set.name].merge set
63
+ else
64
+ root[name][set.name] = set
65
+ end
52
66
  end
53
67
 
54
68
  def get(path)
@@ -76,12 +90,10 @@ module JenkinsPipelineBuilder
76
90
  next
77
91
  end
78
92
  reg_value = registry[key]
79
- if reg_value.is_a?(Array) && reg_value.first.is_a?(Extension)
80
- next unless reg_value.select { |x| x.class == Extension }.size == reg_value.size
81
- # TODO: Actually compare versions installed on box here
82
- reg = reg_value.sort { |x, y| x.min_version <=> y.min_version }.last
83
- logger.debug "Using #{reg.type} #{reg.name} version #{reg.min_version}"
84
- execute_extension(reg, value, n_xml)
93
+ if reg_value.is_a? ExtensionSet
94
+ ext = reg_value.extension
95
+ logger.debug "Using #{ext.type} #{ext.name} version #{ext.min_version}"
96
+ execute_extension ext, value, n_xml
85
97
  elsif value.is_a? Hash
86
98
  traverse_registry reg_value, value, n_xml, true
87
99
  elsif value.is_a? Array
@@ -51,7 +51,7 @@ module JenkinsPipelineBuilder
51
51
  #
52
52
  # args[:git_url] URL to the github main page ex. https://www.github.com/
53
53
  # args[:git_repo] Name of repo only, not url ex. jenkins_pipeline_builder
54
- # args[:git_org] The Orig user ex. igorshare
54
+ # args[:git_org] The Orig user ex. constantcontact
55
55
  # @return = array of pull request numbers
56
56
  def check_for_pull(args)
57
57
  fail 'Please specify all arguments' unless args[:git_url] && args[:git_org] && args[:git_repo]
@@ -21,5 +21,5 @@
21
21
  #
22
22
 
23
23
  module JenkinsPipelineBuilder
24
- VERSION = '0.6.0'
24
+ VERSION = '0.7.0'
25
25
  end
@@ -1,7 +1,7 @@
1
1
  - job:
2
- name: 'Jenkins-Pipeline-Builder'
2
+ name: '{{name}}-Commit'
3
3
  scm_provider: git
4
- scm_url: https://github.com/IgorShare/jenkins_pipeline_builder.git
4
+ scm_url: https://github.com/constantcontact/jenkins_pipeline_builder.git
5
5
  scm_branch: master
6
6
  scm_params:
7
7
  excuded_users: buildmaster
@@ -11,14 +11,10 @@
11
11
  wrappers:
12
12
  - timestamp: true
13
13
  - ansicolor: true
14
- - rvm: "`cat .ruby-version`@`cat .ruby-gemset`"
14
+ - rvm: "`cat .ruby-version`"
15
15
  publishers:
16
16
  - junit_result:
17
17
  test_results: 'out/**/*.xml'
18
- - git:
19
- push-merge: true
20
- push-only-if-success: false
21
- - hipchat: true
22
18
  - coverage_result:
23
19
  report_dir: out/coverage/rcov
24
20
  total:
@@ -0,0 +1,10 @@
1
+ - project:
2
+ name: Jenkins-Pipeline-Builder
3
+ description: 'Do not edit this job through the web!'
4
+ git_repo: git@github.com:constantcontact/jenkins_pipeline_builder.git
5
+ git_branch: master
6
+ discard_days: '30'
7
+ discard_number: '100'
8
+ rvm: '`cat .ruby-version`'
9
+ jobs:
10
+ - '{{name}}-Commit'
@@ -1,6 +1,14 @@
1
1
  require File.expand_path('../spec_helper', __FILE__)
2
- require 'pp'
3
2
  describe JenkinsPipelineBuilder::Compiler do
3
+ before :all do
4
+ JenkinsPipelineBuilder.credentials = {
5
+ server_ip: '127.0.0.1',
6
+ server_port: 8080,
7
+ username: 'username',
8
+ password: 'password',
9
+ log_location: '/dev/null'
10
+ }
11
+ end
4
12
  let(:compiler) { JenkinsPipelineBuilder::Compiler }
5
13
  let(:settings_project) { { name: 'DummyPipeline', type: :project, value: { name: 'DummyPipeline', jobs: ['{{name}}-00', { '{{name}}-01' => { job_name: '{{name}}-02' } }] } } }
6
14
  let(:settings_global) { { name: 'global', description: 'Do not edit this job through the web!', discard_days: '14', pipeline_repo: 'git@github.com:constantcontact/jenkins_pipeline_builder.git', pipeline_branch: 'master' } }
@@ -0,0 +1,53 @@
1
+ require File.expand_path('../../spec_helper', __FILE__)
2
+
3
+ describe 'builders' do
4
+ after :each do
5
+ JenkinsPipelineBuilder.registry.clear_versions
6
+ end
7
+
8
+ before :all do
9
+ JenkinsPipelineBuilder.credentials = {
10
+ server_ip: '127.0.0.1',
11
+ server_port: 8080,
12
+ username: 'username',
13
+ password: 'password',
14
+ log_location: '/dev/null'
15
+ }
16
+ end
17
+
18
+ before :each do
19
+ builder = Nokogiri::XML::Builder.new { |xml| xml.builders }
20
+ @n_xml = builder.doc
21
+ end
22
+
23
+ after :each do |example|
24
+ name = example.description.gsub ' ', '_'
25
+ File.open("./out/xml/builder_#{name}.xml", 'w') { |f| @n_xml.write_xml_to f }
26
+ end
27
+
28
+ context 'multi_job builder' do
29
+ before :each do
30
+ allow(JenkinsPipelineBuilder.client).to receive(:plugin).and_return double(
31
+ list_installed: { 'jenkins-multijob-plugin' => '20.0' })
32
+ end
33
+ it 'generates a configuration' do
34
+ params = { builders: { multi_job: { phases: { foo: { jobs: [{ name: 'foo' }] } } } } }
35
+
36
+ JenkinsPipelineBuilder.registry.traverse_registry_path('job', params, @n_xml)
37
+
38
+ builder = @n_xml.root.children.first
39
+ expect(builder.name).to match 'com.tikal.jenkins.plugins.multijob.MultiJobBuilder'
40
+ end
41
+
42
+ it 'provides job specific config' do
43
+ params = { builders: { multi_job: { phases: { foo: { jobs: [{ name: 'foo', config: {
44
+ predefined_build_parameters: 'bar'
45
+ } }] } } } } }
46
+
47
+ JenkinsPipelineBuilder.registry.traverse_registry_path('job', params, @n_xml)
48
+
49
+ node = @n_xml.xpath '//hudson.plugins.parameterizedtrigger.PredefinedBuildParameters'
50
+ expect(node.children.first.content).to eq 'bar'
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,140 @@
1
+ require File.expand_path('../../spec_helper', __FILE__)
2
+
3
+ describe 'publishers' do
4
+ after :each do
5
+ JenkinsPipelineBuilder.registry.clear_versions
6
+ end
7
+
8
+ before :all do
9
+ JenkinsPipelineBuilder.credentials = {
10
+ server_ip: '127.0.0.1',
11
+ server_port: 8080,
12
+ username: 'username',
13
+ password: 'password',
14
+ log_location: '/dev/null'
15
+ }
16
+ end
17
+
18
+ before :each do
19
+ builder = Nokogiri::XML::Builder.new { |xml| xml.publishers }
20
+ @n_xml = builder.doc
21
+ end
22
+
23
+ after :each do |example|
24
+ name = example.description.gsub ' ', '_'
25
+ File.open("./out/xml/publisher_#{name}.xml", 'w') { |f| @n_xml.write_xml_to f }
26
+ end
27
+
28
+ context 'sonar publisher' do
29
+ before :each do
30
+ allow(JenkinsPipelineBuilder.client).to receive(:plugin).and_return double(
31
+ list_installed: { 'sonar' => '20.0' })
32
+ end
33
+
34
+ it 'generates a configuration' do
35
+ params = { publishers: { sonar_result: {} } }
36
+
37
+ JenkinsPipelineBuilder.registry.traverse_registry_path('job', params, @n_xml)
38
+
39
+ sonar_publisher = @n_xml.root.children.first
40
+ expect(sonar_publisher.name).to match 'hudson.plugins.sonar.SonarPublisher'
41
+ end
42
+
43
+ it 'populates branch' do
44
+ params = { publishers: { sonar_result: { branch: 'test' } } }
45
+
46
+ JenkinsPipelineBuilder.registry.traverse_registry_path('job', params, @n_xml)
47
+
48
+ sonar_nodes = @n_xml.root.children.first.children
49
+ branch = sonar_nodes.select { |node| node.name == 'branch' }
50
+ expect(branch.first.content).to match 'test'
51
+ end
52
+
53
+ it 'populates maven installation name' do
54
+ params = { publishers: { sonar_result: { maven_installation_name: 'test' } } }
55
+
56
+ JenkinsPipelineBuilder.registry.traverse_registry_path('job', params, @n_xml)
57
+
58
+ sonar_nodes = @n_xml.root.children.first.children
59
+ maven_installation_name = sonar_nodes.select { |node| node.name == 'mavenInstallationName' }
60
+ expect(maven_installation_name.first.content).to match 'test'
61
+ end
62
+ end
63
+
64
+ context 'description_setter' do
65
+ before :each do
66
+ allow(JenkinsPipelineBuilder.client).to receive(:plugin).and_return double(
67
+ list_installed: { 'description-setter' => '20.0' })
68
+ end
69
+ it 'generates a configuration' do
70
+ puts JenkinsPipelineBuilder.registry.versions
71
+ params = { publishers: { description_setter: {} } }
72
+
73
+ JenkinsPipelineBuilder.registry.traverse_registry_path('job', params, @n_xml)
74
+
75
+ publisher = @n_xml.root.children.first
76
+ expect(publisher.name).to match 'hudson.plugins.descriptionsetter.DescriptionSetterPublisher'
77
+ end
78
+ end
79
+
80
+ context 'downstream' do
81
+ before :each do
82
+ allow(JenkinsPipelineBuilder.client).to receive(:plugin).and_return double(
83
+ list_installed: { 'parameterized-trigger' => '20.0'
84
+ })
85
+ end
86
+
87
+ it 'generates a configuration' do
88
+ params = { publishers: { downstream: {} } }
89
+
90
+ JenkinsPipelineBuilder.registry.traverse_registry_path('job', params, @n_xml)
91
+
92
+ publisher = @n_xml.root.children.first
93
+ expect(publisher.name).to match 'hudson.plugins.parameterizedtrigger.BuildTrigger'
94
+ end
95
+
96
+ it 'populates data'
97
+ it 'passes params'
98
+ it 'sets the file'
99
+ end
100
+
101
+ context 'hipchat' do
102
+ it 'generates a configuration'
103
+ it 'does an option'
104
+ end
105
+
106
+ context 'git' do
107
+ it 'generates a configuration'
108
+ it 'does an option'
109
+ end
110
+
111
+ context 'junit_result' do
112
+ it 'generates a configuration'
113
+ it 'does an option'
114
+ end
115
+
116
+ context 'coverage_result' do
117
+ it 'generates a configuration'
118
+ it 'does an option'
119
+ end
120
+
121
+ context 'post_build_script' do
122
+ it 'generates a configuration'
123
+ it 'does an option'
124
+ end
125
+
126
+ context 'groovy_postbuild' do
127
+ it 'generates a configuration'
128
+ it 'does an option'
129
+ end
130
+
131
+ context 'archive_artifact' do
132
+ it 'generates a configuration'
133
+ it 'does an option'
134
+ end
135
+
136
+ context 'email_notification' do
137
+ it 'generates a configuration'
138
+ it 'does an option'
139
+ end
140
+ end