jenkins_pipeline_builder 0.4.2 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +65 -0
  3. data/LICENSE +1 -1
  4. data/README.md +64 -2
  5. data/Rakefile +13 -11
  6. data/bin/generate +2 -4
  7. data/jenkins_pipeline_builder.gemspec +14 -11
  8. data/lib/jenkins_pipeline_builder.rb +2 -1
  9. data/lib/jenkins_pipeline_builder/builders.rb +89 -33
  10. data/lib/jenkins_pipeline_builder/cli/base.rb +21 -29
  11. data/lib/jenkins_pipeline_builder/cli/helper.rb +12 -15
  12. data/lib/jenkins_pipeline_builder/cli/pipeline.rb +6 -1
  13. data/lib/jenkins_pipeline_builder/cli/view.rb +2 -2
  14. data/lib/jenkins_pipeline_builder/compiler.rb +58 -56
  15. data/lib/jenkins_pipeline_builder/generator.rb +362 -172
  16. data/lib/jenkins_pipeline_builder/job_builder.rb +48 -45
  17. data/lib/jenkins_pipeline_builder/module_registry.rb +4 -6
  18. data/lib/jenkins_pipeline_builder/publishers.rb +53 -38
  19. data/lib/jenkins_pipeline_builder/pull_request.rb +156 -0
  20. data/lib/jenkins_pipeline_builder/triggers.rb +24 -25
  21. data/lib/jenkins_pipeline_builder/utils.rb +13 -7
  22. data/lib/jenkins_pipeline_builder/version.rb +2 -2
  23. data/lib/jenkins_pipeline_builder/view.rb +120 -98
  24. data/lib/jenkins_pipeline_builder/wrappers.rb +44 -44
  25. data/lib/jenkins_pipeline_builder/xml_helper.rb +4 -4
  26. data/spec/func_tests/spec_helper.rb +2 -2
  27. data/spec/func_tests/view_spec.rb +6 -6
  28. data/spec/unit_tests/compiler_spec.rb +7 -7
  29. data/spec/unit_tests/fixtures/files/Job-Gem-Build.xml +2 -2
  30. data/spec/unit_tests/fixtures/files/Job-Gem-Build.yaml +1 -0
  31. data/spec/unit_tests/fixtures/files/concurrent_build.xml +17 -0
  32. data/spec/unit_tests/fixtures/files/concurrent_build.yaml +4 -0
  33. data/spec/unit_tests/fixtures/files/downstream_blocking.xml +19 -0
  34. data/spec/unit_tests/fixtures/files/downstream_blocking.yaml +15 -0
  35. data/spec/unit_tests/fixtures/files/groovy_postbuild.xml +29 -0
  36. data/spec/unit_tests/fixtures/files/groovy_postbuild.yaml +9 -0
  37. data/spec/unit_tests/generator_spec.rb +30 -25
  38. data/spec/unit_tests/module_registry_spec.rb +9 -9
  39. data/spec/unit_tests/resolve_dependencies_spec.rb +108 -89
  40. data/spec/unit_tests/spec_helper.rb +1 -1
  41. metadata +62 -4
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright (c) 2014 Igor Moochnick
2
+ # Copyright (c) 2014 Constant Contact
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining a copy
5
5
  # of this software and associated documentation files (the "Software"), to deal
@@ -23,7 +23,7 @@
23
23
  module JenkinsPipelineBuilder
24
24
  class JobBuilder
25
25
  def self.change_description(description, n_xml)
26
- desc = n_xml.xpath("//description").first
26
+ desc = n_xml.xpath('//description').first
27
27
  desc.content = "#{description}"
28
28
  end
29
29
 
@@ -34,118 +34,121 @@ module JenkinsPipelineBuilder
34
34
  XmlHelper.update_node_text(n_xml, '//scm/excludedUsers', params[:excluded_users]) if params[:excluded_users]
35
35
  XmlHelper.update_node_text(n_xml, '//scm/userRemoteConfigs/hudson.plugins.git.UserRemoteConfig/name', params[:remote_name]) if params[:remote_name]
36
36
  XmlHelper.update_node_text(n_xml, '//scm/skipTag', params[:skip_tag]) if params[:skip_tag]
