kettle-family 1.2.97 → 1.2.99

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 85cd07ac87342ba42bcea97136be59eb3cdde7737f33e81f8b1f554d9ed5f875
4
- data.tar.gz: fe3d86e41548b66fde62baf1b81dda2636befa505c1db6c0c2e82fe4a6b35b2e
3
+ metadata.gz: e3fff3ab628dc6f5338ddf0a820485b986ce5f40aec27a905f1ee15e18450ab9
4
+ data.tar.gz: fa34533d50ee506f05e2f1cd9f865c011d12e91996b1c38cbabfe76eb0f9c676
5
5
  SHA512:
6
- metadata.gz: 772815e8948f2760a938e55ccff3a2848073a3605b02c3581995e01e40e1a80037356c033abea71b13c01bc06efb2ea3a93a09401266e712f51ddf1bf42290af
7
- data.tar.gz: 0a6886e0040e1389b95b876d6ca90dba2dc3e633024a2b7132db3a50671d9126e9f86e7492f1c14ad723af914fce3d4c78be1fabd1cc76a71aaa50aaaec3580f
6
+ metadata.gz: 81f62b1263cd2afbe483f7af09d0a4c1b3e4efac0328938592c84e381d5d731188031e1e9dad97ce343573b025a50d9de62424ce92d12be7245beced5de9996d
7
+ data.tar.gz: 95713fbc85dd8e285b7b94364bfe799735df2d2b9f19b1205d2ad0819d793f66c94e39aa3b3816826b2987dacabc14519e24f01a0447f29af1edb55567d49f95
checksums.yaml.gz.sig CHANGED
Binary file
data/CHANGELOG.md CHANGED
@@ -30,6 +30,32 @@ Please file a bug if you notice a violation of semantic versioning.
30
30
 
31
31
  ### Security
32
32
 
33
+ ## [1.2.99] - 2026-09-09
34
+
35
+ - TAG: [v1.2.99][1.2.99t]
36
+ - COVERAGE: 93.52% -- 6261/6695 lines in 35 files
37
+ - BRANCH COVERAGE: 78.19% -- 2542/3251 branches in 35 files
38
+ - 32.75% documented
39
+
40
+ ### Fixed
41
+
42
+ - Keep resumed family releases on the prepared CI commit by skipping dependency-floor reconciliation and disabling sibling paths for child release validation.
43
+
44
+ - Scope branch-stack release resumes to the prepared branch so later targets run their complete release lifecycle before CI monitoring.
45
+
46
+ ## [1.2.98] - 2026-09-09
47
+
48
+ - TAG: [v1.2.98][1.2.98t]
49
+ - COVERAGE: 93.50% -- 6245/6679 lines in 35 files
50
+ - BRANCH COVERAGE: 78.08% -- 2529/3239 branches in 35 files
51
+ - 32.75% documented
52
+
53
+ ### Fixed
54
+
55
+ - Commit the final normalized Gemfile.lock after sibling and branch-worktree template runs.
56
+
57
+ - Bootstrap member releases from the family tool bundle before registry lockfile normalization.
58
+
33
59
  ## [1.2.97] - 2026-09-08
34
60
 
35
61
  - TAG: [v1.2.97][1.2.97t]
@@ -2679,7 +2705,11 @@ Please file a bug if you notice a violation of semantic versioning.
2679
2705
  - Fixed CI load failures on engines without compatible `pty` support by falling back to Open3 for interactive release commands.
2680
2706
  - Fixed Ruby 3.2 version-bump support by loading Prism lazily and wiring the Prism gem only for MRI versions that need it.
2681
2707
 
2682
- [Unreleased]: https://github.com/kettle-dev/kettle-family/compare/v1.2.97...HEAD
2708
+ [Unreleased]: https://github.com/kettle-dev/kettle-family/compare/v1.2.99...HEAD
2709
+ [1.2.99]: https://github.com/kettle-dev/kettle-family/compare/v1.2.98...v1.2.99
2710
+ [1.2.99t]: https://github.com/kettle-dev/kettle-family/releases/tag/v1.2.99
2711
+ [1.2.98]: https://github.com/kettle-dev/kettle-family/compare/v1.2.97...v1.2.98
2712
+ [1.2.98t]: https://github.com/kettle-dev/kettle-family/releases/tag/v1.2.98
2683
2713
  [1.2.97]: https://github.com/kettle-dev/kettle-family/compare/v1.2.96...v1.2.97
2684
2714
  [1.2.97t]: https://github.com/kettle-dev/kettle-family/releases/tag/v1.2.97
