kettle-family 1.3.37 → 1.3.38

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: b5f2d0bb8696a55925ff46bffa665da140b2f861e47eab151769c9522d160385
4
- data.tar.gz: e64870163a6fa68862654f72c68ba492382fb8e637d9d1b91c9fb92f4c73dfb5
3
+ metadata.gz: 6f6f4ceee082895db3eb6f2b0c90735263adbcf3e8693640edd5d7b929a01244
4
+ data.tar.gz: 9a1c2c5c05bea72ade7f755329bec2e361aac45b171b92bdb76fa6812209a632
5
5
  SHA512:
6
- metadata.gz: 940c6a65b81be4855325eae21951069520d5ac8ae0e1385e5f31d0060256ce4aed0a81c2baa2e9ec335f010119d0ebdb211d113297c6b7620a5884da637acac5
7
- data.tar.gz: 896a7fed86b1e22518425858c99720c93ae1740b5b1cc32eb7639212fc691313ae9e619dfb3c7c60186454f32ff4624f02427feda30137e860b6545a40e05666
6
+ metadata.gz: 4571f37dfb76b652fbd65cf68eeeda058e43b35a82879c2760937e0ec4f65cb76d7b9264bb5d0859ea631b927649a92e640c087eb964a19c7974d3d2e89bf9d0
7
+ data.tar.gz: 1ec331486c79ae31f99b8ef9d0937fda86b25db2dc350ded8a553c721bb056b25f01e185630fd683aa3c4ac87c61699f23b470badd571a0550b5a69eacc5af5a
checksums.yaml.gz.sig CHANGED
Binary file
data/CHANGELOG.md CHANGED
@@ -30,6 +30,29 @@ Please file a bug if you notice a violation of semantic versioning.
30
30
 
31
31
  ### Security
32
32
 
33
+ ## [1.3.38] - 2026-11-07
34
+
35
+ - TAG: [v1.3.38][1.3.38t]
36
+ - COVERAGE: 93.15% -- 7697/8263 lines in 45 files
37
+ - BRANCH COVERAGE: 77.57% -- 3089/3982 branches in 45 files
38
+ - 39.53% documented
39
+
40
+ ### Added
41
+
42
+ - [kc] template-root-outputs: Monorepo template runs can now update explicitly configured repository-root output paths through the template.root_outputs setting, alongside the nested member being templated. Those outputs are isolated, validated, synchronized, and committed with the template changes.
43
+
44
+ ### Changed
45
+
46
+ - [kc] kettle-jem/prepare: updated 13 project files:
47
+ - configuration (2)
48
+ - dependencies (11)
49
+
50
+ - [kc] kettle-jem/template: updated 7 project files:
51
+ - code and tests (2)
52
+ - dependencies (3)
53
+ - documentation (1)
54
+ - other (1)
55
+
33
56
  ## [1.3.37] - 2026-10-30
34
57
 
35
58
  - TAG: [v1.3.37][1.3.37t]
@@ -3343,7 +3366,9 @@ Please file a bug if you notice a violation of semantic versioning.
3343
3366
  - Fixed CI load failures on engines without compatible `pty` support by falling back to Open3 for interactive release commands.
3344
3367
  - Fixed Ruby 3.2 version-bump support by loading Prism lazily and wiring the Prism gem only for MRI versions that need it.
3345
3368
 
3346
- [Unreleased]: https://github.com/kettle-dev/kettle-family/compare/v1.3.37...HEAD
3369
+ [Unreleased]: https://github.com/kettle-dev/kettle-family/compare/v1.3.38...HEAD
3370
+ [1.3.38]: https://github.com/kettle-dev/kettle-family/compare/v1.3.37...v1.3.38
3371
+ [1.3.38t]: https://github.com/kettle-dev/kettle-family/releases/tag/v1.3.38
3347
3372
  [1.3.37]: https://github.com/kettle-dev/kettle-family/compare/v1.3.36...v1.3.37
3348
3373
  [1.3.37t]: https://github.com/kettle-dev/kettle-family/releases/tag/v1.3.37
3349
3374
  [1.3.36]: https://github.com/kettle-dev/kettle-family/compare/v1.3.35...v1.3.36
