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.
- checksums.yaml +8 -8
- data/.rubocop.yml +4 -4
- data/lib/jenkins_pipeline_builder.rb +5 -0
- data/lib/jenkins_pipeline_builder/compiler.rb +27 -24
- data/lib/jenkins_pipeline_builder/extension_dsl.rb +1 -0
- data/lib/jenkins_pipeline_builder/extension_set.rb +8 -8
- data/lib/jenkins_pipeline_builder/extensions.rb +12 -24
- data/lib/jenkins_pipeline_builder/extensions/builders.rb +36 -27
- data/lib/jenkins_pipeline_builder/extensions/helpers/builders/blocking_downstream_helper.rb +18 -0
- data/lib/jenkins_pipeline_builder/extensions/helpers/builders/maven3_helper.rb +11 -0
- data/lib/jenkins_pipeline_builder/extensions/helpers/extension_helper.rb +26 -0
- data/lib/jenkins_pipeline_builder/extensions/helpers/job_attributes/parameters_helper.rb +18 -0
- data/lib/jenkins_pipeline_builder/extensions/helpers/publishers/cobertura_report_helper.rb +40 -0
- data/lib/jenkins_pipeline_builder/extensions/helpers/publishers/email_ext_helper.rb +148 -0
- data/lib/jenkins_pipeline_builder/extensions/helpers/triggers/upstream_helper.rb +21 -0
- data/lib/jenkins_pipeline_builder/extensions/job_attributes.rb +1 -15
- data/lib/jenkins_pipeline_builder/extensions/publishers.rb +263 -6
- data/lib/jenkins_pipeline_builder/extensions/triggers.rb +3 -17
- data/lib/jenkins_pipeline_builder/extensions/wrappers.rb +3 -3
- data/lib/jenkins_pipeline_builder/generator.rb +10 -11
- data/lib/jenkins_pipeline_builder/job.rb +29 -25
- data/lib/jenkins_pipeline_builder/job_collection.rb +31 -21
- data/lib/jenkins_pipeline_builder/module_registry.rb +5 -1
- data/lib/jenkins_pipeline_builder/project.rb +28 -0
- data/lib/jenkins_pipeline_builder/pull_request_generator.rb +8 -8
- data/lib/jenkins_pipeline_builder/version.rb +1 -1
- data/spec/lib/jenkins_pipeline_builder/extension_dsl_spec.rb +43 -0
- data/spec/lib/jenkins_pipeline_builder/extension_set_spec.rb +110 -0
- data/spec/lib/jenkins_pipeline_builder/extensions/builders_spec.rb +56 -0
- data/spec/lib/jenkins_pipeline_builder/extensions/job_attributes_spec.rb +85 -0
- data/spec/lib/jenkins_pipeline_builder/extensions/publishers_spec.rb +81 -9
- data/spec/lib/jenkins_pipeline_builder/extensions/registered_spec.rb +134 -0
- data/spec/lib/jenkins_pipeline_builder/extensions/triggers_spec.rb +88 -0
- data/spec/lib/jenkins_pipeline_builder/extensions_spec.rb +0 -97
- data/spec/lib/jenkins_pipeline_builder/fixtures/job_collection/extensions/extension.rb +11 -0
- data/spec/lib/jenkins_pipeline_builder/fixtures/job_collection/extensions/helpers/my_test_thing_helper.rb +5 -0
- data/spec/lib/jenkins_pipeline_builder/job_collection_spec.rb +46 -0
- data/spec/lib/jenkins_pipeline_builder/module_registry_spec.rb +1 -110
- data/spec/lib/jenkins_pipeline_builder/spec_helper.rb +12 -0
- 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.
|
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
|
-
|
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
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
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
|
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
|
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
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
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
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
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}
|
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
|
-
|
39
|
-
unless
|
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
|
@@ -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
|