kettle-family 1.2.65 → 1.2.67
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
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +33 -1
- data/README.md +59 -14
- data/lib/kettle/family/cli.rb +4 -0
- data/lib/kettle/family/command_result.rb +4 -2
- data/lib/kettle/family/config.rb +32 -0
- data/lib/kettle/family/report.rb +45 -8
- data/lib/kettle/family/version.rb +1 -1
- data/lib/kettle/family/workflow.rb +75 -15
- data.tar.gz.sig +0 -0
- metadata +8 -8
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b6cce9c43c8db0ddb5984da9e0656dd3790a47dc718fa28195716a73d7b84a68
|
|
4
|
+
data.tar.gz: accd2cad6a1265c9c954e9908e6ab22ed02282bd0258c8116da295a9e6bf725f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f9bb56dbb8b43e418441588cd45c904d874086a7f9af349e097aa78a738779e86cef91dadf41e3f5ca0ae99737f717ccda23f0be250944646c247e24a0b3a99a
|
|
7
|
+
data.tar.gz: 45ea1c723af5437ec77d50961d3c0deca340358b2a904961addd8396ec47c28592faeaf68a94badbad8eb69da92b8124db7ad15fdf904fb91b29234830c6481e
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
data/CHANGELOG.md
CHANGED
|
@@ -30,6 +30,34 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
|
30
30
|
|
|
31
31
|
### Security
|
|
32
32
|
|
|
33
|
+
## [1.2.67] - 2026-08-30
|
|
34
|
+
|
|
35
|
+
- TAG: [v1.2.67][1.2.67t]
|
|
36
|
+
- COVERAGE: 93.17% -- 5453/5853 lines in 33 files
|
|
37
|
+
- BRANCH COVERAGE: 76.13% -- 2210/2903 branches in 33 files
|
|
38
|
+
- 30.32% documented
|
|
39
|
+
|
|
40
|
+
### Changed
|
|
41
|
+
|
|
42
|
+
- Add configurable aggregate release validation that runs shared changelog coverage and one monitored CI validation while preserving excluded independent members.
|
|
43
|
+
|
|
44
|
+
- [kc] release-recovery-docs: Clarify direct release recovery from later steps.
|
|
45
|
+
|
|
46
|
+
### Fixed
|
|
47
|
+
|
|
48
|
+
- Emit member-scoped family release recovery commands from failed child release steps.
|
|
49
|
+
|
|
50
|
+
## [1.2.66] - 2026-08-30
|
|
51
|
+
|
|
52
|
+
- TAG: [v1.2.66][1.2.66t]
|
|
53
|
+
- COVERAGE: 93.11% -- 5404/5804 lines in 33 files
|
|
54
|
+
- BRANCH COVERAGE: 76.06% -- 2179/2865 branches in 33 files
|
|
55
|
+
- 30.03% documented
|
|
56
|
+
|
|
57
|
+
### Fixed
|
|
58
|
+
|
|
59
|
+
- Derive monorepo release lockfile path policy from family configuration and keep sibling tool paths opt-in.
|
|
60
|
+
|
|
33
61
|
## [1.2.65] - 2026-08-30
|
|
34
62
|
|
|
35
63
|
- TAG: [v1.2.65][1.2.65t]
|
|
@@ -2279,7 +2307,11 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
|
2279
2307
|
- Fixed CI load failures on engines without compatible `pty` support by falling back to Open3 for interactive release commands.
|
|
2280
2308
|
- Fixed Ruby 3.2 version-bump support by loading Prism lazily and wiring the Prism gem only for MRI versions that need it.
|
|
2281
2309
|
|
|
2282
|
-
[Unreleased]: https://github.com/kettle-dev/kettle-family/compare/v1.2.
|
|
2310
|
+
[Unreleased]: https://github.com/kettle-dev/kettle-family/compare/v1.2.67...HEAD
|
|
2311
|
+
[1.2.67]: https://github.com/kettle-dev/kettle-family/compare/v1.2.66...v1.2.67
|
|
2312
|
+
[1.2.67t]: https://github.com/kettle-dev/kettle-family/releases/tag/v1.2.67
|
|
2313
|
+
[1.2.66]: https://github.com/kettle-dev/kettle-family/compare/v1.2.65...v1.2.66
|
|
2314
|
+
[1.2.66t]: https://github.com/kettle-dev/kettle-family/releases/tag/v1.2.66
|
|
2283
2315
|
[1.2.65]: https://github.com/kettle-dev/kettle-family/compare/v1.2.64...v1.2.65
|
|
2284
2316
|
[1.2.65t]: https://github.com/kettle-dev/kettle-family/releases/tag/v1.2.65
|
|
2285
2317
|
[1.2.64]: https://github.com/kettle-dev/kettle-family/compare/v1.2.63...v1.2.64
|
data/README.md
CHANGED
|
@@ -249,24 +249,37 @@ release:
|
|
|
249
249
|
family_changelog:
|
|
250
250
|
enabled: true
|
|
251
251
|
command: bundle exec kettle-changelog
|
|
252
|
+
aggregate_validation:
|
|
253
|
+
enabled: true
|
|
254
|
+
exclude_members:
|
|
255
|
+
- kettle-jem
|
|
252
256
|
```
|
|
253
257
|
|
|
254
258
|
`family.local_path_env` names the environment variable that activates local
|
|
255
|
-
path dependencies for this family.
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
+
path dependencies for this family. For an explicitly configured
|
|
260
|
+
`family.mode: monorepo`, `kettle-family` derives a release-lock policy that
|
|
261
|
+
allows only `family.members_root` (or the configured member root) and passes
|
|
262
|
+
that policy to each `kettle-release` child. Those paths are valid because the
|
|
263
|
+
same monorepo checkout exists in CI. The tracked `Gemfile.lock` remains a
|
|
264
|
+
development lockfile and may retain those member `PATH` sources.
|
|
265
|
+
|
|
266
|
+
Sibling-repository families do not receive this exception. Their canonical
|
|
267
|
+
lockfiles must use released dependencies: a local Kettle Dev workspace, or
|
|
268
|
+
any other sibling workspace, is never allowed merely because its `*_DEV`
|
|
269
|
+
variable is set. Use `release.allowed_local_path_roots` together with
|
|
270
|
+
`release.allowed_local_path_env` only for an intentionally CI-available path
|
|
271
|
+
layout that cannot be inferred from a monorepo configuration.
|
|
259
272
|
|
|
260
273
|
`release.disable_local_path_env` is different: it is an extra release-lockfile
|
|
261
274
|
normalization shutoff list for path-injecting env vars that are not themselves
|
|
262
275
|
discoverable as family roots, such as vendored parser/tooling paths.
|
|
263
276
|
|
|
264
|
-
`release.local_path_strategy: waves`
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
277
|
+
`release.local_path_strategy: waves` is for sibling families that explicitly
|
|
278
|
+
choose wave-local development resolution. An explicit monorepo instead keeps
|
|
279
|
+
its configured member-root path available throughout its waves, because its
|
|
280
|
+
canonical development lockfile and CI checkout share that path graph. In both
|
|
281
|
+
cases, release normalization rejects every path outside the configured allow
|
|
282
|
+
list.
|
|
270
283
|
|
|
271
284
|
### Release waves and dependency refresh
|
|
272
285
|
|
|
@@ -314,6 +327,29 @@ configured family name and `K_CHANGELOG_VERSION_FILE` when `version_file` is
|
|
|
314
327
|
configured, so `kettle-changelog` can operate from a repository root without a
|
|
315
328
|
root gemspec.
|
|
316
329
|
|
|
330
|
+
### Aggregate release validation
|
|
331
|
+
|
|
332
|
+
Set `release.aggregate_validation.enabled: true` only for a shared-changelog
|
|
333
|
+
family whose root suite validates the release graph. `kettle-family` then:
|
|
334
|
+
|
|
335
|
+
1. Runs `family_changelog` once, which runs the root coverage suite once.
|
|
336
|
+
2. Marks the first selected non-excluded member's release-prep commit as the
|
|
337
|
+
aggregate CI validation and waits for that one CI run.
|
|
338
|
+
3. Skips member changelog generation, the duplicate `bin/rake` test task, and
|
|
339
|
+
remote CI monitoring for the remaining aggregate members.
|
|
340
|
+
|
|
341
|
+
The marker is explicit (`[kettle-family:aggregate-ci]` for the validation
|
|
342
|
+
commit and `[kettle-family:aggregate-member]` for later members), allowing the
|
|
343
|
+
repository workflow to run one root suite for the validation commit and skip
|
|
344
|
+
redundant jobs for later release-only commits. Configure that workflow behavior
|
|
345
|
+
before enabling this policy.
|
|
346
|
+
|
|
347
|
+
Use `release.aggregate_validation.exclude_members` for a member that remains
|
|
348
|
+
independently releasable. Excluded members keep their own changelog coverage,
|
|
349
|
+
local test task, and monitored CI release flow. This is appropriate for a tool
|
|
350
|
+
such as `kettle-jem`, whose independent releases must not rely on a coordinated
|
|
351
|
+
family release having run first.
|
|
352
|
+
|
|
317
353
|
For a flat repository that releases from multiple long-lived branches, list the
|
|
318
354
|
release branches under `release.target_branches`. The branch list is processed
|
|
319
355
|
in order. Each branch must be clean enough for `git checkout`, and each branch
|
|
@@ -346,6 +382,12 @@ metadata fix requires a new full release run from step 0:
|
|
|
346
382
|
kettle-family release --publish --start-step 10 --local-ci
|
|
347
383
|
```
|
|
348
384
|
|
|
385
|
+
`--skip-changelog` skips only `kettle-changelog`; `--skip-appraisals` skips
|
|
386
|
+
only the Appraisal generation portion of release step 5 and still runs
|
|
387
|
+
`bin/rake yard`; and `--skip-ci` skips only remote CI monitoring. The generic
|
|
388
|
+
`--skip-steps LIST` remains available when a numbered release step is the
|
|
389
|
+
intended boundary.
|
|
390
|
+
|
|
349
391
|
Executed publish runs skip versions that are already published. CI failures
|
|
350
392
|
abort by default; pass `--continue-ci-failures` to set
|
|
351
393
|
`K_RELEASE_CI_CONTINUE=true` for the underlying `kettle-release` process.
|
|
@@ -639,9 +681,12 @@ Executed family resets fail if the resulting lockfiles still contain sibling
|
|
|
639
681
|
path remotes or checksum gaps.
|
|
640
682
|
|
|
641
683
|
Resume a failed family publish after fixing the failure. Already published
|
|
642
|
-
versions are skipped automatically
|
|
643
|
-
for
|
|
644
|
-
|
|
684
|
+
versions are skipped automatically. A release report gives a member-scoped
|
|
685
|
+
resume command for each failed child, including the recorded `--start-step`
|
|
686
|
+
when the child emitted a failed release-step event. Run those commands one at a
|
|
687
|
+
time. If any members were never started, the report also gives a separate
|
|
688
|
+
normal-flow command for exactly those members. Use `--start-step` only after
|
|
689
|
+
the pre-release gate already passed or the failure was intentionally handled:
|
|
645
690
|
|
|
646
691
|
```console
|
|
647
692
|
kettle-family release --publish --execute --start-step 10
|
|
@@ -986,7 +1031,7 @@ Thanks for RTFM. ☺️
|
|
|
986
1031
|
[📌gitmoji]: https://gitmoji.dev
|
|
987
1032
|
[📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
|
|
988
1033
|
[🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
|
|
989
|
-
[🧮kloc-img]: https://img.shields.io/badge/KLOC-5.
|
|
1034
|
+
[🧮kloc-img]: https://img.shields.io/badge/KLOC-5.853-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
|
|
990
1035
|
[🔐security]: https://github.com/kettle-dev/kettle-family/blob/main/SECURITY.md
|
|
991
1036
|
[🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
|
|
992
1037
|
[📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
|
data/lib/kettle/family/cli.rb
CHANGED
|
@@ -164,6 +164,7 @@ module Kettle
|
|
|
164
164
|
release_fast_recovery_members: nil,
|
|
165
165
|
release_skip_ci: false,
|
|
166
166
|
release_skip_changelog: false,
|
|
167
|
+
release_skip_appraisals: false,
|
|
167
168
|
release_local_ci: false,
|
|
168
169
|
release_continue_ci_failures: false,
|
|
169
170
|
release_ci_workflows: nil,
|
|
@@ -537,6 +538,7 @@ module Kettle
|
|
|
537
538
|
option :fast_recovery_members, long: "--fast-recovery-members", value: {type: String, usage: "MEMBERS"}, desc: "Limit fast recovery to selected comma-separated members; defaults to all selected members"
|
|
538
539
|
option :skip_ci, long: "--skip-ci", desc: "Run every selected member from step 0 while skipping only remote CI monitoring; requires --publish"
|
|
539
540
|
option :skip_changelog, long: "--skip-changelog", desc: "Run release checks and child releases while skipping kettle-changelog"
|
|
541
|
+
option :skip_appraisals, long: "--skip-appraisals", desc: "Skip appraisal generation while retaining documentation generation"
|
|
540
542
|
option :local_ci, long: "--local-ci", desc: "Pass --local-ci through to kettle-release commands"
|
|
541
543
|
option :continue_ci_failures, long: "--continue-ci-failures", desc: "Set K_RELEASE_CI_CONTINUE=true for release commands"
|
|
542
544
|
option :ci_workflows, long: "--ci-workflows", value: {type: String, usage: "LIST"}, desc: "Pass a comma-separated CI workflow monitor subset through to kettle-release commands"
|
|
@@ -566,6 +568,7 @@ module Kettle
|
|
|
566
568
|
release_fast_recovery_members: options[:fast_recovery_members],
|
|
567
569
|
release_skip_ci: truthy_option?(:skip_ci),
|
|
568
570
|
release_skip_changelog: truthy_option?(:skip_changelog),
|
|
571
|
+
release_skip_appraisals: truthy_option?(:skip_appraisals),
|
|
569
572
|
release_local_ci: truthy_option?(:local_ci),
|
|
570
573
|
release_continue_ci_failures: truthy_option?(:continue_ci_failures),
|
|
571
574
|
release_ci_workflows: options[:ci_workflows],
|
|
@@ -844,6 +847,7 @@ module Kettle
|
|
|
844
847
|
fast_recovery_members: options[:release_fast_recovery_members],
|
|
845
848
|
skip_ci: options[:release_skip_ci],
|
|
846
849
|
skip_changelog: options[:release_skip_changelog],
|
|
850
|
+
skip_appraisals: options[:release_skip_appraisals],
|
|
847
851
|
local_ci: options[:release_local_ci],
|
|
848
852
|
continue_ci_failures: options[:release_continue_ci_failures],
|
|
849
853
|
ci_workflows: options[:release_ci_workflows],
|
|
@@ -16,7 +16,8 @@ module Kettle
|
|
|
16
16
|
:reason,
|
|
17
17
|
:branch,
|
|
18
18
|
:output_streamed,
|
|
19
|
-
:log_path
|
|
19
|
+
:log_path,
|
|
20
|
+
:resume_step
|
|
20
21
|
) do
|
|
21
22
|
def to_h
|
|
22
23
|
{
|
|
@@ -33,7 +34,8 @@ module Kettle
|
|
|
33
34
|
"skipped" => skipped,
|
|
34
35
|
"reason" => reason,
|
|
35
36
|
"output_streamed" => output_streamed?,
|
|
36
|
-
"log_path" => log_path
|
|
37
|
+
"log_path" => log_path,
|
|
38
|
+
"resume_step" => resume_step
|
|
37
39
|
}
|
|
38
40
|
end
|
|
39
41
|
|
data/lib/kettle/family/config.rb
CHANGED
|
@@ -266,6 +266,23 @@ module Kettle
|
|
|
266
266
|
fetch_path("release", "local_path_strategy").to_s
|
|
267
267
|
end
|
|
268
268
|
|
|
269
|
+
def release_allowed_local_path_roots
|
|
270
|
+
inferred = configured_monorepo_release? ? [family_local_path_root] : []
|
|
271
|
+
configured = Array(fetch_path("release", "allowed_local_path_roots"))
|
|
272
|
+
.map { |path| expand_config_relative_path(path) }
|
|
273
|
+
(inferred + configured).uniq
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
def release_allowed_local_path_env_names
|
|
277
|
+
inferred = configured_monorepo_release? ? [family_local_path_env_name] : []
|
|
278
|
+
configured = Array(fetch_path("release", "allowed_local_path_env"))
|
|
279
|
+
(inferred + configured).compact.map(&:to_s).reject(&:empty?).uniq
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
def configured_monorepo_release?
|
|
283
|
+
fetch_path("family", "mode") == "monorepo"
|
|
284
|
+
end
|
|
285
|
+
|
|
269
286
|
def release_secrets
|
|
270
287
|
stringify_keys(fetch_path("release", "secrets") || {})
|
|
271
288
|
end
|
|
@@ -296,6 +313,21 @@ module Kettle
|
|
|
296
313
|
fetch_path("release", "family_changelog", "command") || "bundle exec kettle-changelog"
|
|
297
314
|
end
|
|
298
315
|
|
|
316
|
+
# An aggregate validation release runs the shared changelog/coverage
|
|
317
|
+
# suite once locally, then validates that family state once in CI before
|
|
318
|
+
# publishing the remaining members. Excluded members retain their normal
|
|
319
|
+
# independent kettle-release test and CI lifecycle.
|
|
320
|
+
def release_aggregate_validation?
|
|
321
|
+
fetch_path("release", "aggregate_validation", "enabled") == true
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
def release_aggregate_validation_excluded_members
|
|
325
|
+
Array(fetch_path("release", "aggregate_validation", "exclude_members"))
|
|
326
|
+
.map(&:to_s)
|
|
327
|
+
.map(&:strip)
|
|
328
|
+
.reject(&:empty?)
|
|
329
|
+
end
|
|
330
|
+
|
|
299
331
|
def release_tag_command
|
|
300
332
|
fetch_path("release", "tag_command") || command_for("release_tag") || "git tag"
|
|
301
333
|
end
|
data/lib/kettle/family/report.rb
CHANGED
|
@@ -67,7 +67,8 @@ module Kettle
|
|
|
67
67
|
"command" => command,
|
|
68
68
|
"results" => results.map(&:to_h),
|
|
69
69
|
"summary" => summary,
|
|
70
|
-
"resume_hint" => resume_hint
|
|
70
|
+
"resume_hint" => resume_hint,
|
|
71
|
+
"resume_hints" => resume_hints
|
|
71
72
|
}
|
|
72
73
|
end
|
|
73
74
|
|
|
@@ -145,7 +146,13 @@ module Kettle
|
|
|
145
146
|
lines << " skipped: #{summary_list(data.fetch("skipped"))}"
|
|
146
147
|
lines << " failed: #{summary_list(data.fetch("failed").map { |entry| summary_entry(entry) })}"
|
|
147
148
|
lines << " pending: #{summary_list(data.fetch("pending").map { |entry| summary_entry(entry) })}"
|
|
148
|
-
|
|
149
|
+
hints = data.fetch("resume_hints")
|
|
150
|
+
if hints.one?
|
|
151
|
+
lines << " resume: #{hints.first}"
|
|
152
|
+
elsif hints.any?
|
|
153
|
+
lines << " resume:"
|
|
154
|
+
hints.each { |hint| lines << " #{hint}" }
|
|
155
|
+
end
|
|
149
156
|
end
|
|
150
157
|
|
|
151
158
|
def report_context_lines
|
|
@@ -170,7 +177,8 @@ module Kettle
|
|
|
170
177
|
"failed" => summary_failed,
|
|
171
178
|
"pending" => summary_pending,
|
|
172
179
|
"release_log_dirs" => release_log_dirs,
|
|
173
|
-
"resume_hint" => resume_hint
|
|
180
|
+
"resume_hint" => resume_hint,
|
|
181
|
+
"resume_hints" => resume_hints
|
|
174
182
|
}
|
|
175
183
|
end
|
|
176
184
|
|
|
@@ -661,21 +669,50 @@ module Kettle
|
|
|
661
669
|
end
|
|
662
670
|
|
|
663
671
|
def resume_hint
|
|
672
|
+
resume_hints.first
|
|
673
|
+
end
|
|
674
|
+
|
|
675
|
+
def resume_hints
|
|
676
|
+
return [] if success?
|
|
677
|
+
return non_release_resume_hints unless command == "release"
|
|
678
|
+
|
|
679
|
+
release_resume_hints
|
|
680
|
+
end
|
|
681
|
+
|
|
682
|
+
def non_release_resume_hints
|
|
664
683
|
failed = results.find { |result| !result.ok? }
|
|
665
|
-
resume_hint_for(failed)
|
|
684
|
+
failed ? [resume_hint_for(failed)] : []
|
|
685
|
+
end
|
|
686
|
+
|
|
687
|
+
def release_resume_hints
|
|
688
|
+
failed_hints = visible_results.reject(&:ok?).map { |result| resume_hint_for(result) }.uniq
|
|
689
|
+
pending_names = summary_pending.map { |entry| entry.fetch("member") }
|
|
690
|
+
return failed_hints if pending_names.empty?
|
|
691
|
+
|
|
692
|
+
[*failed_hints, release_resume_hint_for_pending(pending_names)]
|
|
666
693
|
end
|
|
667
694
|
|
|
668
695
|
def resume_hint_for(result)
|
|
669
|
-
return release_resume_hint if command == "release"
|
|
696
|
+
return release_resume_hint(result) if command == "release"
|
|
670
697
|
|
|
671
698
|
"kettle-family #{command} --start-at #{result.member_name}"
|
|
672
699
|
end
|
|
673
700
|
|
|
674
|
-
def release_resume_hint
|
|
675
|
-
hint =
|
|
676
|
-
hint = "#{hint} --
|
|
701
|
+
def release_resume_hint(result)
|
|
702
|
+
hint = release_resume_base
|
|
703
|
+
hint = "#{hint} --only #{result.member_name}" if result.member_name
|
|
704
|
+
hint = "#{hint} --start-step #{result.resume_step}" if result.respond_to?(:resume_step) && result.resume_step
|
|
677
705
|
hint
|
|
678
706
|
end
|
|
707
|
+
|
|
708
|
+
def release_resume_hint_for_pending(member_names)
|
|
709
|
+
"#{release_resume_base} --only #{member_names.join(",")}"
|
|
710
|
+
end
|
|
711
|
+
|
|
712
|
+
def release_resume_base
|
|
713
|
+
hint = "kettle-family release --execute"
|
|
714
|
+
(release_mode == "publish") ? "#{hint} --publish" : hint
|
|
715
|
+
end
|
|
679
716
|
end
|
|
680
717
|
end
|
|
681
718
|
end
|
|
@@ -5,7 +5,7 @@ module Kettle
|
|
|
5
5
|
# Version namespace for this gem.
|
|
6
6
|
module Version
|
|
7
7
|
# Current gem version.
|
|
8
|
-
VERSION = "1.2.
|
|
8
|
+
VERSION = "1.2.67"
|
|
9
9
|
end
|
|
10
10
|
# Current gem version exposed at the traditional constant location.
|
|
11
11
|
VERSION = Version::VERSION # Traditional Constant Location
|
|
@@ -106,7 +106,7 @@ module Kettle
|
|
|
106
106
|
REGISTRY_WAIT_ATTEMPTS = 15
|
|
107
107
|
REGISTRY_WAIT_INTERVAL_SECONDS = 15
|
|
108
108
|
|
|
109
|
-
def initialize(command:, config:, members:, family_members: nil, execute: false, accept: true, commit: true, allow_dirty: false, autostash: true, template_cleanup: true, publish: false, push: false, tag: false, start_step: nil, skip_steps: nil, fast_recovery: nil, fast_recovery_members: nil, skip_ci: false, skip_changelog: false, local_ci: false, continue_ci_failures: false, ci_workflows: nil, skip_bundle_audit: false, skip_remotes: nil, required_remotes: nil, auto_dependency_floors: nil, validate_ci_bundles: nil, gha_sha_pins_upgrade: "patch", gha_sha_pins_check: false, gha_sha_pins_ttl_days: nil, env_overrides: {}, debug: false, verbose: false, gem_signing_password: nil, secrets_provider: nil, jobs: nil, progress_io: nil, reset_target: nil, bup_args: [], bex_args: [], start_member: nil, start_branch: nil, **options)
|
|
109
|
+
def initialize(command:, config:, members:, family_members: nil, execute: false, accept: true, commit: true, allow_dirty: false, autostash: true, template_cleanup: true, publish: false, push: false, tag: false, start_step: nil, skip_steps: nil, fast_recovery: nil, fast_recovery_members: nil, skip_ci: false, skip_changelog: false, skip_appraisals: false, local_ci: false, continue_ci_failures: false, ci_workflows: nil, skip_bundle_audit: false, skip_remotes: nil, required_remotes: nil, auto_dependency_floors: nil, validate_ci_bundles: nil, gha_sha_pins_upgrade: "patch", gha_sha_pins_check: false, gha_sha_pins_ttl_days: nil, env_overrides: {}, debug: false, verbose: false, gem_signing_password: nil, secrets_provider: nil, jobs: nil, progress_io: nil, reset_target: nil, bup_args: [], bex_args: [], start_member: nil, start_branch: nil, **options)
|
|
110
110
|
@command = command
|
|
111
111
|
@config = config
|
|
112
112
|
@members = members
|
|
@@ -136,6 +136,7 @@ module Kettle
|
|
|
136
136
|
@fast_recovery_members = normalize_fast_recovery_members(fast_recovery_members)
|
|
137
137
|
@skip_ci = !!skip_ci
|
|
138
138
|
@skip_changelog = !!skip_changelog
|
|
139
|
+
@skip_appraisals = !!skip_appraisals
|
|
139
140
|
@local_ci = local_ci
|
|
140
141
|
@continue_ci_failures = continue_ci_failures
|
|
141
142
|
@ci_workflows = validate_ci_workflows(ci_workflows)
|
|
@@ -205,7 +206,7 @@ module Kettle
|
|
|
205
206
|
execute && release_command_delegates_secrets_to_kettle_release?
|
|
206
207
|
end
|
|
207
208
|
|
|
208
|
-
attr_reader :command, :config, :members, :family_members, :execute, :accept, :commit, :allow_dirty, :autostash, :template_cleanup, :publish, :push, :tag, :start_step, :skip_steps, :fast_recovery, :fast_recovery_members, :skip_ci, :skip_changelog, :local_ci, :continue_ci_failures, :ci_workflows, :skip_bundle_audit, :skip_remotes, :required_remotes, :auto_dependency_floors, :validate_ci_bundles, :gha_sha_pins_upgrade, :gha_sha_pins_check, :gha_sha_pins_ttl_days, :env_overrides, :debug, :verbose, :jobs, :progress_io, :reset_target, :bup_args, :bex_args, :start_member, :start_branch
|
|
209
|
+
attr_reader :command, :config, :members, :family_members, :execute, :accept, :commit, :allow_dirty, :autostash, :template_cleanup, :publish, :push, :tag, :start_step, :skip_steps, :fast_recovery, :fast_recovery_members, :skip_ci, :skip_changelog, :skip_appraisals, :local_ci, :continue_ci_failures, :ci_workflows, :skip_bundle_audit, :skip_remotes, :required_remotes, :auto_dependency_floors, :validate_ci_bundles, :gha_sha_pins_upgrade, :gha_sha_pins_check, :gha_sha_pins_ttl_days, :env_overrides, :debug, :verbose, :jobs, :progress_io, :reset_target, :bup_args, :bex_args, :start_member, :start_branch
|
|
209
210
|
|
|
210
211
|
def template_with_worktree_sync_results
|
|
211
212
|
runner = command_runner
|
|
@@ -1219,6 +1220,7 @@ module Kettle
|
|
|
1219
1220
|
runner = release_command_runner
|
|
1220
1221
|
results = []
|
|
1221
1222
|
@release_completed_member_names = []
|
|
1223
|
+
@aggregate_validation_member_name = aggregate_validation_members(release_members).first&.name
|
|
1222
1224
|
append_family_changelog_result(runner: runner, memo: results) if include_family_changelog
|
|
1223
1225
|
return results unless results.all?(&:ok?)
|
|
1224
1226
|
return parallel_release_member_results(release_members, results) if parallel_release_members?(release_members)
|
|
@@ -1376,16 +1378,18 @@ module Kettle
|
|
|
1376
1378
|
memo.last(2).each { |result| emit_member_result_progress(member, result, progress: progress) }
|
|
1377
1379
|
return memo unless memo.last(2).all?(&:ok?)
|
|
1378
1380
|
|
|
1381
|
+
release_event_state = {}
|
|
1379
1382
|
release_result = runner.call(
|
|
1380
1383
|
member: member,
|
|
1381
1384
|
phase: release_phase,
|
|
1382
1385
|
command: release_command_for(member),
|
|
1383
1386
|
env: release_env_for_member(member),
|
|
1384
1387
|
interactive: release_command_interactive?,
|
|
1385
|
-
stdout_line_handler: release_event_line_handler(member, progress: progress),
|
|
1388
|
+
stdout_line_handler: release_event_line_handler(member, progress: progress, state: release_event_state),
|
|
1386
1389
|
log_path: release_command_log_path(member, release_phase),
|
|
1387
1390
|
passthrough_output: release_command_passthrough_output?
|
|
1388
1391
|
)
|
|
1392
|
+
release_result.resume_step = release_event_state[:failed_step] unless release_result.ok?
|
|
1389
1393
|
memo << release_result
|
|
1390
1394
|
emit_member_result_progress(member, memo.last, progress: progress)
|
|
1391
1395
|
return memo unless memo.last.ok?
|
|
@@ -2222,7 +2226,8 @@ module Kettle
|
|
|
2222
2226
|
effective_skip_steps = release_skip_steps_for(member)
|
|
2223
2227
|
args << "start_step=#{effective_start_step}" if effective_start_step
|
|
2224
2228
|
args << "skip_steps=#{effective_skip_steps}" unless effective_skip_steps.empty?
|
|
2225
|
-
args << "--skip-changelog" if skip_changelog
|
|
2229
|
+
args << "--skip-changelog" if skip_changelog || aggregate_validation_member?(member)
|
|
2230
|
+
args << "--skip-appraisals" if skip_appraisals
|
|
2226
2231
|
args << "--ci-workflows=#{ci_workflows}" if ci_workflows && !ci_workflows.to_s.empty?
|
|
2227
2232
|
args << "--local-ci" if local_ci
|
|
2228
2233
|
args << "--skip-bundle-audit" if skip_bundle_audit
|
|
@@ -2245,12 +2250,37 @@ module Kettle
|
|
|
2245
2250
|
(fast_recovery == "retry-ci") ? 10 : 11
|
|
2246
2251
|
end
|
|
2247
2252
|
|
|
2248
|
-
def release_skip_steps_for(
|
|
2253
|
+
def release_skip_steps_for(member)
|
|
2249
2254
|
steps = Array(skip_steps).flat_map { |entry| entry.to_s.split(",") }.map(&:strip).reject(&:empty?)
|
|
2250
2255
|
steps << "10" if skip_ci
|
|
2256
|
+
if aggregate_validation_member?(member)
|
|
2257
|
+
# The shared family changelog already ran the full local suite. The
|
|
2258
|
+
# validation member waits for the one aggregate CI run; all later
|
|
2259
|
+
# aggregate members publish without duplicate test/monitor phases.
|
|
2260
|
+
steps << "4"
|
|
2261
|
+
steps << "10" unless aggregate_validation_member_name?(member)
|
|
2262
|
+
end
|
|
2251
2263
|
steps.uniq.join(",")
|
|
2252
2264
|
end
|
|
2253
2265
|
|
|
2266
|
+
def aggregate_validation_members(release_members = members)
|
|
2267
|
+
return [] unless config.release_aggregate_validation?
|
|
2268
|
+
return [] unless config.shared_changelog?
|
|
2269
|
+
|
|
2270
|
+
excluded = config.release_aggregate_validation_excluded_members
|
|
2271
|
+
Array(release_members).reject { |member| excluded.include?(member.name) }
|
|
2272
|
+
end
|
|
2273
|
+
|
|
2274
|
+
def aggregate_validation_member?(member)
|
|
2275
|
+
return false unless member
|
|
2276
|
+
|
|
2277
|
+
aggregate_validation_members.include?(member)
|
|
2278
|
+
end
|
|
2279
|
+
|
|
2280
|
+
def aggregate_validation_member_name?(member)
|
|
2281
|
+
member && member.name == (@aggregate_validation_member_name || aggregate_validation_members.first&.name)
|
|
2282
|
+
end
|
|
2283
|
+
|
|
2254
2284
|
def fast_recovery_for?(member)
|
|
2255
2285
|
return false unless fast_recovery
|
|
2256
2286
|
return false unless member
|
|
@@ -2349,6 +2379,7 @@ module Kettle
|
|
|
2349
2379
|
def release_env_for_member(member)
|
|
2350
2380
|
env = release_env
|
|
2351
2381
|
env.merge!(release_wave_local_path_env_for(member))
|
|
2382
|
+
env.merge!(release_local_path_policy_env)
|
|
2352
2383
|
# Family release performs one live pin review before member releases.
|
|
2353
2384
|
# Child kettle-release must consume that reviewed cache instead of
|
|
2354
2385
|
# repeating the GitHub API lookup for every member.
|
|
@@ -2376,6 +2407,9 @@ module Kettle
|
|
|
2376
2407
|
# GitHub Release.
|
|
2377
2408
|
env["KETTLE_RELEASE_SKIP_GITHUB_RELEASE"] = "true" if aggregate_monorepo_github_release?
|
|
2378
2409
|
end
|
|
2410
|
+
if aggregate_validation_member?(member)
|
|
2411
|
+
env["KETTLE_RELEASE_FAMILY_CI_MODE"] = aggregate_validation_member_name?(member) ? "validation" : "member"
|
|
2412
|
+
end
|
|
2379
2413
|
return env unless config.shared_changelog?
|
|
2380
2414
|
if config.member_local_changelog?(member)
|
|
2381
2415
|
return env.merge(
|
|
@@ -2412,6 +2446,14 @@ module Kettle
|
|
|
2412
2446
|
# already treated as registry dependencies; this is what makes resume
|
|
2413
2447
|
# runs work after an earlier wave has been published.
|
|
2414
2448
|
def release_wave_local_path_env_for(member)
|
|
2449
|
+
# Monorepo members and their sibling dependencies share the same CI
|
|
2450
|
+
# checkout, so their canonical development lockfile may keep those
|
|
2451
|
+
# paths throughout every release wave.
|
|
2452
|
+
if config.configured_monorepo_release?
|
|
2453
|
+
env_name = config.family_local_path_env_name
|
|
2454
|
+
return env_name ? {env_name => config.family_local_path_root} : {}
|
|
2455
|
+
end
|
|
2456
|
+
|
|
2415
2457
|
return {} unless config.release_local_path_strategy == "waves"
|
|
2416
2458
|
|
|
2417
2459
|
env_name = config.family_local_path_env_name
|
|
@@ -3232,11 +3274,15 @@ module Kettle
|
|
|
3232
3274
|
end
|
|
3233
3275
|
end
|
|
3234
3276
|
|
|
3235
|
-
def release_event_line_handler(member, progress: nil)
|
|
3277
|
+
def release_event_line_handler(member, progress: nil, state: nil)
|
|
3236
3278
|
lambda do |line|
|
|
3237
3279
|
event = parse_template_event(line)
|
|
3238
3280
|
next false unless event
|
|
3239
3281
|
|
|
3282
|
+
if event["type"] == "command_step" && event["phase"] == "release" && event["status"] == "failed"
|
|
3283
|
+
state[:failed_step] = event["index"].to_i if state && event["index"].to_s.match?(/\A\d+\z/)
|
|
3284
|
+
end
|
|
3285
|
+
|
|
3240
3286
|
if progress_io
|
|
3241
3287
|
if suppress_release_secret_provider_event?(event, progress: progress)
|
|
3242
3288
|
next true
|
|
@@ -4034,15 +4080,22 @@ module Kettle
|
|
|
4034
4080
|
end
|
|
4035
4081
|
|
|
4036
4082
|
def release_allowed_local_path_roots
|
|
4037
|
-
|
|
4038
|
-
|
|
4039
|
-
release_local_path_env_detection_sources.filter_map do |key, value|
|
|
4040
|
-
next unless key.end_with?("_LOCAL", "_DEV")
|
|
4041
|
-
next unless local_path_env_value?(value)
|
|
4042
|
-
next unless value.to_s.strip.start_with?("/", "./", "../", "~")
|
|
4083
|
+
config.release_allowed_local_path_roots
|
|
4084
|
+
end
|
|
4043
4085
|
|
|
4044
|
-
|
|
4045
|
-
|
|
4086
|
+
def release_allowed_local_path_env_names
|
|
4087
|
+
config.release_allowed_local_path_env_names
|
|
4088
|
+
end
|
|
4089
|
+
|
|
4090
|
+
def release_local_path_policy_env
|
|
4091
|
+
roots = release_allowed_local_path_roots
|
|
4092
|
+
env_names = release_allowed_local_path_env_names
|
|
4093
|
+
return {} if roots.empty? && env_names.empty?
|
|
4094
|
+
|
|
4095
|
+
{
|
|
4096
|
+
"KETTLE_RELEASE_ALLOWED_LOCAL_PATH_ROOTS" => roots.join(File::PATH_SEPARATOR),
|
|
4097
|
+
"KETTLE_RELEASE_ALLOWED_LOCAL_PATH_ENVS" => env_names.join(",")
|
|
4098
|
+
}
|
|
4046
4099
|
end
|
|
4047
4100
|
|
|
4048
4101
|
def release_lockfile_local_path_env_overrides(member = nil)
|
|
@@ -4051,11 +4104,18 @@ module Kettle
|
|
|
4051
4104
|
key = key.to_s
|
|
4052
4105
|
next unless key.end_with?("_LOCAL", "_DEV")
|
|
4053
4106
|
next unless local_path_env_value?(value)
|
|
4107
|
+
next if release_allowed_local_path_env_names.include?(key)
|
|
4054
4108
|
|
|
4055
4109
|
memo[key] = "false"
|
|
4056
4110
|
end
|
|
4057
4111
|
inferred = member ? release_lockfile_inferred_local_path_env(member).to_h { |key| [key, "false"] } : {}
|
|
4058
|
-
explicit.merge(derived).merge(inferred)
|
|
4112
|
+
explicit.merge(derived).merge(inferred).merge(release_member_local_path_env(member))
|
|
4113
|
+
end
|
|
4114
|
+
|
|
4115
|
+
def release_member_local_path_env(member)
|
|
4116
|
+
return {} unless config.configured_monorepo_release?
|
|
4117
|
+
|
|
4118
|
+
release_wave_local_path_env_for(member)
|
|
4059
4119
|
end
|
|
4060
4120
|
|
|
4061
4121
|
def release_lockfile_inferred_local_path_env(member)
|
data.tar.gz.sig
CHANGED
|
Binary file
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: kettle-family
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.2.
|
|
4
|
+
version: 1.2.67
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Peter H. Boling
|
|
@@ -74,7 +74,7 @@ dependencies:
|
|
|
74
74
|
version: '1.0'
|
|
75
75
|
- - ">="
|
|
76
76
|
- !ruby/object:Gem::Version
|
|
77
|
-
version: 1.0.
|
|
77
|
+
version: 1.0.7
|
|
78
78
|
type: :runtime
|
|
79
79
|
prerelease: false
|
|
80
80
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -84,14 +84,14 @@ dependencies:
|
|
|
84
84
|
version: '1.0'
|
|
85
85
|
- - ">="
|
|
86
86
|
- !ruby/object:Gem::Version
|
|
87
|
-
version: 1.0.
|
|
87
|
+
version: 1.0.7
|
|
88
88
|
- !ruby/object:Gem::Dependency
|
|
89
89
|
name: kettle-dev
|
|
90
90
|
requirement: !ruby/object:Gem::Requirement
|
|
91
91
|
requirements:
|
|
92
92
|
- - ">="
|
|
93
93
|
- !ruby/object:Gem::Version
|
|
94
|
-
version: 3.0.
|
|
94
|
+
version: 3.0.22
|
|
95
95
|
- - "<"
|
|
96
96
|
- !ruby/object:Gem::Version
|
|
97
97
|
version: 4.0.0
|
|
@@ -101,7 +101,7 @@ dependencies:
|
|
|
101
101
|
requirements:
|
|
102
102
|
- - ">="
|
|
103
103
|
- !ruby/object:Gem::Version
|
|
104
|
-
version: 3.0.
|
|
104
|
+
version: 3.0.22
|
|
105
105
|
- - "<"
|
|
106
106
|
- !ruby/object:Gem::Version
|
|
107
107
|
version: 4.0.0
|
|
@@ -441,10 +441,10 @@ licenses:
|
|
|
441
441
|
- AGPL-3.0-only
|
|
442
442
|
metadata:
|
|
443
443
|
homepage_uri: https://kettle-family.galtzo.com
|
|
444
|
-
source_code_uri: https://github.com/kettle-dev/kettle-family/tree/v1.2.
|
|
445
|
-
changelog_uri: https://github.com/kettle-dev/kettle-family/blob/v1.2.
|
|
444
|
+
source_code_uri: https://github.com/kettle-dev/kettle-family/tree/v1.2.67
|
|
445
|
+
changelog_uri: https://github.com/kettle-dev/kettle-family/blob/v1.2.67/CHANGELOG.md
|
|
446
446
|
bug_tracker_uri: https://github.com/kettle-dev/kettle-family/issues
|
|
447
|
-
documentation_uri: https://www.rubydoc.info/gems/kettle-family/1.2.
|
|
447
|
+
documentation_uri: https://www.rubydoc.info/gems/kettle-family/1.2.67
|
|
448
448
|
funding_uri: https://github.com/sponsors/pboling
|
|
449
449
|
wiki_uri: https://github.com/kettle-dev/kettle-family/wiki
|
|
450
450
|
news_uri: https://www.railsbling.com/tags/kettle-family
|
metadata.gz.sig
CHANGED
|
Binary file
|