jenkins_pipeline_builder 0.10.16 → 0.11.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 (40) hide show
  1. checksums.yaml +8 -8
  2. data/.rubocop.yml +4 -4
  3. data/lib/jenkins_pipeline_builder.rb +5 -0
  4. data/lib/jenkins_pipeline_builder/compiler.rb +27 -24
  5. data/lib/jenkins_pipeline_builder/extension_dsl.rb +1 -0
  6. data/lib/jenkins_pipeline_builder/extension_set.rb +8 -8
  7. data/lib/jenkins_pipeline_builder/extensions.rb +12 -24
  8. data/lib/jenkins_pipeline_builder/extensions/builders.rb +36 -27
  9. data/lib/jenkins_pipeline_builder/extensions/helpers/builders/blocking_downstream_helper.rb +18 -0
  10. data/lib/jenkins_pipeline_builder/extensions/helpers/builders/maven3_helper.rb +11 -0
  11. data/lib/jenkins_pipeline_builder/extensions/helpers/extension_helper.rb +26 -0
  12. data/lib/jenkins_pipeline_builder/extensions/helpers/job_attributes/parameters_helper.rb +18 -0
  13. data/lib/jenkins_pipeline_builder/extensions/helpers/publishers/cobertura_report_helper.rb +40 -0
  14. data/lib/jenkins_pipeline_builder/extensions/helpers/publishers/email_ext_helper.rb +148 -0
  15. data/lib/jenkins_pipeline_builder/extensions/helpers/triggers/upstream_helper.rb +21 -0
  16. data/lib/jenkins_pipeline_builder/extensions/job_attributes.rb +1 -15
  17. data/lib/jenkins_pipeline_builder/extensions/publishers.rb +263 -6
  18. data/lib/jenkins_pipeline_builder/extensions/triggers.rb +3 -17
  19. data/lib/jenkins_pipeline_builder/extensions/wrappers.rb +3 -3
  20. data/lib/jenkins_pipeline_builder/generator.rb +10 -11
  21. data/lib/jenkins_pipeline_builder/job.rb +29 -25
  22. data/lib/jenkins_pipeline_builder/job_collection.rb +31 -21
  23. data/lib/jenkins_pipeline_builder/module_registry.rb +5 -1
  24. data/lib/jenkins_pipeline_builder/project.rb +28 -0
  25. data/lib/jenkins_pipeline_builder/pull_request_generator.rb +8 -8
  26. data/lib/jenkins_pipeline_builder/version.rb +1 -1
  27. data/spec/lib/jenkins_pipeline_builder/extension_dsl_spec.rb +43 -0
  28. data/spec/lib/jenkins_pipeline_builder/extension_set_spec.rb +110 -0
  29. data/spec/lib/jenkins_pipeline_builder/extensions/builders_spec.rb +56 -0
  30. data/spec/lib/jenkins_pipeline_builder/extensions/job_attributes_spec.rb +85 -0
  31. data/spec/lib/jenkins_pipeline_builder/extensions/publishers_spec.rb +81 -9
  32. data/spec/lib/jenkins_pipeline_builder/extensions/registered_spec.rb +134 -0
  33. data/spec/lib/jenkins_pipeline_builder/extensions/triggers_spec.rb +88 -0
  34. data/spec/lib/jenkins_pipeline_builder/extensions_spec.rb +0 -97
  35. data/spec/lib/jenkins_pipeline_builder/fixtures/job_collection/extensions/extension.rb +11 -0
  36. data/spec/lib/jenkins_pipeline_builder/fixtures/job_collection/extensions/helpers/my_test_thing_helper.rb +5 -0
  37. data/spec/lib/jenkins_pipeline_builder/job_collection_spec.rb +46 -0
  38. data/spec/lib/jenkins_pipeline_builder/module_registry_spec.rb +1 -110
  39. data/spec/lib/jenkins_pipeline_builder/spec_helper.rb +12 -0
  40. metadata +24 -2
@@ -76,27 +76,13 @@ trigger do
76
76
  announced false
77
77
 
78
78
  xml do |params|
79
- case params[:status]
80
- when 'unstable'
81
- name = 'UNSTABLE'
82
- ordinal = '1'
83
- color = 'yellow'
84
- when 'failed'
85
- name = 'FAILURE'
86
- ordinal = '2'
87
- color = 'RED'
88
- else
89
- name = 'SUCCESS'
90
- ordinal = '0'
91
- color = 'BLUE'
92
- end
93
79
  send('jenkins.triggers.ReverseBuildTrigger') do