37
+ XmlHelper.update_node_text(n_xml, '//scm/userRemoteConfigs/hudson.plugins.git.UserRemoteConfig/refspec', params[:refspec]) if params[:refspec]
37
38
  end
38
39
 
39
40
  def self.hipchat_notifier(params, n_xml)
40
- raise "No HipChat room specified" unless params[:room]
41
+ fail 'No HipChat room specified' unless params[:room]
41
42
 
42
- properties = n_xml.xpath("//properties").first
43
+ properties = n_xml.xpath('//properties').first
43
44
  Nokogiri::XML::Builder.with(properties) do |xml|
44
- xml.send('jenkins.plugins.hipchat.HipChatNotifier_-HipChatJobProperty') {
45
+ xml.send('jenkins.plugins.hipchat.HipChatNotifier_-HipChatJobProperty') do
45
46
  xml.room params[:room]
46
47
  xml.startNotification params[:'start-notify'] || false
47
- }
48
+ end
48
49
  end
49
50
  end
50
51
 
51
52
  def self.use_specific_priority(params, n_xml)
52
53
  n_builders = n_xml.xpath('//properties').first
53
54
  Nokogiri::XML::Builder.with(n_builders) do |xml|
54
- xml.send('jenkins.advancedqueue.AdvancedQueueSorterJobProperty', 'plugin' => 'PrioritySorter') {
55
+ xml.send('jenkins.advancedqueue.AdvancedQueueSorterJobProperty', 'plugin' => 'PrioritySorter') do
55
56
  xml.useJobPriority params[:use_priority]
56
57
  xml.priority params[:job_priority] || -1
57
- }
58
+ end
58
59
  end
59
60
  end
60
61
 
61
62
  def self.build_parameters(params, n_xml)
62
63
  n_builders = n_xml.xpath('//properties').first
63
64
  Nokogiri::XML::Builder.with(n_builders) do |xml|
64
- xml.send('hudson.model.ParametersDefinitionProperty') {
65
- xml.parameterDefinitions {
65
+ xml.send('hudson.model.ParametersDefinitionProperty') do
66
+ xml.parameterDefinitions do
66
67
  param_proc = lambda do |xml, params, type|
67
- xml.send(type) {
68
+ xml.send(type) do
68
69
  xml.name params[:name]
69
70
  xml.description params[:description]
70
71
  xml.defaultValue params[:default]
71
72
  if params[:type] == 'choice'
72
- puts 'choice'
73
- puts params
74
- xml.choices('class' => 'java.util.Arrays$ArrayList') {
75
- xml.a('class' => 'string-array') {
73
+ xml.choices('class' => 'java.util.Arrays$ArrayList') do
74
+ xml.a('class' => 'string-array') do
76
75
  params[:values].each do |value|
77
76
  xml.string value
78
77
  end
79
- }
80
- }
78
+ end
79
+ end
81
80
  end
82
- }
81
+ end
83
82
  end
84
83
  params.each do |param|
85
84
  case param[:type]
86
- when 'string'
87
- paramType = 'hudson.model.StringParameterDefinition'
88
- when 'bool'
89
- paramType = 'hudson.model.BooleanParameterDefinition'
90
- when 'text'
91
- paramType = 'hudson.model.TextParameterDefinition'
92
- when 'password'
93
- paramType = 'hudson.model.PasswordParameterDefinition'
94
- when 'choice'
95
- paramType = 'hudson.model.ChoiceParameterDefinition'
96
- else
97
- paramType = 'hudson.model.StringParameterDefinition'
98
- end
85
+ when 'string'
86
+ paramType = 'hudson.model.StringParameterDefinition'
87
+ when 'bool'
88
+ paramType = 'hudson.model.BooleanParameterDefinition'
89
+ when 'text'
90
+ paramType = 'hudson.model.TextParameterDefinition'
91
+ when 'password'
92
+ paramType = 'hudson.model.PasswordParameterDefinition'
93
+ when 'choice'
94
+ paramType = 'hudson.model.ChoiceParameterDefinition'
95
+ else
96
+ paramType = 'hudson.model.StringParameterDefinition'
97
+ end
99
98
 
100
99
  param_proc.call xml, param, paramType
101
100
  end
102
- }
103
- }
101
+ end
102
+ end
104
103
  end