2685
2715
  [1.2.96]: https://github.com/kettle-dev/kettle-family/compare/v1.2.95...v1.2.96
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
@@ -662,6 +668,15 @@ and leaves RubyGems MFA prompts interactive by default:
662
668
  kettle-family release --publish --execute
663
669
  ```
664
670
 
671
+ Release uses two explicitly separate execution contexts. `release_bootstrap`
672
+ starts `kettle-release` from the family-root tool bundle, so a family can retain
673
+ its configured local sibling graph while it prepares a release wave. It never
674
+ uses a member's development Gemfile to boot the release tool. `release_registry`
675
+ then resets each tracked release lockfile against registry dependencies and is
676
+ also used by every project release child command. Local sibling paths therefore
677
+ remain available only before that transition; they cannot enter the canonical
678
+ lockfile, the release-preparation commit, or CI-facing project commands.
679
+
665
680
  Use named recovery modes when a publish wave has already prepared a member:
666
681
 
667
682
  ```console
@@ -1171,7 +1186,7 @@ Thanks for RTFM. ☺️
1171
1186
  [📌gitmoji]: https://gitmoji.dev
1172
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
1173
1188
  [🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
1174
- [🧮kloc-img]: https://img.shields.io/badge/KLOC-6.670-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
1189
+ [🧮kloc-img]: https://img.shields.io/badge/KLOC-6.695-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
1175
1190
  [🔐security]: https://github.com/kettle-dev/kettle-family/blob/main/SECURITY.md
1176
1191
  [🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
1177
1192
  [📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
@@ -40,6 +40,18 @@ module Kettle
40
40
  host_platform_policy: :active_platform_must_resolve,
41
41
  allowed_mutations: %i[template development_lockfiles generated]
42
42
  ),
43
+ # This profile only starts the release implementation from the family
44
+ # tool bundle. It is intentionally distinct from release_registry:
45
+ # canonical lockfile reset and all project release children use that
46
+ # registry-only profile after the tool has booted.
47
+ release_bootstrap: Definition.new(
48
+ name: :release_bootstrap,
49
+ path_gem_policy: :configured_siblings,
50
+ lockfile_role: :tool,
51
+ install_location: :family,
52
+ host_platform_policy: :active_platform_must_resolve,
53
+ allowed_mutations: %i[release_tool_bootstrap]
54
+ ),
43
55
  release_registry: Definition.new(
44
56
  name: :release_registry,
45
57
  path_gem_policy: :registry_only,
@@ -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.97"
8
+ VERSION = "1.2.99"
9
9
  end
10
10
  # Current gem version exposed at the traditional constant location.
11
11
  VERSION = Version::VERSION # Traditional Constant Location
@@ -1451,6 +1451,7 @@ module Kettle
1451
1451
  normalize_lockfiles(member: member, runner: runner, memo: memo, phase: "normalize_lockfiles", commit_changes: commit_changes)
1452
1452
  emit_member_result_progress(member, memo.last, progress: progress, progress_key: progress_key, progress_label: progress_label)
1453
1453
  commit_template_changes(member: member, runner: runner, memo: memo) if commit_changes
1454
+ commit_template_normalized_gemfile_lock(member: member, runner: runner, memo: memo, commit_changes: commit_changes)
1454
1455
  emit_member_result_progress(member, memo.last, progress: progress, progress_key: progress_key, progress_label: progress_label) if memo.last&.phase == "commit_template"
1455
1456
  ensure
1456
1457
  template_result = memo.find { |result| result.phase == "template" } || memo.last
@@ -1491,7 +1492,7 @@ module Kettle
1491
1492
  memo.concat(template_branch_sync_results(branch_members, runner: runner))
1492
1493
  break memo unless memo.last&.ok?
1493
1494
  end
1494
- branch_results = current_branch_results(branch_members)
1495
+ branch_results = with_release_branch_resume_scope { current_branch_results(branch_members) }
1495
1496
  tag_branch_results(branch_results, branch)
1496
1497
  memo.concat(branch_results)
1497
1498
 
@@ -2603,6 +2604,10 @@ module Kettle
2603
2604
  end
2604
2605
 
2605
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?
2606
2611
  return [] unless execute && auto_dependency_floors
2607
2612
  # Monorepo members intentionally keep their family dependencies as
2608
2613
  # paths in the canonical development lockfile. Registry reconciliation
@@ -2670,6 +2675,7 @@ module Kettle
2670
2675
  end
2671
2676
 
2672
2677
  def append_dependency_floor_results(released_members:, dependent_members:, runner:, memo:)
2678
+ return if release_step_resume?
2673
2679
  return unless auto_dependency_floors
2674
2680
  return if dependent_members.empty?
2675
2681
 
@@ -3485,11 +3491,33 @@ module Kettle
3485
3491
  end
3486
3492
 
3487
3493
  def release_start_step_for(member)
3494
+ return nil if release_branch_resume_scoped? && !@release_branch_resume_active
3488
3495
  return start_step unless fast_recovery_for?(member)
3489
3496
 
3490
3497
  (fast_recovery == "retry-ci") ? 10 : 11
3491
3498
  end
3492
3499
 
3500
+ # A release resume identifies one already-prepared branch commit. Later
3501
+ # branches in the same stack still need their complete lifecycle: build,
3502
+ # commit, push, and only then CI monitoring. Do not carry start_step (or
3503
+ # named CI recovery) beyond that first branch.
3504
+ def with_release_branch_resume_scope
3505
+ return yield unless release_branch_resume_scoped?
3506
+
3507
+ previous = @release_branch_resume_active
3508
+ @release_branch_resume_active = !@release_branch_resume_consumed
3509
+ yield
3510
+ ensure
3511
+ @release_branch_resume_consumed = true if @release_branch_resume_active
3512
+ @release_branch_resume_active = previous
3513
+ end
3514
+
3515
+ def release_branch_resume_scoped?
3516
+ command == "release" &&
3517
+ !config.release_target_branches.empty? &&
3518
+ (!start_step.nil? || !fast_recovery.nil?)
3519
+ end
3520
+
3493
3521
  def release_skip_steps_for(member)
3494
3522
  steps = Array(skip_steps).flat_map { |entry| entry.to_s.split(",") }.map(&:strip).reject(&:empty?)
3495
3523
  steps << "10" if skip_ci
@@ -3637,9 +3665,16 @@ module Kettle
3637
3665
  # changelog may live at the family root. Pass the shared paths to the
3638
3666
  # member release phase as well as to the separate family phase.
3639
3667
  def release_env_for_member(member, family_root: config.root, wave_jobs: 1)
3640
- env = release_env
3668
+ env = execution_profile(release_bootstrap_execution_profile, release_env)
3641
3669
  env.merge!(release_wave_local_path_env_for(member, family_root: family_root))
3642
3670
  env.merge!(release_local_path_policy_env(family_root: family_root))
3671
+ # A resumed child kettle-release starts in the member's mise
3672
+ # environment after the release candidate was already prepared.
3673
+ # Disable sibling paths so mise cannot reactivate them before the
3674
+ # resumed release validates that immutable lockfile. A new release
3675
+ # retains the staged local-graph policy until kettle-release reaches
3676
+ # its own release-lockfile boundary.
3677
+ env.merge!(release_lockfile_local_path_env_overrides(member)) if release_step_resume?
3643
3678
  # Family release performs one live pin review before member releases.
3644
3679
  # Child kettle-release must consume that reviewed cache instead of
3645
3680
  # repeating the GitHub API lookup for every member.
@@ -3703,15 +3738,15 @@ module Kettle
3703
3738
  candidates.find { |path| File.file?(path) }
3704
3739
  end
3705
3740
 
3706
- # A member's development lockfile can pin an older kettle-dev than the
3707
- # family runner. That older release tool may not understand the current
3708
- # family policy, notably configured monorepo PATH dependencies. Launch
3709
- # kettle-release from the family bundle instead; the release tool still
3710
- # runs member project commands from the member checkout.
3741
+ # A member's development Gemfile can contain a deliberately local family
3742
+ # graph that is not independently bootable after an earlier release wave
3743
+ # changes a sibling's dependency floor. Launch kettle-release from the
3744
+ # family tool bundle instead. The release tool still runs project commands
3745
+ # from the member checkout, where it first normalizes canonical lockfiles
3746
+ # with local paths disabled.
3711
3747
  def release_tool_gemfile_path(local_kettle_dev)
3712
3748
  local_kettle_dev_gemfile = local_kettle_dev_gemfile_path(local_kettle_dev)
3713
3749
  return local_kettle_dev_gemfile if local_kettle_dev_gemfile
3714
- return unless config.configured_monorepo_release?
3715
3750
 
3716
3751
  family_gemfile = File.join(config.root, "Gemfile")
3717
3752
  family_gemfile if File.file?(family_gemfile)
@@ -5319,6 +5354,23 @@ module Kettle
5319
5354
  end
5320
5355
  end
5321
5356
 
5357
+ # Kettle Jem commits its own changes for sibling repositories. The final
5358
+ # lockfile normalization therefore happens after that commit and needs a
5359
+ # separate, deliberately narrow cleanup commit. Monorepos defer the
5360
+ # template commit, which already includes the normalized lockfile.
5361
+ def commit_template_normalized_gemfile_lock(member:, runner:, memo:, commit_changes:)
5362
+ return unless execute && commit_changes && memo.all?
5363
+ return if deferred_monorepo_template_commit?(member)
5364
+
5365
+ commit_normalized_lockfiles(
5366
+ branch_members: [member],
5367
+ runner: runner,
5368
+ memo: memo,
5369
+ reason: "template",
5370
+ paths: ["Gemfile.lock"]
5371
+ )
5372
+ end
5373
+
5322
5374
  def template_commit_message(member)
5323
5375
  "🎨 Template #{member.name} by kettle-family"
5324
5376
  end
@@ -5357,6 +5409,10 @@ module Kettle
5357
5409
  ExecutionProfile.fetch(:template_local)
5358
5410
  end
5359
5411
 
5412
+ def release_bootstrap_execution_profile
5413
+ ExecutionProfile.fetch(:release_bootstrap)
5414
+ end
5415
+
5360
5416
  def release_lockfile_execution_profile
5361
5417
  return ExecutionProfile.fetch(:release_recovery) if release_recovery?
5362
5418
  return ExecutionProfile.fetch(:release_monorepo) if preserve_monorepo_template_context?
@@ -5368,6 +5424,10 @@ module Kettle
5368
5424
  !start_step.nil? || !skip_steps.to_s.empty? || fast_recovery || skip_ci
5369
5425
  end
5370
5426
 
5427
+ def release_step_resume?
5428
+ !start_step.nil? || !skip_steps.to_s.empty?
5429
+ end
5430
+
5371
5431
  def execution_profile(profile, env)
5372
5432
  profile = ExecutionProfile.fetch(profile) unless profile.is_a?(ExecutionProfile::Definition)
5373
5433
  env = env.dup
@@ -5375,7 +5435,7 @@ module Kettle
5375
5435
  when :template_local
5376
5436
  env["K_JEM_TEMPLATING"] = "true"
5377
5437
  env["BUNDLE_DISABLE_CHECKSUM_VALIDATION"] = "true"
5378
- when :release_registry, :release_monorepo, :release_recovery
5438
+ when :release_bootstrap, :release_registry, :release_monorepo, :release_recovery
5379
5439
  # Release profiles deliberately leave Bundler mutation decisions to
5380
5440
  # kettle-dev. The profile selection controls which local-path
5381
5441
  # overrides this workflow contributes below.
@@ -5588,10 +5648,14 @@ module Kettle
5588
5648
  text.include?(File::SEPARATOR)
5589
5649
  end
5590
5650
 
5591
- def commit_normalized_lockfiles(branch_members:, runner:, memo:, reason: command, force: false)
5651
+ def commit_normalized_lockfiles(branch_members:, runner:, memo:, reason: command, force: false, paths: nil)
5592
5652
  return unless commit
5593
5653
  return unless force || commit_normalized_lockfiles?(reason)
5594
5654
 
5655
+ pathspecs = Array(paths).map { |path| Shellwords.escape(path) }
5656
+ pathspecs = ["Gemfile.lock", "'*.lock'", "'**/*.lock'"] if pathspecs.empty?
5657
+ pathspec = pathspecs.join(" ")
5658
+
5595
5659
  branch_members.each do |member|
5596
5660
  result = runner.call(
5597
5661
  member: member,
@@ -5599,7 +5663,7 @@ module Kettle
5599
5663
  command: [
5600
5664
  "sh",
5601
5665
  "-lc",
5602
- "files=$(git ls-files --modified --others --exclude-standard -- Gemfile.lock '*.lock' '**/*.lock'); " \
5666
+ "files=$(git ls-files --modified --others --exclude-standard -- #{pathspec}); " \
5603
5667
  "if [ -n \"$files\" ]; then printf '%s\\n' \"$files\" | xargs git add -- && git commit -m " \
5604
5668
  "#{Shellwords.escape(normalized_lockfiles_commit_message(reason))}; fi"
5605
5669
  ]
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.97
4
+ version: 1.2.99
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter H. Boling
@@ -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.97
447
- changelog_uri: https://github.com/kettle-dev/kettle-family/blob/v1.2.97/CHANGELOG.md
446
+ source_code_uri: https://github.com/kettle-dev/kettle-family/tree/v1.2.99
447
+ changelog_uri: https://github.com/kettle-dev/kettle-family/blob/v1.2.99/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.97
449
+ documentation_uri: https://www.rubydoc.info/gems/kettle-family/1.2.99
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