kettle-family 1.3.35 → 1.3.37
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 +49 -1
- data/README.md +5 -5
- data/lib/kettle/family/cli.rb +19 -2
- data/lib/kettle/family/config.rb +29 -0
- data/lib/kettle/family/release_state_check.rb +34 -18
- data/lib/kettle/family/report.rb +15 -6
- data/lib/kettle/family/version.rb +1 -1
- data/lib/kettle/family/version_bump.rb +42 -6
- data/lib/kettle/family/workflow.rb +157 -8
- data.tar.gz.sig +0 -0
- metadata +36 -16
- 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: b5f2d0bb8696a55925ff46bffa665da140b2f861e47eab151769c9522d160385
|
|
4
|
+
data.tar.gz: e64870163a6fa68862654f72c68ba492382fb8e637d9d1b91c9fb92f4c73dfb5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 940c6a65b81be4855325eae21951069520d5ac8ae0e1385e5f31d0060256ce4aed0a81c2baa2e9ec335f010119d0ebdb211d113297c6b7620a5884da637acac5
|
|
7
|
+
data.tar.gz: 896a7fed86b1e22518425858c99720c93ae1740b5b1cc32eb7639212fc691313ae9e619dfb3c7c60186454f32ff4624f02427feda30137e860b6545a40e05666
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
data/CHANGELOG.md
CHANGED
|
@@ -30,6 +30,50 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
|
30
30
|
|
|
31
31
|
### Security
|
|
32
32
|
|
|
33
|
+
## [1.3.37] - 2026-10-30
|
|
34
|
+
|
|
35
|
+
- TAG: [v1.3.37][1.3.37t]
|
|
36
|
+
- COVERAGE: 93.13% -- 7665/8230 lines in 45 files
|
|
37
|
+
- BRANCH COVERAGE: 77.52% -- 3076/3968 branches in 45 files
|
|
38
|
+
- 39.41% documented
|
|
39
|
+
|
|
40
|
+
### Added
|
|
41
|
+
|
|
42
|
+
- Release preflight now blocks on bootstrap dependency drift: a new `bootstrap dependency drift` phase compares each selected member's committed Gemfile.lock against the newest published version satisfying the member's declared floor for bootstrap-managed gems (`release.drift_check.gems`, default `[nomono]`), failing with a `bundle update <gem>` / family template sweep remediation hint; registry lookup failures skip non-fatally instead of blocking.
|
|
43
|
+
|
|
44
|
+
- New family config release.version_series.independent_members: members that keep their own monotonic version series in a shared-version family. They are skipped by lockstep shared-version raises and exempt from the aggregate GitHub Release same-version invariant, while their built artifacts still attach to the aggregate release.
|
|
45
|
+
|
|
46
|
+
### Fixed
|
|
47
|
+
|
|
48
|
+
- kettle-family bump now raises shared-changelog members to the family's next shared version when their release is pending, including a misaligned cohort that previously only aligned to the current maximum and reported ok, leaving the unreleased-entries bump gate uncleared with no documented command able to clear it (#17).
|
|
49
|
+
|
|
50
|
+
- Independently versioned members (release.version_series.independent_members) can no longer be captured by the lockstep shared-version raise: they bump on their own series, are never force-marked pending by the shared cohort, their higher own-series version no longer drags the cohort line, and the aggregate GitHub Release no longer fails its same-version check on them (#18).
|
|
51
|
+
|
|
52
|
+
### Security
|
|
53
|
+
|
|
54
|
+
- Generated resume commands no longer embed secret env values: secret-shaped keys (at minimum `KETTLE_RELEASE_GEM_SIGNING_PASSPHRASE`) are redacted to the shell-safe placeholder `<redacted-reauthorize>`; re-authorize the secret through the release secrets provider (1Password or the `KETTLE_RELEASE_SECRETS_BROKER` cache), or paste the real value over the placeholder, before resuming.
|
|
55
|
+
|
|
56
|
+
## [1.3.36] - 2026-10-28
|
|
57
|
+
|
|
58
|
+
- TAG: [v1.3.36][1.3.36t]
|
|
59
|
+
- COVERAGE: 93.12% -- 7601/8163 lines in 45 files
|
|
60
|
+
- BRANCH COVERAGE: 77.34% -- 3041/3932 branches in 45 files
|
|
61
|
+
- 38.89% documented
|
|
62
|
+
|
|
63
|
+
### Changed
|
|
64
|
+
|
|
65
|
+
- [kc] template-family-resume-hints: Template failures now produce one combined retry hint for failed and pending members, preserving member@branch selectors for branch-stack templates.
|
|
66
|
+
|
|
67
|
+
- [kc] kettle-jem/prepare: updated 7 project files:
|
|
68
|
+
- configuration (1)
|
|
69
|
+
- dependencies (6)
|
|
70
|
+
|
|
71
|
+
- [kc] kettle-jem/template: updated 5 project files:
|
|
72
|
+
- code and tests (1)
|
|
73
|
+
- documentation (1)
|
|
74
|
+
- other (2)
|
|
75
|
+
- workflows (1)
|
|
76
|
+
|
|
33
77
|
## [1.3.35] - 2026-10-26
|
|
34
78
|
|
|
35
79
|
- TAG: [v1.3.35][1.3.35t]
|
|
@@ -3299,7 +3343,11 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
|
3299
3343
|
- Fixed CI load failures on engines without compatible `pty` support by falling back to Open3 for interactive release commands.
|
|
3300
3344
|
- Fixed Ruby 3.2 version-bump support by loading Prism lazily and wiring the Prism gem only for MRI versions that need it.
|
|
3301
3345
|
|
|
3302
|
-
[Unreleased]: https://github.com/kettle-dev/kettle-family/compare/v1.3.
|
|
3346
|
+
[Unreleased]: https://github.com/kettle-dev/kettle-family/compare/v1.3.37...HEAD
|
|
3347
|
+
[1.3.37]: https://github.com/kettle-dev/kettle-family/compare/v1.3.36...v1.3.37
|
|
3348
|
+
[1.3.37t]: https://github.com/kettle-dev/kettle-family/releases/tag/v1.3.37
|
|
3349
|
+
[1.3.36]: https://github.com/kettle-dev/kettle-family/compare/v1.3.35...v1.3.36
|
|
3350
|
+
[1.3.36t]: https://github.com/kettle-dev/kettle-family/releases/tag/v1.3.36
|
|
3303
3351
|
[1.3.35]: https://github.com/kettle-dev/kettle-family/compare/v1.3.34...v1.3.35
|
|
3304
3352
|
[1.3.35t]: https://github.com/kettle-dev/kettle-family/releases/tag/v1.3.35
|
|
3305
3353
|
[1.3.34]: https://github.com/kettle-dev/kettle-family/compare/v1.3.33...v1.3.34
|
data/README.md
CHANGED
|
@@ -64,12 +64,12 @@ configuration, create their own GitHub Release through `kettle-release`.
|
|
|
64
64
|
|
|
65
65
|
### Compatibility
|
|
66
66
|
|
|
67
|
-
|
|
67
|
+
The gem's declared runtime compatibility floor is MRI Ruby 4.0.0+, with concordant releases of JRuby and TruffleRuby.
|
|
68
68
|
CI workflows and Appraisals are generated for MRI Ruby 4.0.0+.
|
|
69
69
|
The current MRI CI lane runs on Linux and macOS.
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
not
|
|
70
|
+
The test floor is configured by `ruby.test_minimum` in `.kettle-jem.yml`.
|
|
71
|
+
When it is higher than the runtime floor, older runtime-compatible Rubies are
|
|
72
|
+
not covered by the generated CI or Appraisal matrix.
|
|
73
73
|
|
|
74
74
|
<a href="https://github.com/kettle-dev"><img alt="kettle-dev Logo by Aboling0, CC BY-SA 4.0" src="https://logos.galtzo.com/assets/images/kettle-dev/avatar-128px.svg" width="14%" align="right"/></a>
|
|
75
75
|
|
|
@@ -1191,7 +1191,7 @@ Thanks for RTFM. ☺️
|
|
|
1191
1191
|
[📌gitmoji]: https://gitmoji.dev
|
|
1192
1192
|
[📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
|
|
1193
1193
|
[🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
|
|
1194
|
-
[🧮kloc-img]: https://img.shields.io/badge/KLOC-8.
|
|
1194
|
+
[🧮kloc-img]: https://img.shields.io/badge/KLOC-8.230-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
|
|
1195
1195
|
[🔐security]: https://github.com/kettle-dev/kettle-family/blob/main/SECURITY.md
|
|
1196
1196
|
[🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
|
|
1197
1197
|
[📄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
|
@@ -1475,19 +1475,29 @@ module Kettle
|
|
|
1475
1475
|
def shared_bump_member_names(config:, members:)
|
|
1476
1476
|
return [] unless config.shared_changelog?
|
|
1477
1477
|
|
|
1478
|
-
members
|
|
1478
|
+
members
|
|
1479
|
+
.reject { |member| config.member_local_changelog?(member) }
|
|
1480
|
+
.reject { |member| config.independent_version_series_member?(member) }
|
|
1481
|
+
.map(&:name)
|
|
1479
1482
|
end
|
|
1480
1483
|
|
|
1481
1484
|
def shared_bump_target_version(config:, members:, options:, release_state_results: nil)
|
|
1482
1485
|
return unless config.shared_changelog?
|
|
1483
1486
|
return unless Kettle::Dev::VersionBump::BUMP_TYPES.include?(options[:target_version].to_s)
|
|
1484
1487
|
|
|
1488
|
+
# The lockstep raise cohort excludes members carrying their own
|
|
1489
|
+
# changelog AND independently versioned members: an independent
|
|
1490
|
+
# series must never be captured by (or drag) the shared version
|
|
1491
|
+
# line, in either direction.
|
|
1485
1492
|
shared_members = members.reject { |member| config.member_local_changelog?(member) }
|
|
1493
|
+
.reject { |member| config.independent_version_series_member?(member) }
|
|
1486
1494
|
return if shared_members.empty?
|
|
1487
1495
|
|
|
1488
1496
|
versions = shared_members.map { |member| Gem::Version.new(member.version.to_s) }.uniq
|
|
1489
1497
|
current = versions.max
|
|
1490
|
-
|
|
1498
|
+
# Without release-state results (explicit member selection) a
|
|
1499
|
+
# misaligned cohort still aligns to its maximum, as before.
|
|
1500
|
+
return current.to_s if versions.length > 1 && release_state_results.nil?
|
|
1491
1501
|
|
|
1492
1502
|
released_versions = Array(release_state_results).filter_map do |result|
|
|
1493
1503
|
next unless shared_members.any? { |member| member.name == result.member_name }
|
|
@@ -1502,8 +1512,15 @@ module Kettle
|
|
|
1502
1512
|
rescue ArgumentError
|
|
1503
1513
|
nil
|
|
1504
1514
|
end
|
|
1515
|
+
# Mid-prep (the cohort line already moved past the last release):
|
|
1516
|
+
# laggards align up to the in-flight version and nothing increments.
|
|
1505
1517
|
return current.to_s if released_versions.any? && current > released_versions.max
|
|
1506
1518
|
|
|
1519
|
+
# Otherwise the cohort owes a release: every shared member is raised
|
|
1520
|
+
# to the family's NEXT shared version — including a misaligned
|
|
1521
|
+
# cohort, which previously aligned to the current maximum and then
|
|
1522
|
+
# reported ok, leaving the unreleased-entries bump gate uncleared
|
|
1523
|
+
# with no documented command able to clear it (#17).
|
|
1507
1524
|
Kettle::Dev::VersionBump.resolve_target_version(options[:target_version].to_s, current.to_s)
|
|
1508
1525
|
end
|
|
1509
1526
|
|
data/lib/kettle/family/config.rb
CHANGED
|
@@ -308,6 +308,17 @@ module Kettle
|
|
|
308
308
|
end.compact
|
|
309
309
|
end
|
|
310
310
|
|
|
311
|
+
# Bootstrap-managed gems whose committed member locks must not lag the
|
|
312
|
+
# newest published version satisfying the member's declared requirement
|
|
313
|
+
# (release.drift_check.gems; default: nomono, the bootstrap gem whose
|
|
314
|
+
# lock/registry drift killed the SM-ruby wave on 2026-10-30). An empty
|
|
315
|
+
# list disables the drift preflight phase entirely.
|
|
316
|
+
def release_drift_check_gems
|
|
317
|
+
configured = fetch_path("release", "drift_check", "gems")
|
|
318
|
+
gems = configured.nil? ? [NomonoBootstrap::GEM_NAME] : Array(configured)
|
|
319
|
+
gems.map(&:to_s).map(&:strip).reject(&:empty?).uniq
|
|
320
|
+
end
|
|
321
|
+
|
|
311
322
|
def release_required_remotes
|
|
312
323
|
fetch_path("release", "required_remotes")
|
|
313
324
|
end
|
|
@@ -405,6 +416,24 @@ module Kettle
|
|
|
405
416
|
fetch_path("release", "aggregate_validation", "enabled") == true
|
|
406
417
|
end
|
|
407
418
|
|
|
419
|
+
# Members that keep their own monotonic version series even in a
|
|
420
|
+
# shared-version family (release.version_series.independent_members;
|
|
421
|
+
# default empty). An independent-series member is skipped by lockstep
|
|
422
|
+
# shared-version raises — its bumps stay on its own series — and is
|
|
423
|
+
# exempt from the aggregate GitHub Release same-version invariant,
|
|
424
|
+
# while its built artifacts still attach to the aggregate release.
|
|
425
|
+
def release_version_series_independent_members
|
|
426
|
+
Array(fetch_path("release", "version_series", "independent_members"))
|
|
427
|
+
.map(&:to_s)
|
|
428
|
+
.map(&:strip)
|
|
429
|
+
.reject(&:empty?)
|
|
430
|
+
.uniq
|
|
431
|
+
end
|
|
432
|
+
|
|
433
|
+
def independent_version_series_member?(member)
|
|
434
|
+
release_version_series_independent_members.include?(member.name.to_s)
|
|
435
|
+
end
|
|
436
|
+
|
|
408
437
|
def release_aggregate_validation_excluded_members
|
|
409
438
|
Array(fetch_path("release", "aggregate_validation", "exclude_members"))
|
|
410
439
|
.map(&:to_s)
|
|
@@ -113,7 +113,7 @@ module Kettle
|
|
|
113
113
|
|
|
114
114
|
def check_member(member, branch: nil, event_handler: nil)
|
|
115
115
|
started = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
116
|
-
command = release_state_command
|
|
116
|
+
command = release_state_command(member)
|
|
117
117
|
emit_event(event_handler, member: member, branch: branch, action: "member_start", status: "running", command: command)
|
|
118
118
|
emit_event(event_handler, member: member, branch: branch, action: "changelog_command", status: "running", command: command)
|
|
119
119
|
stdout, stderr, status = capture_release_state(
|
|
@@ -142,15 +142,16 @@ module Kettle
|
|
|
142
142
|
emit_event(event_handler, member: member, branch: branch, action: "member_complete", status: success ? "ok" : "failed", elapsed_seconds: elapsed, status_code: status.exitstatus)
|
|
143
143
|
result
|
|
144
144
|
rescue JSON::ParserError => error
|
|
145
|
-
result = result(member: member, command: command || release_state_command, stdout: stdout, stderr: stderr, status: 1, elapsed: elapsed || 0.0, success: false, state: {}, reason: "invalid release-state JSON: #{error.message}", branch: branch)
|
|
145
|
+
result = result(member: member, command: command || release_state_command(member), stdout: stdout, stderr: stderr, status: 1, elapsed: elapsed || 0.0, success: false, state: {}, reason: "invalid release-state JSON: #{error.message}", branch: branch)
|
|
146
146
|
emit_event(event_handler, member: member, branch: branch, action: "member_complete", status: "failed", elapsed_seconds: elapsed || 0.0, status_code: 1, reason: result.reason)
|
|
147
147
|
result
|
|
148
148
|
end
|
|
149
149
|
|
|
150
|
-
def release_state_command
|
|
151
|
-
|
|
150
|
+
def release_state_command(member = nil)
|
|
151
|
+
version_args = member&.version ? ["--version", member.version.to_s] : []
|
|
152
|
+
[RbConfig.ruby, kettle_changelog_executable, *version_args, "--release-state", "--json"]
|
|
152
153
|
rescue Gem::Exception
|
|
153
|
-
[RbConfig.ruby, "-S", "kettle-changelog", "--release-state", "--json"]
|
|
154
|
+
[RbConfig.ruby, "-S", "kettle-changelog", *version_args, "--release-state", "--json"]
|
|
154
155
|
end
|
|
155
156
|
|
|
156
157
|
def kettle_changelog_executable
|
|
@@ -176,7 +177,7 @@ module Kettle
|
|
|
176
177
|
|
|
177
178
|
def check_shared_changelog_member(member, branch: nil, event_handler: nil)
|
|
178
179
|
started = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
179
|
-
command = release_state_command
|
|
180
|
+
command = release_state_command(member)
|
|
180
181
|
emit_event(event_handler, member: member, branch: branch, action: "member_start", status: "running", command: command)
|
|
181
182
|
emit_event(event_handler, member: member, branch: branch, action: "changelog_command", status: "running", command: command)
|
|
182
183
|
stdout, stderr, status = capture_release_state(
|
|
@@ -216,13 +217,13 @@ module Kettle
|
|
|
216
217
|
emit_event(event_handler, member: member, branch: branch, action: "member_complete", status: success ? "ok" : "failed", elapsed_seconds: elapsed, status_code: status.exitstatus)
|
|
217
218
|
result
|
|
218
219
|
rescue JSON::ParserError => error
|
|
219
|
-
result = result(member: member, command: command || release_state_command, stdout: stdout, stderr: stderr, status: 1, elapsed: elapsed || 0.0, success: false, state: {}, reason: "invalid release-state JSON: #{error.message}", branch: branch)
|
|
220
|
+
result = result(member: member, command: command || release_state_command(member), stdout: stdout, stderr: stderr, status: 1, elapsed: elapsed || 0.0, success: false, state: {}, reason: "invalid release-state JSON: #{error.message}", branch: branch)
|
|
220
221
|
emit_event(event_handler, member: member, branch: branch, action: "member_complete", status: "failed", elapsed_seconds: elapsed || 0.0, status_code: 1, reason: result.reason)
|
|
221
222
|
result
|
|
222
223
|
rescue Error => error
|
|
223
224
|
result = result(
|
|
224
225
|
member: member,
|
|
225
|
-
command: command || release_state_command,
|
|
226
|
+
command: command || release_state_command(member),
|
|
226
227
|
stdout: "",
|
|
227
228
|
stderr: error.message,
|
|
228
229
|
status: 1,
|
|
@@ -804,8 +805,6 @@ module Kettle
|
|
|
804
805
|
return unless member_config
|
|
805
806
|
|
|
806
807
|
current_result = check_member(member, event_handler: event_handler)
|
|
807
|
-
return [current_result] unless current_result.ok?
|
|
808
|
-
|
|
809
808
|
[current_result, *self.class.new(config: member_config, members: [member]).results(event_handler: event_handler)]
|
|
810
809
|
end
|
|
811
810
|
|
|
@@ -831,8 +830,9 @@ module Kettle
|
|
|
831
830
|
end
|
|
832
831
|
|
|
833
832
|
# Version-locked siblings move in lockstep. Members not declared
|
|
834
|
-
# independently releasable (release.aggregate_validation.exclude_members
|
|
835
|
-
# share the family
|
|
833
|
+
# independently releasable (release.aggregate_validation.exclude_members
|
|
834
|
+
# or release.version_series.independent_members) share the family
|
|
835
|
+
# version line, so:
|
|
836
836
|
# 1. when any of them needs a version bump, all of them do — including
|
|
837
837
|
# members without unreleased changelog entries of their own and
|
|
838
838
|
# brand-new members that have never been released (empty
|
|
@@ -840,12 +840,13 @@ module Kettle
|
|
|
840
840
|
# 2. a member whose checkout version sits behind the cohort's version
|
|
841
841
|
# line (e.g. a cohort that already bumped while it stayed put) needs
|
|
842
842
|
# a catch-up bump on its own.
|
|
843
|
-
# Independently
|
|
844
|
-
# bump only when their own unreleased entries require it
|
|
845
|
-
#
|
|
846
|
-
#
|
|
843
|
+
# Independently versioned members keep per-member bump semantics: they
|
|
844
|
+
# bump only when their own unreleased entries require it, and their
|
|
845
|
+
# (possibly higher) own-series version never drags the cohort line.
|
|
846
|
+
# Members whose checkout version already moved past their last release
|
|
847
|
+
# are mid-prep and are never double-bumped.
|
|
847
848
|
def normalize_lockstep_version_bump(results)
|
|
848
|
-
excluded =
|
|
849
|
+
excluded = independent_bump_member_names
|
|
849
850
|
return results if excluded.empty?
|
|
850
851
|
|
|
851
852
|
aggregate = results.select do |result|
|
|
@@ -895,6 +896,17 @@ module Kettle
|
|
|
895
896
|
nil
|
|
896
897
|
end
|
|
897
898
|
|
|
899
|
+
# Members exempt from lockstep bump semantics: aggregate-validation
|
|
900
|
+
# exclusions plus independently versioned members. Both keep per-member
|
|
901
|
+
# bump behavior; neither may be force-marked pending by the cohort, and
|
|
902
|
+
# an independent-series version never participates in the cohort line.
|
|
903
|
+
def independent_bump_member_names
|
|
904
|
+
Array(config&.release_aggregate_validation_excluded_members)
|
|
905
|
+
.concat(Array(config&.release_version_series_independent_members))
|
|
906
|
+
.map(&:to_s)
|
|
907
|
+
.uniq
|
|
908
|
+
end
|
|
909
|
+
|
|
898
910
|
def normalize_shared_version_bump(results)
|
|
899
911
|
shared_results = results.select { |result| result.ok? && shared_changelog_member_result?(result) }
|
|
900
912
|
return results unless shared_results.any? { |result| result.state["bump_release_pending"] == true }
|
|
@@ -920,7 +932,11 @@ module Kettle
|
|
|
920
932
|
|
|
921
933
|
def shared_changelog_member_result?(result)
|
|
922
934
|
member = members.find { |candidate| candidate.name == result.member_name }
|
|
923
|
-
member && !member_local_changelog?(member)
|
|
935
|
+
member && !member_local_changelog?(member) && !independent_version_series_member?(member)
|
|
936
|
+
end
|
|
937
|
+
|
|
938
|
+
def independent_version_series_member?(member)
|
|
939
|
+
config&.independent_version_series_member?(member) || false
|
|
924
940
|
end
|
|
925
941
|
|
|
926
942
|
def git_root
|
data/lib/kettle/family/report.rb
CHANGED
|
@@ -125,7 +125,7 @@ module Kettle
|
|
|
125
125
|
lines << " #{result_state(result)} #{result_identity(result)} #{result.phase} #{result.reason || ""}".rstrip
|
|
126
126
|
append_result_stdout(lines, result)
|
|
127
127
|
append_indented_output(lines, result.stderr) if !result.ok? && !result.stderr.to_s.empty?
|
|
128
|
-
resume_hint = resume_hint_for(result)
|
|
128
|
+
resume_hint = resume_hint_for(result) unless command == "template"
|
|
129
129
|
lines << " resume: #{resume_hint}" if !result.ok? && resume_hint
|
|
130
130
|
end
|
|
131
131
|
append_template_summary(lines) if command == "template"
|
|
@@ -764,11 +764,10 @@ module Kettle
|
|
|
764
764
|
failed ? [resume_hint_for(failed)] : []
|
|
765
765
|
end
|
|
766
766
|
|
|
767
|
-
#
|
|
768
|
-
#
|
|
769
|
-
#
|
|
770
|
-
#
|
|
771
|
-
# selected subset.
|
|
767
|
+
# Test gets one hint per failure plus a set-based hint for members that never
|
|
768
|
+
# ran. --only selects by name rather than position, so it resumes exactly the
|
|
769
|
+
# unfinished members regardless of how dispatch ordered them. Template uses
|
|
770
|
+
# one combined hint because it is idempotent and family-lockstep.
|
|
772
771
|
#
|
|
773
772
|
# A family-root failure takes precedence and suppresses the set-based hint:
|
|
774
773
|
# that phase aborts the entire run before member dispatch, so every member
|
|
@@ -776,6 +775,7 @@ module Kettle
|
|
|
776
775
|
def non_positional_resume_hints
|
|
777
776
|
root_failure = results.find { |result| !result.ok? && family_root_phase?(result.phase) }
|
|
778
777
|
return [resume_hint_for(root_failure)] if root_failure
|
|
778
|
+
return template_resume_hints if command == "template"
|
|
779
779
|
|
|
780
780
|
failed_hints = visible_results.reject(&:ok?).filter_map { |result| resume_hint_for(result) }.uniq
|
|
781
781
|
pending_names = summary_pending.map { |entry| entry.fetch("member") }
|
|
@@ -784,6 +784,15 @@ module Kettle
|
|
|
784
784
|
[*failed_hints, "kettle-family #{command} --only #{pending_names.join(",")}"]
|
|
785
785
|
end
|
|
786
786
|
|
|
787
|
+
def template_resume_hints
|
|
788
|
+
member_names = visible_results.reject(&:ok?).map { |result| result_identity(result) }
|
|
789
|
+
member_names.concat(summary_pending.map { |entry| entry.fetch("member") })
|
|
790
|
+
member_names = member_names.compact.uniq.sort
|
|
791
|
+
return ["kettle-family template"] if member_names.empty?
|
|
792
|
+
|
|
793
|
+
["kettle-family template --only #{member_names.join(",")}"]
|
|
794
|
+
end
|
|
795
|
+
|
|
787
796
|
def release_resume_hints
|
|
788
797
|
failed_hints = visible_results.reject(&:ok?).filter_map { |result| resume_hint_for(result) }.uniq
|
|
789
798
|
pending_names = summary_pending.map { |entry| entry.fetch("member") }
|
|
@@ -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.3.
|
|
8
|
+
VERSION = "1.3.37"
|
|
9
9
|
end
|
|
10
10
|
# Current gem version exposed at the traditional constant location.
|
|
11
11
|
VERSION = Version::VERSION # Traditional Constant Location
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "kettle/dev"
|
|
4
|
+
require "ast/crispr/ruby/prism"
|
|
4
5
|
|
|
5
6
|
module Kettle
|
|
6
7
|
module Family
|
|
@@ -74,12 +75,20 @@ module Kettle
|
|
|
74
75
|
end
|
|
75
76
|
|
|
76
77
|
def collect_edits(member, member_target_version)
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
78
|
+
begin
|
|
79
|
+
version_edits = with_dev_errors do
|
|
80
|
+
Kettle::Dev::VersionBump.new(
|
|
81
|
+
root: member.root,
|
|
82
|
+
current_version: member.version,
|
|
83
|
+
target_version: member_target_version
|
|
84
|
+
).edits
|
|
85
|
+
end
|
|
86
|
+
rescue Error => error
|
|
87
|
+
bump = Kettle::Dev::VersionBump.new(root: member.root, current_version: member.version, target_version: member_target_version)
|
|
88
|
+
computed_version_edits = prism_computed_version_edits(member, member_target_version)
|
|
89
|
+
raise error if computed_version_edits.empty?
|
|
90
|
+
|
|
91
|
+
version_edits = computed_version_edits + bump.send(:gemspec_version_edits)
|
|
83
92
|
end
|
|
84
93
|
version_edits = version_edits.map do |edit|
|
|
85
94
|
if same_file?(edit.fetch(:path), member.gemspec_path)
|
|
@@ -91,6 +100,33 @@ module Kettle
|
|
|
91
100
|
version_edits + gemspec_dependency_edits(member)
|
|
92
101
|
end
|
|
93
102
|
|
|
103
|
+
def prism_computed_version_edits(member, target_version)
|
|
104
|
+
version = Gem::Version.new(target_version)
|
|
105
|
+
replacements = {major: version.segments[0] || 0, minor: version.segments[1] || 0, patch: version.segments[2] || 0}
|
|
106
|
+
Kettle::Dev::Versioning.version_file_candidates(member.root).flat_map do |path|
|
|
107
|
+
source = File.read(path)
|
|
108
|
+
analysis = Ast::Crispr::Ruby::Prism.document_context(content: source, source_label: path).ast
|
|
109
|
+
root = analysis.parse_result.value
|
|
110
|
+
nodes = Kettle::Dev::VersionBump.each_node(root).to_a
|
|
111
|
+
version_constant = nodes.find do |node|
|
|
112
|
+
node.is_a?(Prism::ConstantWriteNode) && node.name == :VERSION && node.value.is_a?(Prism::CallNode) && node.value.name == :to_s
|
|
113
|
+
end
|
|
114
|
+
next [] unless version_constant
|
|
115
|
+
|
|
116
|
+
replacements.filter_map do |method_name, replacement_value|
|
|
117
|
+
method = nodes.find { |node| node.is_a?(Prism::DefNode) && node.name == method_name }
|
|
118
|
+
literal = method&.body&.body&.last
|
|
119
|
+
next unless literal.is_a?(Prism::IntegerNode) || literal.is_a?(Prism::StringNode)
|
|
120
|
+
|
|
121
|
+
next if literal.is_a?(Prism::IntegerNode) && literal.value == replacement_value
|
|
122
|
+
next if literal.is_a?(Prism::StringNode) && literal.unescaped == replacement_value.to_s
|
|
123
|
+
|
|
124
|
+
replacement = literal.is_a?(Prism::StringNode) ? Kettle::Dev::VersionBump.quote_like(literal.location.slice, replacement_value.to_s) : replacement_value.to_s
|
|
125
|
+
Kettle::Dev::VersionBump.file_edit(path, source, literal.location.start_offset, literal.location.end_offset, replacement)
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
94
130
|
def same_file?(left, right)
|
|
95
131
|
right && File.identical?(left, right)
|
|
96
132
|
rescue SystemCallError
|
|
@@ -108,6 +108,16 @@ module Kettle
|
|
|
108
108
|
REGISTRY_WAIT_ATTEMPTS = 15
|
|
109
109
|
REGISTRY_WAIT_INTERVAL_SECONDS = 15
|
|
110
110
|
TEMPLATE_GEMSPEC_RETRY_DELAY_SECONDS = 0.25
|
|
111
|
+
# Placeholder substituted for secret-valued env keys in generated resume
|
|
112
|
+
# commands (see aggregate_github_release_resume_command).
|
|
113
|
+
RESUME_COMMAND_REDACTED_VALUE = "<redacted-reauthorize>"
|
|
114
|
+
# Env key names whose values must never appear in printed commands.
|
|
115
|
+
# Matches by name shape, not a fixed list, so future secrets plumbing
|
|
116
|
+
# (new passphrase/OTP/token transports) is scrubbed by default. The
|
|
117
|
+
# excluded suffixes are routing metadata an operator needs to
|
|
118
|
+
# re-authorize (source/provider/broker/field NAME), never a secret.
|
|
119
|
+
RESUME_COMMAND_SECRET_ENV_KEY_RE = /PASSPHRASE|PASSWORD|SECRET|TOKEN|OTP|CREDENTIAL/i
|
|
120
|
+
RESUME_COMMAND_SECRET_ENV_KEY_EXCLUDE_RE = /(?:_SOURCE|_PROVIDER|_BROKER|_FIELD)\z/i
|
|
111
121
|
|
|
112
122
|
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, template_branch_selection: {}, release_state_results: nil, event_tape: nil, mise_adapter: nil, **options)
|
|
113
123
|
@command = command
|
|
@@ -2024,12 +2034,13 @@ module Kettle
|
|
|
2024
2034
|
def release_preflight_phases
|
|
2025
2035
|
maintenance_phase = {label: "pre-release maintenance", method: :release_preflight_maintenance_results} unless config.release_preflight_commands.empty?
|
|
2026
2036
|
bump_phase = {label: "release version bump", method: :release_preflight_version_bump_results} unless release_state_results.empty?
|
|
2037
|
+
drift_phase = {label: "bootstrap dependency drift", method: :release_preflight_bootstrap_drift_results} unless config.release_drift_check_gems.empty?
|
|
2027
2038
|
dirty_phase = {label: "branch checkout readiness", method: :release_preflight_branch_checkout_dirty_results}
|
|
2028
2039
|
signing_phase = {label: "gem signing password", method: :release_preflight_signing_password_results}
|
|
2029
2040
|
secrets_phase = release_secrets_authorization_required? ? {label: "secrets provider authorization", method: :release_preflight_secrets_authorization_results} : nil
|
|
2030
2041
|
gha_sha_pins_phase = release_gha_sha_pins_review_required? ? {label: "GitHub Actions SHA pins", method: :release_preflight_gha_sha_pins_results} : nil
|
|
2031
2042
|
|
|
2032
|
-
[maintenance_phase, bump_phase, secrets_phase, gha_sha_pins_phase, dirty_phase, signing_phase].compact
|
|
2043
|
+
[maintenance_phase, bump_phase, drift_phase, secrets_phase, gha_sha_pins_phase, dirty_phase, signing_phase].compact
|
|
2033
2044
|
end
|
|
2034
2045
|
|
|
2035
2046
|
# Family-declared pre-release maintenance hooks (release.preflight_commands
|
|
@@ -2075,6 +2086,108 @@ module Kettle
|
|
|
2075
2086
|
results
|
|
2076
2087
|
end
|
|
2077
2088
|
|
|
2089
|
+
# Bootstrap-managed gems (config release.drift_check.gems, default:
|
|
2090
|
+
# nomono) are activated by a member's own Gemfile bootstrap, while CI
|
|
2091
|
+
# resolves fresh bundles from the registry. When a newer published
|
|
2092
|
+
# version satisfies the member's declared floor but the committed lock
|
|
2093
|
+
# pins an older one, CI activates the newer version while the member
|
|
2094
|
+
# bootstrap activates the locked older one, and the wave dies mid-job
|
|
2095
|
+
# with a Gem::LoadError deep in a cold-start (observed 2026-10-30:
|
|
2096
|
+
# nomono locked 1.1.16 vs published 1.1.17 satisfying a ">= 1.1.16"
|
|
2097
|
+
# floor, run 40998206316). Nothing compared locked vs
|
|
2098
|
+
# published-satisfying versions pre-release, so this phase blocks early
|
|
2099
|
+
# with the remediation instead of letting CI discover the drift.
|
|
2100
|
+
def release_preflight_bootstrap_drift_results
|
|
2101
|
+
config.release_drift_check_gems.flat_map do |gem|
|
|
2102
|
+
members.filter_map { |member| bootstrap_dependency_drift_result(member, gem) }
|
|
2103
|
+
end
|
|
2104
|
+
end
|
|
2105
|
+
|
|
2106
|
+
def bootstrap_dependency_drift_result(member, gem)
|
|
2107
|
+
locked = locked_bootstrap_gem_version(member, gem)
|
|
2108
|
+
return nil if locked.nil?
|
|
2109
|
+
|
|
2110
|
+
requirement = declared_bootstrap_gem_requirement(member, gem)
|
|
2111
|
+
newest = newest_published_satisfying_version(gem, requirement)
|
|
2112
|
+
if newest.nil?
|
|
2113
|
+
# A registry outage must never become a false release block: treat
|
|
2114
|
+
# "could not consult the registry" as a skip with a diagnostic.
|
|
2115
|
+
warn "[kettle-family] bootstrap dependency drift check skipped for #{gem}: registry could not be consulted"
|
|
2116
|
+
return nil
|
|
2117
|
+
end
|
|
2118
|
+
return nil if locked >= newest
|
|
2119
|
+
|
|
2120
|
+
release_preflight_error_result(
|
|
2121
|
+
"bootstrap_dependency_drift",
|
|
2122
|
+
"Release blocked: bootstrap dependency drift: #{member.name} locks #{gem} #{locked} but #{newest} satisfies its floor; " \
|
|
2123
|
+
"run the family template sweep or `bundle update #{gem}` in the member before releasing.",
|
|
2124
|
+
member: member
|
|
2125
|
+
)
|
|
2126
|
+
end
|
|
2127
|
+
|
|
2128
|
+
# The version a member's committed lock pins for the gem, from the
|
|
2129
|
+
# registry-sourced GEM section only: a PATH or GIT pin is local-only
|
|
2130
|
+
# state that has no published counterpart to drift against.
|
|
2131
|
+
def locked_bootstrap_gem_version(member, gem)
|
|
2132
|
+
lockfile_path = File.join(member.root, "Gemfile.lock")
|
|
2133
|
+
return nil unless File.file?(lockfile_path)
|
|
2134
|
+
|
|
2135
|
+
section = nil
|
|
2136
|
+
File.foreach(lockfile_path) do |line|
|
|
2137
|
+
section = line.strip unless line.match?(/\A\s/)
|
|
2138
|
+
next unless section == "GEM"
|
|
2139
|
+
|
|
2140
|
+
match = line.match(/\A {4}#{Regexp.escape(gem)} \(([^)]+)\)\s*\z/)
|
|
2141
|
+
next unless match
|
|
2142
|
+
|
|
2143
|
+
begin
|
|
2144
|
+
return Gem::Version.new(match[1])
|
|
2145
|
+
rescue ArgumentError
|
|
2146
|
+
return nil
|
|
2147
|
+
end
|
|
2148
|
+
end
|
|
2149
|
+
nil
|
|
2150
|
+
end
|
|
2151
|
+
|
|
2152
|
+
# The requirement the member's Gemfile declared for the gem, read from
|
|
2153
|
+
# the lock's DEPENDENCIES section (Bundler records the DSL requirement
|
|
2154
|
+
# there verbatim). A bare declaration means "any version".
|
|
2155
|
+
def declared_bootstrap_gem_requirement(member, gem)
|
|
2156
|
+
lockfile_path = File.join(member.root, "Gemfile.lock")
|
|
2157
|
+
return Gem::Requirement.default unless File.file?(lockfile_path)
|
|
2158
|
+
|
|
2159
|
+
section = nil
|
|
2160
|
+
File.foreach(lockfile_path) do |line|
|
|
2161
|
+
section = line.strip unless line.match?(/\A\s/)
|
|
2162
|
+
next unless section == "DEPENDENCIES"
|
|
2163
|
+
|
|
2164
|
+
match = line.match(/\A {2}#{Regexp.escape(gem)}(?: \((.+)\))?\s*\z/)
|
|
2165
|
+
next unless match
|
|
2166
|
+
|
|
2167
|
+
constraints = (match[1] || "").split(",").map(&:strip).reject(&:empty?)
|
|
2168
|
+
return Gem::Requirement.new(constraints) unless constraints.empty?
|
|
2169
|
+
|
|
2170
|
+
return Gem::Requirement.default
|
|
2171
|
+
end
|
|
2172
|
+
Gem::Requirement.default
|
|
2173
|
+
end
|
|
2174
|
+
|
|
2175
|
+
# Newest published (non-prerelease) version satisfying the requirement,
|
|
2176
|
+
# via the ETag-cached registry lookup shared with the rest of the
|
|
2177
|
+
# toolchain; nil when the registry could not be consulted.
|
|
2178
|
+
def newest_published_satisfying_version(gem, requirement)
|
|
2179
|
+
numbers = Kettle::Dev::RubyGemsVersions.published_version_numbers(gem)
|
|
2180
|
+
return nil if numbers.nil?
|
|
2181
|
+
|
|
2182
|
+
numbers.filter_map do |number|
|
|
2183
|
+
Gem::Version.new(number)
|
|
2184
|
+
rescue ArgumentError
|
|
2185
|
+
nil
|
|
2186
|
+
end.select do |version|
|
|
2187
|
+
!version.prerelease? && requirement.satisfied_by?(version)
|
|
2188
|
+
end.max
|
|
2189
|
+
end
|
|
2190
|
+
|
|
2078
2191
|
def release_gha_sha_pins_review_required?
|
|
2079
2192
|
execute && kettle_release_command?(raw_release_command) && !release_gha_sha_pins_offline_requested?
|
|
2080
2193
|
end
|
|
@@ -2119,11 +2232,14 @@ module Kettle
|
|
|
2119
2232
|
@secrets_provider.is_a?(Secrets::OnePassword)
|
|
2120
2233
|
end
|
|
2121
2234
|
|
|
2122
|
-
def release_preflight_error_result(phase, message)
|
|
2235
|
+
def release_preflight_error_result(phase, message, member: nil)
|
|
2123
2236
|
# A preflight failure blocks the selected release invocation. Attribute
|
|
2124
2237
|
# it to that invocation's first member so generated resume commands do
|
|
2125
|
-
# not target the synthetic family name or an unselected sibling.
|
|
2126
|
-
member
|
|
2238
|
+
# not target the synthetic family name or an unselected sibling. Phases
|
|
2239
|
+
# that identify a specific offending member (e.g. bootstrap dependency
|
|
2240
|
+
# drift) override that attribution so the resume hint targets the
|
|
2241
|
+
# member that needs the fix.
|
|
2242
|
+
member ||= members.first || family_member
|
|
2127
2243
|
CommandResult.new(
|
|
2128
2244
|
member_name: member.name,
|
|
2129
2245
|
phase: phase,
|
|
@@ -3789,6 +3905,7 @@ module Kettle
|
|
|
3789
3905
|
def append_kettle_release_args(command, member: nil)
|
|
3790
3906
|
command = replace_kettle_release_provider(command) if @release_secrets_broker
|
|
3791
3907
|
args = []
|
|
3908
|
+
args << "--version=#{member.version}" if member&.version && !command_includes_arg?(command, "--version")
|
|
3792
3909
|
effective_start_step = release_start_step_for(member)
|
|
3793
3910
|
command, configured_skip_steps = extract_kettle_release_skip_steps(command)
|
|
3794
3911
|
effective_skip_steps = (configured_skip_steps + release_skip_steps_for(member).split(",")).uniq.join(",")
|
|
@@ -3888,6 +4005,16 @@ module Kettle
|
|
|
3888
4005
|
aggregate_validation_members.include?(member)
|
|
3889
4006
|
end
|
|
3890
4007
|
|
|
4008
|
+
# An independently versioned member (release.version_series.
|
|
4009
|
+
# independent_members) keeps its own monotonic series: it is exempt
|
|
4010
|
+
# from lockstep raises and from the aggregate same-version invariant,
|
|
4011
|
+
# but remains part of the aggregate release for artifact attachment.
|
|
4012
|
+
def independent_version_series_member?(member)
|
|
4013
|
+
return false unless member
|
|
4014
|
+
|
|
4015
|
+
config.independent_version_series_member?(member)
|
|
4016
|
+
end
|
|
4017
|
+
|
|
3891
4018
|
def aggregate_validation_member_name?(member)
|
|
3892
4019
|
member && member.name == (@aggregate_validation_member_name || aggregate_validation_members.first&.name)
|
|
3893
4020
|
end
|
|
@@ -4108,12 +4235,19 @@ module Kettle
|
|
|
4108
4235
|
|
|
4109
4236
|
# simplecov:disable Covered by monorepo release integration, not sibling-repository suite.
|
|
4110
4237
|
def aggregate_monorepo_github_release(members)
|
|
4111
|
-
version
|
|
4238
|
+
# The same-version invariant describes the shared-version cohort.
|
|
4239
|
+
# Independently versioned members (release.version_series.
|
|
4240
|
+
# independent_members) can never satisfy it by design, so they are
|
|
4241
|
+
# exempt from the uniformity check while their artifacts still
|
|
4242
|
+
# attach — at their own series version, not the cohort's.
|
|
4243
|
+
shared_members = members.reject { |member| independent_version_series_member?(member) }
|
|
4244
|
+
version = shared_members.map { |member| member.version.to_s }.uniq
|
|
4112
4245
|
return aggregate_release_result("all selected members must have the same version") unless version.length == 1
|
|
4113
4246
|
|
|
4114
4247
|
assets = members.flat_map do |member|
|
|
4115
|
-
|
|
4116
|
-
|
|
4248
|
+
asset_version = independent_version_series_member?(member) ? member.version.to_s : version.first
|
|
4249
|
+
gem_path = Paths.glob(member.root, "pkg", "*.gem").select { |path| File.basename(path).end_with?("-#{asset_version}.gem") }
|
|
4250
|
+
checksum_paths = %w[sha256 sha512].map { |algorithm| File.join(member.root, "checksums", "#{member.name}-#{asset_version}.gem.#{algorithm}") }
|
|
4117
4251
|
gem_path + checksum_paths.select { |path| File.file?(path) }
|
|
4118
4252
|
end
|
|
4119
4253
|
command = ["bundle", "exec", "kettle-gh-release", "--allow-unpublished", "--events", "--release-version", version.first]
|
|
@@ -4158,11 +4292,26 @@ module Kettle
|
|
|
4158
4292
|
|
|
4159
4293
|
def aggregate_github_release_resume_command(env, command)
|
|
4160
4294
|
assignments = env.sort_by { |key, _value| key }.filter_map do |key, value|
|
|
4161
|
-
|
|
4295
|
+
next if value.nil?
|
|
4296
|
+
|
|
4297
|
+
# Resume commands land in terminal output, run summaries, and
|
|
4298
|
+
# transcripts. Env built from the broker-cached secrets used to
|
|
4299
|
+
# embed KETTLE_RELEASE_GEM_SIGNING_PASSPHRASE in plaintext here
|
|
4300
|
+
# (2026-10-30 incident). Redact secret-valued keys instead: the
|
|
4301
|
+
# printed command keeps its shape, and the operator re-authorizes
|
|
4302
|
+
# the secret through the release secrets provider (1Password, or
|
|
4303
|
+
# the KETTLE_RELEASE_SECRETS_BROKER cache) — or pastes the real
|
|
4304
|
+
# passphrase in place of the placeholder — before resuming.
|
|
4305
|
+
rendered_value = resume_command_secret_env_key?(key) ? Shellwords.escape(RESUME_COMMAND_REDACTED_VALUE) : Shellwords.escape(value.to_s)
|
|
4306
|
+
"#{key}=#{rendered_value}"
|
|
4162
4307
|
end
|
|
4163
4308
|
(["env", *assignments].join(" ") + " " + Shellwords.join(command)).strip
|
|
4164
4309
|
end
|
|
4165
4310
|
|
|
4311
|
+
def resume_command_secret_env_key?(key)
|
|
4312
|
+
key.match?(RESUME_COMMAND_SECRET_ENV_KEY_RE) && !key.match?(RESUME_COMMAND_SECRET_ENV_KEY_EXCLUDE_RE)
|
|
4313
|
+
end
|
|
4314
|
+
|
|
4166
4315
|
def aggregate_github_release_event_line_handler(member)
|
|
4167
4316
|
lambda do |line|
|
|
4168
4317
|
event = parse_template_event(line)
|
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.3.
|
|
4
|
+
version: 1.3.37
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Peter H. Boling
|
|
@@ -57,6 +57,26 @@ dependencies:
|
|
|
57
57
|
- - ">="
|
|
58
58
|
- !ruby/object:Gem::Version
|
|
59
59
|
version: 7.1.11
|
|
60
|
+
- !ruby/object:Gem::Dependency
|
|
61
|
+
name: ast-crispr-ruby-prism
|
|
62
|
+
requirement: !ruby/object:Gem::Requirement
|
|
63
|
+
requirements:
|
|
64
|
+
- - "~>"
|
|
65
|
+
- !ruby/object:Gem::Version
|
|
66
|
+
version: '7.1'
|
|
67
|
+
- - ">="
|
|
68
|
+
- !ruby/object:Gem::Version
|
|
69
|
+
version: 7.1.10
|
|
70
|
+
type: :runtime
|
|
71
|
+
prerelease: false
|
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
73
|
+
requirements:
|
|
74
|
+
- - "~>"
|
|
75
|
+
- !ruby/object:Gem::Version
|
|
76
|
+
version: '7.1'
|
|
77
|
+
- - ">="
|
|
78
|
+
- !ruby/object:Gem::Version
|
|
79
|
+
version: 7.1.10
|
|
60
80
|
- !ruby/object:Gem::Dependency
|
|
61
81
|
name: ast-crispr-toml
|
|
62
82
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -114,7 +134,7 @@ dependencies:
|
|
|
114
134
|
version: '1.0'
|
|
115
135
|
- - ">="
|
|
116
136
|
- !ruby/object:Gem::Version
|
|
117
|
-
version: 1.0.
|
|
137
|
+
version: 1.0.15
|
|
118
138
|
type: :runtime
|
|
119
139
|
prerelease: false
|
|
120
140
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -124,7 +144,7 @@ dependencies:
|
|
|
124
144
|
version: '1.0'
|
|
125
145
|
- - ">="
|
|
126
146
|
- !ruby/object:Gem::Version
|
|
127
|
-
version: 1.0.
|
|
147
|
+
version: 1.0.15
|
|
128
148
|
- !ruby/object:Gem::Dependency
|
|
129
149
|
name: kettle-deps-floor
|
|
130
150
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -134,7 +154,7 @@ dependencies:
|
|
|
134
154
|
version: '0.1'
|
|
135
155
|
- - ">="
|
|
136
156
|
- !ruby/object:Gem::Version
|
|
137
|
-
version: 0.1.
|
|
157
|
+
version: 0.1.2
|
|
138
158
|
type: :runtime
|
|
139
159
|
prerelease: false
|
|
140
160
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -144,7 +164,7 @@ dependencies:
|
|
|
144
164
|
version: '0.1'
|
|
145
165
|
- - ">="
|
|
146
166
|
- !ruby/object:Gem::Version
|
|
147
|
-
version: 0.1.
|
|
167
|
+
version: 0.1.2
|
|
148
168
|
- !ruby/object:Gem::Dependency
|
|
149
169
|
name: kettle-dev
|
|
150
170
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -154,7 +174,7 @@ dependencies:
|
|
|
154
174
|
version: '3.1'
|
|
155
175
|
- - ">="
|
|
156
176
|
- !ruby/object:Gem::Version
|
|
157
|
-
version: 3.1.
|
|
177
|
+
version: 3.1.26
|
|
158
178
|
type: :runtime
|
|
159
179
|
prerelease: false
|
|
160
180
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -164,7 +184,7 @@ dependencies:
|
|
|
164
184
|
version: '3.1'
|
|
165
185
|
- - ">="
|
|
166
186
|
- !ruby/object:Gem::Version
|
|
167
|
-
version: 3.1.
|
|
187
|
+
version: 3.1.26
|
|
168
188
|
- !ruby/object:Gem::Dependency
|
|
169
189
|
name: kettle-gha-pins
|
|
170
190
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -174,7 +194,7 @@ dependencies:
|
|
|
174
194
|
version: '0.3'
|
|
175
195
|
- - ">="
|
|
176
196
|
- !ruby/object:Gem::Version
|
|
177
|
-
version: 0.3.
|
|
197
|
+
version: 0.3.20
|
|
178
198
|
type: :runtime
|
|
179
199
|
prerelease: false
|
|
180
200
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -184,7 +204,7 @@ dependencies:
|
|
|
184
204
|
version: '0.3'
|
|
185
205
|
- - ">="
|
|
186
206
|
- !ruby/object:Gem::Version
|
|
187
|
-
version: 0.3.
|
|
207
|
+
version: 0.3.20
|
|
188
208
|
- !ruby/object:Gem::Dependency
|
|
189
209
|
name: kettle-jem
|
|
190
210
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -214,7 +234,7 @@ dependencies:
|
|
|
214
234
|
version: '0.1'
|
|
215
235
|
- - ">="
|
|
216
236
|
- !ruby/object:Gem::Version
|
|
217
|
-
version: 0.1.
|
|
237
|
+
version: 0.1.23
|
|
218
238
|
type: :runtime
|
|
219
239
|
prerelease: false
|
|
220
240
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -224,7 +244,7 @@ dependencies:
|
|
|
224
244
|
version: '0.1'
|
|
225
245
|
- - ">="
|
|
226
246
|
- !ruby/object:Gem::Version
|
|
227
|
-
version: 0.1.
|
|
247
|
+
version: 0.1.23
|
|
228
248
|
- !ruby/object:Gem::Dependency
|
|
229
249
|
name: kettle-test
|
|
230
250
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -234,7 +254,7 @@ dependencies:
|
|
|
234
254
|
version: '2.0'
|
|
235
255
|
- - ">="
|
|
236
256
|
- !ruby/object:Gem::Version
|
|
237
|
-
version: 2.0.
|
|
257
|
+
version: 2.0.29
|
|
238
258
|
type: :runtime
|
|
239
259
|
prerelease: false
|
|
240
260
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -244,7 +264,7 @@ dependencies:
|
|
|
244
264
|
version: '2.0'
|
|
245
265
|
- - ">="
|
|
246
266
|
- !ruby/object:Gem::Version
|
|
247
|
-
version: 2.0.
|
|
267
|
+
version: 2.0.29
|
|
248
268
|
- !ruby/object:Gem::Dependency
|
|
249
269
|
name: psych-merge
|
|
250
270
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -608,10 +628,10 @@ licenses:
|
|
|
608
628
|
- AGPL-3.0-only
|
|
609
629
|
metadata:
|
|
610
630
|
homepage_uri: https://kettle-family.galtzo.com
|
|
611
|
-
source_code_uri: https://github.com/kettle-dev/kettle-family/tree/v1.3.
|
|
612
|
-
changelog_uri: https://github.com/kettle-dev/kettle-family/blob/v1.3.
|
|
631
|
+
source_code_uri: https://github.com/kettle-dev/kettle-family/tree/v1.3.37
|
|
632
|
+
changelog_uri: https://github.com/kettle-dev/kettle-family/blob/v1.3.37/CHANGELOG.md
|
|
613
633
|
bug_tracker_uri: https://github.com/kettle-dev/kettle-family/issues
|
|
614
|
-
documentation_uri: https://www.rubydoc.info/gems/kettle-family/1.3.
|
|
634
|
+
documentation_uri: https://www.rubydoc.info/gems/kettle-family/1.3.37
|
|
615
635
|
funding_uri: https://github.com/sponsors/pboling
|
|
616
636
|
wiki_uri: https://github.com/kettle-dev/kettle-family/wiki
|
|
617
637
|
news_uri: https://www.railsbling.com/tags/kettle-family
|
metadata.gz.sig
CHANGED
|
Binary file
|