kettle-family 1.2.93 → 1.2.95

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: a1a24d4a7f560730b58dea502aa74c1f7c2b6b5821c92bc565ee5d0eff79d8be
4
- data.tar.gz: 58f47810263c6279e727419acb896abb959ccac76bff444c83b19c88c85f64f5
3
+ metadata.gz: 9b482c620e7f5e341caead6b52476cc8dc26e56c5d0ecde281ca27f7aaacc3e3
4
+ data.tar.gz: 78c5c14ec0d5a90a34341650d010216e241fb4927983dff9507b66d9e9ccaf6d
5
5
  SHA512:
6
- metadata.gz: 7bb4085cb68b1d1ee1592ad1ab43d55afbc08a4c12a341ffffb6f1b3d712f43e51e0b8b4f59095fdd8402e1fa7c21822d6b43da8c8bd4caf340e102418d2974c
7
- data.tar.gz: c12db5ebfea5489500b221fbc39f8d638fc6f4ad119eb73a210e195b779804325be2effad8970a78b65f7a5f0b837a9d324bb12242ab33c61b782877de5d6343
6
+ metadata.gz: 61ab40f1165dc584b786cf9e5f72005390aa786bcc2f6d0b1f4e9c172d566d8efd310625bac5a218312b221e5f8577071d699dc0eadaa6b1260cdb7ac4444736
7
+ data.tar.gz: f4097829a8ca4127f0a2a6dc4f53ea84886d14e68c9df2ec82db9319904482ba9d6f2339d087596b048419d7c63707462f5c38e45e8bf475149e295fc4479868
checksums.yaml.gz.sig CHANGED
@@ -1,3 +1,3 @@
1
- :��H+>��|L̖��~�̃���c:���j�yIs�0���ٛ-I��W~i��E����fb�؃G�~�fl�X<�� $��u��"��7���/���v����]���# q,�/�2o��|.bM���xv.yA!�z�����xH�����0�=���g%r7�Sʶ!�X _���K����ei��V>Cu��
2
- � �,�M�pye� ��`�+
3
- 63`o�L���nW ��I��V"��[)Zg�%�d���'50���]�Ǖ�}A���J�b��<���}(�_[[��{Q��5����g���)/�2�ܓ�Τ�J
1
+ A(�#�-]Zf��(��ȯ�7ֺJ2Qf
2
+ �Mx'{UM:�F�롄�>�����q�!b�w��2ɤ8#+e*d>#�`NǚB��z��6�8|r�^@����߰���7���G������?�5*݆��.�s9� �y���D��eJ^�N�h����!O]k 2ǯ8�/y T5�}Ϥ�'x�hHg�0�wHE$�~���h�Ť��a���I��W9u�.^J3���%-�YJ�ӓ�����>0����K36���4p
3
+ ����U�1?ɔo(S�FC�
data/CHANGELOG.md CHANGED
@@ -30,6 +30,30 @@ Please file a bug if you notice a violation of semantic versioning.
30
30
 
31
31
  ### Security
32
32
 
33
+ ## [1.2.95] - 2026-09-07
34
+
35
+ - TAG: [v1.2.95][1.2.95t]
36
+ - COVERAGE: 93.49% -- 6199/6631 lines in 35 files
37
+ - BRANCH COVERAGE: 78.03% -- 2515/3223 branches in 35 files
38
+ - 32.58% documented
39
+
40
+ ### Fixed
41
+
42
+ - Run release-target branch worktrees through the full template bootstrap workflow before member preparation.
43
+
44
+ ## [1.2.94] - 2026-09-07
45
+
46
+ - TAG: [v1.2.94][1.2.94t]
47
+ - COVERAGE: 93.50% -- 6183/6613 lines in 35 files
48
+ - BRANCH COVERAGE: 78.04% -- 2512/3219 branches in 35 files
49
+ - 32.58% documented
50
+
51
+ ### Fixed
52
+
53
+ - Restrict inferred monorepo release path allowances to CI-resident paths, preserving external development overrides for local-only dependency work.
54
+
55
+ - Allow bup and bupb to commit explicitly selected development path graphs while continuing to reject unrequested local lockfile paths.
56
+
33
57
  ## [1.2.93] - 2026-09-07
34
58
 
35
59
  - TAG: [v1.2.93][1.2.93t]
@@ -2627,7 +2651,11 @@ Please file a bug if you notice a violation of semantic versioning.
2627
2651
  - Fixed CI load failures on engines without compatible `pty` support by falling back to Open3 for interactive release commands.
2628
2652
  - Fixed Ruby 3.2 version-bump support by loading Prism lazily and wiring the Prism gem only for MRI versions that need it.
2629
2653
 
2630
- [Unreleased]: https://github.com/kettle-dev/kettle-family/compare/v1.2.93...HEAD
2654
+ [Unreleased]: https://github.com/kettle-dev/kettle-family/compare/v1.2.95...HEAD
2655
+ [1.2.95]: https://github.com/kettle-dev/kettle-family/compare/v1.2.94...v1.2.95
2656
+ [1.2.95t]: https://github.com/kettle-dev/kettle-family/releases/tag/v1.2.95
2657
+ [1.2.94]: https://github.com/kettle-dev/kettle-family/compare/v1.2.93...v1.2.94
2658
+ [1.2.94t]: https://github.com/kettle-dev/kettle-family/releases/tag/v1.2.94
2631
2659
  [1.2.93]: https://github.com/kettle-dev/kettle-family/compare/v1.2.92...v1.2.93
2632
2660
  [1.2.93t]: https://github.com/kettle-dev/kettle-family/releases/tag/v1.2.93
2633
2661
  [1.2.92]: https://github.com/kettle-dev/kettle-family/compare/v1.2.91...v1.2.92
data/README.md CHANGED
@@ -255,13 +255,19 @@ release:
255
255
  - kettle-jem
256
256
  ```
257
257
 
258
- `family.local_path_env` names the environment variable that activates local
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.
258
+ `family.local_path_env` names the environment variable that activates the
259
+ family's development path graph. It does not, by itself, make a path valid in
260
+ CI or safe to retain in a release lockfile. For an explicitly configured
261
+ `family.mode: monorepo`, `kettle-family` derives a release-lock policy only
262
+ when that path is contained by the family repository; this is the case when
263
+ the CI checkout contains the same member graph. The tracked `Gemfile.lock`
264
+ may then retain those member `PATH` sources.
265
+
266
+ A monorepo can also reference a separate checkout, for example a shared base
267
+ gem in its parent workspace. That is an external development override, not an
268
+ internal monorepo path: it is removed for release unless
269
+ `release.allowed_local_path_roots` and `release.allowed_local_path_env`
270
+ explicitly describe matching CI checkout provisioning.
265
271
 
266
272
  Sibling-repository families do not receive this exception. Their canonical
267
273
  lockfiles must use released dependencies: a local Kettle Dev workspace, or
@@ -607,9 +613,13 @@ family-root lockfile is also validated and committed for monorepos, where the
607
613
  root and members share one Git repository. A sibling-repository family root is
608
614
  updated for its orchestration bundle but is not included in any member commit.
609
615
  Use `--no-commit` for a working-tree-only refresh, or `--commit` to state the
610
- default explicitly. Local dependency environment variables are preserved when
611
- explicitly supplied, so use the family's local or released dependency mode
612
- deliberately before running it.
616
+ default explicitly. `bup` and `bupb` validate the development graph selected
617
+ by their explicit local-path environment and commit it by default; this keeps
618
+ template synchronization from being blocked by expected local-path lockfile
619
+ changes. Release workflows separately normalize and validate their
620
+ CI/release graph. A normal family-local graph and an unreleased external
621
+ Kettle toolchain are separate choices; project task wrappers should not
622
+ silently enable the latter for ordinary `bup` or `bupb` runs.
613
623
 
614
624
  Plan or update GitHub Actions workflow SHA pins across the selected family
615
625
  members:
@@ -892,6 +902,23 @@ the template dependency graph. It must not invoke release-lockfile reset logic:
892
902
  release normalization intentionally disables local paths, while template
893
903
  recovery needs configured sibling paths to resolve unreleased family versions.
894
904
 
905
+ ### Branch Worktree Equivalence
906
+
907
+ A release-target branch worktree is a separate checkout of the same template
908
+ member, not a reduced template workflow. Before its member template body runs,
909
+ it executes the same debugger, Appraisal, and Nomono bootstrap boundary as an
910
+ ordinary member. It then executes the same lockfile preparation, dependency
911
+ preparation and recovery, `kettle-jem` invocation, lockfile normalization, and
912
+ template commit path with the same `template_local` environment.
913
+
914
+ Only checkout mechanics differ: Family creates and trusts the linked worktree,
915
+ rebases that target branch on its own upstream when one exists, attaches the
916
+ branch name to the results, and removes the worktree after completion. These
917
+ steps are necessary because each target has a distinct Git ref and an absolute
918
+ `mise` configuration path. They do not change the dependency graph or omit a
919
+ template phase. Regression specs assert that branch worktrees call the shared
920
+ bootstrap boundary and cannot start a member template body when it fails.
921
+
895
922
  ## 🔐 Security
896
923
 
897
924
  See [SECURITY.md][🔐security].
@@ -1144,7 +1171,7 @@ Thanks for RTFM. ☺️
1144
1171
  [📌gitmoji]: https://gitmoji.dev
1145
1172
  [📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
1146
1173
  [🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
1147
- [🧮kloc-img]: https://img.shields.io/badge/KLOC-6.591-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
1174
+ [🧮kloc-img]: https://img.shields.io/badge/KLOC-6.631-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
1148
1175
  [🔐security]: https://github.com/kettle-dev/kettle-family/blob/main/SECURITY.md
1149
1176
  [🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
1150
1177
  [📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
@@ -285,18 +285,29 @@ module Kettle
285
285
  end
286
286
 
287
287
  def release_allowed_local_path_roots
288
- inferred = configured_monorepo_release? ? [family_local_path_root] : []
288
+ inferred = ci_resident_monorepo_local_path_graph? ? [family_local_path_root] : []
289
289
  configured = Array(fetch_path("release", "allowed_local_path_roots"))
290
290
  .map { |path| expand_config_relative_path(path) }
291
291
  (inferred + configured).uniq
292
292
  end
293
293
 
294
294
  def release_allowed_local_path_env_names
295
- inferred = configured_monorepo_release? ? [family_local_path_env_name] : []
295
+ inferred = ci_resident_monorepo_local_path_graph? ? [family_local_path_env_name] : []
296
296
  configured = Array(fetch_path("release", "allowed_local_path_env"))
297
297
  (inferred + configured).compact.map(&:to_s).reject(&:empty?).uniq
298
298
  end
299
299
 
300
+ # A monorepo may still use an environment switch to reach a separate
301
+ # sibling checkout. Only a path contained by this repository can be
302
+ # inferred as CI-resident and retained in release lockfiles.
303
+ def ci_resident_monorepo_local_path_graph?
304
+ return false unless fetch_path("family", "mode") == "monorepo"
305
+
306
+ path_within_root?(family_local_path_root)
307
+ end
308
+
309
+ # This remains the repository-topology predicate used by release
310
+ # scheduling. CI-safe local path inference is deliberately narrower.
300
311
  def configured_monorepo_release?
301
312
  fetch_path("family", "mode") == "monorepo"
302
313
  end
@@ -371,6 +382,12 @@ module Kettle
371
382
 
372
383
  private
373
384
 
385
+ def path_within_root?(path)
386
+ expanded_path = File.expand_path(path)
387
+ expanded_root = File.expand_path(root)
388
+ expanded_path == expanded_root || expanded_path.start_with?("#{expanded_root}/")
389
+ end
390
+
374
391
  def expand_config_relative_path(value)
375
392
  text = value.to_s
376
393
  return text if text.start_with?("/")
@@ -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.93"
8
+ VERSION = "1.2.95"
9
9
  end
10
10
  # Current gem version exposed at the traditional constant location.
11
11
  VERSION = Version::VERSION # Traditional Constant Location
@@ -932,14 +932,8 @@ module Kettle
932
932
  end
933
933
 
934
934
  def template_member_workflow_results(workflow_members)
935
- debugger_results = template_debugger_bootstrap_results(workflow_members)
936
- return debugger_results unless debugger_results.all?(&:ok?)
937
-
938
- appraisal_results = template_appraisal_bootstrap_results(workflow_members)
939
- return debugger_results + appraisal_results unless appraisal_results.all?(&:ok?)
940
-
941
- bootstrap_results = template_bootstrap_dependency_results(workflow_members)
942
- return debugger_results + appraisal_results + bootstrap_results unless bootstrap_results.all?(&:ok?)
935
+ bootstrap_results = template_member_bootstrap_results(workflow_members)
936
+ return bootstrap_results unless bootstrap_results.all?(&:ok?)
943
937
 
944
938
  template_progress = start_template_progress(workflow_members)
945
939
  results = template_dependency_waves(workflow_members).each_with_object([]) do |wave, memo|
@@ -948,7 +942,22 @@ module Kettle
948
942
  break memo unless wave_results.all?(&:ok?)
949
943
  end
950
944
  emit_template_progress_summary(results, progress: template_progress)
951
- debugger_results + appraisal_results + bootstrap_results + results
945
+ bootstrap_results + results
946
+ end
947
+
948
+ # This is the common preparation boundary for every template member,
949
+ # regardless of whether it runs in its primary checkout, a monorepo
950
+ # worktree, or a release-target branch worktree. Keep branch mechanics
951
+ # outside this method so they cannot silently omit a bootstrap phase.
952
+ def template_member_bootstrap_results(workflow_members)
953
+ debugger_results = template_debugger_bootstrap_results(workflow_members)
954
+ return debugger_results unless debugger_results.all?(&:ok?)
955
+
956
+ appraisal_results = template_appraisal_bootstrap_results(workflow_members)
957
+ return debugger_results + appraisal_results unless appraisal_results.all?(&:ok?)
958
+
959
+ bootstrap_results = template_bootstrap_dependency_results(workflow_members)
960
+ debugger_results + appraisal_results + bootstrap_results
952
961
  end
953
962
 
954
963
  def template_debugger_bootstrap_results(workflow_members)
@@ -1650,6 +1659,17 @@ module Kettle
1650
1659
  end
1651
1660
 
1652
1661
  def template_branch_worktree_entries_results(entries)
1662
+ results = template_branch_worktree_sync_results(entries)
1663
+ return results unless results.all?(&:ok?)
1664
+
1665
+ # A branch worktree is a different checkout, not a different template
1666
+ # profile. Run the exact same member bootstrap boundary used by normal
1667
+ # members before any branch begins its member template body.
1668
+ bootstrap_results = template_member_bootstrap_results(entries.map { |entry| entry.fetch(:member) })
1669
+ tag_template_worktree_results(bootstrap_results, entries)
1670
+ results.concat(bootstrap_results)
1671
+ return results unless bootstrap_results.all?(&:ok?)
1672
+
1653
1673
  wave_jobs = template_jobs(entries)
1654
1674
  queue = Queue.new
1655
1675
  entries.each_with_index { |entry, index| queue << [index, entry] }
@@ -1671,23 +1691,41 @@ module Kettle
1671
1691
  end
1672
1692
  end
1673
1693
  end.each(&:join)
1674
- ordered_results.compact.flatten
1694
+ results + ordered_results.compact.flatten
1675
1695
  end
1676
1696
 
1677
1697
  def template_branch_worktree_entry_results(entry, wave_jobs: 1)
1678
1698
  member = entry.fetch(:member)
1679
1699
  branch = entry.fetch(:branch)
1680
- runner = command_runner
1681
- results = []
1682
- if git_upstream_for(member)
1683
- results << runner.call(member: member, phase: "template_branch_sync", command: ["git", "rebase", "@{upstream}"])
1684
- end
1685
- results.concat(template_results_for_member(member, wave_jobs: wave_jobs)) if results.all?(&:ok?)
1700
+ # Bootstrap and upstream synchronization are deliberately performed
1701
+ # for the complete branch set before workers start. The member body is
1702
+ # the same method normal template waves invoke.
1703
+ results = template_results_for_member(member, wave_jobs: wave_jobs)
1686
1704
  tag_branch_results(results, branch)
1687
1705
  emit_template_event_line(member, results.all?(&:ok?) ? "." : "F", "branch #{branch}")
1688
1706
  results
1689
1707
  end
1690
1708
 
1709
+ def template_branch_worktree_sync_results(entries)
1710
+ runner = command_runner
1711
+ entries.filter_map do |entry|
1712
+ member = entry.fetch(:member)
1713
+ upstream = git_upstream_for(member)
1714
+ next unless upstream
1715
+
1716
+ result = runner.call(member: member, phase: "template_branch_sync", command: ["git", "rebase", "@{upstream}"])
1717
+ result.branch = entry.fetch(:branch)
1718
+ result
1719
+ end
1720
+ end
1721
+
1722
+ def tag_template_worktree_results(results, entries)
1723
+ branches_by_root = entries.to_h { |entry| [File.expand_path(entry.fetch(:member).root), entry.fetch(:branch)] }
1724
+ results.each do |result|
1725
+ result.branch = branches_by_root[File.expand_path(result.workdir)] if result.workdir
1726
+ end
1727
+ end
1728
+
1691
1729
  def template_branch_worktree_cleanup_results(entries, runner:, control_member:)
1692
1730
  entries.filter_map do |entry|
1693
1731
  worktree_root = entry[:worktree_root]
@@ -5580,7 +5618,7 @@ module Kettle
5580
5618
  "",
5581
5619
  0.0,
5582
5620
  false,
5583
- diagnostics.empty? ? nil : "bundle update produced release-invalid lockfile"
5621
+ diagnostics.empty? ? nil : "bundle update produced an unexpected local-path lockfile"
5584
5622
  )
5585
5623
  memo << result
5586
5624
  result.ok?
@@ -5606,8 +5644,35 @@ module Kettle
5606
5644
  ReadinessCheck.call(
5607
5645
  member: member,
5608
5646
  config: config,
5609
- allowed_local_path_roots: release_allowed_local_path_roots
5610
- ).stdout.lines.grep(/^release lockfile has local path remote at /).map(&:chomp)
5647
+ allowed_local_path_roots: bundle_update_allowed_local_path_roots
5648
+ ).stdout.lines.grep(/^release lockfile has local path remote at /).map do |line|
5649
+ line.sub("release lockfile", "bundle update lockfile").chomp
5650
+ end
5651
+ end
5652
+
5653
+ # Bundle updates record the graph intentionally selected by the caller.
5654
+ # Release validation remains stricter: it accepts only CI-resident paths.
5655
+ def bundle_update_allowed_local_path_roots
5656
+ explicit = explicit_local_path_env_overrides
5657
+ roots = release_allowed_local_path_roots.dup
5658
+ family_env_name = config.family_local_path_env_name
5659
+
5660
+ explicit.each do |name, value|
5661
+ next unless local_path_env_value?(value)
5662
+
5663
+ if name == family_env_name
5664
+ roots << config.family_local_path_root
5665
+ elsif explicit_local_path_root?(value)
5666
+ roots << File.expand_path(value, config.root)
5667
+ end
5668
+ end
5669
+
5670
+ roots.uniq
5671
+ end
5672
+
5673
+ def explicit_local_path_root?(value)
5674
+ text = value.to_s.strip
5675
+ !%w[true yes 1 on enabled].include?(text.downcase)
5611
5676
  end
5612
5677
 
5613
5678
  def commit_bex_changes(member:, runner:, memo:)
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.93
4
+ version: 1.2.95
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter H. Boling
@@ -91,7 +91,7 @@ dependencies:
91
91
  requirements:
92
92
  - - ">="
93
93
  - !ruby/object:Gem::Version
94
- version: 3.0.31
94
+ version: 3.0.32
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.31
104
+ version: 3.0.32
105
105
  - - "<"
106
106
  - !ruby/object:Gem::Version
107
107
  version: 4.0.0
@@ -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.93
447
- changelog_uri: https://github.com/kettle-dev/kettle-family/blob/v1.2.93/CHANGELOG.md
446
+ source_code_uri: https://github.com/kettle-dev/kettle-family/tree/v1.2.95
447
+ changelog_uri: https://github.com/kettle-dev/kettle-family/blob/v1.2.95/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.93
449
+ documentation_uri: https://www.rubydoc.info/gems/kettle-family/1.2.95
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