data/README.md CHANGED
@@ -10,7 +10,7 @@
10
10
 
11
11
  `if ci_badges.map(&:color).all? { it == "green"}` 👇️ send money so I can do more of this. FLOSS maintenance is now my full-time job.
12
12
 
13
- [![OpenCollective Backers][🖇osc-backers-i]][🖇osc-backers] [![OpenCollective Sponsors][🖇osc-sponsors-i]][🖇osc-sponsors] [![Sponsor Me on Github][🖇sponsor-img]][🖇sponsor] [![Liberapay Goal Progress][⛳liberapay-img]][⛳liberapay] [![Donate on PayPal][🖇paypal-img]][🖇paypal] [![Buy me a coffee][🖇buyme-small-img]][🖇buyme] [![Donate at ko-fi.com][🖇kofi-img]][🖇kofi]
13
+ [![Sponsor Me on Github][🖇sponsor-img]][🖇sponsor] [![Liberapay Goal Progress][⛳liberapay-img]][⛳liberapay] [![Donate on PayPal][🖇paypal-img]][🖇paypal] [![Buy me a coffee][🖇buyme-small-img]][🖇buyme] [![Donate at ko-fi.com][🖇kofi-img]][🖇kofi]
14
14
 
15
15
  <details markdown="1">
16
16
  <summary>👣 How will this project approach the September 2025 hostile takeover of RubyGems? 🚑️</summary>
@@ -91,28 +91,6 @@ The _amazing_ test matrix is powered by the kettle-dev stack.
91
91
 
92
92
  </details>
93
93
 
94
- ### Federated DVCS
95
-
96
- <details markdown="1">
97
- <summary>Find this repo on federated forges (Coming soon!)</summary>
98
-
99
- | Federated [DVCS][💎d-in-dvcs] Repository | Status | Issues | PRs | Wiki | CI |
100
- |-------------------------------------------------|-------------------------------------------|-------------------|------------------|-----------------|----------------|
101
- | 🧪 [kettle-dev/kettle-family on GitLab][📜src-gl] | The Truth | [💚][🤝gl-issues] | [💚][🤝gl-pulls] | [💚][📜gl-wiki] | 🐭 Tiny Matrix |
102
- | 🧊 [kettle-dev/kettle-family on CodeBerg][📜src-cb] | An Ethical Mirror ([Donate][🤝cb-donate]) | [💚][🤝cb-issues] | [💚][🤝cb-pulls] | ➖ | ⭕️ No Matrix |
103
- | 🐙 [kettle-dev/kettle-family on GitHub][📜src-gh] | Another Mirror | [💚][🤝gh-issues] | [💚][🤝gh-pulls] | [💚][📜gh-wiki] | 💯 Full Matrix |
104
-
105
- </details>
106
-
107
- ### Enterprise Support
108
-
109
- For enterprise support from the maintainer, use [Upwork][👨🏼‍🏫expsup-upwork] or [CodeMentor][👨🏼‍🏫expsup-codementor].
110
-
111
- Other support channels:
112
-
113
- - [![Ruby Users Forum][✉️ruby-forum-img]][✉️ruby-forum]
114
- - [![Live Chat on Discord][✉️discord-invite-img-ftb]][✉️discord-invite]
115
-
116
94
  ## ✨ Installation
117
95
 
118
96
  Install the gem and add to the application's Gemfile by executing:
@@ -955,36 +933,6 @@ We [![Keep A Changelog][📗keep-changelog-img]][📗keep-changelog] so if you m
955
933
 
956
934
  See [CONTRIBUTING.md][🤝contributing] for more detailed instructions.
957
935
 
