jenkins_pipeline_builder 0.10.16 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
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