105
104
  end
106
105
 
107
106
  def self.discard_old_param(params, n_xml)
108
107
  properties = n_xml.child
109
108
  Nokogiri::XML::Builder.with(properties) do |xml|
110
- xml.send('logRotator', 'class' => 'hudson.tasks.LogRotator') {
109
+ xml.send('logRotator', 'class' => 'hudson.tasks.LogRotator') do
111
110
  xml.daysToKeep params[:days] if params[:days]
112
111
  xml.numToKeep params[:number] || -1
113
112
  xml.artifactDaysToKeep params[:artifact_days] || -1
114
113
  xml.artifactNumToKeep params[:artifact_number] || -1
115
- }
114
+ end
116
115
  end
117
116
  end
118
117
 
119
118
  def self.throttle_job(params, n_xml)
120
119
  properties = n_xml.xpath('//properties').first
121
- cat_set = params[:option]=="category"
120
+ cat_set = params[:option] == 'category'
122
121
  Nokogiri::XML::Builder.with(properties) do |xml|
123
- xml.send('hudson.plugins.throttleconcurrents.ThrottleJobProperty', 'plugin' => 'throttle-concurrents') {
122
+ xml.send('hudson.plugins.throttleconcurrents.ThrottleJobProperty', 'plugin' => 'throttle-concurrents') do
124
123
  xml.maxConcurrentPerNode params[:max_per_node] || 0
125
124
  xml.maxConcurrentTotal params[:max_total] || 0
126
125
  xml.throttleEnabled true
127
- xml.throttleOption params[:option] || "alone"
128
- xml.categories {
126
+ xml.throttleOption params[:option] || 'alone'
127
+ xml.categories do
129
128
  xml.string params[:category] if cat_set
130
- }
131
- }
129
+ end
130
+ end
132
131
  end
133
132
  end
134
133
 
135
134
  def self.prepare_environment(params, n_xml)
136
135
  properties = n_xml.xpath('//properties').first
137
136
  Nokogiri::XML::Builder.with(properties) do |xml|
138
- xml.send('EnvInjectJobProperty') {
139
- xml.info{
137
+ xml.send('EnvInjectJobProperty') do
138
+ xml.info do
140
139
  xml.propertiesContent params[:properties_content] if params[:properties_content]
141
140
  xml.loadFilesFromMaster params[:load_from_master] if params[:load_from_master]
142
- }
141
+ end
143
142
  xml.on true
144
143
  xml.keepJenkinsSystemVariables params[:keep_environment] if params[:keep_environment]
145
144
  xml.keepBuildVariables params[:keep_build] if params[:keep_build]
146
- }
145
+ end
147
146
  end
148
147
  end
149
148
 
149
+ def self.concurrent_build(params, n_xml)
150
+ concurrentBuild = n_xml.xpath('//concurrentBuild').first
151
+ concurrentBuild.content = (params == true) ? 'true' : 'false'
152
+ end
150
153
  end
151
154
  end
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright (c) 2014 Igor Moochnick
2
+ # Copyright (c) 2014 Constant Contact
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining a copy
5
5
  # of this software and associated documentation files (the "Software"), to deal
@@ -30,14 +30,12 @@ module JenkinsPipelineBuilder
30
30
 
31
31
  def get(path)
32
32
  parts = path.split('/')
33
- self.get_by_path_collection(parts, @registry)
33
+ get_by_path_collection(parts, @registry)
34
34
  end
35
35
 
36
36
  def get_by_path_collection(path, registry)
37
37
  item = registry[path.shift.to_sym]
38
- if path.count == 0
39
- return item
40
- end
38
+ return item if path.count == 0
41
39
 
42
40
  get_by_path_collection(path, item)
43
41
  end
@@ -67,7 +65,7 @@ module JenkinsPipelineBuilder
67
65
  sub_registry = registry_item[:registry]
68
66
  method = registry_item[:method]
69
67
  method.call(sub_registry, value, n_xml)
70
- elsif registry_item.kind_of?(Method)
68
+ elsif registry_item.kind_of?(Method) || registry_item.kind_of?(Proc)
71
69
  registry_item.call(value, n_xml) unless registry_item.nil?
