toys-release 0.1.1 → 0.3.0
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 +31 -0
- data/README.md +4 -4
- data/docs/guide.md +826 -1
- data/lib/toys/release/version.rb +1 -1
- data/toys/.data/templates/release-request.yml.erb +1 -1
- data/toys/.lib/toys/release/artifact_dir.rb +21 -1
- data/toys/.lib/toys/release/change_set.rb +8 -8
- data/toys/.lib/toys/release/component.rb +24 -85
- data/toys/.lib/toys/release/environment_utils.rb +29 -6
- data/toys/.lib/toys/release/performer.rb +48 -43
- data/toys/.lib/toys/release/pipeline.rb +577 -0
- data/toys/.lib/toys/release/pull_request.rb +0 -2
- data/toys/.lib/toys/release/repo_settings.rb +494 -332
- data/toys/.lib/toys/release/repository.rb +7 -8
- data/toys/.lib/toys/release/request_spec.rb +1 -1
- data/toys/.lib/toys/release/steps.rb +295 -441
- data/toys/.toys.rb +2 -2
- data/toys/_onclosed.rb +9 -1
- data/toys/gen-config.rb +137 -0
- data/toys/gen-workflows.rb +23 -6
- data/toys/perform.rb +7 -5
- data/toys/retry.rb +20 -14
- metadata +5 -6
- data/toys/.data/templates/release-hook-on-open.yml.erb +0 -30
- data/toys/_onopen.rb +0 -158
- data/toys/gen-settings.rb +0 -46
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require "yaml"
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
require "toys/release/semver"
|
|
6
6
|
|
|
7
7
|
module Toys
|
|
8
8
|
module Release
|
|
@@ -14,16 +14,31 @@ module Toys
|
|
|
14
14
|
ScopeInfo = ::Struct.new(:semver, :header)
|
|
15
15
|
|
|
16
16
|
##
|
|
17
|
-
# Create
|
|
18
|
-
# default to patch releases) or a hash with fields.
|
|
17
|
+
# Create an empty settings for an unknown tag
|
|
19
18
|
#
|
|
20
|
-
|
|
19
|
+
# @param tag [String] Conventional commit tag
|
|
20
|
+
# @return [CommitTagSettings]
|
|
21
|
+
#
|
|
22
|
+
def self.empty(tag)
|
|
23
|
+
new({"tag" => tag, "header" => nil}, [])
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
##
|
|
27
|
+
# @private
|
|
28
|
+
# Create a CommitTagSettings from an input hash.
|
|
29
|
+
#
|
|
30
|
+
def initialize(info, errors)
|
|
31
|
+
@tag = info.delete("tag").to_s
|
|
32
|
+
errors << "Commit tag missing : #{info}" if @tag.empty?
|
|
33
|
+
@header = info.fetch("header", @tag.upcase) || :hidden
|
|
34
|
+
info.delete("header")
|
|
35
|
+
@semver = load_semver(info.delete("semver"), errors)
|
|
21
36
|
@scopes = {}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
37
|
+
info.delete("scopes")&.each do |scope_info|
|
|
38
|
+
load_scope(scope_info, errors)
|
|
39
|
+
end
|
|
40
|
+
info.each_key do |key|
|
|
41
|
+
errors << "Unknown key #{key.inspect} in configuration of tag #{@tag.inspect}"
|
|
27
42
|
end
|
|
28
43
|
end
|
|
29
44
|
|
|
@@ -70,86 +85,27 @@ module Toys
|
|
|
70
85
|
end
|
|
71
86
|
end
|
|
72
87
|
|
|
73
|
-
##
|
|
74
|
-
# Make specified modifications to the settings
|
|
75
|
-
#
|
|
76
|
-
# @param input [Hash] Modifications
|
|
77
|
-
#
|
|
78
|
-
def modify(input)
|
|
79
|
-
if input.key?("header") || input.key?("label")
|
|
80
|
-
@header = input.fetch("header", input["label"]) || :hidden
|
|
81
|
-
end
|
|
82
|
-
if input.key?("semver")
|
|
83
|
-
@semver = load_semver(input["semver"])
|
|
84
|
-
end
|
|
85
|
-
input["scopes"]&.each do |key, value|
|
|
86
|
-
if value.nil?
|
|
87
|
-
@scopes.delete(key)
|
|
88
|
-
else
|
|
89
|
-
scope_info = load_scope(key, value)
|
|
90
|
-
@scopes[key] = scope_info if scope_info
|
|
91
|
-
end
|
|
92
|
-
end
|
|
93
|
-
end
|
|
94
|
-
|
|
95
88
|
private
|
|
96
89
|
|
|
97
|
-
def
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
if value.is_a?(::Hash)
|
|
108
|
-
@tag = key
|
|
109
|
-
load_hash(value)
|
|
110
|
-
elsif key == "tag"
|
|
111
|
-
@tag = value
|
|
112
|
-
@header = @tag.upcase
|
|
113
|
-
@semver = Semver::PATCH
|
|
114
|
-
else
|
|
115
|
-
@tag = key
|
|
116
|
-
@header = @tag.upcase
|
|
117
|
-
@semver = load_semver(value)
|
|
118
|
-
end
|
|
119
|
-
else
|
|
120
|
-
@tag = input["tag"]
|
|
121
|
-
raise "tag missing in #{input}" unless @tag
|
|
122
|
-
load_hash(input)
|
|
90
|
+
def load_scope(info, errors)
|
|
91
|
+
scope = info.delete("scope").to_s
|
|
92
|
+
errors << "Commit tag scope missing under tag #{@tag.inspect} : #{info}" if scope.empty?
|
|
93
|
+
scope_semver = load_semver(info.delete("semver"), errors, scope) if info.key?("semver")
|
|
94
|
+
scope_header = info.fetch("header", :inherit) || :hidden
|
|
95
|
+
info.delete("header")
|
|
96
|
+
scope_header = nil if scope_header == :inherit
|
|
97
|
+
@scopes[scope] = ScopeInfo.new(scope_semver, scope_header)
|
|
98
|
+
info.each_key do |key|
|
|
99
|
+
errors << "Unknown key #{key.inspect} in configuration of tag \"#{@tag}(#{scope})\""
|
|
123
100
|
end
|
|
124
101
|
end
|
|
125
102
|
|
|
126
|
-
def
|
|
127
|
-
@header = input.fetch("header", input.fetch("label", @tag.upcase)) || :hidden
|
|
128
|
-
@semver = load_semver(input.fetch("semver", "patch"))
|
|
129
|
-
input["scopes"]&.each do |key, value|
|
|
130
|
-
scope_info = load_scope(key, value)
|
|
131
|
-
@scopes[key] = scope_info if scope_info
|
|
132
|
-
end
|
|
133
|
-
end
|
|
134
|
-
|
|
135
|
-
def load_scope(key, value)
|
|
136
|
-
case value
|
|
137
|
-
when ::String
|
|
138
|
-
semver = load_semver(value, key)
|
|
139
|
-
ScopeInfo.new(semver, nil)
|
|
140
|
-
when ::Hash
|
|
141
|
-
semver = load_semver(value["semver"], key) if value.key?("semver")
|
|
142
|
-
header = value.fetch("header", value.fetch("label", :inherit)) || :hidden
|
|
143
|
-
header = nil if header == :inherit
|
|
144
|
-
ScopeInfo.new(semver, header)
|
|
145
|
-
end
|
|
146
|
-
end
|
|
147
|
-
|
|
148
|
-
def load_semver(value, scope = nil)
|
|
103
|
+
def load_semver(value, errors, scope = nil)
|
|
149
104
|
result = Semver.for_name(value || "none")
|
|
150
105
|
unless result
|
|
151
106
|
tag = scope ? "#{@tag}(#{scope})" : @tag
|
|
152
|
-
|
|
107
|
+
errors << "Unknown semver: #{value} for tag #{tag}"
|
|
108
|
+
result = Semver::NONE
|
|
153
109
|
end
|
|
154
110
|
result
|
|
155
111
|
end
|
|
@@ -160,6 +116,7 @@ module Toys
|
|
|
160
116
|
#
|
|
161
117
|
class ComponentSettings
|
|
162
118
|
##
|
|
119
|
+
# @private
|
|
163
120
|
# Create a ComponentSettings from input data structures
|
|
164
121
|
#
|
|
165
122
|
# @param info [Hash] Nested hash input
|
|
@@ -167,13 +124,13 @@ module Toys
|
|
|
167
124
|
# components
|
|
168
125
|
#
|
|
169
126
|
def initialize(repo_settings, info, has_multiple_components)
|
|
170
|
-
@name = info
|
|
171
|
-
@type = info["type"] || "component"
|
|
172
|
-
|
|
127
|
+
@name = info.delete("name").to_s
|
|
173
128
|
read_path_info(info, has_multiple_components)
|
|
174
129
|
read_file_modification_info(info)
|
|
175
130
|
read_gh_pages_info(repo_settings, info, has_multiple_components)
|
|
176
131
|
read_steps_info(repo_settings, info)
|
|
132
|
+
read_commit_tag_info(repo_settings, info)
|
|
133
|
+
check_problems(repo_settings, info)
|
|
177
134
|
end
|
|
178
135
|
|
|
179
136
|
##
|
|
@@ -181,12 +138,6 @@ module Toys
|
|
|
181
138
|
#
|
|
182
139
|
attr_reader :name
|
|
183
140
|
|
|
184
|
-
##
|
|
185
|
-
# @return [String] The type of component. Default is `"component"`.
|
|
186
|
-
# Subclasses may define other types.
|
|
187
|
-
#
|
|
188
|
-
attr_reader :type
|
|
189
|
-
|
|
190
141
|
##
|
|
191
142
|
# @return [String] The directory within the repo in which the component
|
|
192
143
|
# is located
|
|
@@ -245,6 +196,24 @@ module Toys
|
|
|
245
196
|
#
|
|
246
197
|
attr_reader :steps
|
|
247
198
|
|
|
199
|
+
##
|
|
200
|
+
# @return [Array<CommitTagSettings>] The conventional commit types
|
|
201
|
+
# recognized as release-triggering, along with information on the
|
|
202
|
+
# change they map to.
|
|
203
|
+
#
|
|
204
|
+
attr_reader :commit_tags
|
|
205
|
+
|
|
206
|
+
##
|
|
207
|
+
# @return [String] Header for breaking changes in a changelog
|
|
208
|
+
#
|
|
209
|
+
attr_reader :breaking_change_header
|
|
210
|
+
|
|
211
|
+
##
|
|
212
|
+
# @return [String] Notice displayed in the changelog when there are
|
|
213
|
+
# otherwise no significant updates in the release
|
|
214
|
+
#
|
|
215
|
+
attr_reader :no_significant_updates_notice
|
|
216
|
+
|
|
248
217
|
##
|
|
249
218
|
# @return [StepSettings,nil] The unique step with the given name
|
|
250
219
|
#
|
|
@@ -252,41 +221,69 @@ module Toys
|
|
|
252
221
|
steps.find { |t| t.name == name }
|
|
253
222
|
end
|
|
254
223
|
|
|
224
|
+
##
|
|
225
|
+
# Look up the settings for the given named tag.
|
|
226
|
+
#
|
|
227
|
+
# @param tag [String] Conventional commit tag to look up
|
|
228
|
+
# @return [CommitTagSettings] The commit tag settings for the given tag
|
|
229
|
+
#
|
|
230
|
+
def commit_tag_named(tag)
|
|
231
|
+
commit_tags.find { |elem| elem.tag == tag } || CommitTagSettings.empty(tag)
|
|
232
|
+
end
|
|
233
|
+
|
|
255
234
|
private
|
|
256
235
|
|
|
257
236
|
def read_path_info(info, has_multiple_components)
|
|
258
|
-
@directory = info
|
|
259
|
-
@include_globs = Array(info
|
|
260
|
-
@exclude_globs = Array(info
|
|
237
|
+
@directory = info.delete("directory") || (has_multiple_components ? name : ".")
|
|
238
|
+
@include_globs = Array(info.delete("include_globs"))
|
|
239
|
+
@exclude_globs = Array(info.delete("exclude_globs"))
|
|
261
240
|
end
|
|
262
241
|
|
|
263
242
|
def read_file_modification_info(info)
|
|
264
|
-
segments =
|
|
243
|
+
segments = @name.split("-")
|
|
265
244
|
name_path = segments.join("/")
|
|
266
|
-
@version_rb_path = info
|
|
267
|
-
@version_constant = info
|
|
245
|
+
@version_rb_path = info.delete("version_rb_path") || "lib/#{name_path}/version.rb"
|
|
246
|
+
@version_constant = info.delete("version_constant") ||
|
|
268
247
|
(segments.map { |seg| camelize(seg) } + ["VERSION"])
|
|
269
248
|
@version_constant = @version_constant.split("::") if @version_constant.is_a?(::String)
|
|
270
|
-
@changelog_path = info
|
|
249
|
+
@changelog_path = info.delete("changelog_path") || "CHANGELOG.md"
|
|
271
250
|
end
|
|
272
251
|
|
|
273
252
|
def read_gh_pages_info(repo_settings, info, has_multiple_components)
|
|
274
|
-
@gh_pages_directory = info["gh_pages_directory"] || (has_multiple_components ? name : ".")
|
|
275
|
-
@gh_pages_version_var = info["gh_pages_version_var"] ||
|
|
276
|
-
(has_multiple_components ? "version_#{name}".tr("-", "_") : "version")
|
|
277
253
|
@gh_pages_enabled = info.fetch("gh_pages_enabled") do |_key|
|
|
278
254
|
repo_settings.gh_pages_enabled ||
|
|
279
255
|
info.key?("gh_pages_directory") ||
|
|
280
256
|
info.key?("gh_pages_version_var")
|
|
281
257
|
end
|
|
258
|
+
info.delete("gh_pages_enabled")
|
|
259
|
+
@gh_pages_directory = info.delete("gh_pages_directory") || (has_multiple_components ? name : ".")
|
|
260
|
+
@gh_pages_version_var = info.delete("gh_pages_version_var") ||
|
|
261
|
+
(has_multiple_components ? "version_#{name}".tr("-", "_") : "version")
|
|
282
262
|
end
|
|
283
263
|
|
|
284
264
|
def read_steps_info(repo_settings, info)
|
|
285
|
-
@steps =
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
265
|
+
@steps =
|
|
266
|
+
if info.key?("steps")
|
|
267
|
+
repo_settings.read_steps(info.delete("steps"))
|
|
268
|
+
else
|
|
269
|
+
repo_settings.steps.map(&:deep_copy)
|
|
270
|
+
end
|
|
271
|
+
@steps = repo_settings.modify_steps(@steps, info.delete("modify_steps") || [])
|
|
272
|
+
@steps = repo_settings.prepend_steps(@steps, info.delete("prepend_steps") || [])
|
|
273
|
+
@steps = repo_settings.append_steps(@steps, info.delete("append_steps") || [])
|
|
274
|
+
@steps = repo_settings.delete_steps(@steps, info.delete("delete_steps") || [])
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
def read_commit_tag_info(repo_settings, info)
|
|
278
|
+
@commit_tags =
|
|
279
|
+
if info.key?("commit_tags")
|
|
280
|
+
repo_settings.read_commit_tags(info.delete("commit_tags"))
|
|
281
|
+
else
|
|
282
|
+
repo_settings.commit_tags.dup
|
|
283
|
+
end
|
|
284
|
+
@breaking_change_header = info.delete("breaking_change_header") || repo_settings.breaking_change_header
|
|
285
|
+
@no_significant_updates_notice =
|
|
286
|
+
info.delete("no_significant_updates_notice") || repo_settings.no_significant_updates_notice
|
|
290
287
|
end
|
|
291
288
|
|
|
292
289
|
def camelize(str)
|
|
@@ -296,16 +293,173 @@ module Toys
|
|
|
296
293
|
.gsub(/_+/, "_")
|
|
297
294
|
.gsub(/(?:^|_)([a-zA-Z])/) { ::Regexp.last_match(1).upcase }
|
|
298
295
|
end
|
|
296
|
+
|
|
297
|
+
def check_problems(repo_settings, info)
|
|
298
|
+
info.each_key do |key|
|
|
299
|
+
repo_settings.errors << "Unknown key #{key.inspect} in component #{@name.inspect}"
|
|
300
|
+
end
|
|
301
|
+
repo_settings.errors << 'Component is missing required key "name"' if @name.empty?
|
|
302
|
+
end
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
##
|
|
306
|
+
# Configuration of input settings for a step.
|
|
307
|
+
# An input declares a dependency on a step, and copies any files output by
|
|
308
|
+
# that dependency.
|
|
309
|
+
#
|
|
310
|
+
class InputSettings
|
|
311
|
+
##
|
|
312
|
+
# @private
|
|
313
|
+
# Construct input settings
|
|
314
|
+
#
|
|
315
|
+
# @param info [Hash,String] Config data
|
|
316
|
+
#
|
|
317
|
+
def initialize(info, errors, containing_step_name)
|
|
318
|
+
@step_name = @dest = @source_path = @dest_path = nil
|
|
319
|
+
case info
|
|
320
|
+
when ::String
|
|
321
|
+
@step_name = info
|
|
322
|
+
@dest = "component"
|
|
323
|
+
when ::Hash
|
|
324
|
+
@step_name = info.delete("name").to_s
|
|
325
|
+
if @step_name.empty?
|
|
326
|
+
errors << "Missing required key \"name\" in input for step #{containing_step_name.inspect}"
|
|
327
|
+
end
|
|
328
|
+
@dest = info.delete("dest")
|
|
329
|
+
if @dest == false
|
|
330
|
+
@dest = "none"
|
|
331
|
+
elsif @dest.nil?
|
|
332
|
+
@dest = "component"
|
|
333
|
+
end
|
|
334
|
+
@source_path = info.delete("source_path")
|
|
335
|
+
@dest_path = info.delete("dest_path")
|
|
336
|
+
@collisions = info.delete("collisions") || "error"
|
|
337
|
+
info.each_key do |key|
|
|
338
|
+
errors << "Unknown key #{key.inspect} in input for step #{containing_step_name.inspect}"
|
|
339
|
+
end
|
|
340
|
+
end
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
##
|
|
344
|
+
# @return [String] Name of the step to copy data from.
|
|
345
|
+
#
|
|
346
|
+
attr_reader :step_name
|
|
347
|
+
|
|
348
|
+
##
|
|
349
|
+
# @return [String,false] Where to copy data to. Possible values are
|
|
350
|
+
# "component", "repo_root", "output", "temp", and "none". If "none",
|
|
351
|
+
# no copying is performed and this input declares a dependency only.
|
|
352
|
+
#
|
|
353
|
+
attr_reader :dest
|
|
354
|
+
|
|
355
|
+
##
|
|
356
|
+
# @return [String,nil] Path in the source to copy from. Can be a path to
|
|
357
|
+
# a file or a directory. If nil, copy everything from the input.
|
|
358
|
+
#
|
|
359
|
+
attr_reader :source_path
|
|
360
|
+
|
|
361
|
+
##
|
|
362
|
+
# @return [String,nil] Path in the destination to copy to, relative to
|
|
363
|
+
# the destination. If nil, uses the source path.
|
|
364
|
+
#
|
|
365
|
+
attr_reader :dest_path
|
|
366
|
+
|
|
367
|
+
##
|
|
368
|
+
# @return [String] What to do if a collision occurs. Possible values are
|
|
369
|
+
# "error", "replace", and "keep".
|
|
370
|
+
#
|
|
371
|
+
attr_reader :collisions
|
|
372
|
+
|
|
373
|
+
##
|
|
374
|
+
# @return [Hash] the hash representation
|
|
375
|
+
#
|
|
376
|
+
def to_h
|
|
377
|
+
{
|
|
378
|
+
"name" => step_name,
|
|
379
|
+
"dest" => dest,
|
|
380
|
+
"source_path" => source_path,
|
|
381
|
+
"dest_path" => dest_path,
|
|
382
|
+
"collisions" => collisions,
|
|
383
|
+
}
|
|
384
|
+
end
|
|
385
|
+
end
|
|
386
|
+
|
|
387
|
+
##
|
|
388
|
+
# Configuration of output info for a step.
|
|
389
|
+
# An output automatically copies files from the repo directory to this
|
|
390
|
+
# step's output where they can be imported by another step.
|
|
391
|
+
#
|
|
392
|
+
class OutputSettings
|
|
393
|
+
##
|
|
394
|
+
# @private
|
|
395
|
+
# Construct output settings
|
|
396
|
+
#
|
|
397
|
+
# @param info [Hash,String] Config data
|
|
398
|
+
#
|
|
399
|
+
def initialize(info, errors, containing_step_name)
|
|
400
|
+
@source = @source_path = @dest_path = nil
|
|
401
|
+
case info
|
|
402
|
+
when ::String
|
|
403
|
+
@source_path = info
|
|
404
|
+
@source = "component"
|
|
405
|
+
when ::Hash
|
|
406
|
+
@source = info.delete("source") || "component"
|
|
407
|
+
@source_path = info.delete("source_path")
|
|
408
|
+
@dest_path = info.delete("dest_path")
|
|
409
|
+
@collisions = info.delete("collisions") || "error"
|
|
410
|
+
info.each_key do |key|
|
|
411
|
+
errors << "Unknown key #{key.inspect} in output for step #{containing_step_name.inspect}"
|
|
412
|
+
end
|
|
413
|
+
end
|
|
414
|
+
end
|
|
415
|
+
|
|
416
|
+
##
|
|
417
|
+
# @return [String] Where to copy data from. Possible values are
|
|
418
|
+
# "component", "repo_root", and "temp".
|
|
419
|
+
#
|
|
420
|
+
attr_reader :source
|
|
421
|
+
|
|
422
|
+
##
|
|
423
|
+
# @return [String,nil] Path to copy from, relative to the source. Can be
|
|
424
|
+
# a file or a directory. If nil, copy everything in the source.
|
|
425
|
+
#
|
|
426
|
+
attr_reader :source_path
|
|
427
|
+
|
|
428
|
+
##
|
|
429
|
+
# @return [String,nil] Path in the step's output to copy to.
|
|
430
|
+
# If nil, uses the source path.
|
|
431
|
+
#
|
|
432
|
+
attr_reader :dest_path
|
|
433
|
+
|
|
434
|
+
##
|
|
435
|
+
# @return [String] What to do if a collision occurs. Possible values are
|
|
436
|
+
# "error", "replace", and "keep".
|
|
437
|
+
#
|
|
438
|
+
attr_reader :collisions
|
|
439
|
+
|
|
440
|
+
##
|
|
441
|
+
# @return [Hash] the hash representation
|
|
442
|
+
#
|
|
443
|
+
def to_h
|
|
444
|
+
{
|
|
445
|
+
"source" => source,
|
|
446
|
+
"source_path" => source_path,
|
|
447
|
+
"dest_path" => dest_path,
|
|
448
|
+
"collisions" => collisions,
|
|
449
|
+
}
|
|
450
|
+
end
|
|
299
451
|
end
|
|
300
452
|
|
|
301
453
|
##
|
|
454
|
+
# @private
|
|
302
455
|
# Configuration of a step
|
|
303
456
|
#
|
|
304
457
|
class StepSettings
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
458
|
+
##
|
|
459
|
+
# Create a StepSettings
|
|
460
|
+
#
|
|
461
|
+
def initialize(info, errors)
|
|
462
|
+
from_h(info.dup, errors)
|
|
309
463
|
end
|
|
310
464
|
|
|
311
465
|
##
|
|
@@ -318,18 +472,66 @@ module Toys
|
|
|
318
472
|
#
|
|
319
473
|
attr_reader :type
|
|
320
474
|
|
|
475
|
+
##
|
|
476
|
+
# @return [boolean] Whether this step is explicitly requested
|
|
477
|
+
#
|
|
478
|
+
def requested?
|
|
479
|
+
@requested
|
|
480
|
+
end
|
|
481
|
+
|
|
482
|
+
##
|
|
483
|
+
# @return [Array<InputSettings>] Inputs for this step
|
|
484
|
+
#
|
|
485
|
+
attr_reader :inputs
|
|
486
|
+
|
|
487
|
+
##
|
|
488
|
+
# @return [Array<OutputSettings>] Extra outputs for this step
|
|
489
|
+
#
|
|
490
|
+
attr_reader :outputs
|
|
491
|
+
|
|
321
492
|
##
|
|
322
493
|
# @return [Hash{String=>Object}] Options for this step
|
|
323
494
|
#
|
|
324
495
|
attr_reader :options
|
|
325
496
|
|
|
497
|
+
##
|
|
498
|
+
# @return [Hash] the hash representation
|
|
499
|
+
#
|
|
500
|
+
def to_h
|
|
501
|
+
{
|
|
502
|
+
"name" => name,
|
|
503
|
+
"type" => type,
|
|
504
|
+
"run" => requested?,
|
|
505
|
+
"inputs" => inputs.map(&:to_h),
|
|
506
|
+
"outputs" => outputs.map(&:to_h),
|
|
507
|
+
}.merge(RepoSettings.deep_copy(options))
|
|
508
|
+
end
|
|
509
|
+
|
|
326
510
|
##
|
|
327
511
|
# Make a deep copy
|
|
328
512
|
#
|
|
329
513
|
# @return [StepSettings] A deep copy
|
|
330
514
|
#
|
|
331
515
|
def deep_copy
|
|
332
|
-
StepSettings.new(
|
|
516
|
+
StepSettings.new(to_h, [])
|
|
517
|
+
end
|
|
518
|
+
|
|
519
|
+
##
|
|
520
|
+
# @private
|
|
521
|
+
# Initialize the step from the given hash.
|
|
522
|
+
# The hash will be deconstructed in place.
|
|
523
|
+
#
|
|
524
|
+
def from_h(info, errors)
|
|
525
|
+
@type = info.delete("type") || info["name"] || "noop"
|
|
526
|
+
@name = info.delete("name") || "_anon_#{@type}_#{object_id}"
|
|
527
|
+
@requested = info.delete("run") ? true : false
|
|
528
|
+
@inputs = Array(info.delete("inputs")).map do |input_info|
|
|
529
|
+
InputSettings.new(input_info, errors, @name)
|
|
530
|
+
end
|
|
531
|
+
@outputs = Array(info.delete("outputs")).map do |output_info|
|
|
532
|
+
OutputSettings.new(output_info, errors, @name)
|
|
533
|
+
end
|
|
534
|
+
@options = info
|
|
333
535
|
end
|
|
334
536
|
end
|
|
335
537
|
|
|
@@ -368,6 +570,7 @@ module Toys
|
|
|
368
570
|
end
|
|
369
571
|
|
|
370
572
|
##
|
|
573
|
+
# @private
|
|
371
574
|
# Create a repo configuration object.
|
|
372
575
|
#
|
|
373
576
|
# @param info [Hash] Configuration hash read from JSON.
|
|
@@ -375,14 +578,14 @@ module Toys
|
|
|
375
578
|
def initialize(info)
|
|
376
579
|
@warnings = []
|
|
377
580
|
@errors = []
|
|
378
|
-
@default_component_name = nil
|
|
379
581
|
read_global_info(info)
|
|
582
|
+
read_required_checks_info(info)
|
|
380
583
|
read_label_info(info)
|
|
381
|
-
|
|
382
|
-
read_commit_tag_info(info)
|
|
584
|
+
read_default_commit_tag_info(info)
|
|
383
585
|
read_default_step_info(info)
|
|
384
586
|
read_component_info(info)
|
|
385
587
|
read_coordination_info(info)
|
|
588
|
+
check_global_problems(info)
|
|
386
589
|
end
|
|
387
590
|
|
|
388
591
|
##
|
|
@@ -417,11 +620,6 @@ module Toys
|
|
|
417
620
|
#
|
|
418
621
|
attr_reader :git_user_email
|
|
419
622
|
|
|
420
|
-
##
|
|
421
|
-
# @return [String] The name of the default component to release
|
|
422
|
-
#
|
|
423
|
-
attr_reader :default_component_name
|
|
424
|
-
|
|
425
623
|
##
|
|
426
624
|
# @return [Array<Array<String>>] An array of groups of component names
|
|
427
625
|
# whose releases should be coordinated.
|
|
@@ -435,12 +633,6 @@ module Toys
|
|
|
435
633
|
#
|
|
436
634
|
attr_reader :required_checks_regexp
|
|
437
635
|
|
|
438
|
-
##
|
|
439
|
-
# @return [Regexp,nil] A regular expression identifying all the
|
|
440
|
-
# release-related GitHub checks
|
|
441
|
-
#
|
|
442
|
-
attr_reader :release_jobs_regexp
|
|
443
|
-
|
|
444
636
|
##
|
|
445
637
|
# @return [Numeric] The number of seconds that releases will wait for
|
|
446
638
|
# checks to complete.
|
|
@@ -453,23 +645,18 @@ module Toys
|
|
|
453
645
|
attr_reader :gh_pages_enabled
|
|
454
646
|
|
|
455
647
|
##
|
|
456
|
-
# @return [Array<
|
|
457
|
-
#
|
|
648
|
+
# @return [Array<CommitTagSettings>] The conventional commit types
|
|
649
|
+
# recognized as release-triggering, along with information on the
|
|
650
|
+
# change they map to.
|
|
458
651
|
#
|
|
459
|
-
attr_reader :
|
|
652
|
+
attr_reader :commit_tags
|
|
460
653
|
|
|
461
654
|
##
|
|
462
|
-
#
|
|
463
|
-
# linting commit messages.
|
|
655
|
+
# Get the build step pipeline
|
|
464
656
|
#
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
##
|
|
468
|
-
# @return [Hash{String=>CommitTagSettings}] The conventional commit types
|
|
469
|
-
# recognized as release-triggering, along with the type of change they
|
|
470
|
-
# map to.
|
|
657
|
+
# @return [Array<StepSettings>] Step pipeline
|
|
471
658
|
#
|
|
472
|
-
attr_reader :
|
|
659
|
+
attr_reader :steps
|
|
473
660
|
|
|
474
661
|
##
|
|
475
662
|
# @return [String] Header for breaking changes in a changelog
|
|
@@ -477,7 +664,8 @@ module Toys
|
|
|
477
664
|
attr_reader :breaking_change_header
|
|
478
665
|
|
|
479
666
|
##
|
|
480
|
-
# @return [String]
|
|
667
|
+
# @return [String] Notice displayed in the changelog when there are
|
|
668
|
+
# otherwise no significant updates in the release
|
|
481
669
|
#
|
|
482
670
|
attr_reader :no_significant_updates_notice
|
|
483
671
|
|
|
@@ -506,6 +694,16 @@ module Toys
|
|
|
506
694
|
#
|
|
507
695
|
attr_reader :release_branch_prefix
|
|
508
696
|
|
|
697
|
+
##
|
|
698
|
+
# Look up the settings for the given named tag.
|
|
699
|
+
#
|
|
700
|
+
# @param tag [String] Conventional commit tag to look up
|
|
701
|
+
# @return [CommitTagSettings] The commit tag settings for the given tag
|
|
702
|
+
#
|
|
703
|
+
def commit_tag_named(tag)
|
|
704
|
+
commit_tags.find { |elem| elem.tag == tag } || CommitTagSettings.empty(tag)
|
|
705
|
+
end
|
|
706
|
+
|
|
509
707
|
##
|
|
510
708
|
# @return [String] The owner of the repo
|
|
511
709
|
#
|
|
@@ -535,21 +733,6 @@ module Toys
|
|
|
535
733
|
@enable_release_automation
|
|
536
734
|
end
|
|
537
735
|
|
|
538
|
-
##
|
|
539
|
-
# @return [boolean] Whether conventional commit linting errors should fail
|
|
540
|
-
# GitHub checks.
|
|
541
|
-
#
|
|
542
|
-
def commit_lint_fail_checks?
|
|
543
|
-
@commit_lint_fail_checks
|
|
544
|
-
end
|
|
545
|
-
|
|
546
|
-
##
|
|
547
|
-
# @return [boolean] Whether to perform conventional commit linting.
|
|
548
|
-
#
|
|
549
|
-
def commit_lint_active?
|
|
550
|
-
@commit_lint_active
|
|
551
|
-
end
|
|
552
|
-
|
|
553
736
|
##
|
|
554
737
|
# @return [Array<String>] A list of all component names.
|
|
555
738
|
#
|
|
@@ -575,34 +758,17 @@ module Toys
|
|
|
575
758
|
@components[name]
|
|
576
759
|
end
|
|
577
760
|
|
|
578
|
-
##
|
|
579
|
-
# Get the default step pipeline settings for a component type
|
|
580
|
-
#
|
|
581
|
-
# @param component_type [String] Type of component
|
|
582
|
-
# @return [Array<StepSettings>] Step pipeline
|
|
583
|
-
#
|
|
584
|
-
def default_steps(component_type)
|
|
585
|
-
(@default_steps[component_type] || @default_steps["component"]).map(&:deep_copy)
|
|
586
|
-
end
|
|
587
|
-
|
|
588
761
|
# @private
|
|
589
762
|
def read_steps(info)
|
|
590
|
-
|
|
591
|
-
info.each do |step_info|
|
|
592
|
-
step_info = step_info.dup
|
|
593
|
-
name = step_info.delete("name")
|
|
594
|
-
type = step_info.delete("type")
|
|
595
|
-
if type
|
|
596
|
-
steps << StepSettings.new(name, type, step_info)
|
|
597
|
-
else
|
|
598
|
-
@errors << "No step type provided for step #{name.inspect}"
|
|
599
|
-
end
|
|
600
|
-
end
|
|
601
|
-
steps
|
|
763
|
+
Array(info).map { |step_info| StepSettings.new(step_info, @errors) }
|
|
602
764
|
end
|
|
603
765
|
|
|
604
766
|
# @private
|
|
605
|
-
def modify_steps(steps, modifications)
|
|
767
|
+
def modify_steps(steps, modifications) # rubocop:disable Metrics/MethodLength
|
|
768
|
+
unless modifications.is_a?(::Array)
|
|
769
|
+
@errors << "modify_steps expected an array of modification dictionaries"
|
|
770
|
+
return steps
|
|
771
|
+
end
|
|
606
772
|
modifications.each do |mod_data|
|
|
607
773
|
mod_name = mod_data.delete("name")
|
|
608
774
|
mod_type = mod_data.delete("type")
|
|
@@ -610,14 +776,15 @@ module Toys
|
|
|
610
776
|
steps.each do |step|
|
|
611
777
|
next if (mod_name && step.name != mod_name) || (mod_type && step.type != mod_type)
|
|
612
778
|
count += 1
|
|
613
|
-
|
|
779
|
+
modified_info = step.to_h
|
|
614
780
|
mod_data.each do |key, value|
|
|
615
781
|
if value.nil?
|
|
616
|
-
|
|
782
|
+
modified_info.delete(key)
|
|
617
783
|
else
|
|
618
|
-
|
|
784
|
+
modified_info[key] = value
|
|
619
785
|
end
|
|
620
786
|
end
|
|
787
|
+
step.from_h(modified_info, @errors)
|
|
621
788
|
end
|
|
622
789
|
if count.zero?
|
|
623
790
|
@errors << "Unable to find step to modify for name=#{mod_name.inspect} and type=#{mod_type.inspect}."
|
|
@@ -628,86 +795,112 @@ module Toys
|
|
|
628
795
|
|
|
629
796
|
# @private
|
|
630
797
|
def prepend_steps(steps, info)
|
|
631
|
-
|
|
632
|
-
|
|
798
|
+
before = []
|
|
799
|
+
insert = []
|
|
800
|
+
after = steps
|
|
801
|
+
case info
|
|
802
|
+
when ::Hash
|
|
803
|
+
if (before_name = info["before"])
|
|
804
|
+
before_index = steps.find_index { |step| step.name == before_name }
|
|
805
|
+
if before_index
|
|
806
|
+
before = steps[...before_index]
|
|
807
|
+
after = steps[before_index..]
|
|
808
|
+
else
|
|
809
|
+
@errors << "Unable to find step named #{before_name} in prepend_steps.before"
|
|
810
|
+
end
|
|
811
|
+
end
|
|
812
|
+
if (steps_info = info["steps"]).is_a?(::Array)
|
|
813
|
+
insert = read_steps(steps_info)
|
|
814
|
+
else
|
|
815
|
+
@errors << "steps expected in prepend_steps"
|
|
816
|
+
end
|
|
817
|
+
when ::Array
|
|
818
|
+
insert = read_steps(info)
|
|
819
|
+
else
|
|
820
|
+
@errors << "prepend_steps expected a hash or array"
|
|
821
|
+
end
|
|
822
|
+
before + insert + after
|
|
633
823
|
end
|
|
634
824
|
|
|
635
825
|
# @private
|
|
636
826
|
def append_steps(steps, info)
|
|
637
|
-
|
|
638
|
-
|
|
827
|
+
before = steps
|
|
828
|
+
insert = []
|
|
829
|
+
after = []
|
|
830
|
+
case info
|
|
831
|
+
when ::Hash
|
|
832
|
+
if (after_name = info["after"])
|
|
833
|
+
after_index = steps.find_index { |step| step.name == after_name }
|
|
834
|
+
if after_index
|
|
835
|
+
before = steps[..after_index]
|
|
836
|
+
after = steps[(after_index + 1)..]
|
|
837
|
+
else
|
|
838
|
+
@errors << "Unable to find step named #{after_name} in append_steps.after"
|
|
839
|
+
end
|
|
840
|
+
end
|
|
841
|
+
if (steps_info = info["steps"]).is_a?(::Array)
|
|
842
|
+
insert = read_steps(steps_info)
|
|
843
|
+
else
|
|
844
|
+
@errors << "steps expected in append_steps"
|
|
845
|
+
end
|
|
846
|
+
when ::Array
|
|
847
|
+
insert = read_steps(info)
|
|
848
|
+
else
|
|
849
|
+
@errors << "append_steps expected a hash or array"
|
|
850
|
+
end
|
|
851
|
+
before + insert + after
|
|
639
852
|
end
|
|
640
853
|
|
|
641
854
|
# @private
|
|
642
855
|
def delete_steps(steps, info)
|
|
643
|
-
info.
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
856
|
+
if info.is_a?(::Array)
|
|
857
|
+
info.each do |del_name|
|
|
858
|
+
index = steps.find_index { |step| step.name == del_name }
|
|
859
|
+
if index
|
|
860
|
+
steps.delete_at(index)
|
|
861
|
+
else
|
|
862
|
+
@errors << "Unable to find step named #{del_name} to delete."
|
|
863
|
+
end
|
|
649
864
|
end
|
|
865
|
+
else
|
|
866
|
+
@errors << "delete_steps expected an array of names"
|
|
650
867
|
end
|
|
651
868
|
steps
|
|
652
869
|
end
|
|
653
870
|
|
|
871
|
+
# @private
|
|
872
|
+
def read_commit_tags(info)
|
|
873
|
+
Array(info).map { |tag_info| CommitTagSettings.new(tag_info, @errors) }
|
|
874
|
+
end
|
|
875
|
+
|
|
654
876
|
private
|
|
655
877
|
|
|
656
878
|
DEFAULT_MAIN_BRAMCH = "main"
|
|
657
879
|
private_constant :DEFAULT_MAIN_BRAMCH
|
|
658
880
|
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
"name" => "bundle",
|
|
683
|
-
"type" => "Bundle",
|
|
684
|
-
}.freeze,
|
|
685
|
-
{
|
|
686
|
-
"name" => "build-gem",
|
|
687
|
-
"type" => "BuildGem",
|
|
688
|
-
}.freeze,
|
|
689
|
-
{
|
|
690
|
-
"name" => "build-yard",
|
|
691
|
-
"type" => "BuildYard",
|
|
692
|
-
"require_gh_pages_enabled" => true,
|
|
693
|
-
}.freeze,
|
|
694
|
-
{
|
|
695
|
-
"name" => "github-release",
|
|
696
|
-
"type" => "GitHubRelease",
|
|
697
|
-
}.freeze,
|
|
698
|
-
{
|
|
699
|
-
"name" => "release-gem",
|
|
700
|
-
"type" => "ReleaseGem",
|
|
701
|
-
"input" => "build-gem",
|
|
702
|
-
}.freeze,
|
|
703
|
-
{
|
|
704
|
-
"name" => "push-gh-pages",
|
|
705
|
-
"type" => "PushGhPages",
|
|
706
|
-
"input" => "build-yard",
|
|
707
|
-
}.freeze,
|
|
708
|
-
].freeze,
|
|
709
|
-
}.freeze
|
|
710
|
-
private_constant :DEFAULT_STEPS
|
|
881
|
+
DEFAULT_COMMIT_TAGS_YAML = <<~STRING
|
|
882
|
+
- tag: feat
|
|
883
|
+
semver: minor
|
|
884
|
+
header: ADDED
|
|
885
|
+
- tag: fix
|
|
886
|
+
semver: patch
|
|
887
|
+
header: FIXED
|
|
888
|
+
- tag: docs
|
|
889
|
+
semver: patch
|
|
890
|
+
STRING
|
|
891
|
+
private_constant :DEFAULT_COMMIT_TAGS_YAML
|
|
892
|
+
|
|
893
|
+
DEFAULT_STEPS_YAML = <<~STRING
|
|
894
|
+
- name: bundle
|
|
895
|
+
- name: build_gem
|
|
896
|
+
- name: build_yard
|
|
897
|
+
- name: release_github
|
|
898
|
+
- name: release_gem
|
|
899
|
+
source: build_gem
|
|
900
|
+
- name: push_gh_pages
|
|
901
|
+
source: build_yard
|
|
902
|
+
STRING
|
|
903
|
+
private_constant :DEFAULT_STEPS_YAML
|
|
711
904
|
|
|
712
905
|
DEFAULT_BREAKING_CHANGE_HEADER = "BREAKING CHANGE"
|
|
713
906
|
private_constant :DEFAULT_BREAKING_CHANGE_HEADER
|
|
@@ -728,114 +921,71 @@ module Toys
|
|
|
728
921
|
private_constant :DEFAULT_RELEASE_COMPLETE_LABEL
|
|
729
922
|
|
|
730
923
|
def read_global_info(info)
|
|
731
|
-
@main_branch = info
|
|
732
|
-
@repo_path = info
|
|
733
|
-
@signoff_commits = info
|
|
734
|
-
@gh_pages_enabled = info
|
|
735
|
-
@enable_release_automation = info
|
|
736
|
-
|
|
737
|
-
@
|
|
738
|
-
@
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
@
|
|
924
|
+
@main_branch = info.delete("main_branch") || DEFAULT_MAIN_BRAMCH
|
|
925
|
+
@repo_path = info.delete("repo")
|
|
926
|
+
@signoff_commits = info.delete("signoff_commits") ? true : false
|
|
927
|
+
@gh_pages_enabled = info.delete("gh_pages_enabled") ? true : false
|
|
928
|
+
@enable_release_automation = info.delete("enable_release_automation") != false
|
|
929
|
+
@release_branch_prefix = info.delete("release_branch_prefix") || "release"
|
|
930
|
+
@git_user_name = info.delete("git_user_name")
|
|
931
|
+
@git_user_email = info.delete("git_user_email")
|
|
932
|
+
end
|
|
933
|
+
|
|
934
|
+
def read_required_checks_info(info)
|
|
935
|
+
required_checks = info.delete("required_checks")
|
|
936
|
+
@required_checks_regexp =
|
|
937
|
+
case required_checks
|
|
938
|
+
when false
|
|
939
|
+
nil
|
|
940
|
+
when true
|
|
941
|
+
//
|
|
942
|
+
else
|
|
943
|
+
::Regexp.new(required_checks.to_s)
|
|
944
|
+
end
|
|
945
|
+
@required_checks_timeout = info.delete("required_checks_timeout") || 900
|
|
744
946
|
end
|
|
745
947
|
|
|
746
948
|
def read_label_info(info)
|
|
747
|
-
@release_pending_label = info
|
|
748
|
-
@release_error_label = info
|
|
749
|
-
@release_aborted_label = info
|
|
750
|
-
@release_complete_label = info
|
|
751
|
-
end
|
|
752
|
-
|
|
753
|
-
def read_commit_lint_info(info)
|
|
754
|
-
info = info["commit_lint"]
|
|
755
|
-
@commit_lint_active = !info.nil?
|
|
756
|
-
info = {} unless info.is_a?(::Hash)
|
|
757
|
-
@commit_lint_fail_checks = info["fail_checks"] ? true : false
|
|
758
|
-
@commit_lint_merge = Array(info["merge"] || ["squash", "merge", "rebase"])
|
|
759
|
-
@commit_lint_allowed_types = info["allowed_types"]
|
|
760
|
-
if @commit_lint_allowed_types
|
|
761
|
-
@commit_lint_allowed_types = Array(@commit_lint_allowed_types).map(&:downcase)
|
|
762
|
-
end
|
|
949
|
+
@release_pending_label = info.delete("release_pending_label") || DEFAULT_RELEASE_PENDING_LABEL
|
|
950
|
+
@release_error_label = info.delete("release_error_label") || DEFAULT_RELEASE_ERROR_LABEL
|
|
951
|
+
@release_aborted_label = info.delete("release_aborted_label") || DEFAULT_RELEASE_ABORTED_LABEL
|
|
952
|
+
@release_complete_label = info.delete("release_complete_label") || DEFAULT_RELEASE_COMPLETE_LABEL
|
|
763
953
|
end
|
|
764
954
|
|
|
765
|
-
def
|
|
766
|
-
@
|
|
767
|
-
info
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
elsif (tag_settings = @release_commit_tags[tag])
|
|
771
|
-
tag_settings.modify(data)
|
|
772
|
-
end
|
|
773
|
-
end
|
|
774
|
-
@release_commit_tags = read_commit_tag_info_set(info["prepend_release_commit_tags"]).merge(@release_commit_tags)
|
|
775
|
-
@release_commit_tags.merge!(read_commit_tag_info_set(info["append_release_commit_tags"]))
|
|
776
|
-
@breaking_change_header = info["breaking_change_header"] || DEFAULT_BREAKING_CHANGE_HEADER
|
|
777
|
-
@no_significant_updates_notice = info["no_significant_updates_notice"] || DEFAULT_NO_SIGNIFICANT_UPDATES_NOTICE
|
|
955
|
+
def read_default_commit_tag_info(info)
|
|
956
|
+
@commit_tags = read_commit_tags(info.delete("commit_tags") || ::YAML.load(DEFAULT_COMMIT_TAGS_YAML))
|
|
957
|
+
@breaking_change_header = info.delete("breaking_change_header") || DEFAULT_BREAKING_CHANGE_HEADER
|
|
958
|
+
@no_significant_updates_notice =
|
|
959
|
+
info.delete("no_significant_updates_notice") || DEFAULT_NO_SIGNIFICANT_UPDATES_NOTICE
|
|
778
960
|
end
|
|
779
961
|
|
|
780
|
-
def
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
def read_default_step_info(info) # rubocop:disable Metrics/AbcSize
|
|
788
|
-
default_step_data = info["default_steps"] || DEFAULT_STEPS
|
|
789
|
-
@default_steps = {}
|
|
790
|
-
default_step_data.each do |key, data|
|
|
791
|
-
@default_steps[key] = read_steps(data)
|
|
792
|
-
end
|
|
793
|
-
(info["modify_default_steps"] || {}).each do |key, data|
|
|
794
|
-
@default_steps[key] = modify_steps(@default_steps[key], data)
|
|
795
|
-
end
|
|
796
|
-
(info["append_default_steps"] || {}).each do |key, data|
|
|
797
|
-
@default_steps[key] = append_steps(@default_steps[key], data)
|
|
798
|
-
end
|
|
799
|
-
(info["prepend_default_steps"] || {}).each do |key, data|
|
|
800
|
-
@default_steps[key] = prepend_steps(@default_steps[key], data)
|
|
801
|
-
end
|
|
802
|
-
(info["delete_default_steps"] || {}).each do |key, data|
|
|
803
|
-
@default_steps[key] = delete_steps(@default_steps[key], data)
|
|
804
|
-
end
|
|
962
|
+
def read_default_step_info(info)
|
|
963
|
+
@steps = read_steps(info.delete("steps") || ::YAML.load(DEFAULT_STEPS_YAML))
|
|
964
|
+
@steps = modify_steps(@steps, info.delete("modify_steps") || [])
|
|
965
|
+
@steps = prepend_steps(@steps, info.delete("prepend_steps") || [])
|
|
966
|
+
@steps = append_steps(@steps, info.delete("append_steps") || [])
|
|
967
|
+
@steps = delete_steps(@steps, info.delete("delete_steps") || [])
|
|
805
968
|
end
|
|
806
969
|
|
|
807
970
|
def read_component_info(info)
|
|
808
971
|
@components = {}
|
|
809
|
-
|
|
810
|
-
@has_multiple_components =
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
972
|
+
component_info_array = Array(info.delete("components")) + Array(info.delete("gems"))
|
|
973
|
+
@has_multiple_components = component_info_array.size > 1
|
|
974
|
+
component_info_array.each do |component_info|
|
|
975
|
+
component = ComponentSettings.new(self, component_info, @has_multiple_components)
|
|
976
|
+
if component.name.empty?
|
|
977
|
+
@errors << "A component is missing a name"
|
|
978
|
+
elsif @components[component.name]
|
|
979
|
+
@errors << "Duplicate component #{component.name.inspect}"
|
|
980
|
+
else
|
|
981
|
+
@components[component.name] = component
|
|
982
|
+
end
|
|
817
983
|
end
|
|
818
984
|
@errors << "No components found" if @components.empty?
|
|
819
985
|
end
|
|
820
986
|
|
|
821
|
-
def read_component_settings(component_info)
|
|
822
|
-
component = ComponentSettings.new(self, component_info, @has_multiple_components)
|
|
823
|
-
if component.name.empty?
|
|
824
|
-
@errors << "A component is missing a name"
|
|
825
|
-
elsif @components[component.name]
|
|
826
|
-
@errors << "Duplicate component #{component.name.inspect}"
|
|
827
|
-
else
|
|
828
|
-
@components[component.name] = component
|
|
829
|
-
@default_component_name ||= component.name
|
|
830
|
-
end
|
|
831
|
-
end
|
|
832
|
-
|
|
833
987
|
def read_coordination_info(info)
|
|
834
|
-
|
|
835
|
-
@coordination_groups = [@components.keys]
|
|
836
|
-
return
|
|
837
|
-
end
|
|
838
|
-
@coordination_groups = Array(info["coordination_groups"])
|
|
988
|
+
@coordination_groups = Array(info.delete("coordination_groups"))
|
|
839
989
|
@coordination_groups = [@coordination_groups] if @coordination_groups.first.is_a?(::String)
|
|
840
990
|
seen = {}
|
|
841
991
|
@coordination_groups.each do |group|
|
|
@@ -849,6 +999,18 @@ module Toys
|
|
|
849
999
|
end
|
|
850
1000
|
end
|
|
851
1001
|
end
|
|
1002
|
+
if info.delete("coordinate_versions") && @coordination_groups.empty?
|
|
1003
|
+
@coordination_groups = [@components.keys]
|
|
1004
|
+
end
|
|
1005
|
+
end
|
|
1006
|
+
|
|
1007
|
+
def check_global_problems(info)
|
|
1008
|
+
info.each_key do |key|
|
|
1009
|
+
@errors << "Unknown top level key #{key.inspect} in releases.yml"
|
|
1010
|
+
end
|
|
1011
|
+
@errors << 'Required key "repo" missing from releases.yml' unless @repo_path
|
|
1012
|
+
@errors << 'Required key "git_user_name" missing from releases.yml' unless @git_user_name
|
|
1013
|
+
@errors << 'Required key "git_user_email" missing from releases.yml' unless @git_user_email
|
|
852
1014
|
end
|
|
853
1015
|
end
|
|
854
1016
|
end
|