94
80
  spec
95
81
  upstreamProjects params[:projects]
96
82
  send('threshold') do
97
- name name
98
- ordinal ordinal
99
- color color
83
+ name params.name
84
+ ordinal params.ordinal
85
+ color params.color
100
86
  completeBuild true
101
87
  end
102
88
  end
@@ -92,11 +92,11 @@ wrapper do
92
92
 
93
93
  xml do |wrapper|
94
94
  EnvInjectPasswordWrapper do
95
- if wrapper.is_a? Array
96
- passwords = wrapper
97
- else
95
+ if wrapper.respond_to? :keys
98
96
  injectGlobalPasswords wrapper[:inject_global_passwords]
99
97
  passwords = wrapper[:passwords]
98
+ else
99
+ passwords = wrapper
100
100
  end
101
101
  break unless passwords
102
102
  passwordEntries do
@@ -69,13 +69,7 @@ module JenkinsPipelineBuilder
69
69
  errors = {}
70
70
  job_collection.projects.each do |project|
71
71
  next unless project[:name] == project_name || project_name.nil?
72
- logger.info "Using Project #{project}"
73
-
74
- pull_request_generator = JenkinsPipelineBuilder::PullRequestGenerator.new project, self
75
-
76
- unless pull_request_generator.valid?
77
- errors[pull_request_generator.pull_generator[:name]] = pull_request_generator.errors
78
- end
72
+ errors.merge! process_pull_request_project project
79
73
 
80
74
  end
81
75
  errors.each do |k, v|
@@ -132,12 +126,17 @@ module JenkinsPipelineBuilder
132
126
  [true, project]
133
127
  end
134
128
 
135
- #
136
- # BEGIN PRIVATE METHODS
137
- #
138
-
139
129
  private
140
130
 
131
+ def process_pull_request_project(project)
132
+ logger.info "Using Project #{project}"
133
+
134
+ pull_request_generator = JenkinsPipelineBuilder::PullRequestGenerator.new project, self
135
+
136
+ return {} if pull_request_generator.valid?
137
+ { pull_request_generator.pull_generator[:name] => pull_request_generator.errors }
138
+ end
139
+
141
140
  def prepare_jobs(jobs)
142
141
  jobs.map! do |job|
143
142
  job.is_a?(String) ? { job.to_sym => {} } : job
@@ -18,13 +18,7 @@ module JenkinsPipelineBuilder
18
18
  success, payload = to_xml
19
19
  return success, payload unless success
20
20
  xml = payload
21
- if JenkinsPipelineBuilder.debug || JenkinsPipelineBuilder.file_mode
22
- logger.info "Will create job #{job}"
23
- logger.info "#{xml}" if @debug
24
- FileUtils.mkdir_p(out_dir) unless File.exist?(out_dir)
25
- File.open("#{out_dir}/#{name}.xml", 'w') { |f| f.write xml }
26
- return [true, nil]
27
- end
21
+ return local_output(xml) if JenkinsPipelineBuilder.debug || JenkinsPipelineBuilder.file_mode
28
22
 
29
23
  if JenkinsPipelineBuilder.client.job.exists?(name)
30
24
  JenkinsPipelineBuilder.client.job.update(name, xml)
@@ -39,28 +33,38 @@ module JenkinsPipelineBuilder
39
33
 
40
34
  logger.info "Creating Yaml Job #{job}"
41
35
  job[:job_type] = 'free_style' unless job[:job_type]
42
- case job[:job_type]
43
- when 'job_dsl'
44
- @xml = setup_freestyle_base(job)
45
- payload = update_job_dsl
46
- when 'multi_project'
47
- # TODO: Add multi_job as another, more logically named option
48
- @xml = setup_freestyle_base(job)
49
- payload = adjust_multi_project
50
- when 'build_flow'
51
- @xml = setup_freestyle_base(job)
52
- payload = add_job_dsl
53
- when 'free_style', 'pull_request_generator'
54
- payload = setup_freestyle_base job
55
- else
56
- return false, "Job type: #{job[:job_type]} is not one of job_dsl, multi_project, build_flow or free_style"
57
- end
36
+ type = job[:job_type]
37
+ return false, "Job type: #{type} is not one of #{job_methods.join(', ')}" unless known_type? type
38
+ @xml = setup_freestyle_base(job)
39
+ payload = send("update_#{type}")
58
40
 