958
- ### 🚀 Release Instructions
959
-
960
- See [CONTRIBUTING.md][🤝contributing].
961
-
962
- ### Code Coverage
963
-
964
- <details markdown="1">
965
- <summary>Coverage service badges</summary>
966
-
967
- [![Coverage Graph][🏀codecov-g]][🏀codecov]
968
-
969
- [![Coveralls Test Coverage][🏀coveralls-img]][🏀coveralls]
970
-
971
- [![QLTY Test Coverage][🏀qlty-covi]][🏀qlty-cov]
972
-
973
- </details>
974
-
975
- ### 🪇 Code of Conduct
976
-
977
- Everyone interacting with this project's codebases, issue trackers,
978
- chat rooms and mailing lists agrees to follow the [![Contributor Covenant 2.1][🪇conduct-img]][🪇conduct].
979
-
980
- ## 🌈 Contributors
981
-
982
- [![Contributors][🖐contributors-img]][🖐contributors]
983
-
984
- Made with [contributors-img][🖐contrib-rocks].
985
-
986
- Also see GitLab Contributors: [https://gitlab.com/kettle-dev/kettle-family/-/graphs/main][🚎contributors-gl]
987
-
988
936
  ## 📌 Versioning
989
937
 
990
938
  This library follows [![Semantic Versioning 2.0.0][📌semver-img]][📌semver] for its public API where practical.
@@ -1018,55 +966,9 @@ See [LICENSE.md][📄license] for details.
1018
966
 
1019
967
  If none of the available licenses suit your use case, please [contact us](mailto:floss@galtzo.com) to discuss a custom commercial license.
1020
968
 
1021
- ### © Copyright
1022
-
1023
- See [LICENSE.md][📄license] for the official copyright notice.
1024
-
1025
- <details markdown="1">
1026
- <summary>Copyright holders</summary>
1027
-
1028
- - Copyright (c) 2026 Peter H. Boling
1029
-
1030
- </details>
1031
-
1032
- ## 🤑 A request for help
1033
-
1034
- Maintainers have teeth and need to pay their dentists.
1035
- After getting laid off in an RIF in March, and encountering difficulty finding a new one,
1036
- I began spending most of my time building open source tools.
1037
- I'm hoping to be able to pay for my kids' health insurance this month,
1038
- so if you value the work I am doing, I need your support.
1039
- Please consider sponsoring me or the project.
1040
-
1041
- To join the community or get help, use the RubyForum or Discord.
1042
-
1043
- [![Ruby Users Forum][✉️ruby-forum-img]][✉️ruby-forum]
1044
- [![Live Chat on Discord][✉️discord-invite-img-ftb]][✉️discord-invite]
1045
-
1046
- To say "thanks!" ☝️ Join the community or 👇️ send money.
1047
-
1048
- [![Sponsor kettle-dev/kettle-family on Open Source Collective][🖇osc-all-bottom-img]][🖇osc] 💌 [![Sponsor me on GitHub Sponsors][🖇sponsor-bottom-img]][🖇sponsor] 💌 [![Sponsor me on Liberapay][⛳liberapay-bottom-img]][⛳liberapay] 💌 [![Donate on PayPal][🖇paypal-bottom-img]][🖇paypal]
1049
-
1050
- ### Please give the project a star ⭐ ♥.
1051
-
1052
- Many parts of this project are actively managed by a [kettle-jem](https://github.com/structuredmerge/structuredmerge-ruby/tree/main/gems/kettle-jem) smart template utilizing [StructuredMerge.org](https://structuredmerge.org) merge contracts.
1053
-
1054
- Thanks for RTFM. ☺️
1055
-
1056
969
  [⛳liberapay-img]: https://img.shields.io/liberapay/goal/pboling.svg?logo=liberapay&color=a51611&style=flat
1057
970
  [⛳liberapay-bottom-img]: https://img.shields.io/liberapay/goal/pboling.svg?style=for-the-badge&logo=liberapay&color=a51611
1058
971
  [⛳liberapay]: https://liberapay.com/pboling/donate
1059
- [🖇osc-all-img]: https://img.shields.io/opencollective/all/kettle-dev
1060
- [🖇osc-sponsors-img]: https://img.shields.io/opencollective/sponsors/kettle-dev
1061
- [🖇osc-backers-img]: https://img.shields.io/opencollective/backers/kettle-dev
1062
- [🖇osc-backers]: https://opencollective.com/kettle-dev#backer
1063
- [🖇osc-backers-i]: https://opencollective.com/kettle-dev/backers/badge.svg?style=flat
1064
- [🖇osc-sponsors]: https://opencollective.com/kettle-dev#sponsor
1065
- [🖇osc-sponsors-i]: https://opencollective.com/kettle-dev/sponsors/badge.svg?style=flat
1066
- [🖇osc-all-bottom-img]: https://img.shields.io/opencollective/all/kettle-dev?style=for-the-badge
1067
- [🖇osc-sponsors-bottom-img]: https://img.shields.io/opencollective/sponsors/kettle-dev?style=for-the-badge
1068
- [🖇osc-backers-bottom-img]: https://img.shields.io/opencollective/backers/kettle-dev?style=for-the-badge
1069
- [🖇osc]: https://opencollective.com/kettle-dev
1070
972
  [🖇sponsor-img]: https://img.shields.io/badge/Sponsor_Me!-pboling.svg?style=social&logo=github
1071
973
  [🖇sponsor-bottom-img]: https://img.shields.io/badge/Sponsor_Me!-pboling-blue?style=for-the-badge&logo=github
1072
974
  [🖇sponsor]: https://github.com/sponsors/pboling
@@ -1087,7 +989,6 @@ Thanks for RTFM. ☺️
1087
989
  [✉️ruby-forum-top-img]: https://img.shields.io/discourse/topics?server=https%3A%2F%2Fwww.rubyforum.org&style=flat&logo=discourse&label=Ruby%20Users%20Forum
1088
990
  [✉️ruby-forum-img]: https://img.shields.io/discourse/topics?server=https%3A%2F%2Fwww.rubyforum.org&style=for-the-badge&logo=discourse&label=Ruby%20Users%20Forum
1089
991
  [✉️ruby-forum]: https://www.rubyforum.org/tag/kettle-dev
1090
-
1091
992
  [✇bundle-group-pattern]: https://gist.github.com/pboling/4564780
1092
993
  [⛳️gem-namespace]: https://github.com/kettle-dev/kettle-family
1093
994
  [⛳️namespace-img]: https://img.shields.io/badge/namespace-Kettle::Family-3C2D2D.svg?style=square&logo=ruby&logoColor=white
@@ -1177,7 +1078,6 @@ Thanks for RTFM. ☺️
1177
1078
  [🖐contrib-rocks]: https://contrib.rocks
1178
1079
  [🖐contributors]: https://github.com/kettle-dev/kettle-family/graphs/contributors
1179
1080
  [🖐contributors-img]: https://contrib.rocks/image?repo=kettle-dev/kettle-family
1180
- [🚎contributors-gl]: https://gitlab.com/kettle-dev/kettle-family/-/graphs/main
1181
1081
  [🪇conduct]: https://github.com/kettle-dev/kettle-family/blob/main/CODE_OF_CONDUCT.md
1182
1082
  [🪇conduct-img]: https://img.shields.io/badge/Contributor_Covenant-2.1-259D6C.svg
1183
1083
  [📌pvc]: http://guides.rubygems.org/patterns/#pessimistic-version-constraint
@@ -1191,7 +1091,7 @@ Thanks for RTFM. ☺️
1191
1091
  [📌gitmoji]: https://gitmoji.dev
1192
1092
  [📌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
1093
  [🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
1194
- [🧮kloc-img]: https://img.shields.io/badge/KLOC-8.230-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
1094
+ [🧮kloc-img]: https://img.shields.io/badge/KLOC-8.263-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
1195
1095
  [🔐security]: https://github.com/kettle-dev/kettle-family/blob/main/SECURITY.md
1196
1096
  [🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
1197
1097
  [📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
@@ -1200,7 +1100,6 @@ Thanks for RTFM. ☺️
1200
1100
  [📄license-img]: https://img.shields.io/badge/License-AGPL--3.0--only-259D6C.svg
1201
1101
  [📄license-compat]: https://www.apache.org/legal/resolved.html#category-x
1202
1102
  [📄license-compat-img]: https://img.shields.io/badge/Apache_Incompatible:_Category_X-%E2%9C%97-C0392B.svg?style=flat&logo=Apache
1203
-
1204
1103
  [📄ilo-declaration]: https://www.ilo.org/declaration/lang--en/index.htm
1205
1104
  [📄ilo-declaration-img]: https://img.shields.io/badge/ILO_Fundamental_Principles-✓-259D6C.svg?style=flat
1206
1105
  [🚎yard-current]: http://rubydoc.info/gems/kettle-family
@@ -1212,14 +1111,3 @@ Thanks for RTFM. ☺️
1212
1111
  [💎appraisal2]: https://github.com/appraisal-rb/appraisal2
1213
1112
  [💎appraisal2-img]: https://img.shields.io/badge/appraised_by-appraisal2-34495e.svg?plastic&logo=ruby&logoColor=white
1214
1113
  [💎d-in-dvcs]: https://railsbling.com/posts/dvcs/put_the_d_in_dvcs/
1215
-
1216
- <!-- kettle-jem:metadata:start -->
1217
- | Field | Value |
1218
- |---|---|
1219
- | Package | kettle-family |
1220
- | Description | 👩‍👩‍👧‍👧 Kettle::Family provides scripts and conventions for coordinating related Ruby gems as one family. |
1221
- | Homepage | https://github.com/kettle-dev/kettle-family |
1222
- | Source | https://github.com/kettle-dev/kettle-family |
1223
- | License | `AGPL-3.0-only` |
1224
- | Funding | https://github.com/sponsors/pboling, https://ko-fi.com/pboling, https://liberapay.com/pboling/donate, https://opencollective.com/kettle-dev, https://thanks.dev/u/gh/pboling, https://www.buymeacoffee.com/pboling |
1225
- <!-- kettle-jem:metadata:end -->
@@ -232,19 +232,19 @@ module Kettle
232
232
  @mise_adapter = mise_adapter || Kettle::Family.mise_adapter
233
233
  end
234
234
 
235
- def call(member:, phase:, command:, env: {}, interactive: false, raw: false, stdout_line_handler: nil, log_path: nil, passthrough_output: true)
235
+ def call(member:, phase:, command:, env: {}, interactive: false, raw: false, stdout_line_handler: nil, log_path: nil, passthrough_output: true, chdir: member.root, **options)
236
236
  argv = command_argv(member: member, command: command, env: env, raw: raw)
237
237
  process_env = process_env(member: member, env: env)
238
238
  spawn_options = process_options
239
239
  return skipped_result(member: member, phase: phase, argv: argv) unless execute
240
240
 
241
241
  started = Process.clock_gettime(Process::CLOCK_MONOTONIC)
242
- stdout, stderr, status = with_transcript(log_path, argv: argv, chdir: member.root) do |log_io|
242
+ stdout, stderr, status = with_transcript(log_path, argv: argv, chdir: chdir) do |log_io|
243
243
  if interactive
244
244
  run_interactive(
245
245
  env: process_env,
246
246
  argv: argv,
247
- chdir: member.root,
247
+ chdir: chdir,
248
248
  member_name: member.name,
249
249
  process_options: spawn_options,
250
250
  stdout_line_handler: stdout_line_handler,
@@ -252,9 +252,9 @@ module Kettle
252
252
  passthrough_output: passthrough_output
253
253
  )
254
254
  elsif stdout_line_handler
255
- run_streaming(env: process_env, argv: argv, chdir: member.root, process_options: spawn_options, stdout_line_handler: stdout_line_handler, log_io: log_io)
255
+ run_streaming(env: process_env, argv: argv, chdir: chdir, process_options: spawn_options, stdout_line_handler: stdout_line_handler, log_io: log_io)
256
256
  else
257
- result = Open3.capture3(process_env, *argv, chdir: member.root, **spawn_options)
257
+ result = Open3.capture3(process_env, *argv, chdir: chdir, **spawn_options)
258
258
  transcript_write(log_io, result[0])
259
259
  transcript_write(log_io, result[1])
260
260
  result
@@ -267,7 +267,7 @@ module Kettle
267
267
  member_name: member.name,
268
268
  phase: phase,
269
269
  command: argv,
270
- workdir: member.root,
270
+ workdir: chdir,
271
271
  status: status.exitstatus,
272
272
  success: status.success?,
273
273
  stdout: stdout,
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "yaml"
4
+ require "pathname"
4
5
 
5
6
  module Kettle
6
7
  module Family
@@ -208,6 +209,21 @@ module Kettle
208
209
  fetch_path("template", "jobs")
209
210
  end
210
211
 
212
+ # Root paths that a nested monorepo member's Kettle Jem run may update.
213
+ # These are explicit repository-relative output paths, never globs.
214
+ def template_root_outputs
215
+ paths = Array(fetch_path("template", "root_outputs"))
216
+ paths.map do |path|
217
+ value = path.to_s
218
+ expanded = File.expand_path(value, root)
219
+ unless !value.empty? && !value.end_with?("/") && !Pathname.new(value).absolute? && Paths.within?(expanded, root) && expanded != root
220
+ raise Error, "template.root_outputs entries must be repository-relative paths below the family root: #{value.inspect}"
221
+ end
222
+
223
+ Pathname.new(expanded).relative_path_from(Pathname.new(root)).to_s
224
+ end.uniq
225
+ end
226
+
211
227
  # Additional local dependency selectors used by the generated
212
228
  # `local-template` task. Values may use Mise's `{{config_root}}` token.
213
229
  def template_local_env
@@ -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.37"
8
+ VERSION = "1.3.38"
9
9
  end
10
10
  # Current gem version exposed at the traditional constant location.
11
11
  VERSION = Version::VERSION # Traditional Constant Location
@@ -1129,7 +1129,15 @@ module Kettle
1129
1129
  end
1130
1130
 
1131
1131
  def monorepo_template_worktrees?(wave)
1132
- monorepo_template_worktrees_enabled? && wave.length > 1
1132
+ (monorepo_template_worktrees_enabled? && wave.length > 1) || monorepo_nested_template_worktree?(wave)
1133
+ end
1134
+
1135
+ def monorepo_nested_template_worktree?(wave)
1136
+ return false unless execute && monorepo_template? && wave.length == 1
1137
+
1138
+ member = wave.first
1139
+ nested = Paths.within?(member.root, config.root) && !Paths.same?(member.root, config.root)
1140
+ nested && !config.template_root_outputs.empty? && kettle_jem_template_command?(config.template_command || DEFAULT_COMMANDS.fetch("template"))
1133
1141
  end
1134
1142
 
1135
1143
  def monorepo_template_worktrees_enabled?
@@ -1207,7 +1215,8 @@ module Kettle
1207
1215
  progress: progress,
1208
1216
  progress_started: true,
1209
1217
  commit_changes: false,
1210
- wave_jobs: wave_jobs
1218
+ wave_jobs: wave_jobs,
1219
+ template_worktree_root: monorepo_template_allowed_paths(entry.fetch(:original_member)).empty? ? nil : entry.fetch(:worktree_root)
1211
1220
  )
1212
1221
  mutex.synchronize do
1213
1222
  ordered_results[index] = member_results
@@ -1234,17 +1243,18 @@ module Kettle
1234
1243
  paths = monorepo_template_worktree_changed_paths(worktree_root)
1235
1244
  return template_worktree_failure_result(original_member, paths, phase: "template_worktree_materialize") if paths.is_a?(String)
1236
1245
 
1237
- invalid_paths = paths.reject { |path| path == relative_root || path.start_with?("#{relative_root}/") }
1246
+ allowed_paths = monorepo_template_allowed_paths(original_member)
1247
+ invalid_paths = paths.reject { |path| monorepo_template_path_allowed?(path, relative_root, allowed_paths) }
1238
1248
  unless invalid_paths.empty?
1239
1249
  return template_worktree_failure_result(
1240
1250
  original_member,
1241
- "isolated template worker modified shared path(s): #{invalid_paths.sort.join(", ")}; only #{relative_root}/ may be materialized",
1251
+ "isolated template worker modified shared path(s): #{invalid_paths.sort.join(", ")}; only #{([relative_root] + allowed_paths).join(", ")} may be materialized",
1242
1252
  phase: "template_worktree_materialize"
1243
1253
  )
1244
1254
  end
1245
1255
 
1246
- initial_state = entry.fetch(:primary_member_state)
1247
- current_state = monorepo_template_member_state(config.root, relative_root)
1256
+ initial_state = entry[:primary_allowed_state] || entry.fetch(:primary_member_state)
1257
+ current_state = monorepo_template_allowed_state(config.root, relative_root, allowed_paths)
1248
1258
  changed_primary_paths = changed_monorepo_template_state_paths(initial_state, current_state)
1249
1259
  unless changed_primary_paths.empty?
1250
1260
  return template_worktree_failure_result(
@@ -1271,19 +1281,40 @@ module Kettle
1271
1281
  changed_paths = monorepo_template_worktree_changed_paths(config.root)
1272
1282
  raise Error, changed_paths if changed_paths.is_a?(String)
1273
1283
 
1274
- member_changed_paths = changed_paths.select do |path|
1275
- path == relative_root || path.start_with?("#{relative_root}/")
1276
- end
1284
+ allowed_paths = monorepo_template_allowed_paths(original_member)
1285
+ member_changed_paths = changed_paths.select { |path| monorepo_template_path_allowed?(path, relative_root, allowed_paths) }
1277
1286
  sync_monorepo_template_paths(config.root, entry.fetch(:worktree_root), member_changed_paths)
1278
- primary_state = monorepo_template_member_state(config.root, relative_root)
1279
- worktree_state = monorepo_template_member_state(entry.fetch(:worktree_root), relative_root)
1287
+ primary_state = monorepo_template_allowed_state(config.root, relative_root, allowed_paths)
1288
+ worktree_state = monorepo_template_allowed_state(entry.fetch(:worktree_root), relative_root, allowed_paths)
1280
1289
  unless primary_state == worktree_state
1281
1290
  changed = changed_monorepo_template_state_paths(primary_state, worktree_state)
1282
- raise Error, "isolated template worker seed differs from primary member: #{changed.join(", ")}"
1291
+ raise Error, "isolated template worker seed differs from primary allowed paths: #{changed.join(", ")}"
1283
1292
  end
1284
1293
 
1285
1294
  entry[:primary_changed_paths] = member_changed_paths
1286
- entry[:primary_member_state] = primary_state
1295
+ entry[:primary_allowed_state] = primary_state
1296
+ entry[:primary_member_state] = primary_state if allowed_paths.empty?
1297
+ end
1298
+
1299
+ def monorepo_template_allowed_paths(member)
1300
+ return [] unless Paths.within?(member.root, config.root) && !Paths.same?(member.root, config.root)
1301
+
1302
+ config.template_root_outputs
1303
+ end
1304
+
1305
+ def monorepo_template_path_allowed?(path, relative_root, allowed_paths)
1306
+ path == relative_root || path.start_with?("#{relative_root}/") || allowed_paths.include?(path)
1307
+ end
1308
+
1309
+ def monorepo_template_allowed_state(root, relative_root, allowed_paths)
1310
+ member_state = monorepo_template_member_state(root, relative_root)
1311
+ shared_state = allowed_paths.each_with_object({}) do |allowed, state|
1312
+ paths = git_worktree_paths(root, ["ls-files", "--cached", "--others", "--exclude-standard", "-z", "--", allowed])
1313
+ raise Error, paths if paths.is_a?(String)
1314
+
1315
+ paths.each { |path| state[path] = monorepo_template_path_signature(root, path) }
1316
+ end
1317
+ member_state.merge(shared_state)
1287
1318
  end
1288
1319
 
1289
1320
  def monorepo_template_relative_root(member)
@@ -1556,7 +1587,7 @@ module Kettle
1556
1587
  )
1557
1588
  end
1558
1589
 
1559
- def template_results_for_member(member, progress: nil, progress_key: nil, progress_label: nil, progress_started: false, commit_changes: true, wave_jobs: 1)
1590
+ def template_results_for_member(member, progress: nil, progress_key: nil, progress_label: nil, progress_started: false, commit_changes: true, wave_jobs: 1, template_worktree_root: nil)
1560
1591
  progress_key ||= member.name
1561
1592
  progress_label ||= member.name
1562
1593
  start_template_member_progress(progress, member, progress_key: progress_key, progress_label: progress_label) unless progress_started
@@ -1583,6 +1614,7 @@ module Kettle
1583
1614
  phase: command,
1584
1615
  command: workflow_command(member),
1585
1616
  env: template_command_env(wave_jobs: wave_jobs, member: member),
1617
+ chdir: template_worktree_root || member.root,
1586
1618
  stdout_line_handler: template_event_line_handler(member, progress: progress, progress_key: progress_key, progress_label: progress_label)
1587
1619
  )
1588
1620
  emit_member_result_progress(member, memo.last, progress: progress, progress_key: progress_key, progress_label: progress_label)
@@ -6044,14 +6076,17 @@ module Kettle
6044
6076
  return unless memo.all?(&:ok?)
6045
6077
 
6046
6078
  synchronize_template_commit do
6079
+ allowed_paths = monorepo_template_allowed_paths(member)
6080
+ paths = allowed_paths.empty? ? ["."] : [monorepo_template_relative_root(member)] + allowed_paths
6081
+ pathspec = paths.map { |path| Shellwords.escape(path) }.join(" ")
6047
6082
  memo << runner.call(
6048
6083
  member: member,
6049
6084
  phase: "commit_template",
6050
6085
  command: [
6051
6086
  "sh",
6052
6087
  "-lc",
6053
- "if [ -n \"$(git status --porcelain -- .)\" ]; then " \
6054
- "git add -A -- . && git commit -m #{Shellwords.escape(template_commit_message(member))}; " \
6088
+ "if [ -n \"$(git status --porcelain -- #{pathspec})\" ]; then " \
6089
+ "git add -A -- #{pathspec} && git commit -m #{Shellwords.escape(template_commit_message(member))} -- #{pathspec}; " \
6055
6090
  "fi"
6056
6091
  ],
6057
6092
  env: workflow_env
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.37
4
+ version: 1.3.38
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter H. Boling
@@ -134,7 +134,7 @@ dependencies:
134
134
  version: '1.0'
135
135
  - - ">="
136
136
  - !ruby/object:Gem::Version
137
- version: 1.0.15
137
+ version: 1.0.16
138
138
  type: :runtime
139
139
  prerelease: false
140
140
  version_requirements: !ruby/object:Gem::Requirement
@@ -144,7 +144,7 @@ dependencies:
144
144
  version: '1.0'
145
145
  - - ">="
146
146
  - !ruby/object:Gem::Version
147
- version: 1.0.15
147
+ version: 1.0.16
148
148
  - !ruby/object:Gem::Dependency
149
149
  name: kettle-deps-floor
150
150
  requirement: !ruby/object:Gem::Requirement
@@ -627,11 +627,11 @@ homepage: https://github.com/kettle-dev/kettle-family
627
627
  licenses:
628
628
  - AGPL-3.0-only
629
629
  metadata:
630
- homepage_uri: https://kettle-family.galtzo.com
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
630
+ homepage_uri: https://structuredmerge.org
631
+ source_code_uri: https://github.com/kettle-dev/kettle-family/tree/v1.3.38
632
+ changelog_uri: https://github.com/kettle-dev/kettle-family/blob/v1.3.38/CHANGELOG.md
633
633
  bug_tracker_uri: https://github.com/kettle-dev/kettle-family/issues
634
- documentation_uri: https://www.rubydoc.info/gems/kettle-family/1.3.37
634
+ documentation_uri: https://www.rubydoc.info/gems/kettle-family/1.3.38
635
635
  funding_uri: https://github.com/sponsors/pboling
636
636
  wiki_uri: https://github.com/kettle-dev/kettle-family/wiki
637
637
  news_uri: https://www.railsbling.com/tags/kettle-family
@@ -662,7 +662,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
662
662
  - !ruby/object:Gem::Version
663
663
  version: '0'
664
664
  requirements: []
665
- rubygems_version: 4.0.20
665
+ rubygems_version: 4.0.24
666
666
  specification_version: 4
667
667
  summary: "\U0001F469‍\U0001F469‍\U0001F467‍\U0001F467 CLI helpers for managing related
668
668
  Ruby gems as a family."
metadata.gz.sig CHANGED
Binary file