kettle-family 1.2.98 → 1.2.100
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 +7 -1
- data/lib/kettle/family/command_runner.rb +32 -1
- data/lib/kettle/family/dependency_floor.rb +18 -0
- data/lib/kettle/family/version.rb +1 -1
- data/lib/kettle/family/workflow.rb +47 -6
- data.tar.gz.sig +0 -0
- metadata +6 -6
- 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: 8b8d7a476e1af0096eca0bc0870cd9a8623b2ad2ccdcfa5080ec184b5b561096
|
|
4
|
+
data.tar.gz: df5707cdac3c7838df5cbbc83731ffb7741dfe818e440a83d917792a1f4290b3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1cc3290cedbd5e35c1c77f4810b6fba3e562297e66a8f1c0d5a0f575110c231771cb460ae67617d289dcf845cde1f0ef4ed09aa996ca5774631fbe1f0c8a4556
|
|
7
|
+
data.tar.gz: f6e8a65bfd5e7dd3c544a6b47443383a7a9d4cfc7597a52e509bbc9cf765cf1835624f8b4022db1b80b45b2cb0e40c3a5de77acb08f0cfd953c44913d6611454
|
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.100] - 2026-09-09
|
|
34
|
+
|
|
35
|
+
- TAG: [v1.2.100][1.2.100t]
|
|
36
|
+
- COVERAGE: 93.51% -- 6283/6719 lines in 35 files
|
|
37
|
+
- BRANCH COVERAGE: 78.15% -- 2553/3267 branches in 35 files
|
|
38
|
+
- 32.84% documented
|
|
39
|
+
|
|
40
|
+
### Fixed
|
|
41
|
+
|
|
42
|
+
- Run each family member through its own mise runtime instead of inheriting the orchestrator runtime.
|
|
43
|
+
|
|
44
|
+
- Refresh dependent release lockfiles after a runtime sibling publishes without waiting for later Gemfile-only tooling dependencies.
|
|
45
|
+
|
|
46
|
+
- Preserve the Mise launcher path when running commands in member worktrees from a Bundler environment.
|
|
47
|
+
|
|
48
|
+
## [1.2.99] - 2026-09-09
|
|
49
|
+
|
|
50
|
+
- TAG: [v1.2.99][1.2.99t]
|
|
51
|
+
- COVERAGE: 93.52% -- 6261/6695 lines in 35 files
|
|
52
|
+
- BRANCH COVERAGE: 78.19% -- 2542/3251 branches in 35 files
|
|
53
|
+
- 32.75% documented
|
|
54
|
+
|
|
55
|
+
### Fixed
|
|
56
|
+
|
|
57
|
+
- Keep resumed family releases on the prepared CI commit by skipping dependency-floor reconciliation and disabling sibling paths for child release validation.
|
|
58
|
+
|
|
59
|
+
- Scope branch-stack release resumes to the prepared branch so later targets run their complete release lifecycle before CI monitoring.
|
|
60
|
+
|
|
33
61
|
## [1.2.98] - 2026-09-09
|
|
34
62
|
|
|
35
63
|
- TAG: [v1.2.98][1.2.98t]
|
|
@@ -2692,7 +2720,11 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
|
2692
2720
|
- Fixed CI load failures on engines without compatible `pty` support by falling back to Open3 for interactive release commands.
|
|
2693
2721
|
- Fixed Ruby 3.2 version-bump support by loading Prism lazily and wiring the Prism gem only for MRI versions that need it.
|
|
2694
2722
|
|
|
2695
|
-
[Unreleased]: https://github.com/kettle-dev/kettle-family/compare/v1.2.
|
|
2723
|
+
[Unreleased]: https://github.com/kettle-dev/kettle-family/compare/v1.2.100...HEAD
|
|
2724
|
+
[1.2.100]: https://github.com/kettle-dev/kettle-family/compare/v1.2.99...v1.2.100
|
|
2725
|
+
[1.2.100t]: https://github.com/kettle-dev/kettle-family/releases/tag/v1.2.100
|
|
2726
|
+
[1.2.99]: https://github.com/kettle-dev/kettle-family/compare/v1.2.98...v1.2.99
|
|
2727
|
+
[1.2.99t]: https://github.com/kettle-dev/kettle-family/releases/tag/v1.2.99
|
|
2696
2728
|
[1.2.98]: https://github.com/kettle-dev/kettle-family/compare/v1.2.97...v1.2.98
|
|
2697
2729
|
[1.2.98t]: https://github.com/kettle-dev/kettle-family/releases/tag/v1.2.98
|
|
2698
2730
|
[1.2.97]: https://github.com/kettle-dev/kettle-family/compare/v1.2.96...v1.2.97
|
data/README.md
CHANGED
|
@@ -435,6 +435,12 @@ metadata fix requires a new full release run from step 0:
|
|
|
435
435
|
kettle-family release --publish --start-step 10 --local-ci
|
|
436
436
|
```
|
|
437
437
|
|
|
438
|
+
For `release.target_branches`, a resume position applies only to the first
|
|
439
|
+
selected branch, which is the one whose already-pushed release commit is being
|
|
440
|
+
resumed. Each later branch starts from step 0 so it creates, commits, and pushes
|
|
441
|
+
its own release candidate before `kettle-release` begins remote CI monitoring.
|
|
442
|
+
Use `--start-at member@branch` when the resumed branch is not the first target.
|
|
443
|
+
|
|
438
444
|
`--skip-changelog` skips only `kettle-changelog`; `--skip-appraisals` skips
|
|
439
445
|
only the Appraisal generation portion of release step 5 and still runs
|
|
440
446
|
`bin/rake yard`; and `--skip-ci` skips only remote CI monitoring. The generic
|
|
@@ -1180,7 +1186,7 @@ Thanks for RTFM. ☺️
|
|
|
1180
1186
|
[📌gitmoji]: https://gitmoji.dev
|
|
1181
1187
|
[📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
|
|
1182
1188
|
[🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
|
|
1183
|
-
[🧮kloc-img]: https://img.shields.io/badge/KLOC-6.
|
|
1189
|
+
[🧮kloc-img]: https://img.shields.io/badge/KLOC-6.719-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
|
|
1184
1190
|
[🔐security]: https://github.com/kettle-dev/kettle-family/blob/main/SECURITY.md
|
|
1185
1191
|
[🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
|
|
1186
1192
|
[📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
|
|
@@ -10,6 +10,7 @@ module Kettle
|
|
|
10
10
|
SENSITIVE_ENV_KEYS = [
|
|
11
11
|
"KETTLE_RELEASE_GEM_SIGNING_PASSPHRASE"
|
|
12
12
|
].freeze
|
|
13
|
+
MISE_SESSION_ENV_PREFIX = "__MISE_"
|
|
13
14
|
|
|
14
15
|
class OtpCoordinator
|
|
15
16
|
def initialize(input: $stdin, output: $stdout, queue_total: nil, secrets_provider: nil, event_handler: nil)
|
|
@@ -616,11 +617,14 @@ module Kettle
|
|
|
616
617
|
|
|
617
618
|
def process_env(member:, env:)
|
|
618
619
|
base_env = unbundled_process_env
|
|
620
|
+
clear_outer_mise_session!(base_env) if mise_configured?(member)
|
|
619
621
|
# Bundler's unbundled environment intentionally omits activation
|
|
620
622
|
# variables, but it may also omit PATH. When `unsetenv_others` is used
|
|
621
623
|
# for mise-managed members, dropping PATH makes nested commands such
|
|
622
624
|
# as `bundle` unresolvable inside kettle-jem.
|
|
623
|
-
base_env["PATH"] = if
|
|
625
|
+
base_env["PATH"] = if mise_configured?(member)
|
|
626
|
+
mise_member_path(base_env["PATH"], ENV["PATH"])
|
|
627
|
+
elsif base_env.key?("PATH")
|
|
624
628
|
executable_path(base_env["PATH"])
|
|
625
629
|
else
|
|
626
630
|
ENV["PATH"]
|
|
@@ -647,6 +651,33 @@ module Kettle
|
|
|
647
651
|
paths.compact.map(&:to_s).flat_map { |value| value.split(File::PATH_SEPARATOR) }.reject(&:empty?).uniq.join(File::PATH_SEPARATOR)
|
|
648
652
|
end
|
|
649
653
|
|
|
654
|
+
# `mise exec` selects a member's declared runtime. Do not let the
|
|
655
|
+
# orchestrator's Ruby or gem bin directory precede it on PATH: Bundler
|
|
656
|
+
# otherwise executes the outer runtime after `mise` has entered the
|
|
657
|
+
# member directory, and can rewrite that member's lockfile with the
|
|
658
|
+
# wrong Bundler version.
|
|
659
|
+
def mise_member_path(*paths)
|
|
660
|
+
outer_runtime_paths = [Gem.bindir, File.dirname(RbConfig.ruby)].filter_map do |entry|
|
|
661
|
+
canonical_path(entry) unless entry.to_s.empty?
|
|
662
|
+
end
|
|
663
|
+
paths.flat_map { |path| path.to_s.split(File::PATH_SEPARATOR) }.reject(&:empty?).reject do |entry|
|
|
664
|
+
outer_runtime_paths.include?(canonical_path(entry))
|
|
665
|
+
end.uniq.join(File::PATH_SEPARATOR)
|
|
666
|
+
end
|
|
667
|
+
|
|
668
|
+
# Mise records its active configuration in private `__MISE_*` variables.
|
|
669
|
+
# Retaining them across a nested `mise exec -C member` makes Mise reuse
|
|
670
|
+
# the orchestrator's tool set instead of loading the member's mise.toml.
|
|
671
|
+
def clear_outer_mise_session!(env)
|
|
672
|
+
env.delete_if { |key, _value| key.start_with?(MISE_SESSION_ENV_PREFIX) }
|
|
673
|
+
end
|
|
674
|
+
|
|
675
|
+
def canonical_path(path)
|
|
676
|
+
File.realpath(path)
|
|
677
|
+
rescue Errno::ENOENT, Errno::ENOTDIR
|
|
678
|
+
File.expand_path(path)
|
|
679
|
+
end
|
|
680
|
+
|
|
650
681
|
def unbundled_process_env
|
|
651
682
|
return Bundler.unbundled_env if defined?(Bundler) && Bundler.respond_to?(:unbundled_env)
|
|
652
683
|
return Bundler.original_env if defined?(Bundler) && Bundler.respond_to?(:original_env)
|
|
@@ -7,6 +7,24 @@ module Kettle
|
|
|
7
7
|
class DependencyFloor
|
|
8
8
|
DEPENDENCY_METHODS = %i[add_dependency add_runtime_dependency add_development_dependency].freeze
|
|
9
9
|
|
|
10
|
+
# Return only dependencies declared by the gemspec itself. Release
|
|
11
|
+
# ordering also observes Gemfile-only tooling dependencies, but those
|
|
12
|
+
# cannot have their published floor rewritten by this class.
|
|
13
|
+
def self.gemspec_dependency_names(member)
|
|
14
|
+
return [] unless member.gemspec_path && File.file?(member.gemspec_path)
|
|
15
|
+
|
|
16
|
+
source = File.read(member.gemspec_path)
|
|
17
|
+
parse_result = Kettle::Dev::VersionBump.parse_source(source, member.gemspec_path)
|
|
18
|
+
Kettle::Dev::VersionBump.each_node(parse_result.value).filter_map do |node|
|
|
19
|
+
next unless node.is_a?(Prism::CallNode) && DEPENDENCY_METHODS.include?(node.name)
|
|
20
|
+
|
|
21
|
+
name_node = node.arguments&.arguments&.first
|
|
22
|
+
name_node.unescaped if name_node.is_a?(Prism::StringNode)
|
|
23
|
+
end.uniq
|
|
24
|
+
rescue Kettle::Dev::Error => error
|
|
25
|
+
raise Error, error.message
|
|
26
|
+
end
|
|
27
|
+
|
|
10
28
|
def initialize(released_members:, dependent_members:, mode: :dry_run)
|
|
11
29
|
@released_members = released_members
|
|
12
30
|
@dependent_members = dependent_members
|
|
@@ -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.100"
|
|
9
9
|
end
|
|
10
10
|
# Current gem version exposed at the traditional constant location.
|
|
11
11
|
VERSION = Version::VERSION # Traditional Constant Location
|
|
@@ -1492,7 +1492,7 @@ module Kettle
|
|
|
1492
1492
|
memo.concat(template_branch_sync_results(branch_members, runner: runner))
|
|
1493
1493
|
break memo unless memo.last&.ok?
|
|
1494
1494
|
end
|
|
1495
|
-
branch_results = current_branch_results(branch_members)
|
|
1495
|
+
branch_results = with_release_branch_resume_scope { current_branch_results(branch_members) }
|
|
1496
1496
|
tag_branch_results(branch_results, branch)
|
|
1497
1497
|
memo.concat(branch_results)
|
|
1498
1498
|
|
|
@@ -2604,6 +2604,10 @@ module Kettle
|
|
|
2604
2604
|
end
|
|
2605
2605
|
|
|
2606
2606
|
def release_dependency_floor_reconciliation_results(release_members)
|
|
2607
|
+
# A step resume must continue the already-prepared release commit.
|
|
2608
|
+
# Reconciliation can rewrite lockfiles and create a new commit, which
|
|
2609
|
+
# invalidates the CI SHA selected by the caller's --start-step.
|
|
2610
|
+
return [] if release_step_resume?
|
|
2607
2611
|
return [] unless execute && auto_dependency_floors
|
|
2608
2612
|
# Monorepo members intentionally keep their family dependencies as
|
|
2609
2613
|
# paths in the canonical development lockfile. Registry reconciliation
|
|
@@ -2671,6 +2675,7 @@ module Kettle
|
|
|
2671
2675
|
end
|
|
2672
2676
|
|
|
2673
2677
|
def append_dependency_floor_results(released_members:, dependent_members:, runner:, memo:)
|
|
2678
|
+
return if release_step_resume?
|
|
2674
2679
|
return unless auto_dependency_floors
|
|
2675
2680
|
return if dependent_members.empty?
|
|
2676
2681
|
|
|
@@ -2718,13 +2723,16 @@ module Kettle
|
|
|
2718
2723
|
end
|
|
2719
2724
|
end
|
|
2720
2725
|
|
|
2721
|
-
# A release-valid lockfile must resolve every selected sibling
|
|
2722
|
-
#
|
|
2723
|
-
#
|
|
2724
|
-
#
|
|
2726
|
+
# A release-valid lockfile must resolve every selected sibling whose
|
|
2727
|
+
# gemspec floor can be rewritten by DependencyFloor. Release ordering
|
|
2728
|
+
# deliberately also includes Gemfile-only tooling dependencies, but
|
|
2729
|
+
# those do not have a floor to reconcile and must not delay a runtime
|
|
2730
|
+
# dependency's lockfile refresh until a later wave.
|
|
2725
2731
|
def dependency_floor_refresh_ready?(member, released_members:)
|
|
2726
2732
|
selected_names = members.map(&:name)
|
|
2727
|
-
selected_dependencies =
|
|
2733
|
+
selected_dependencies = DependencyFloor.gemspec_dependency_names(member).select do |dependency|
|
|
2734
|
+
selected_names.include?(dependency)
|
|
2735
|
+
end
|
|
2728
2736
|
completed_names = Array(@release_completed_member_names) + released_members.map(&:name)
|
|
2729
2737
|
selected_dependencies.all? { |dependency| completed_names.include?(dependency) }
|
|
2730
2738
|
end
|
|
@@ -3486,11 +3494,33 @@ module Kettle
|
|
|
3486
3494
|
end
|
|
3487
3495
|
|
|
3488
3496
|
def release_start_step_for(member)
|
|
3497
|
+
return nil if release_branch_resume_scoped? && !@release_branch_resume_active
|
|
3489
3498
|
return start_step unless fast_recovery_for?(member)
|
|
3490
3499
|
|
|
3491
3500
|
(fast_recovery == "retry-ci") ? 10 : 11
|
|
3492
3501
|
end
|
|
3493
3502
|
|
|
3503
|
+
# A release resume identifies one already-prepared branch commit. Later
|
|
3504
|
+
# branches in the same stack still need their complete lifecycle: build,
|
|
3505
|
+
# commit, push, and only then CI monitoring. Do not carry start_step (or
|
|
3506
|
+
# named CI recovery) beyond that first branch.
|
|
3507
|
+
def with_release_branch_resume_scope
|
|
3508
|
+
return yield unless release_branch_resume_scoped?
|
|
3509
|
+
|
|
3510
|
+
previous = @release_branch_resume_active
|
|
3511
|
+
@release_branch_resume_active = !@release_branch_resume_consumed
|
|
3512
|
+
yield
|
|
3513
|
+
ensure
|
|
3514
|
+
@release_branch_resume_consumed = true if @release_branch_resume_active
|
|
3515
|
+
@release_branch_resume_active = previous
|
|
3516
|
+
end
|
|
3517
|
+
|
|
3518
|
+
def release_branch_resume_scoped?
|
|
3519
|
+
command == "release" &&
|
|
3520
|
+
!config.release_target_branches.empty? &&
|
|
3521
|
+
(!start_step.nil? || !fast_recovery.nil?)
|
|
3522
|
+
end
|
|
3523
|
+
|
|
3494
3524
|
def release_skip_steps_for(member)
|
|
3495
3525
|
steps = Array(skip_steps).flat_map { |entry| entry.to_s.split(",") }.map(&:strip).reject(&:empty?)
|
|
3496
3526
|
steps << "10" if skip_ci
|
|
@@ -3641,6 +3671,13 @@ module Kettle
|
|
|
3641
3671
|
env = execution_profile(release_bootstrap_execution_profile, release_env)
|
|
3642
3672
|
env.merge!(release_wave_local_path_env_for(member, family_root: family_root))
|
|
3643
3673
|
env.merge!(release_local_path_policy_env(family_root: family_root))
|
|
3674
|
+
# A resumed child kettle-release starts in the member's mise
|
|
3675
|
+
# environment after the release candidate was already prepared.
|
|
3676
|
+
# Disable sibling paths so mise cannot reactivate them before the
|
|
3677
|
+
# resumed release validates that immutable lockfile. A new release
|
|
3678
|
+
# retains the staged local-graph policy until kettle-release reaches
|
|
3679
|
+
# its own release-lockfile boundary.
|
|
3680
|
+
env.merge!(release_lockfile_local_path_env_overrides(member)) if release_step_resume?
|
|
3644
3681
|
# Family release performs one live pin review before member releases.
|
|
3645
3682
|
# Child kettle-release must consume that reviewed cache instead of
|
|
3646
3683
|
# repeating the GitHub API lookup for every member.
|
|
@@ -5390,6 +5427,10 @@ module Kettle
|
|
|
5390
5427
|
!start_step.nil? || !skip_steps.to_s.empty? || fast_recovery || skip_ci
|
|
5391
5428
|
end
|
|
5392
5429
|
|
|
5430
|
+
def release_step_resume?
|
|
5431
|
+
!start_step.nil? || !skip_steps.to_s.empty?
|
|
5432
|
+
end
|
|
5433
|
+
|
|
5393
5434
|
def execution_profile(profile, env)
|
|
5394
5435
|
profile = ExecutionProfile.fetch(profile) unless profile.is_a?(ExecutionProfile::Definition)
|
|
5395
5436
|
env = env.dup
|
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.100
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Peter H. Boling
|
|
@@ -94,7 +94,7 @@ dependencies:
|
|
|
94
94
|
version: '3.0'
|
|
95
95
|
- - ">="
|
|
96
96
|
- !ruby/object:Gem::Version
|
|
97
|
-
version: 3.0.
|
|
97
|
+
version: 3.0.34
|
|
98
98
|
type: :runtime
|
|
99
99
|
prerelease: false
|
|
100
100
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -104,7 +104,7 @@ dependencies:
|
|
|
104
104
|
version: '3.0'
|
|
105
105
|
- - ">="
|
|
106
106
|
- !ruby/object:Gem::Version
|
|
107
|
-
version: 3.0.
|
|
107
|
+
version: 3.0.34
|
|
108
108
|
- !ruby/object:Gem::Dependency
|
|
109
109
|
name: kettle-gha-pins
|
|
110
110
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -443,10 +443,10 @@ licenses:
|
|
|
443
443
|
- AGPL-3.0-only
|
|
444
444
|
metadata:
|
|
445
445
|
homepage_uri: https://kettle-family.galtzo.com
|
|
446
|
-
source_code_uri: https://github.com/kettle-dev/kettle-family/tree/v1.2.
|
|
447
|
-
changelog_uri: https://github.com/kettle-dev/kettle-family/blob/v1.2.
|
|
446
|
+
source_code_uri: https://github.com/kettle-dev/kettle-family/tree/v1.2.100
|
|
447
|
+
changelog_uri: https://github.com/kettle-dev/kettle-family/blob/v1.2.100/CHANGELOG.md
|
|
448
448
|
bug_tracker_uri: https://github.com/kettle-dev/kettle-family/issues
|
|
449
|
-
documentation_uri: https://www.rubydoc.info/gems/kettle-family/1.2.
|
|
449
|
+
documentation_uri: https://www.rubydoc.info/gems/kettle-family/1.2.100
|
|
450
450
|
funding_uri: https://github.com/sponsors/pboling
|
|
451
451
|
wiki_uri: https://github.com/kettle-dev/kettle-family/wiki
|
|
452
452
|
news_uri: https://www.railsbling.com/tags/kettle-family
|
metadata.gz.sig
CHANGED
|
Binary file
|