59
41
  [true, payload]
60
42
  end
61
43
 
62
44
  private
63
45
 
46
+ [:free_style, :pull_request_generator].each do |method_name|
47
+ define_method "update_#{method_name}" do
48
+ @xml
49
+ end
50
+ end
51
+
52
+ def known_type?(type)
53
+ job_methods.include? type
54
+ end
55
+
56
+ def job_methods
57
+ %w(job_dsl multi_project build_flow free_style pull_request_generator)
58
+ end
59
+
60
+ def local_output(xml)
61
+ logger.info "Will create job #{job}"
62
+ logger.info "#{xml}" if @debug
63
+ FileUtils.mkdir_p(out_dir) unless File.exist?(out_dir)
64
+ File.open("#{out_dir}/#{name}.xml", 'w') { |f| f.write xml }
65
+ [true, nil]
66
+ end
67
+
64
68
  def out_dir
65
69
  'out/xml'
66
70
  end
@@ -88,14 +92,14 @@ module JenkinsPipelineBuilder
88
92
  end
89
93
  end
90
94
 
91
- def adjust_multi_project
95
+ def update_multi_project
92
96
  n_xml = Nokogiri::XML(@xml)
93
97
  root = n_xml.root
94
98
  root.name = 'com.tikal.jenkins.plugins.multijob.MultiJobProject'
95
99
  n_xml.to_xml
96
100
  end
97
101
 
98
- def add_job_dsl
102
+ def update_build_flow
99
103
  n_xml = Nokogiri::XML(@xml)
100
104
  n_xml.root.name = 'com.cloudbees.plugins.flow.BuildFlow'
101
105
  Nokogiri::XML::Builder.with(n_xml.root) do |b_xml|
@@ -74,29 +74,39 @@ module JenkinsPipelineBuilder
74
74
  end
75
75
  logger.info "Loading file #{path}"
76
76
  hash.each do |section|
77
- Utils.symbolize_keys_deep!(section)
78
- key = section.keys.first
79
- value = section[key]
80
- if key == :dependencies
81
- logger.info 'Resolving Dependencies for remote project'
82
- remote_dependencies.load value
83
- next
84
- end
85
- name = value[:name]
86
- if collection.key?(name)
87
- existing_remote = collection[name.to_s][:remote]
88
- # skip if the existing item is local and the new item is remote
89
- if remote && !existing_remote
90
- next
77
+ load_section section, remote
78
+ end
79
+ end
80
+
81
+ def load_section(section, remote)
82
+ Utils.symbolize_keys_deep!(section)
83
+ key = section.keys.first
84
+ value = section[key]
85
+ if key == :dependencies
86
+ logger.info 'Resolving Dependencies for remote project'
87
+ remote_dependencies.load value
88
+ return
89
+ end
90
+ name = value[:name]
91
+ process_collection! name, key, value, remote
92
+ end
93
+
94
+ # TODO: This should be cleaned up a bit. I'm sure we can get rid of
95
+ # the elsif and we should be more clear on the order of loading of things
96
+ def process_collection!(name, key, value, remote)
97
+ if collection.key?(name)
98
+ existing_remote = collection[name.to_s][:remote]
99
+ # skip if the existing item is local and the new item is remote
100
+ if remote && !existing_remote
101
+ return
91
102
  # override if the existing item is remote and the new is local
92
- elsif existing_remote && !remote
93
- logger.info "Duplicate item with name '#{name}' was detected from the remote folder."
94
- else
95
- fail "Duplicate item with name '#{name}' was detected."
96
- end
103
+ elsif existing_remote && !remote
104
+ logger.info "Duplicate item with name '#{name}' was detected from the remote folder."
105
+ else
106
+ fail "Duplicate item with name '#{name}' was detected."
97
107
  end
98
- collection[name.to_s] = { name: name.to_s, type: key, value: value, remote: remote }
99
108
  end
109
+ collection[name.to_s] = { name: name.to_s, type: key, value: value, remote: remote }
100
110
  end
101
111
 
102
112
  def load_extensions(path)
