jenkins_pipeline_builder 0.6.0 → 0.7.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.
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