72
70
  end
73
71
  end
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright (c) 2014 Igor Moochnick
2
+ # Copyright (c) 2014 Constant Contact
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining a copy
5
5
  # of this software and associated documentation files (the "Software"), to deal
@@ -23,106 +23,121 @@
23
23
  module JenkinsPipelineBuilder
24
24
  class Publishers
25
25
  def self.description_setter(params, xml)
26
- xml.send('hudson.plugins.descriptionsetter.DescriptionSetterPublisher') {
26
+ xml.send('hudson.plugins.descriptionsetter.DescriptionSetterPublisher') do
27
27
  xml.regexp params[:regexp]
28
28
  xml.regexpForFailed params[:regexp]
29
29
  xml.description params[:description]
30
30
  xml.descriptionForFailed params[:description]
31
31
  xml.setForMatrix false
32
- }
32
+ end
33
33
  end
34
34
 
35
35
  def self.push_to_projects(params, xml)
36
- xml.send('hudson.plugins.parameterizedtrigger.BuildTrigger') {
37
- xml.configs {
38
- xml.send('hudson.plugins.parameterizedtrigger.BuildTriggerConfig') {
39
- xml.configs {
40
- params[:data] = [ { params: "" } ] unless params[:data]
36
+ xml.send('hudson.plugins.parameterizedtrigger.BuildTrigger') do
37
+ xml.configs do
38
+ xml.send('hudson.plugins.parameterizedtrigger.BuildTriggerConfig') do
39
+ xml.configs do
40
+ params[:data] = [{ params: '' }] unless params[:data]
41
41
  params[:data].each do |config|
42
42
  if config[:params]
43
- xml.send('hudson.plugins.parameterizedtrigger.PredefinedBuildParameters') {
43
+ xml.send('hudson.plugins.parameterizedtrigger.PredefinedBuildParameters') do
44
44
  xml.properties config[:params]
45
- }
45
+ end
46
46
  end
47
47
  if config[:file]
48
- xml.send('hudson.plugins.parameterizedtrigger.FileBuildParameters') {
48
+ xml.send('hudson.plugins.parameterizedtrigger.FileBuildParameters') do
49
49
  xml.propertiesFile config[:file]
50
50
  xml.failTriggerOnMissing false
51
- }
51
+ end
52
52
  end
53
53
  end
54
- }
54
+ end
55
55
  xml.projects params[:project]
56
56
  xml.condition params[:condition] || 'SUCCESS'
57
57
  xml.triggerWithNoParameters params[:trigger_with_no_parameters] || false
58
- }
59
- }
60
- }
58
+ end
59
+ end
60
+ end
61
61
  end
62
62
 
63
63
  def self.push_to_hipchat(params, xml)
64
64
  params = {} if params == true
65
- xml.send('jenkins.plugins.hipchat.HipChatNotifier') {
65
+ xml.send('jenkins.plugins.hipchat.HipChatNotifier') do
66
66
  xml.jenkinsUrl params[:jenkinsUrl] || ''
67
67
  xml.authToken params[:authToken] || ''
68
68
  xml.room params[:room] || ''
69
- }
69
+ end
70
70
  end
71
71
 
72
72
  def self.push_to_git(params, xml)
73
- xml.send('hudson.plugins.git.GitPublisher') {
73
+ xml.send('hudson.plugins.git.GitPublisher') do
74
74
  xml.configVersion params[:configVersion] || 2
75
75
  xml.pushMerge params[:'push-merge'] || false
76
76
  xml.pushOnlyIfSuccess params[:'push-only-if-success'] || false
77
- xml.branchesToPush {
78
- xml.send('hudson.plugins.git.GitPublisher_-BranchToPush') {
77
+ xml.branchesToPush do
78
+ xml.send('hudson.plugins.git.GitPublisher_-BranchToPush') do
79
79
  xml.targetRepoName params[:targetRepoName] || 'origin'
80
80
  xml.branchName params[:branchName] || 'master'
81
- }
82
- }
83
- }
81
+ end
82
+ end
83
+ end
84
84
  end
85
85
 
86
86
  def self.publish_junit(params, xml)