@@ -105,7 +115,7 @@ module JenkinsPipelineBuilder
105
115
  return unless File.directory?(path)
106
116
  logger.info "Loading extensions from folder #{path}"
107
117
  logger.info Dir.glob("#{path}/*.rb").inspect
108
- Dir.glob("#{path}/*.rb").each do |file|
118
+ Dir.glob("#{path}/**/*.rb").each do |file|
109
119
  logger.info "Loaded #{file}"
110
120
  require file
111
121
  end
@@ -33,8 +33,12 @@ module JenkinsPipelineBuilder
33
33
  @versions ||= JenkinsPipelineBuilder.client.plugin.list_installed
34
34
  end
35
35
 
36
- def clear_versions
36
+ def clear_versions(sets = registry.values)
37
37
  @versions = nil
38
+ sets.each do |entry|
39
+ entry.clear_installed_version if entry.is_a? ExtensionSet
40
+ clear_versions entry.values if entry.respond_to? :values
41
+ end
38
42
  end
39
43
 
40
44
  def logger
@@ -0,0 +1,28 @@
1
+ module JenkinsPipelineBuilder
2
+ class Project
3
+ attr_reader :input
4
+ attr_accessor :errors
5
+ def initialize(name, input)
6
+ @name = name
7
+ @input = input
8
+ @errors = {}
9
+ end
10
+
11
+ def publish
12
+ success, payload = resolve_project(input)
13
+ if success
14
+ logger.info 'successfully resolved project'
15
+ compiled_project = payload
16
+ else
17
+ return { project_name: 'Failed to resolve' }
18
+ end
19
+
20
+ self.errors = publish_jobs(compiled_project[:value][:jobs]) if compiled_project[:value][:jobs]
21
+ return unless compiled_project[:value][:views]
22
+ compiled_project[:value][:views].each do |v|
23
+ compiled_view = v[:result]
24
+ view.create(compiled_view)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -29,17 +29,13 @@ module JenkinsPipelineBuilder
29
29
  def initialize(project, generator)
30
30
  @project = project
31
31
  @generator = generator
32
-
33
32
  @purge = []
34
33
  @create = []
35
-
36
34
  @errors = {}
35
+
37
36
  @pull_generator = find
38
- success, payload = compile_generator
39
- unless success
40
- @errors[@pull_generator[:name]] = payload
41
- return false
42
- end
37
+ payload = compile_generator
38
+ return unless payload
43
39
  @jobs = filter_jobs
44
40
 
45
41
  # old init
@@ -113,7 +109,11 @@ module JenkinsPipelineBuilder
113
109
  settings = defaults.nil? ? {} : defaults[:value] || {}
114
110
  compiler = Compiler.new generator
115
111
  settings = compiler.get_settings_bag(project, settings)
116
- generator.resolve_job_by_name(pull_generator[:name], settings)
112
+ success, payload = generator.resolve_job_by_name(pull_generator[:name], settings)
113
+ return payload if success
114
+
115
+ @errors[@pull_generator[:name]] = payload
116
+ false
117
117
  end
118
118
 
119
119
  def find
@@ -21,5 +21,5 @@
21
21
  #
22
22
 
23
23
  module JenkinsPipelineBuilder
24
- VERSION = '0.10.16'
24
+ VERSION = '0.11.0'
25
25
  end
