kettle-family 1.3.30 → 1.3.32

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: e1834021ad7c719f89aee9e9c7408bb2fd772797bf85087620e913f2d0b5cbc5
4
- data.tar.gz: abcb663c3eaffcebd396befa0443c3d5eb331cfdbcce6de417881cbda9e15679
3
+ metadata.gz: '08c77450947a59e4d899708d9ea06ac1f6a3ecdbca9f1875697a111221c8a513'
4
+ data.tar.gz: 39bab3f859dffecd3c7c7bf218bf60a31d593d174f7bf35cc78ee00120796e77
5
5
  SHA512:
6
- metadata.gz: fd431e1b40c4c7b7119461eabb4cf55625a2ebea4f37e9c553ee96f3fb7f66af690441f063a33b2118a1d60ed7fdd48be98e9a6c85016cbbc106946206a152b8
7
- data.tar.gz: b91b8eeb298ec02137d844df600e1ac2fe8ffefc5ff3c94fd055c8f10f57c162499deb1118a2c4034cd7ced3e2b0154b005255f2d95cdafe74744323ae9e6fb1
6
+ metadata.gz: e11ec34af3513c579f0de85e0ac3967736d9296edd3181c824661d0e77c958dba7fde98870a37b8ab0e030776f24ff8f90cee743e989b174ded6745f6c589363
7
+ data.tar.gz: f3420d41b085ff447bc05e0f4976fa4ee12b1eba42b73047a1afb5cadf8966b82f7a17430a2e9a5c7923f66ef6498646bcb7225aa71677264ed57cbf8c10fda6
checksums.yaml.gz.sig CHANGED
Binary file
data/CHANGELOG.md CHANGED
@@ -30,6 +30,28 @@ Please file a bug if you notice a violation of semantic versioning.
30
30
 
31
31
  ### Security
32
32
 
33
+ ## [1.3.32] - 2026-10-23
34
+
35
+ - TAG: [v1.3.32][1.3.32t]
36
+ - COVERAGE: 93.10% -- 7548/8107 lines in 45 files
37
+ - BRANCH COVERAGE: 77.70% -- 3034/3905 branches in 45 files
38
+ - 38.69% documented
39
+
40
+ ### Fixed
41
+
42
+ - MiseTasks.materialize_managed_suite no longer silently deletes root mise.toml task definitions that duplicate the managed suite. Root redefinitions shadow the managed file under mise precedence and may be deliberate local overrides; they are now REPORTED (template workflow, kettle-jem plugin, and mise-tasks CLI all warn with the same message and remediation hint) and removal stays opt-in via kettle-family mise-tasks --clean. Previously the CLI's documented warn-by-default path was dead code: materialize cleaned before the warning check ran, so redefinitions vanished without notice on every template run.
43
+
44
+ ## [1.3.31] - 2026-10-23
45
+
46
+ - TAG: [v1.3.31][1.3.31t]
47
+ - COVERAGE: 93.06% -- 7540/8102 lines in 45 files
48
+ - BRANCH COVERAGE: 77.65% -- 3029/3901 branches in 45 files
49
+ - 38.57% documented
50
+
51
+ ### Added
52
+
53
+ - release.preflight_commands family config: a list of {name, command} maintenance hooks run at the family root, in declaration order, as the FIRST release preflight phase — so template dependency floors, workflow pins, and similar generated-state maintenance land before version/state validation instead of failing the wave mid-publish. Commands may be strings or argv arrays; a failing command blocks the release; dry-run plans without executing. kettle-family ships only the mechanism — each family declares its own maintenance in its own .kettle-family.yml.
54
+
33
55
  ## [1.3.30] - 2026-10-22
34
56
 
35
57
  - TAG: [v1.3.30][1.3.30t]
@@ -3214,7 +3236,11 @@ Please file a bug if you notice a violation of semantic versioning.
3214
3236
  - Fixed CI load failures on engines without compatible `pty` support by falling back to Open3 for interactive release commands.
3215
3237
  - Fixed Ruby 3.2 version-bump support by loading Prism lazily and wiring the Prism gem only for MRI versions that need it.
3216
3238
 
3217
- [Unreleased]: https://github.com/kettle-dev/kettle-family/compare/v1.3.30...HEAD
3239
+ [Unreleased]: https://github.com/kettle-dev/kettle-family/compare/v1.3.32...HEAD
3240
+ [1.3.32]: https://github.com/kettle-dev/kettle-family/compare/v1.3.31...v1.3.32
3241
+ [1.3.32t]: https://github.com/kettle-dev/kettle-family/releases/tag/v1.3.32
3242
+ [1.3.31]: https://github.com/kettle-dev/kettle-family/compare/v1.3.30...v1.3.31
3243
+ [1.3.31t]: https://github.com/kettle-dev/kettle-family/releases/tag/v1.3.31
3218
3244
  [1.3.30]: https://github.com/kettle-dev/kettle-family/compare/v1.3.29...v1.3.30