87
- xml.send('hudson.tasks.junit.JUnitResultArchiver') {
87
+ xml.send('hudson.tasks.junit.JUnitResultArchiver') do
88
88
  xml.testResults params[:test_results] || ''
89
89
  xml.keepLongStdio false
90
90
  xml.testDataPublishers
91
- }
91
+ end
92
92
  end
93
93
 
94
94
  def self.coverage_metric(name, params, xml)
95
- xml.send('hudson.plugins.rubyMetrics.rcov.model.MetricTarget') {
95
+ xml.send('hudson.plugins.rubyMetrics.rcov.model.MetricTarget') do
96
96
  xml.metric name
97
97
  xml.healthy params[:healthy]
98
98
  xml.unhealthy params[:unhealthy]
99
99
  xml.unstable params[:unstable]
100
- }
100
+ end
101
101
  end
102
102
 
103
103
  def self.publish_rcov(params, xml)
104
- xml.send('hudson.plugins.rubyMetrics.rcov.RcovPublisher') {
104
+ xml.send('hudson.plugins.rubyMetrics.rcov.RcovPublisher') do
105
105
  xml.reportDir params[:report_dir]
106
- xml.targets {
106
+ xml.targets do
107
107
  coverage_metric('TOTAL_COVERAGE', params[:total], xml)
108
108
  coverage_metric('CODE_COVERAGE', params[:code], xml)
109
- }
110
- }
109
+ end
110
+ end
111
111
  end
112
112
 
113
113
  def self.post_build_script(params, xml)
114
- xml.send('org.jenkinsci.plugins.postbuildscript.PostBuildScript') {
115
- xml.buildSteps {
114
+ xml.send('org.jenkinsci.plugins.postbuildscript.PostBuildScript') do
115
+ xml.buildSteps do
116
116
  if params[:shell_command]
117
- xml.send('hudson.tasks.Shell') {
117
+ xml.send('hudson.tasks.Shell') do
118
118
  xml.command params[:shell_command]
119
- }
119
+ end
120
120
  end
121
- }
121
+ end
122
122
  xml.scriptOnlyIfSuccess params[:on_success]
123
123
  xml.scriptOnlyIfFailure params[:on_failure]
124
124
  xml.executeOn params[:execute_on] || 'BOTH'
125
- }
125
+ end
126
+ end
127
+
128
+ def self.groovy_postbuild(params, xml)
129
+ xml.send('org.jvnet.hudson.plugins.groovypostbuild.GroovyPostbuildRecorder', 'plugin' => 'groovy-postbuild') do
130
+ xml.groovyScript params[:groovy_script]
131
+ xml.behavior params[:behavior] || '0'
132
+ xml.runFormMatrixParent 'false'
133
+ if params[:additional_classpaths]
134
+ params[:additional_classpaths].each do |path|
135
+ xml.send('org.jvnet.hudson.plugins.groovypostbuild.GroovyScriptPath') do
136
+ xml.path path[:path] || '/'
137
+ end
138
+ end
139
+ end
140
+ end
126
141
  end
127
142
  end
128
143
  end
