jenkins_pipeline_builder 0.12.4 → 0.13.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/lib/jenkins_pipeline_builder.rb +0 -1
- data/lib/jenkins_pipeline_builder/generator.rb +28 -37
- data/lib/jenkins_pipeline_builder/pull_request_generator.rb +32 -127
- data/lib/jenkins_pipeline_builder/version.rb +1 -1
- data/spec/lib/jenkins_pipeline_builder/fixtures/generator_tests/pullrequest_pipeline/PullRequest-40-PullRequestGenerator.yaml +0 -6
- data/spec/lib/jenkins_pipeline_builder/fixtures/generator_tests/pullrequest_pipeline/project.yaml +5 -4
- data/spec/lib/jenkins_pipeline_builder/generator_spec.rb +20 -19
- data/spec/lib/jenkins_pipeline_builder/pull_request_generator_spec.rb +117 -84
- metadata +2 -5
- data/lib/jenkins_pipeline_builder/pull_request.rb +0 -92
- data/spec/lib/jenkins_pipeline_builder/pull_request_spec.rb +0 -161
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
ZGMzZGY0Yzk1MzZiMGYzNzc1ZGZlODIwNmQ3NDRjMWZkYWEzZWVkMw==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
OWNkMTcwZDE1NTgxYTU1MWU0MTlhZGNmOTZjNGEwYjE5NTIwNTIzMA==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
NmE2YTA2MGI3NmU1MjkxMzI0YjkzNjY1NmE2ZGYwOTMwMzY2NDU5Yzg5ZWM3
|
10
|
+
YjJmMjcyY2NhNjkwOWJhZTY0ZTgyODcxNjY0NWExZGU3MmY3ZmU0MDFhMTY3
|
11
|
+
NDUyMjA5MTBlOTg4YTc5YzA2NjM5NjFiNGZhY2ViODgxMzBlODQ=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
NmJiYjMyOGU5MDgyN2Y3MjI4MDEyZDVhNGZkOGEzZjE1YjNlMTE2YzRmNDZl
|
14
|
+
N2M5ZWIyYmFhNzZlZDg3ZjFmOTRkODRmOTFkYmVjYTNmYWEzY2ViMTYxNDVk
|
15
|
+
YzU2ZWJjYzM5N2VmMWY1NDAzYTUyY2ExMTg1ZTQ5OGNmMDI5Mzk=
|
@@ -28,7 +28,6 @@ require 'jenkins_pipeline_builder/utils'
|
|
28
28
|
require 'jenkins_pipeline_builder/compiler'
|
29
29
|
require 'jenkins_pipeline_builder/module_registry'
|
30
30
|
require 'jenkins_pipeline_builder/pull_request_generator'
|
31
|
-
require 'jenkins_pipeline_builder/pull_request'
|
32
31
|
require 'jenkins_pipeline_builder/view'
|
33
32
|
require 'jenkins_pipeline_builder/job_collection'
|
34
33
|
require 'jenkins_pipeline_builder/job'
|
@@ -1,6 +1,5 @@
|
|
1
1
|
#
|
2
2
|
# Copyright (c) 2014 Constant Contact
|
3
|
-
#
|
4
3
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
4
|
# of this software and associated documentation files (the "Software"), to deal
|
6
5
|
# in the Software without restriction, including without limitation the rights
|
@@ -48,29 +47,22 @@ module JenkinsPipelineBuilder
|
|
48
47
|
|
49
48
|
def bootstrap(path, project_name = nil)
|
50
49
|
logger.info "Bootstrapping pipeline from path #{path}"
|
51
|
-
|
52
|
-
job_collection.
|
53
|
-
|
54
|
-
if job_collection.projects.any?
|
55
|
-
errors = publish_project(project_name)
|
56
|
-
else
|
57
|
-
errors = publish_jobs(job_collection.standalone_jobs)
|
58
|
-
end
|
59
|
-
print_compile_errors errors
|
60
|
-
errors
|
50
|
+
load_job_collection path
|
51
|
+
publish(project_name || job_collection.projects.first[:name])
|
61
52
|
end
|
62
53
|
|
63
54
|
def pull_request(path, project_name)
|
64
55
|
logger.info "Pull Request Generator Running from path #{path}"
|
65
|
-
|
66
|
-
job_collection.
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
56
|
+
load_job_collection path
|
57
|
+
defaults = job_collection.defaults[:value]
|
58
|
+
pr_generator = PullRequestGenerator.new defaults
|
59
|
+
pr_generator.delete_closed_prs
|
60
|
+
errors = []
|
61
|
+
pr_generator.open_prs.each do |pr|
|
62
|
+
pr_generator.convert! job_collection, pr
|
63
|
+
error = publish(project_name)
|
64
|
+
errors << error unless error.empty?
|
72
65
|
end
|
73
|
-
print_compile_errors errors
|
74
66
|
errors.empty?
|
75
67
|
end
|
76
68
|
|
@@ -112,6 +104,21 @@ module JenkinsPipelineBuilder
|
|
112
104
|
|
113
105
|
private
|
114
106
|
|
107
|
+
def load_job_collection(path)
|
108
|
+
job_collection.load_from_path(path)
|
109
|
+
job_collection.remote_dependencies.cleanup
|
110
|
+
end
|
111
|
+
|
112
|
+
def publish(project_name)
|
113
|
+
if job_collection.projects.any?
|
114
|
+
errors = publish_project(project_name)
|
115
|
+
else
|
116
|
+
errors = publish_jobs(job_collection.standalone_jobs)
|
117
|
+
end
|
118
|
+
print_compile_errors errors
|
119
|
+
errors
|
120
|
+
end
|
121
|
+
|
115
122
|
def process_project(project)
|
116
123
|
project_body = project[:value]
|
117
124
|
jobs = prepare_jobs(project_body[:jobs]) if project_body[:jobs]
|
@@ -139,15 +146,6 @@ module JenkinsPipelineBuilder
|
|
139
146
|
end
|
140
147
|
end
|
141
148
|
|
142
|
-
def process_pull_request_project(project)
|
143
|
-
logger.info "Using Project #{project}"
|
144
|
-
|
145
|
-
pull_request_generator = JenkinsPipelineBuilder::PullRequestGenerator.new project, self
|
146
|
-
|
147
|
-
return {} if pull_request_generator.valid?
|
148
|
-
{ pull_request_generator.pull_generator[:name] => pull_request_generator.errors }
|
149
|
-
end
|
150
|
-
|
151
149
|
def prepare_jobs(jobs)
|
152
150
|
jobs.map! do |job|
|
153
151
|
job.is_a?(String) ? { job.to_sym => {} } : job
|
@@ -221,15 +219,8 @@ module JenkinsPipelineBuilder
|
|
221
219
|
end
|
222
220
|
|
223
221
|
def publish_project(project_name)
|
224
|
-
|
225
|
-
|
226
|
-
job_collection.projects.each do |project|
|
227
|
-
next if project[:name] != project_name && !project_name.nil?
|
228
|
-
found = true
|
229
|
-
errors = create_jobs_and_views(project)
|
230
|
-
end
|
231
|
-
fail "Project #{project_name} not found!" unless found
|
232
|
-
errors
|
222
|
+
project = job_collection.projects.find { |p| p[:name] == project_name }
|
223
|
+
create_jobs_and_views(project || fail("Project #{project_name} not found!"))
|
233
224
|
end
|
234
225
|
|
235
226
|
def publish_jobs(jobs, errors = {})
|
@@ -19,149 +19,54 @@
|
|
19
19
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
20
20
|
# THE SOFTWARE.
|
21
21
|
#
|
22
|
-
|
23
22
|
module JenkinsPipelineBuilder
|
24
23
|
class PullRequestGenerator
|
25
24
|
class NotFound < StandardError; end
|
25
|
+
attr_accessor :open_prs, :application_name
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
@project = project
|
31
|
-
@generator = generator
|
32
|
-
@purge = []
|
33
|
-
@create = []
|
34
|
-
@errors = {}
|
35
|
-
|
36
|
-
@pull_generator = find
|
37
|
-
payload = compile_generator
|
38
|
-
return unless payload
|
39
|
-
@jobs = filter_jobs
|
40
|
-
|
41
|
-
# old init
|
42
|
-
@pull_requests = check_for_pull payload
|
43
|
-
find_old_pull_requests
|
44
|
-
generate_pull_requests
|
45
|
-
|
46
|
-
collection.merge! @jobs
|
47
|
-
@errors.merge! create_jobs
|
48
|
-
|
49
|
-
purge_jobs
|
50
|
-
end
|
51
|
-
|
52
|
-
def valid?
|
53
|
-
errors.empty?
|
27
|
+
def initialize(defaults = {})
|
28
|
+
@application_name = defaults[:application_name]
|
29
|
+
@open_prs = active_prs defaults[:github_site], defaults[:git_org], defaults[:git_repo_name]
|
54
30
|
end
|
55
31
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
@pull_requests.each do |number|
|
60
|
-
req = JenkinsPipelineBuilder::PullRequest.new(project, number, jobs, @pull_generator)
|
61
|
-
@jobs.merge! req.jobs
|
62
|
-
project_new = req.project
|
63
|
-
|
64
|
-
# Overwrite the jobs from the generator to the project
|
65
|
-
project_new[:value][:jobs] = req.jobs.keys
|
66
|
-
@create << project_new
|
67
|
-
end
|
32
|
+
def convert!(job_collection, pr)
|
33
|
+
job_collection.defaults[:value][:application_name] = "#{application_name}-PR#{pr}"
|
34
|
+
job_collection.jobs.each { |j| override j[:value], pr }
|
68
35
|
end
|
69
36
|
|
70
|
-
def
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
end
|
37
|
+
def delete_closed_prs
|
38
|
+
return if JenkinsPipelineBuilder.debug
|
39
|
+
jobs_to_delete = JenkinsPipelineBuilder.client.job.list "#{application_name}-PR.*"
|
40
|
+
open_prs.each do |n|
|
41
|
+
jobs_to_delete.reject! { |j| j.start_with? "#{application_name}-PR#{n}" }
|
76
42
|
end
|
43
|
+
jobs_to_delete.each { |j| JenkinsPipelineBuilder.client.job.delete j }
|
77
44
|
end
|
78
45
|
|
79
|
-
|
80
|
-
errors = {}
|
81
|
-
create.each do |pull_project|
|
82
|
-
success, compiled_project = generator.resolve_project(pull_project)
|
83
|
-
compiled_project[:value][:jobs].each do |i|
|
84
|
-
job = i[:result]
|
85
|
-
job = Job.new job
|
86
|
-
success, payload = job.create_or_update
|
87
|
-
errors[job.name] = payload unless success
|
88
|
-
end
|
89
|
-
end
|
90
|
-
errors
|
91
|
-
end
|
92
|
-
|
93
|
-
def collection
|
94
|
-
generator.job_collection.collection
|
95
|
-
end
|
96
|
-
|
97
|
-
def filter_jobs
|
98
|
-
jobs = {}
|
99
|
-
pull_jobs = pull_generator[:value][:jobs] || []
|
100
|
-
pull_jobs.each do |job|
|
101
|
-
if job.is_a? String
|
102
|
-
jobs[job.to_s] = collection[job.to_s]
|
103
|
-
else
|
104
|
-
jobs[job.keys.first.to_s] = collection[job.keys.first.to_s]
|
105
|
-
end
|
106
|
-
end
|
107
|
-
fail 'No jobs found for pull request' if jobs.empty?
|
108
|
-
jobs
|
109
|
-
end
|
110
|
-
|
111
|
-
def compile_generator
|
112
|
-
defaults = generator.job_collection.defaults
|
113
|
-
settings = defaults.nil? ? {} : defaults[:value] || {}
|
114
|
-
compiler = Compiler.new generator
|
115
|
-
settings = compiler.get_settings_bag(project, settings)
|
116
|
-
success, payload = generator.resolve_job_by_name(pull_generator[:name], settings)
|
117
|
-
return payload if success
|
46
|
+
private
|
118
47
|
|
119
|
-
|
120
|
-
|
48
|
+
def override(job, pr)
|
49
|
+
git_version = JenkinsPipelineBuilder.registry.registry[:job][:scm_params].installed_version
|
50
|
+
job[:scm_branch] = "origin/pr/#{pr}/head"
|
51
|
+
job[:scm_params] ||= {}
|
52
|
+
job[:scm_params][:refspec] = "refs/pull/#{pr}/head:refs/remotes/origin/pr/#{pr}/head"
|
53
|
+
job[:scm_params][:changelog_to_branch] ||= {}
|
54
|
+
job[:scm_params][:changelog_to_branch]
|
55
|
+
.merge!(remote: 'origin', branch: "pr/#{pr}/head") if Gem::Version.new(2.0) < git_version
|
121
56
|
end
|
122
57
|
|
123
|
-
def
|
124
|
-
|
125
|
-
pull_job = nil
|
126
|
-
project_jobs.each do |job|
|
127
|
-
job = job.keys.first if job.is_a? Hash
|
128
|
-
job = collection[job.to_s]
|
129
|
-
|
130
|
-
pull_job = job if job[:value][:job_type] == 'pull_request_generator'
|
131
|
-
end
|
132
|
-
fail NotFound, 'No jobs of type pull_request_generator found' unless pull_job
|
133
|
-
pull_job
|
134
|
-
end
|
135
|
-
|
136
|
-
# Check for Github Pull Requests
|
137
|
-
#
|
138
|
-
# args[:git_url] URL to the github main page ex. https://www.github.com/
|
139
|
-
# args[:git_repo] Name of repo only, not url ex. jenkins_pipeline_builder
|
140
|
-
# args[:git_org] The Orig user ex. constantcontact
|
141
|
-
# @return = array of pull request numbers
|
142
|
-
def check_for_pull(args)
|
143
|
-
fail 'Please specify all arguments' unless args[:git_url] && args[:git_org] && args[:git_repo]
|
58
|
+
def active_prs(git_url, git_org, git_repo)
|
59
|
+
(git_url && git_org && git_repo) || fail('Please set github_site, git_org and git_repo_name in your project.')
|
144
60
|
# Build the Git URL
|
145
|
-
|
146
|
-
|
61
|
+
url = "#{git_url}/api/v3/repos/#{git_org}/#{git_repo}/pulls"
|
147
62
|
# Download the JSON Data from the API
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
# Read File
|
156
|
-
# FIXME: Shouldn't this be opening just with read permissions?
|
157
|
-
old_requests = File.new('pull_requests.csv', 'a+').read.split(',')
|
158
|
-
|
159
|
-
# Pop off current pull requests
|
160
|
-
old_requests.delete_if { |req| reqs.include?("#{req}") }
|
161
|
-
@purge = old_requests
|
162
|
-
|
163
|
-
# Write File
|
164
|
-
File.open('pull_requests.csv', 'w+') { |file| file.write reqs.join(',') }
|
63
|
+
begin
|
64
|
+
resp = Net::HTTP.get_response(URI.parse(url))
|
65
|
+
pulls = JSON.parse(resp.body)
|
66
|
+
pulls.map { |p| p['number'] }
|
67
|
+
rescue StandardError
|
68
|
+
raise 'Failed connecting to github!'
|
69
|
+
end
|
165
70
|
end
|
166
71
|
end
|
167
72
|
end
|
@@ -1,11 +1,5 @@
|
|
1
1
|
- job:
|
2
2
|
name: '{{name}}-40-PullRequestGenerator'
|
3
|
-
job_type: pull_request_generator
|
4
|
-
git_url: '{{git_url}}'
|
5
|
-
git_repo: '{{git_repo}}'
|
6
|
-
git_org: '{{git_org}}'
|
7
|
-
jobs:
|
8
|
-
- '{{name}}-10-SampleJob'
|
9
3
|
builders:
|
10
4
|
- shell_command: |
|
11
5
|
generate -v || gem install jenkins_pipeline_builder
|
data/spec/lib/jenkins_pipeline_builder/fixtures/generator_tests/pullrequest_pipeline/project.yaml
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
- defaults:
|
2
2
|
name: global
|
3
|
+
application_name: 'testapp'
|
3
4
|
description: 'Test pipeline for generator_spec.rb'
|
4
|
-
|
5
|
-
git_org: '
|
6
|
-
|
5
|
+
github_site: 'https://github.com'
|
6
|
+
git_org: 'testorg'
|
7
|
+
git_repo_name: 'generator_tests'
|
7
8
|
|
8
|
-
- project:
|
9
|
+
- project:
|
9
10
|
name: PullRequest
|
10
11
|
jobs:
|
11
12
|
- '{{name}}-10-SampleJob'
|
@@ -135,31 +135,32 @@ describe JenkinsPipelineBuilder::Generator do
|
|
135
135
|
let(:path) { File.expand_path('../fixtures/generator_tests/pullrequest_pipeline', __FILE__) }
|
136
136
|
it 'produces no errors while creating pipeline PullRequest' do
|
137
137
|
job_name = 'PullRequest'
|
138
|
-
|
139
|
-
|
138
|
+
pr_generator = double('pr_generator')
|
139
|
+
expect(JenkinsPipelineBuilder::PullRequestGenerator).to receive(:new)
|
140
|
+
.with(hash_including(application_name: 'testapp',
|
141
|
+
github_site: 'https://github.com',
|
142
|
+
git_org: 'testorg',
|
143
|
+
git_repo_name: 'generator_tests'))
|
144
|
+
.and_return(pr_generator)
|
145
|
+
expect(pr_generator).to receive(:delete_closed_prs)
|
146
|
+
expect(pr_generator).to receive(:convert!)
|
147
|
+
expect(pr_generator).to receive(:open_prs).and_return [1]
|
140
148
|
success = @generator.pull_request(path, job_name)
|
141
149
|
expect(success).to be_truthy
|
142
150
|
end
|
143
151
|
|
144
152
|
it 'correctly creates jobs when there are multiple pulls open' do
|
145
153
|
job_name = 'PullRequest'
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
).
|
155
|
-
expect(
|
156
|
-
name: 'PullRequest-PR2-10-SampleJob', scm_branch: 'origin/pr/2/head', scm_params: {
|
157
|
-
refspec: 'refs/pull/2/head:refs/remotes/origin/pr/2/head',
|
158
|
-
changelog_to_branch: { remote: 'origin', branch: 'pr/2/head' }
|
159
|
-
}
|
160
|
-
).and_return job2
|
161
|
-
expect(job1).to receive(:create_or_update).and_return true
|
162
|
-
expect(job2).to receive(:create_or_update).and_return true
|
154
|
+
pr_generator = double('pr_generator')
|
155
|
+
expect(JenkinsPipelineBuilder::PullRequestGenerator).to receive(:new)
|
156
|
+
.with(hash_including(application_name: 'testapp',
|
157
|
+
github_site: 'https://github.com',
|
158
|
+
git_org: 'testorg',
|
159
|
+
git_repo_name: 'generator_tests'))
|
160
|
+
.and_return(pr_generator)
|
161
|
+
expect(pr_generator).to receive(:delete_closed_prs)
|
162
|
+
expect(pr_generator).to receive(:convert!).twice
|
163
|
+
expect(pr_generator).to receive(:open_prs).and_return [1, 2]
|
163
164
|
expect(@generator.pull_request(path, job_name)).to be_truthy
|
164
165
|
end
|
165
166
|
# Things to check for
|
@@ -1,99 +1,132 @@
|
|
1
1
|
require File.expand_path('../spec_helper', __FILE__)
|
2
|
-
require '
|
2
|
+
require 'json'
|
3
3
|
|
4
4
|
describe JenkinsPipelineBuilder::PullRequestGenerator do
|
5
|
-
let(:
|
6
|
-
let(:
|
5
|
+
let(:application_name) { 'testapp' }
|
6
|
+
let(:github_site) { 'https://github.com' }
|
7
|
+
let(:git_org) { 'git_org' }
|
8
|
+
let(:git_repo_name) { 'git_repo' }
|
9
|
+
let(:prs) { (1..10).map { |n| "#{application_name}-PR#{n}" } }
|
10
|
+
let(:closed_prs) { (1..6).map { |n| "#{application_name}-PR#{n}" } }
|
11
|
+
let(:open_prs_json) { (7..10).map { |n| { number: n } }.to_json }
|
12
|
+
let(:url) { "#{github_site}/api/v3/repos/#{git_org}/#{git_repo_name}/pulls" }
|
13
|
+
let(:params) do
|
7
14
|
{
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
jobs: [
|
13
|
-
{
|
14
|
-
name: '{{name}}-00',
|
15
|
-
type: :job,
|
16
|
-
job_type: 'pull_request_generator',
|
17
|
-
git_url: 'https://www.github.com/',
|
18
|
-
git_repo: 'jenkins_pipeline_builder',
|
19
|
-
git_org: 'constantcontact',
|
20
|
-
jobs: [
|
21
|
-
'{{name}}-10',
|
22
|
-
'{{name}}-11'
|
23
|
-
],
|
24
|
-
builders: [{ shell_command: 'generate -v || gem install jenkins_pipeline_builder\ngenerate pipeline -c config/{{login_config}} pull_request pipeline/ {{name}}\n' }]
|
25
|
-
},
|
26
|
-
'{{name}}-10',
|
27
|
-
'{{name}}-11']
|
28
|
-
}
|
15
|
+
github_site: github_site,
|
16
|
+
git_org: git_org,
|
17
|
+
git_repo_name: git_repo_name,
|
18
|
+
application_name: application_name
|
29
19
|
}
|
30
20
|
end
|
31
|
-
let(:
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
type: :'job-template',
|
36
|
-
value: {
|
37
|
-
name: '{{name}}-10',
|
38
|
-
description: '{{description}}',
|
39
|
-
publishers: [{ downstream: { project: '{{job@{{name}}-11}}' } }]
|
40
|
-
}
|
41
|
-
},
|
42
|
-
'{{name}}-11' => {
|
43
|
-
name: '{{name}}-11',
|
44
|
-
type: :'job-template',
|
45
|
-
value: {
|
46
|
-
name: '{{name}}-11',
|
47
|
-
description: '{{description}}' }
|
48
|
-
}
|
49
|
-
}
|
21
|
+
let(:job_collection) do
|
22
|
+
double('job_collection',
|
23
|
+
defaults: { value: { application_name: application_name } },
|
24
|
+
jobs: [{ value: { scm_branch: 'master', scm_params: { random: 'foo' } } }])
|
50
25
|
end
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
'{{name}}-11'],
|
69
|
-
pull_request_number: '6'
|
70
|
-
}
|
71
|
-
}
|
72
|
-
]
|
26
|
+
subject { JenkinsPipelineBuilder::PullRequestGenerator.new params }
|
27
|
+
|
28
|
+
context '#initialize' do
|
29
|
+
it 'fails when one of the params is not set' do
|
30
|
+
expect do
|
31
|
+
JenkinsPipelineBuilder::PullRequestGenerator.new(application_name: 'name')
|
32
|
+
end.to raise_error('Please set github_site, git_org and git_repo_name in your project.')
|
33
|
+
end
|
34
|
+
it 'fails when github is not reponding properly' do
|
35
|
+
stub_request(:get, url)
|
36
|
+
.with(headers: { 'Accept' => '*/*',
|
37
|
+
'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
|
38
|
+
'Host' => 'github.com',
|
39
|
+
'User-Agent' => 'Ruby' })
|
40
|
+
.to_raise 'error'
|
41
|
+
expect { subject }.to raise_error('Failed connecting to github!')
|
42
|
+
end
|
73
43
|
end
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
44
|
+
|
45
|
+
context '#delete_closed_prs' do
|
46
|
+
it 'deletes closed prs' do
|
47
|
+
stub_request(:get, url)
|
48
|
+
.with(headers: { 'Accept' => '*/*',
|
49
|
+
'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
|
50
|
+
'Host' => 'github.com',
|
51
|
+
'User-Agent' => 'Ruby' })
|
52
|
+
.to_return(status: 200, body: open_prs_json, headers: {})
|
53
|
+
job = double('job')
|
54
|
+
expect(job).to receive(:list).with("#{application_name}-PR.*").and_return prs
|
55
|
+
client = double('client', job: job)
|
56
|
+
expect(JenkinsPipelineBuilder).to receive(:debug).and_return false
|
57
|
+
allow(JenkinsPipelineBuilder).to receive(:client).and_return client
|
58
|
+
closed_prs.each { |pr| expect(job).to receive(:delete).with(pr) }
|
59
|
+
subject.delete_closed_prs
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'does not fail when there are no closed prs' do
|
63
|
+
stub_request(:get, url)
|
64
|
+
.with(headers: { 'Accept' => '*/*',
|
65
|
+
'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
|
66
|
+
'Host' => 'github.com',
|
67
|
+
'User-Agent' => 'Ruby' })
|
68
|
+
.to_return(status: 200, body: open_prs_json, headers: {})
|
69
|
+
job = double('job')
|
70
|
+
expect(job).to receive(:list).with("#{application_name}-PR.*").and_return prs - closed_prs
|
71
|
+
client = double('client', job: job)
|
72
|
+
expect(JenkinsPipelineBuilder).to receive(:debug).and_return false
|
73
|
+
allow(JenkinsPipelineBuilder).to receive(:client).and_return client
|
74
|
+
expect(job).not_to receive(:delete)
|
75
|
+
subject.delete_closed_prs
|
76
|
+
end
|
79
77
|
end
|
80
|
-
|
81
|
-
|
82
|
-
|
78
|
+
|
79
|
+
context '#convert!' do
|
80
|
+
it 'converts the job application name' do
|
81
|
+
stub_request(:get, url)
|
82
|
+
.with(headers: { 'Accept' => '*/*',
|
83
|
+
'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
|
84
|
+
'Host' => 'github.com',
|
85
|
+
'User-Agent' => 'Ruby' })
|
86
|
+
.to_return(status: 200, body: open_prs_json, headers: {})
|
87
|
+
collection = job_collection.clone
|
88
|
+
subject.convert! collection, 8
|
89
|
+
expect(collection.defaults[:value][:application_name]).to eq "#{application_name}-PR8"
|
83
90
|
end
|
84
91
|
|
85
|
-
it '
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
92
|
+
it 'overrides the git params' do
|
93
|
+
stub_request(:get, url)
|
94
|
+
.with(headers: { 'Accept' => '*/*',
|
95
|
+
'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
|
96
|
+
'Host' => 'github.com',
|
97
|
+
'User-Agent' => 'Ruby' })
|
98
|
+
.to_return(status: 200, body: open_prs_json, headers: {})
|
99
|
+
pr = 8
|
100
|
+
collection = job_collection.clone
|
101
|
+
subject.convert! collection, pr
|
102
|
+
expect(collection.jobs.first[:value]).to eq(
|
103
|
+
scm_branch: "origin/pr/#{pr}/head",
|
104
|
+
scm_params: {
|
105
|
+
refspec: "refs/pull/#{pr}/head:refs/remotes/origin/pr/#{pr}/head",
|
106
|
+
changelog_to_branch: { remote: 'origin', branch: "pr/#{pr}/head" },
|
107
|
+
random: 'foo'
|
108
|
+
}
|
109
|
+
)
|
91
110
|
end
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
111
|
+
|
112
|
+
it 'does not override extra params' do
|
113
|
+
stub_request(:get, url)
|
114
|
+
.with(headers: { 'Accept' => '*/*',
|
115
|
+
'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
|
116
|
+
'Host' => 'github.com',
|
117
|
+
'User-Agent' => 'Ruby' })
|
118
|
+
.to_return(status: 200, body: open_prs_json, headers: {})
|
119
|
+
pr = 8
|
120
|
+
collection = job_collection.clone
|
121
|
+
subject.convert! collection, pr
|
122
|
+
expect(collection.jobs.first[:value]).to eq(
|
123
|
+
scm_branch: "origin/pr/#{pr}/head",
|
124
|
+
scm_params: {
|
125
|
+
refspec: "refs/pull/#{pr}/head:refs/remotes/origin/pr/#{pr}/head",
|
126
|
+
changelog_to_branch: { remote: 'origin', branch: "pr/#{pr}/head" },
|
127
|
+
random: 'foo'
|
128
|
+
}
|
129
|
+
)
|
97
130
|
end
|
98
131
|
end
|
99
132
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jenkins_pipeline_builder
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.13.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Igor Moochnick
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2015-
|
12
|
+
date: 2015-11-04 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: nokogiri
|
@@ -370,7 +370,6 @@ files:
|
|
370
370
|
- lib/jenkins_pipeline_builder/job_collection.rb
|
371
371
|
- lib/jenkins_pipeline_builder/module_registry.rb
|
372
372
|
- lib/jenkins_pipeline_builder/project.rb
|
373
|
-
- lib/jenkins_pipeline_builder/pull_request.rb
|
374
373
|
- lib/jenkins_pipeline_builder/pull_request_generator.rb
|
375
374
|
- lib/jenkins_pipeline_builder/remote_dependencies.rb
|
376
375
|
- lib/jenkins_pipeline_builder/utils.rb
|
@@ -427,7 +426,6 @@ files:
|
|
427
426
|
- spec/lib/jenkins_pipeline_builder/job_spec.rb
|
428
427
|
- spec/lib/jenkins_pipeline_builder/module_registry_spec.rb
|
429
428
|
- spec/lib/jenkins_pipeline_builder/pull_request_generator_spec.rb
|
430
|
-
- spec/lib/jenkins_pipeline_builder/pull_request_spec.rb
|
431
429
|
- spec/lib/jenkins_pipeline_builder/spec_helper.rb
|
432
430
|
- spec/lib/jenkins_pipeline_builder/utils_spec.rb
|
433
431
|
- spec/lib/jenkins_pipeline_builder/view_spec.rb
|
@@ -505,7 +503,6 @@ test_files:
|
|
505
503
|
- spec/lib/jenkins_pipeline_builder/job_spec.rb
|
506
504
|
- spec/lib/jenkins_pipeline_builder/module_registry_spec.rb
|
507
505
|
- spec/lib/jenkins_pipeline_builder/pull_request_generator_spec.rb
|
508
|
-
- spec/lib/jenkins_pipeline_builder/pull_request_spec.rb
|
509
506
|
- spec/lib/jenkins_pipeline_builder/spec_helper.rb
|
510
507
|
- spec/lib/jenkins_pipeline_builder/utils_spec.rb
|
511
508
|
- spec/lib/jenkins_pipeline_builder/view_spec.rb
|
@@ -1,92 +0,0 @@
|
|
1
|
-
#
|
2
|
-
# Copyright (c) 2014 Constant Contact
|
3
|
-
#
|
4
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
-
# of this software and associated documentation files (the "Software"), to deal
|
6
|
-
# in the Software without restriction, including without limitation the rights
|
7
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
-
# copies of the Software, and to permit persons to whom the Software is
|
9
|
-
# furnished to do so, subject to the following conditions:
|
10
|
-
#
|
11
|
-
# The above copyright notice and this permission notice shall be included in
|
12
|
-
# all copies or substantial portions of the Software.
|
13
|
-
#
|
14
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
17
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
19
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
20
|
-
# THE SOFTWARE.
|
21
|
-
#
|
22
|
-
module JenkinsPipelineBuilder
|
23
|
-
class PullRequest
|
24
|
-
attr_reader :project # The root project YAML as a hash
|
25
|
-
attr_reader :number # The pull request number
|
26
|
-
attr_reader :jobs # The jobs in the pull request as an array of hashes
|
27
|
-
attr_reader :pull_generator # The generator job YAML as a hash
|
28
|
-
|
29
|
-
def initialize(project, number, jobs, pull_generator)
|
30
|
-
@project = Marshal.load(Marshal.dump(project))
|
31
|
-
@number = number
|
32
|
-
@jobs = Marshal.load(Marshal.dump(jobs))
|
33
|
-
@pull_generator = Marshal.load(Marshal.dump(pull_generator))
|
34
|
-
@project[:value][:pull_request_number] = "#{@number}"
|
35
|
-
|
36
|
-
run!
|
37
|
-
end
|
38
|
-
|
39
|
-
private
|
40
|
-
|
41
|
-
def run!
|
42
|
-
git_version = JenkinsPipelineBuilder.registry.registry[:job][:scm_params].installed_version
|
43
|
-
if git_version >= Gem::Version.new(2.0)
|
44
|
-
@jobs.each_value do |j|
|
45
|
-
override_git_2_params j
|
46
|
-
end
|
47
|
-
end
|
48
|
-
update_jobs!
|
49
|
-
change_git!
|
50
|
-
change_name!
|
51
|
-
end
|
52
|
-
|
53
|
-
def override_git_2_params(job)
|
54
|
-
job[:value][:scm_params] ||= {}
|
55
|
-
job[:value][:scm_params][:changelog_to_branch] = { remote: 'origin', branch: 'pr/{{pull_request_number}}/head' }
|
56
|
-
end
|
57
|
-
|
58
|
-
# Change the git branch for each job
|
59
|
-
def change_git!
|
60
|
-
@jobs.each_value do |job|
|
61
|
-
job[:value][:scm_branch] = 'origin/pr/{{pull_request_number}}/head'
|
62
|
-
job[:value][:scm_params] = {} unless job[:value][:scm_params]
|
63
|
-
refspec = 'refs/pull/{{pull_request_number}}/head:refs/remotes/origin/pr/{{pull_request_number}}/head'
|
64
|
-
job[:value][:scm_params][:refspec] = refspec
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
# Change the name of the pull request project
|
69
|
-
def change_name!
|
70
|
-
@project[:name] = "#{@project[:name]}-PR#{@number}" if @project[:name]
|
71
|
-
@project[:value][:name] = "#{@project[:value][:name]}-PR#{@number}" if @project[:value][:name]
|
72
|
-
|
73
|
-
return unless pull_generator[:value][:inject_pr_into]
|
74
|
-
|
75
|
-
key = pull_generator[:value][:inject_pr_into].to_sym
|
76
|
-
project[:value][key] = "{{#{key}}}-PR#{@number}" if project[:value]
|
77
|
-
end
|
78
|
-
|
79
|
-
# Apply any specified changes to each job
|
80
|
-
def update_jobs!
|
81
|
-
@jobs.each_value do |job|
|
82
|
-
name = job[:name]
|
83
|
-
changes = nil
|
84
|
-
@pull_generator[:value][:jobs].each do |gen|
|
85
|
-
changes = gen[name.to_sym] if gen.is_a?(Hash) && gen.keys[0] == name.to_sym
|
86
|
-
end
|
87
|
-
# Apply changes
|
88
|
-
Utils.hash_merge!(job[:value], changes) unless changes.nil?
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|
@@ -1,161 +0,0 @@
|
|
1
|
-
require File.expand_path('../spec_helper', __FILE__)
|
2
|
-
require 'webmock/rspec'
|
3
|
-
|
4
|
-
describe JenkinsPipelineBuilder::PullRequest do
|
5
|
-
before :each do
|
6
|
-
JenkinsPipelineBuilder.registry.registry[:job][:scm_params].installed_version = '1000.0'
|
7
|
-
end
|
8
|
-
after :each do
|
9
|
-
JenkinsPipelineBuilder.registry.registry[:job][:scm_params].clear_installed_version
|
10
|
-
end
|
11
|
-
let(:project) do
|
12
|
-
{
|
13
|
-
name: 'pull_req_test',
|
14
|
-
type: :project,
|
15
|
-
value: {
|
16
|
-
name: 'pull_req_test',
|
17
|
-
jobs: ['{{name}}-00', '{{name}}-10', '{{name}}-11']
|
18
|
-
}
|
19
|
-
}
|
20
|
-
end
|
21
|
-
let(:value) { { jobs: ['{{name}}-10', '{{name}}-11'] } }
|
22
|
-
let(:pull_request) do
|
23
|
-
{
|
24
|
-
name: '{{name}}-00',
|
25
|
-
type: :job,
|
26
|
-
job_type: 'pull_request_generator',
|
27
|
-
git_url: 'https://www.github.com/',
|
28
|
-
git_repo: 'jenkins_pipeline_builder',
|
29
|
-
git_org: 'constantcontact',
|
30
|
-
value: value,
|
31
|
-
builders: [
|
32
|
-
{ shell_command: 'echo "shell command"' }
|
33
|
-
]
|
34
|
-
}
|
35
|
-
end
|
36
|
-
let(:job1) { '{{name}}-10' }
|
37
|
-
let(:job2) { '{{name}}-11' }
|
38
|
-
let(:jobs) do
|
39
|
-
{
|
40
|
-
job1 => {
|
41
|
-
name: job1,
|
42
|
-
type: :'job-template',
|
43
|
-
value: {
|
44
|
-
name: job1,
|
45
|
-
description: '{{description}}',
|
46
|
-
publishers: [{ downstream: { project: "{{job@#{job2}}}" } }]
|
47
|
-
}
|
48
|
-
},
|
49
|
-
job2 => {
|
50
|
-
name: job2,
|
51
|
-
type: :'job-template',
|
52
|
-
value: {
|
53
|
-
name: job2,
|
54
|
-
description: '{{description}}'
|
55
|
-
}
|
56
|
-
}
|
57
|
-
}
|
58
|
-
end
|
59
|
-
let(:post_scm_params) do
|
60
|
-
{
|
61
|
-
changelog_to_branch: {
|
62
|
-
remote: 'origin',
|
63
|
-
branch: 'pr/{{pull_request_number}}/head'
|
64
|
-
},
|
65
|
-
refspec: 'refs/pull/{{pull_request_number}}/head:refs/remotes/origin/pr/{{pull_request_number}}/head'
|
66
|
-
}
|
67
|
-
end
|
68
|
-
let(:post_jobs) do
|
69
|
-
{
|
70
|
-
'{{name}}-10' => {
|
71
|
-
name: '{{name}}-10',
|
72
|
-
type: :'job-template',
|
73
|
-
value: {
|
74
|
-
name: '{{name}}-10',
|
75
|
-
description: '{{description}}',
|
76
|
-
publishers: [{ downstream: { project: '{{job@{{name}}-11}}' } }],
|
77
|
-
scm_branch: 'origin/pr/{{pull_request_number}}/head',
|
78
|
-
scm_params: post_scm_params
|
79
|
-
}
|
80
|
-
},
|
81
|
-
'{{name}}-11' => {
|
82
|
-
name: '{{name}}-11',
|
83
|
-
type: :'job-template',
|
84
|
-
value: {
|
85
|
-
name: '{{name}}-11',
|
86
|
-
description: '{{description}}',
|
87
|
-
scm_branch: 'origin/pr/{{pull_request_number}}/head',
|
88
|
-
scm_params: post_scm_params
|
89
|
-
}
|
90
|
-
}
|
91
|
-
}
|
92
|
-
end
|
93
|
-
describe '#initialize' do
|
94
|
-
it 'process pull_request' do
|
95
|
-
pull = described_class.new(project, 2, jobs, pull_request)
|
96
|
-
post_project = {
|
97
|
-
name: 'pull_req_test-PR2',
|
98
|
-
type: :project,
|
99
|
-
value: {
|
100
|
-
name: 'pull_req_test-PR2',
|
101
|
-
jobs: ['{{name}}-00', '{{name}}-10', '{{name}}-11'],
|
102
|
-
pull_request_number: '2'
|
103
|
-
}
|
104
|
-
}
|
105
|
-
|
106
|
-
expect(pull.project).to eq(post_project)
|
107
|
-
expect(pull.jobs).to eq(post_jobs)
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
describe '#git_version_0' do
|
112
|
-
let(:post_scm_params) do
|
113
|
-
{ refspec: 'refs/pull/{{pull_request_number}}/head:refs/remotes/origin/pr/{{pull_request_number}}/head' }
|
114
|
-
end
|
115
|
-
|
116
|
-
before :each do
|
117
|
-
JenkinsPipelineBuilder.registry.registry[:job][:scm_params].installed_version = '0'
|
118
|
-
end
|
119
|
-
it 'process pull_request' do
|
120
|
-
pull = described_class.new(project, 2, jobs, pull_request)
|
121
|
-
expect(pull.jobs).to eq(post_jobs)
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
describe '#git_version_2' do
|
126
|
-
before :each do
|
127
|
-
JenkinsPipelineBuilder.registry.registry[:job][:scm_params].installed_version = '2.0'
|
128
|
-
end
|
129
|
-
it 'process pull_request' do
|
130
|
-
pull = described_class.new(project, 2, jobs, pull_request)
|
131
|
-
expect(pull.jobs).to eq(post_jobs)
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
context 'when the job does not have {{name}} in it' do
|
136
|
-
let(:project) do
|
137
|
-
{
|
138
|
-
name: 'pull_req_test',
|
139
|
-
type: :project,
|
140
|
-
app_name: 'my_app',
|
141
|
-
value: {
|
142
|
-
name: 'pull_req_test',
|
143
|
-
app_name: 'my_app',
|
144
|
-
jobs: ['{{app_name}}-00', '{{app_name}}-10', '{{app_name}}-11']
|
145
|
-
}
|
146
|
-
}
|
147
|
-
end
|
148
|
-
let(:value) do
|
149
|
-
{
|
150
|
-
inject_pr_into: :app_name,
|
151
|
-
jobs: ['{{app_name}}-10', '{{app_name}}-11']
|
152
|
-
}
|
153
|
-
end
|
154
|
-
let(:job1) { '{{app_name}}-10' }
|
155
|
-
let(:job2) { '{{app_name}}-11' }
|
156
|
-
it 'injects the pr number into the job name when told to' do
|
157
|
-
pull = described_class.new project, 2, jobs, pull_request
|
158
|
-
expect(pull.project[:value][:app_name]).to eq '{{app_name}}-PR2'
|
159
|
-
end
|
160
|
-
end
|
161
|
-
end
|