3219
3245
  [1.3.30t]: https://github.com/kettle-dev/kettle-family/releases/tag/v1.3.30
3220
3246
  [1.3.29]: https://github.com/kettle-dev/kettle-family/compare/v1.3.28...v1.3.29
data/README.md CHANGED
@@ -1225,7 +1225,7 @@ Thanks for RTFM. ☺️
1225
1225
  [📌gitmoji]: https://gitmoji.dev
1226
1226
  [📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
1227
1227
  [🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
1228
- [🧮kloc-img]: https://img.shields.io/badge/KLOC-8.088-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
1228
+ [🧮kloc-img]: https://img.shields.io/badge/KLOC-8.107-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
1229
1229
  [🔐security]: https://github.com/kettle-dev/kettle-family/blob/main/SECURITY.md
1230
1230
  [🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
1231
1231
  [📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
@@ -272,6 +272,28 @@ module Kettle
272
272
  fetch_path("release", "publish_command") || command_for("release_publish") || "bundle exec kettle-release"
273
273
  end
274
274
 
275
+ # Family-declared pre-release maintenance commands (e.g. template
276
+ # dependency floors and workflow pins). Each entry is a map with `name`
277
+ # (displayed in preflight output) and `command` (run at the family root,
278
+ # raw — no mise exec wrapping). Commands run in declaration order before
279
+ # every other release preflight phase, so maintenance that edits floors
280
+ # or generated files lands before version/state validation. A failing
281
+ # command blocks the release. Tools that write are expected to
282
+ # self-commit; the hook does not commit on their behalf.
283
+ def release_preflight_commands
284
+ entries = fetch_path("release", "preflight_commands") || []
285
+ Array(entries).map do |entry|
286
+ map = entry.is_a?(Hash) ? stringify_keys(entry) : {}
287
+ name = map["name"].to_s
288
+ command = map["command"]
289
+ command = command.map(&:to_s) if command.is_a?(Array)
290
+ command = command.to_s unless command.is_a?(Array)
291
+ next nil if name.empty? || command.empty?
292
+
293
+ {"name" => name, "command" => command}
294
+ end.compact
295
+ end
296
+
275
297
  def release_required_remotes
276
298
  fetch_path("release", "required_remotes")
277
299
  end
@@ -8,10 +8,12 @@ module Kettle
8
8
  module Family
9
9
  # Slice-1044 family mise tasks primitive: ensure a destination root
10
10
  # `mise.toml` references the kettle-family-managed TOML task file via
11
- # `[task_config] includes`, and report (optionally clean) task
12
- # redefinitions between the root file and the managed file. Family
13
- # refreshes migrate managed task names out of the root so old commands
14
- # cannot shadow generated fixes. Other tasks and settings remain local.
11
+ # `[task_config] includes`, and report (never silently remove) task
12
+ # redefinitions between the root file and the managed file. Removal is
13
+ # the caller's explicit choice (`kettle-family mise-tasks --clean`): a
14
+ # root redefinition shadows the managed definition under mise precedence
15
+ # and may be a deliberate local override. Other tasks and settings remain
16
+ # local.
15
17
  #
16
18
  # All edits go through ast-crispr Actors with the ast-crispr-toml adapter.
17
19
  module MiseTasks
@@ -320,14 +322,23 @@ module Kettle
320
322
 
321
323
  task_file_path = File.join(root, task_file_name)
322
324
  original = File.read(root_mise)
323
- included = ensure_include(root_content: original, task_file_name: task_file_name)
324
- result = clean_redefinitions(
325
- root_content: included.content,
326
- task_file_name: task_file_name,
327
- task_file_content: content
328
- )
325
+ result = ensure_include(root_content: original, task_file_name: task_file_name, task_file_content: content)
329
326
  File.write(task_file_path, content) unless File.exist?(task_file_path) && File.read(task_file_path) == content
330
327
  File.write(root_mise, result.content) unless result.content == original
328
+ result
329
+ end
330
+
331
+ # Warn about each redefinition to the given stream. Shared by the CLI
332
+ # command, the template workflow, and the kettle-jem plugin so the
333
+ # message and remediation hint stay identical everywhere.
334
+ #
335
+ # @param redefinitions [Array<String>]
336
+ # @param task_file_name [String]
337
+ # @param err [IO]
338
+ def self.warn_redefinitions(redefinitions, task_file_name: DEFAULT_TASK_FILE_NAME, err: $stderr)
339
+ Array(redefinitions).each do |name|
340
+ err.puts("kettle-family: task #{name.inspect} is defined in both mise.toml and #{task_file_name}; root mise.toml wins (redefinition allowed; run `kettle-family mise-tasks --clean` to restore the managed definition)")
341
+ end
331
342
  end
332
343
 
333
344
  # Comprehensive managed family mise task suite, generated from family
@@ -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.30"
8
+ VERSION = "1.3.32"
9
9
  end
10
10
  # Current gem version exposed at the traditional constant location.
11
11
  VERSION = Version::VERSION # Traditional Constant Location
@@ -259,7 +259,8 @@ module Kettle
259
259
  )
260
260
  results = checkout_preflight + sync_results + workflow_results + rollback_results + restore_results
261
261
  if results.all?(&:ok?)
262
- MiseTasks.materialize_managed_suite(context: {project_root: config.root})
262
+ suite_result = MiseTasks.materialize_managed_suite(context: {project_root: config.root})
263
+ MiseTasks.warn_redefinitions(suite_result&.redefinitions)
263
264
  # `mise trust` requires the mise executable; spec environments and
264
265
  # minimal CI images may not have it installed. Trust is only an
265
266
  # enabler for subsequent nested mise runs, so skip when absent.
@@ -2021,13 +2022,31 @@ module Kettle
2021
2022
  end
2022
2023
 
2023
2024
  def release_preflight_phases
2025
+ maintenance_phase = {label: "pre-release maintenance", method: :release_preflight_maintenance_results} unless config.release_preflight_commands.empty?
2024
2026
  bump_phase = {label: "release version bump", method: :release_preflight_version_bump_results} unless release_state_results.empty?
2025
2027
  dirty_phase = {label: "branch checkout readiness", method: :release_preflight_branch_checkout_dirty_results}
2026
2028
  signing_phase = {label: "gem signing password", method: :release_preflight_signing_password_results}
2027
2029
  secrets_phase = release_secrets_authorization_required? ? {label: "secrets provider authorization", method: :release_preflight_secrets_authorization_results} : nil
2028
2030
  gha_sha_pins_phase = release_gha_sha_pins_review_required? ? {label: "GitHub Actions SHA pins", method: :release_preflight_gha_sha_pins_results} : nil
2029
2031
 
2030
- [bump_phase, secrets_phase, gha_sha_pins_phase, dirty_phase, signing_phase].compact
2032
+ [maintenance_phase, bump_phase, secrets_phase, gha_sha_pins_phase, dirty_phase, signing_phase].compact
2033
+ end
2034
+
2035
+ # Family-declared pre-release maintenance hooks (release.preflight_commands
2036
+ # in the family config): run at the family root in declaration order,
2037
+ # before any other preflight phase, so maintenance that edits floors or
2038
+ # generated files lands before version/state validation. kettle-family
2039
+ # ships only the mechanism — each family declares its own commands.
2040
+ def release_preflight_maintenance_results
2041
+ config.release_preflight_commands.map do |entry|
2042
+ command_runner.call(
2043
+ member: family_member,
2044
+ phase: "release_preflight_command",
2045
+ command: entry.fetch("command"),
2046
+ env: command_env,
2047
+ raw: true
2048
+ )
2049
+ end
2031
2050
  end
2032
2051
 
2033
2052
  def release_preflight_version_bump_results
data/lib/kettle/family.rb CHANGED
@@ -71,7 +71,8 @@ module Kettle
71
71
 
72
72
  def register_kettle_jem_plugin(registrar)
73
73
  registrar.on_phase("remaining_files", timing: :after) do |context:|
74
- MiseTasks.materialize_managed_suite(context: context)
74
+ suite_result = MiseTasks.materialize_managed_suite(context: context)
75
+ MiseTasks.warn_redefinitions(suite_result&.redefinitions)
75
76
  end
76
77
  end
77
78
  end
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.30
4
+ version: 1.3.32
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter H. Boling
@@ -568,10 +568,10 @@ licenses:
568
568
  - AGPL-3.0-only
569
569
  metadata:
570
570
  homepage_uri: https://kettle-family.galtzo.com
571
- source_code_uri: https://github.com/kettle-dev/kettle-family/tree/v1.3.30
572
- changelog_uri: https://github.com/kettle-dev/kettle-family/blob/v1.3.30/CHANGELOG.md
571
+ source_code_uri: https://github.com/kettle-dev/kettle-family/tree/v1.3.32
572
+ changelog_uri: https://github.com/kettle-dev/kettle-family/blob/v1.3.32/CHANGELOG.md
573
573
  bug_tracker_uri: https://github.com/kettle-dev/kettle-family/issues
574
- documentation_uri: https://www.rubydoc.info/gems/kettle-family/1.3.30
574
+ documentation_uri: https://www.rubydoc.info/gems/kettle-family/1.3.32
575
575
  funding_uri: https://github.com/sponsors/pboling
576
576
  wiki_uri: https://github.com/kettle-dev/kettle-family/wiki
577
577
  news_uri: https://www.railsbling.com/tags/kettle-family
metadata.gz.sig CHANGED
Binary file