@@ -0,0 +1,43 @@
1
+ require File.expand_path('../spec_helper', __FILE__)
2
+
3
+ describe 'extension dsl' do
4
+ before :all do
5
+ JenkinsPipelineBuilder.credentials = {
6
+ server_ip: '127.0.0.1',
7
+ server_port: 8080,
8
+ username: 'username',
9
+ password: 'password',
10
+ log_location: '/dev/null'
11
+ }
12
+ end
13
+
14
+ after :each do
15
+ JenkinsPipelineBuilder.registry.clear_versions
16
+ end
17
+
18
+ it 'overrides included extensions with local ones' do
19
+ builder do
20
+ name :shell_command
21
+ plugin_id 'builtin'
22
+ description 'Lets you run shell commands as a build step.'
23
+ jenkins_name 'Execute shell'
24
+ announced false
25
+
26
+ xml do |param|
27
+ newShell do
28
+ command param
29
+ end
30
+ end
31
+ end
32
+
33
+ allow(JenkinsPipelineBuilder.client).to receive(:plugin).and_return double(
34
+ list_installed: { 'parameterized-trigger' => '20.0' })
35
+
36
+ @n_xml = Nokogiri::XML::Builder.new { |xml| xml.builders }.doc
37
+ params = { builders: { shell_command: 'asdf' } }
38
+ JenkinsPipelineBuilder.registry.traverse_registry_path('job', params, @n_xml)
39
+
40
+ builder = @n_xml.root.children.first
41
+ expect(builder.name).to match 'newShell'
42
+ end
43
+ end
@@ -0,0 +1,110 @@
1
+ require File.expand_path('../spec_helper', __FILE__)
2
+
3
+ describe JenkinsPipelineBuilder::ExtensionSet do
4
+ subject(:set) { JenkinsPipelineBuilder::ExtensionSet.new('foo') {} }
5
+
6
+ before :each do
7
+ set.name 'example'
8
+ end
9
+
10
+ context 'xml' do
11
+ it 'returns the block for the correct version'
12
+ it 'sets the min_version if a parameter is provided' do
13
+ set.xml version: '0.2' do
14
+ true
15
+ end
16
+ expect(set.blocks).to have_key '0.2'
17
+ end
18
+ it 'uses the path if provided' do
19
+ set.xml path: 'foo' do
20
+ true
21
+ end
22
+ expect(set.blocks['0'][:path]).to eq 'foo'
23
+ end
24
+ end
25
+
26
+ context '#installed_version' do
27
+ it 'parses three digits' do
28
+ set.installed_version = '0.1.2'
29
+ expect(set.installed_version.version).to eq '0.1.2'
30
+ end
31
+
32
+ it 'parses only two digits' do
33
+ set.installed_version = '0.1'
34
+ expect(set.installed_version.version).to eq '0.1'
35
+ end
36
+ end
37
+
38
+ context '#extension' do
39
+ def new_ext(version = '0.0')
40
+ ext = JenkinsPipelineBuilder::Extension.new
41
+ ext.name 'foo'
42
+ ext.plugin_id 'foo'
43
+ ext.min_version version
44
+ ext.xml -> { true }
45
+ ext.type 'foo'
46
+ ext.path 'foo'
47
+ ext
48
+ end
49
+
50
+ def ext_versions(versions)
51
+ versions.each do |v|
52
+ ext = new_ext(v)
53
+ expect(ext).to be_valid
54
+ set.extensions << ext
55
+ end
56
+
57
+ expect(set).to be_valid
58
+ expect(set.extensions.size).to eq versions.size
59
+ end
60
+
61
+ it 'returns an extension' do
62
+ ext_versions ['0.0']
63
+ set.installed_version = '0.1'
64
+ expect(set.extension).to be_kind_of JenkinsPipelineBuilder::Extension
65
+ end
66
+
67
+ it 'returns the highest that is lower than the installed version' do
68
+ ext_versions ['0.0', '0.2']
69
+
70
+ set.installed_version = '0.1'
71
+
72
+ expect(set.extension.min_version).to eq '0.0'
73
+ end
74
+
75
+ it 'returns highest available if the installed version is higher' do
76
+ ext_versions ['0.0', '0.2']
77
+
78
+ set.installed_version = '0.3'
79
+
80
+ expect(set.extension.min_version).to eq '0.2'
81
+ end
82
+
83
+ it 'works for complicated version comparions' do
84
+ ext_versions ['10.5', '9.2', '100.4']
85
+
86
+ set.installed_version = '11.3'
87
+
88
+ expect(set.extension.min_version).to eq '10.5'
89
+ end
90
+
91
+ it 'raises an error if the registered versions are too high' do
92
+ ext_versions ['10.5', '9.2']
93
+
94
+ set.installed_version = '1.3'
95
+
96
+ expect { set.extension.min_version }.to raise_error
97
+ end
98
+
99
+ it 'works for snapshot/beta stuff' do
100
+ ext_versions ['1.9', '2.3']
101
+
102
+ set.installed_version = '2.0-SNAPSHOT (private-06/06/2014 09:51-bgaulin)'
103
+ # Other examples
104
+ # set.installed_version = '2.0-beta-1'
105
+ # set.installed_version = '2.0+build.93'
106
+ # set.installed_version = '2.0.8'
107
+ expect(set.extension.min_version).to eq '1.9'
108
+ end
109
+ end
110
+ end