@@ -0,0 +1,156 @@
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
+
23
+ module JenkinsPipelineBuilder
24
+ class PullRequestGenerator
25
+ # Initializes a new View object.
26
+ #
27
+ # @param generator [Generator] the client object
28
+ #
29
+ # @return [View] the view object
30
+ #
31
+ def initialize(generator)
32
+ @generator = generator
33
+ @client = generator.client
34
+ @logger = @client.logger
35
+ end
36
+
37
+ # Check for Github Pull Requests
38
+ #
39
+ # args[:git_url] URL to the github main page ex. https://www.github.com/
40
+ # args[:git_repo] Name of repo only, not url ex. jenkins_pipeline_builder
41
+ # args[:git_org] The Orig user ex. igorshare
42
+ # @return = array of pull request numbers
43
+ def check_for_pull(args)
44
+ fail 'Please specify all arguments' unless args[:git_url] && args[:git_org] && args[:git_repo]
45
+ # Build the Git URL
46
+ git_url = "#{args[:git_url]}api/v3/repos/#{args[:git_org]}/#{args[:git_repo]}/pulls"
47
+
48
+ # Download the JSON Data from the API
49
+ resp = Net::HTTP.get_response(URI.parse(git_url))
50
+ pulls = JSON.parse(resp.body)
51
+ pulls.map { |p| p['number'] }
52
+ end
53
+
54
+ # Purge old builds
55
+ def purge_old(pull_requests, project)
56
+ reqs = pull_requests.clone.map { |req| "#{project[:name]}-PR#{req}" }
57
+ @logger.info "Current pull requests: #{reqs}"
58
+ # Read File
59
+ old_requests = File.new('pull_requests.csv', 'a+').read.split(',')
60
+
61
+ # Pop off current pull requests
62
+ old_requests.delete_if { |req| reqs.include?("#{req}") }
63
+
64
+ # Delete the old requests from jenkins
65
+ @logger.info "Purging old requests: #{old_requests}"
66
+ old_requests.each do |req|
67
+ jobs = @client.job.list "#{req}.*"
68
+ jobs.each do |job|
69
+ @client.job.delete job
70
+ end
71
+ end
72
+ # Write File
73
+ File.open('pull_requests.csv', 'w+') { |file| file.write reqs.join(',') }
74
+ end
75
+
76
+ def run(project, job_collection, generator_job)
77
+ @logger.info 'Begin running Pull Request Generator'
78
+ pull_requests = check_for_pull generator_job[:value]
79
+ purge_old(pull_requests, project)
80
+ main_collection = job_collection
81
+ @logger.info pull_requests
82
+ pull_requests.each do |number|
83
+ # Manipulate the YAML
84
+ req = JenkinsPipelineBuilder::PullRequest.new(project, number, main_collection, generator_job)
85
+ @generator.job_collection.merge req.jobs
86
+ project = req.project
87
+
88
+ # Overwrite the jobs from the generator to the project
89
+ project[:value][:jobs] = generator_job[:value][:jobs]
90
+
91
+ # Build the jobs
92
+ success, compiled_project = @generator.resolve_project(project)
93
+ compiled_project[:value][:jobs].each do |i|
94
+ job = i[:result]
95
+ success, payload = @generator.compile_job_to_xml(job)
96
+ @generator.create_or_update(job, payload) if success
97
+ end
98
+ end
99
+ end
100
+ end
101
+
102
+ class PullRequest
103
+ attr_reader :project # The root project YAML as a hash
104
+ attr_reader :number # The pull request number
105
+ attr_reader :jobs # The jobs in the pull request as an array of hashes
106
+ attr_reader :generator # The generator job YAML as a hash
107
+
108
+ # Initialize
109
+ def initialize(project, number, jobs, generator)
110
+ @project = project.clone
111
+ @number = number
112
+ @jobs = jobs.clone
113
+ @generator = generator.clone
114
+
115
+ run!
116
+ end
117
+
118
+ private
119
+
120
+ # Apply all changes
121
+ def run!
122
+ update_jobs!
123
+ change_git!
124
+ change_name!
125
+ end
126
+
127
+ # Change the git branch for each job
128
+ def change_git!
129
+ @jobs.each_value do |job|
130
+ job[:value][:scm_branch] = "origin/pr/#{@number}/head"
131
+ job[:value][:scm_params] = {} unless job[:value][:scm_params]
132
+ job[:value][:scm_params][:refspec] = 'refs/pull/*:refs/remotes/origin/pr/*'
133
+ end
134
+ end
135
+
136
+ # Change the name of the pull request project
137
+ def change_name!
138
+ @project[:name] = "#{@project[:name]}-PR#{@number}" if @project[:name]
139
+ @project[:value][:name] = "#{@project[:value][:name]}-PR#{@number}" if @project[:value][:name]
140
+ end
141
+
142
+ # Apply any specified changes to each job
143
+ def update_jobs!
144
+ @jobs.each_value do |job|
145
+ name = job[:name]
146
+ changes = nil
147
+ # Search the generator for changes
148
+ @generator[:value][:jobs].each do |gen|
149
+ changes = gen[name.to_sym] if gen.is_a?(Hash) && gen.keys[0] == name.to_sym
150
+ end
151
+ # Apply changes
152
+ Utils.hash_merge!(job[:value], changes) unless changes.nil?
153
+ end
154
+ end
155
+ end
156
+ end