toys-release 0.1.1 → 0.2.2
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +18 -0
- data/README.md +3 -3
- data/lib/toys/release/version.rb +1 -1
- data/toys/.lib/toys/release/artifact_dir.rb +21 -1
- data/toys/.lib/toys/release/change_set.rb +1 -1
- data/toys/.lib/toys/release/component.rb +19 -19
- data/toys/.lib/toys/release/environment_utils.rb +16 -6
- data/toys/.lib/toys/release/performer.rb +46 -36
- data/toys/.lib/toys/release/pipeline.rb +548 -0
- data/toys/.lib/toys/release/pull_request.rb +0 -2
- data/toys/.lib/toys/release/repo_settings.rb +250 -114
- data/toys/.lib/toys/release/repository.rb +4 -5
- data/toys/.lib/toys/release/request_spec.rb +1 -1
- data/toys/.lib/toys/release/steps.rb +265 -428
- data/toys/_onclosed.rb +1 -1
- data/toys/perform.rb +7 -5
- data/toys/retry.rb +20 -14
- metadata +4 -5
- data/toys/.data/templates/release-hook-on-open.yml.erb +0 -30
- data/toys/_onopen.rb +0 -158
|
@@ -0,0 +1,548 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "fileutils"
|
|
4
|
+
|
|
5
|
+
module Toys
|
|
6
|
+
module Release
|
|
7
|
+
##
|
|
8
|
+
# The pipeline context
|
|
9
|
+
#
|
|
10
|
+
class Pipeline
|
|
11
|
+
##
|
|
12
|
+
# Internal exception signaling that the step should end immediately but
|
|
13
|
+
# the pipeline should continue.
|
|
14
|
+
# @private
|
|
15
|
+
#
|
|
16
|
+
class StepExit < ::StandardError
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
##
|
|
20
|
+
# Internal exception signaling that the step should end immediately and
|
|
21
|
+
# the pipeline should be aborted.
|
|
22
|
+
# @private
|
|
23
|
+
#
|
|
24
|
+
class PipelineExit < ::StandardError
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
##
|
|
28
|
+
# Context provided to a step implementation
|
|
29
|
+
#
|
|
30
|
+
class StepContext
|
|
31
|
+
# @private
|
|
32
|
+
def initialize(pipeline, step_settings)
|
|
33
|
+
@pipeline = pipeline
|
|
34
|
+
@step_settings = step_settings
|
|
35
|
+
type_name = step_settings.type
|
|
36
|
+
type_name = type_name.upcase unless type_name =~ /^[A-Z]/
|
|
37
|
+
@step_impl = begin
|
|
38
|
+
::Toys::Release::Steps.const_get(type_name)
|
|
39
|
+
rescue ::NameError
|
|
40
|
+
pipeline.repository.utils.error("Unknown step type: #{type_name}")
|
|
41
|
+
end
|
|
42
|
+
@step_impl = @step_impl.new if @step_impl.is_a?(::Class)
|
|
43
|
+
@will_run = false
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
##
|
|
47
|
+
# @return [boolean] Whether this step has been marked as will_run
|
|
48
|
+
#
|
|
49
|
+
def will_run?
|
|
50
|
+
@will_run
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
##
|
|
54
|
+
# @return [boolean] Whether this step is explicitly requested in config
|
|
55
|
+
#
|
|
56
|
+
def requested?
|
|
57
|
+
@step_settings.requested?
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
##
|
|
61
|
+
# @return [String] The step name
|
|
62
|
+
#
|
|
63
|
+
def name
|
|
64
|
+
@step_settings.name
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
##
|
|
68
|
+
# @return [Array<Toys::Release::InputSettings>] The input settings
|
|
69
|
+
#
|
|
70
|
+
def input_settings
|
|
71
|
+
@step_settings.inputs
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
##
|
|
75
|
+
# @return [Array<Toys::Release::OutputSettings>] The output settings
|
|
76
|
+
#
|
|
77
|
+
def output_settings
|
|
78
|
+
@step_settings.outputs
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
##
|
|
82
|
+
# @return [Toys::Release::EnvironmentUtils] Environment utils
|
|
83
|
+
#
|
|
84
|
+
def utils
|
|
85
|
+
@pipeline.utils
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
##
|
|
89
|
+
# @return [Toys::Release::Repository] The repository
|
|
90
|
+
#
|
|
91
|
+
def repository
|
|
92
|
+
@pipeline.repository
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
##
|
|
96
|
+
# @return [Toys::Release::Component] Component being released
|
|
97
|
+
#
|
|
98
|
+
def component
|
|
99
|
+
@pipeline.component
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
##
|
|
103
|
+
# @return [::Gem::Version] Version being released
|
|
104
|
+
#
|
|
105
|
+
def release_version
|
|
106
|
+
@pipeline.release_version
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
##
|
|
110
|
+
# @return [String] The name of the git remote
|
|
111
|
+
#
|
|
112
|
+
def git_remote
|
|
113
|
+
@pipeline.git_remote
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
##
|
|
117
|
+
# @return [boolean] Whether this is running in dry run mode
|
|
118
|
+
#
|
|
119
|
+
def dry_run?
|
|
120
|
+
@pipeline.dry_run
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
##
|
|
124
|
+
# @return [String] Short description of the release, including the
|
|
125
|
+
# component name and version
|
|
126
|
+
#
|
|
127
|
+
def release_description
|
|
128
|
+
"#{component.name} #{release_version}"
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
##
|
|
132
|
+
# @return [String] Name of the gem package for this release
|
|
133
|
+
#
|
|
134
|
+
def gem_package_name
|
|
135
|
+
"#{component.name}-#{release_version}.gem"
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
##
|
|
139
|
+
# @return [String] Name of the git tag
|
|
140
|
+
#
|
|
141
|
+
def tag_name
|
|
142
|
+
"#{component.name}/v#{release_version}"
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
##
|
|
146
|
+
# Log a message
|
|
147
|
+
#
|
|
148
|
+
# @param message [String] Message to log
|
|
149
|
+
#
|
|
150
|
+
def log(message)
|
|
151
|
+
@pipeline.utils.log(message)
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
##
|
|
155
|
+
# Log a warning
|
|
156
|
+
#
|
|
157
|
+
# @param message [String] Message to log
|
|
158
|
+
#
|
|
159
|
+
def warning(message)
|
|
160
|
+
@pipeline.utils.warning(message)
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
##
|
|
164
|
+
# Add a message to the successes list
|
|
165
|
+
#
|
|
166
|
+
# @param message [String] Success to report
|
|
167
|
+
#
|
|
168
|
+
def add_success(message)
|
|
169
|
+
@pipeline.performer_result.successes << message
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
##
|
|
173
|
+
# Exit the step immediately, but does not abort the pipeline.
|
|
174
|
+
# If an error message is given, it is added to the error stream.
|
|
175
|
+
#
|
|
176
|
+
# @param error_message [String] Optional error message
|
|
177
|
+
#
|
|
178
|
+
def exit_step(error_message = nil)
|
|
179
|
+
utils.error(error_message) if error_message
|
|
180
|
+
raise StepExit, error_message
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
##
|
|
184
|
+
# Exit the step immediately, and abort the pipeline.
|
|
185
|
+
# The error message is added to the error stream.
|
|
186
|
+
#
|
|
187
|
+
# @param error_message [String] Required error message
|
|
188
|
+
#
|
|
189
|
+
def abort_pipeline(error_message)
|
|
190
|
+
utils.error(error_message)
|
|
191
|
+
raise PipelineExit, error_message
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
##
|
|
195
|
+
# Get the option with the given key.
|
|
196
|
+
#
|
|
197
|
+
# @param key [String] Option name to fetch
|
|
198
|
+
# @param required [boolean] Whether to exit with an error if the option
|
|
199
|
+
# is not set. Defaults to false, which instead returns the default.
|
|
200
|
+
# @param default [Object] Default value to return if the option is not
|
|
201
|
+
# set and required is set to false.
|
|
202
|
+
#
|
|
203
|
+
# @return [Object] The option value
|
|
204
|
+
#
|
|
205
|
+
def option(key, required: false, default: nil)
|
|
206
|
+
return @step_settings.options[key] if @step_settings.options.key?(key)
|
|
207
|
+
return default unless required
|
|
208
|
+
abort_pipeline("Missing required option: #{key.inspect} for step #{name.inspect}")
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
##
|
|
212
|
+
# Get the path to an output directory.
|
|
213
|
+
# If the step_name argument is provided, its output directory is
|
|
214
|
+
# returned. Otherwise, the current step's output directory is returned.
|
|
215
|
+
#
|
|
216
|
+
# @param step_name [String,nil] Optional name of the step whose
|
|
217
|
+
# directory should be returned.
|
|
218
|
+
# @return [String]
|
|
219
|
+
#
|
|
220
|
+
def output_dir(step_name = nil)
|
|
221
|
+
@pipeline.artifact_dir.output(step_name || name)
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
##
|
|
225
|
+
# Get the path to a private temporary directory for use by this step.
|
|
226
|
+
#
|
|
227
|
+
# @return [String]
|
|
228
|
+
#
|
|
229
|
+
def temp_dir
|
|
230
|
+
@pipeline.artifact_dir.temp(name)
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
##
|
|
234
|
+
# Copy the given item from an input directory
|
|
235
|
+
#
|
|
236
|
+
# @param source_step [String] Name of the source step
|
|
237
|
+
# @param source_path [String] Path to the file or directory to copy
|
|
238
|
+
# @param dest [:component,:repo_root,:temp,:output] Symbolic destination
|
|
239
|
+
# @param dest_path [String] Path in the destination
|
|
240
|
+
#
|
|
241
|
+
def copy_from_input(source_step, source_path: nil, dest: :component, dest_path: nil)
|
|
242
|
+
source_dir = output_dir(source_step)
|
|
243
|
+
source_path ||= "."
|
|
244
|
+
dest_path ||= source_path
|
|
245
|
+
dest_dir =
|
|
246
|
+
case dest
|
|
247
|
+
when :component
|
|
248
|
+
component.directory(from: :absolute)
|
|
249
|
+
when :repo_root
|
|
250
|
+
@pipeline.utils.repo_root_directory
|
|
251
|
+
when :output
|
|
252
|
+
output_dir
|
|
253
|
+
when :temp
|
|
254
|
+
temp_dir
|
|
255
|
+
else
|
|
256
|
+
abort_pipeline("Unrecognized destination for copy_from_input: #{source.inspect}")
|
|
257
|
+
end
|
|
258
|
+
source = ::File.expand_path(source_path, source_dir)
|
|
259
|
+
dest = ::File.expand_path(dest_path, dest_dir)
|
|
260
|
+
utils.log("Copying #{source_path.inspect} from step #{source_step.inspect}")
|
|
261
|
+
@pipeline.copy_tree(self, source, dest, source_path)
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
##
|
|
265
|
+
# Copy the given item to the output directory
|
|
266
|
+
#
|
|
267
|
+
# @param source_path [String] Path to the file or directory to copy
|
|
268
|
+
# @param source [:component,:repo_root,:temp] Symbolic source
|
|
269
|
+
#
|
|
270
|
+
def copy_to_output(source: :component, source_path: nil, dest_path: nil)
|
|
271
|
+
source_path ||= "."
|
|
272
|
+
dest_path ||= source_path
|
|
273
|
+
source_dir =
|
|
274
|
+
case source
|
|
275
|
+
when :component
|
|
276
|
+
component.directory(from: :absolute)
|
|
277
|
+
when :repo_root
|
|
278
|
+
@pipeline.utils.repo_root_directory
|
|
279
|
+
when :temp
|
|
280
|
+
temp_dir
|
|
281
|
+
else
|
|
282
|
+
abort_pipeline("Unrecognized source for copy_to_output: #{source.inspect}")
|
|
283
|
+
end
|
|
284
|
+
source = ::File.expand_path(source_path, source_dir)
|
|
285
|
+
dest = ::File.expand_path(dest_path, output_dir)
|
|
286
|
+
utils.log("Copying #{source_path.inspect} to output")
|
|
287
|
+
@pipeline.copy_tree(self, source, dest, source_path)
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
# ---- called internally from the pipeline ----
|
|
291
|
+
|
|
292
|
+
# @private
|
|
293
|
+
def mark_will_run!
|
|
294
|
+
@will_run = true
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
# @private
|
|
298
|
+
def primary?
|
|
299
|
+
@step_impl.respond_to?(:primary?) && @step_impl.primary?(self)
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
# @private
|
|
303
|
+
def dependencies
|
|
304
|
+
if @step_impl.respond_to?(:dependencies)
|
|
305
|
+
Array(@step_impl.dependencies(self))
|
|
306
|
+
else
|
|
307
|
+
[]
|
|
308
|
+
end
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
# @private
|
|
312
|
+
def run!
|
|
313
|
+
@step_impl.run(self) if @step_impl.respond_to?(:run)
|
|
314
|
+
end
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
##
|
|
318
|
+
# Construct the pipeline context
|
|
319
|
+
#
|
|
320
|
+
def initialize(repository:, component:, version:, performer_result:, artifact_dir:, dry_run:, git_remote:)
|
|
321
|
+
@repository = repository
|
|
322
|
+
@component = component
|
|
323
|
+
@release_version = version
|
|
324
|
+
@performer_result = performer_result
|
|
325
|
+
@artifact_dir = artifact_dir
|
|
326
|
+
@dry_run = dry_run
|
|
327
|
+
@git_remote = git_remote || "origin"
|
|
328
|
+
@utils = repository.utils
|
|
329
|
+
@steps = []
|
|
330
|
+
@steps_locked = false
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
attr_reader :repository
|
|
334
|
+
attr_reader :component
|
|
335
|
+
attr_reader :release_version
|
|
336
|
+
attr_reader :performer_result
|
|
337
|
+
attr_reader :artifact_dir
|
|
338
|
+
attr_reader :dry_run
|
|
339
|
+
attr_reader :git_remote
|
|
340
|
+
attr_reader :utils
|
|
341
|
+
|
|
342
|
+
##
|
|
343
|
+
# Add a step
|
|
344
|
+
#
|
|
345
|
+
# @param step_settings [Toys::Release::StepSettings] step settings
|
|
346
|
+
# @return [Toys::Release::Pipeline::StepContext]
|
|
347
|
+
#
|
|
348
|
+
def add_step(step_settings)
|
|
349
|
+
raise "Steps locked" if @steps_locked
|
|
350
|
+
step = StepContext.new(self, step_settings)
|
|
351
|
+
@steps << step
|
|
352
|
+
step
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
##
|
|
356
|
+
# Resolve which steps should run
|
|
357
|
+
#
|
|
358
|
+
def resolve_run
|
|
359
|
+
@utils.log("Resolving which steps to run...")
|
|
360
|
+
@steps_locked = true
|
|
361
|
+
@steps.each_with_index do |step, index|
|
|
362
|
+
if step.requested?
|
|
363
|
+
@utils.log("Step #{step.name} is explicitly requested in config")
|
|
364
|
+
mark_step_index(index)
|
|
365
|
+
elsif step.primary?
|
|
366
|
+
@utils.log("Step #{step.name} declares itself as a primary step")
|
|
367
|
+
mark_step_index(index)
|
|
368
|
+
end
|
|
369
|
+
end
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
##
|
|
373
|
+
# Run the runnable steps in the pipeline
|
|
374
|
+
#
|
|
375
|
+
def run
|
|
376
|
+
@steps.each do |step|
|
|
377
|
+
unless step.will_run?
|
|
378
|
+
@utils.log("Skipping step #{step.name}")
|
|
379
|
+
next
|
|
380
|
+
end
|
|
381
|
+
begin
|
|
382
|
+
clean_repo(step)
|
|
383
|
+
pull_inputs(step)
|
|
384
|
+
@utils.log("Running step #{step.name}")
|
|
385
|
+
step.run!
|
|
386
|
+
@utils.log("Completed step #{step.name}")
|
|
387
|
+
push_outputs(step)
|
|
388
|
+
rescue StepExit => e
|
|
389
|
+
@utils.log("Exited step #{step.name}: #{e.message}")
|
|
390
|
+
# Continue
|
|
391
|
+
rescue PipelineExit => e
|
|
392
|
+
@utils.log("Aborted pipeline: #{e.message}")
|
|
393
|
+
return nil
|
|
394
|
+
end
|
|
395
|
+
end
|
|
396
|
+
end
|
|
397
|
+
|
|
398
|
+
##
|
|
399
|
+
# @private
|
|
400
|
+
#
|
|
401
|
+
def copy_tree(step, src, dest, src_name)
|
|
402
|
+
if ::File.directory?(src)
|
|
403
|
+
if ::File.exist?(dest) && !::File.directory?(dest)
|
|
404
|
+
step.abort_pipeline("Unable to copy #{src_name} because a non-directory exists at the destination")
|
|
405
|
+
end
|
|
406
|
+
::FileUtils.mkdir_p(dest)
|
|
407
|
+
::Dir.children(src).each do |child|
|
|
408
|
+
copy_tree(step, ::File.join(src, child), ::File.join(dest, child), ::File.join(src_name, child))
|
|
409
|
+
end
|
|
410
|
+
elsif ::File.exist?(src)
|
|
411
|
+
if ::File.exist?(dest)
|
|
412
|
+
step.abort_pipeline("Unable to copy #{src_name} because something already exists at the destination")
|
|
413
|
+
end
|
|
414
|
+
::FileUtils.copy_entry(src, dest)
|
|
415
|
+
else
|
|
416
|
+
step.abort_pipeline("Unable to copy #{src_name} because it does not exist")
|
|
417
|
+
end
|
|
418
|
+
end
|
|
419
|
+
|
|
420
|
+
private
|
|
421
|
+
|
|
422
|
+
##
|
|
423
|
+
# @private
|
|
424
|
+
# Recursive routine to mark steps as runnable
|
|
425
|
+
#
|
|
426
|
+
def mark_step_index(index)
|
|
427
|
+
step = @steps[index]
|
|
428
|
+
return if step.will_run?
|
|
429
|
+
step.mark_will_run!
|
|
430
|
+
step.input_settings.each do |input_settings|
|
|
431
|
+
dep_index = @steps[...index].find_index { |item| item.name == input_settings.step_name }
|
|
432
|
+
unless dep_index
|
|
433
|
+
@utils.error("Input dependency #{input_settings.name} not found before step #{step.name}")
|
|
434
|
+
return nil
|
|
435
|
+
end
|
|
436
|
+
@utils.log("Step #{@steps[dep_index].name} requested as a dependency of #{step.name}")
|
|
437
|
+
mark_step_index(dep_index)
|
|
438
|
+
end
|
|
439
|
+
step.dependencies.each do |dep_name|
|
|
440
|
+
dep_index = @steps[...index].find_index { |item| item.name == dep_name }
|
|
441
|
+
unless dep_index
|
|
442
|
+
@utils.error("Dependency #{dep_name} not found before step #{step.name}")
|
|
443
|
+
return nil
|
|
444
|
+
end
|
|
445
|
+
@utils.log("Step #{dep_name} requested as a dependency of #{step.name}")
|
|
446
|
+
mark_step_index(dep_index)
|
|
447
|
+
end
|
|
448
|
+
end
|
|
449
|
+
|
|
450
|
+
##
|
|
451
|
+
# @private
|
|
452
|
+
# Entry point to clean the repo
|
|
453
|
+
#
|
|
454
|
+
def clean_repo(step)
|
|
455
|
+
if step.option("clean") == false
|
|
456
|
+
@utils.log("Pre-cleaning disabled by the step #{step.name}")
|
|
457
|
+
return
|
|
458
|
+
end
|
|
459
|
+
@utils.log("Pre-cleaning the repo for step #{step.name}")
|
|
460
|
+
count = clean_tree(nil)
|
|
461
|
+
@utils.log("Cleaned #{count} items") if count.positive?
|
|
462
|
+
end
|
|
463
|
+
|
|
464
|
+
##
|
|
465
|
+
# @private
|
|
466
|
+
# Recursive repo cleaner
|
|
467
|
+
#
|
|
468
|
+
def clean_tree(subdir)
|
|
469
|
+
count = 0
|
|
470
|
+
::Dir.children(subdir || ".").each do |child|
|
|
471
|
+
next if child == ".git"
|
|
472
|
+
child = ::File.join(subdir, child) if subdir
|
|
473
|
+
if ::File.directory?(child)
|
|
474
|
+
clean_tree(child)
|
|
475
|
+
elsif !git_files.include?(child)
|
|
476
|
+
count += 1
|
|
477
|
+
@utils.log("Cleaning: #{child}")
|
|
478
|
+
::FileUtils.rm_rf(child)
|
|
479
|
+
end
|
|
480
|
+
end
|
|
481
|
+
count
|
|
482
|
+
end
|
|
483
|
+
|
|
484
|
+
##
|
|
485
|
+
# @private
|
|
486
|
+
# Return all files known by git
|
|
487
|
+
#
|
|
488
|
+
def git_files
|
|
489
|
+
@git_files ||= @utils.capture(["git", "ls-files"], e: true).strip.split("\n")
|
|
490
|
+
end
|
|
491
|
+
|
|
492
|
+
##
|
|
493
|
+
# @private
|
|
494
|
+
# Pull data from all inputs for the given step
|
|
495
|
+
#
|
|
496
|
+
def pull_inputs(step)
|
|
497
|
+
step.input_settings.each do |input|
|
|
498
|
+
next if input.dest == "none"
|
|
499
|
+
source_path = input.source_path || "."
|
|
500
|
+
dest_path = input.dest_path || source_path
|
|
501
|
+
source = ::File.expand_path(source_path, @artifact_dir.output(input.step_name))
|
|
502
|
+
dest_dir =
|
|
503
|
+
case input.dest
|
|
504
|
+
when "component"
|
|
505
|
+
step.component.directory(from: :absolute)
|
|
506
|
+
when "repo_root"
|
|
507
|
+
@utils.repo_root_directory
|
|
508
|
+
when "output"
|
|
509
|
+
step.output_dir
|
|
510
|
+
when "temp"
|
|
511
|
+
step.temp_dir
|
|
512
|
+
else
|
|
513
|
+
step.abort_pipeline("Unrecognized destination for input: #{input.dest.inspect}")
|
|
514
|
+
end
|
|
515
|
+
dest = ::File.expand_path(dest_path, dest_dir)
|
|
516
|
+
@utils.log("Copying #{source_path.inspect} from step #{input.step_name.inspect}")
|
|
517
|
+
copy_tree(step, source, dest, source_path)
|
|
518
|
+
end
|
|
519
|
+
end
|
|
520
|
+
|
|
521
|
+
##
|
|
522
|
+
# @private
|
|
523
|
+
# Push data to output from the given step
|
|
524
|
+
#
|
|
525
|
+
def push_outputs(step)
|
|
526
|
+
step.output_settings.each do |output|
|
|
527
|
+
source_path = output.source_path || "."
|
|
528
|
+
dest_path = output.dest_path || source_path
|
|
529
|
+
source_dir =
|
|
530
|
+
case output.source
|
|
531
|
+
when "component"
|
|
532
|
+
step.component.directory(from: :absolute)
|
|
533
|
+
when "repo_root"
|
|
534
|
+
@utils.repo_root_directory
|
|
535
|
+
when "temp"
|
|
536
|
+
step.temp_dir
|
|
537
|
+
else
|
|
538
|
+
step.abort_pipeline("Unrecognized source for output: #{output.source.inspect}")
|
|
539
|
+
end
|
|
540
|
+
source = ::File.expand_path(source_path, source_dir)
|
|
541
|
+
dest = ::File.expand_path(dest_path, step.output_dir)
|
|
542
|
+
@utils.log("Copying #{source_path.inspect} to output")
|
|
543
|
+
copy_tree(step, source, dest, source_path)
|
|
544
|
+
end
|
|
545
|
+
end
|
|
546
|
+
end
|
|
547
|
+
end
|
|
548
|
+
end
|