kettle-family 1.2.68 → 1.2.69

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: 92f9921c54769cc9de3e665525d947ca363034e6aa1195e54542abc14ac2e034
4
- data.tar.gz: 5dbb47c3eeec83bd468bcf490a400f9c27972a60d8985f938401981010c4b92a
3
+ metadata.gz: a3f10c970b0e0ae29cdb82ca1a9b3b6cc714cd94368cd9ec371ff2ac870b9800
4
+ data.tar.gz: 2721e7a64d0fce16c6891a68c48972089c27b9d2a7a69892879a8d4f2dbb06f0
5
5
  SHA512:
6
- metadata.gz: 85b47651e690a179449e7bdf2ee815aa5720b896c92092a8df6d5dc6bce832e54354a5a6d2835f1d88ff12ca4b33291c63984781c0596e727b19d06a4bf0bcca
7
- data.tar.gz: 35ecc3796e6bf354cd7ebe72b68fc186407c04a4bcea8a38185c9a7b3d56343339a7ef5da0b5ab11a7d7d51ebe97167fe496e5810acbec56cc3d1d60dfbde4a3
6
+ metadata.gz: 1f2da27cc1a98f1652d0ee74e4d00863faa531ee18bf584a050fa0887d574f470c698b3a0b62025b6483fc90c5672e594082c7939d4d3a4e19e6e4a02b071bd2
7
+ data.tar.gz: fb463b7508060c144a365c7e6cd856933354ddad5bed11efaaea44759fccb8d24efd33f5527bf26a3f9291c173e9d868b16f85607d13f8af972dafbbbd68ac11
checksums.yaml.gz.sig CHANGED
Binary file
data/CHANGELOG.md CHANGED
@@ -30,6 +30,21 @@ Please file a bug if you notice a violation of semantic versioning.
30
30
 
31
31
  ### Security
32
32
 
33
+ ## [1.2.69] - 2026-08-30
34
+
35
+ - TAG: [v1.2.69][1.2.69t]
36
+ - COVERAGE: 93.22% -- 5500/5900 lines in 33 files
37
+ - BRANCH COVERAGE: 76.36% -- 2255/2953 branches in 33 files
38
+ - 30.50% documented
39
+
40
+ ### Fixed
41
+
42
+ - Block release execution before family changelog generation when a selected member still requires a version bump.
43
+
44
+ - Avoid release-state probes for executed build-only releases.
45
+
46
+ - Replay original release options in member-scoped family release resume hints.
47
+
33
48
  ## [1.2.68] - 2026-08-30
34
49
 
35
50
  - TAG: [v1.2.68][1.2.68t]
@@ -2318,7 +2333,9 @@ Please file a bug if you notice a violation of semantic versioning.
2318
2333
  - Fixed CI load failures on engines without compatible `pty` support by falling back to Open3 for interactive release commands.
2319
2334
  - Fixed Ruby 3.2 version-bump support by loading Prism lazily and wiring the Prism gem only for MRI versions that need it.
2320
2335
 
2321
- [Unreleased]: https://github.com/kettle-dev/kettle-family/compare/v1.2.68...HEAD
2336
+ [Unreleased]: https://github.com/kettle-dev/kettle-family/compare/v1.2.69...HEAD
2337
+ [1.2.69]: https://github.com/kettle-dev/kettle-family/compare/v1.2.68...v1.2.69
2338
+ [1.2.69t]: https://github.com/kettle-dev/kettle-family/releases/tag/v1.2.69
2322
2339
  [1.2.68]: https://github.com/kettle-dev/kettle-family/compare/v1.2.67...v1.2.68
2323
2340
  [1.2.68t]: https://github.com/kettle-dev/kettle-family/releases/tag/v1.2.68
2324
2341
  [1.2.67]: https://github.com/kettle-dev/kettle-family/compare/v1.2.66...v1.2.67
data/README.md CHANGED
@@ -527,6 +527,12 @@ The supported release-state tokens are:
527
527
  When `--only` is omitted, `kettle-family bump` defaults to `--only bump` and
528
528
  `kettle-family release` defaults to `--only pending`.
529
529
 
530
+ Before starting release work, `kettle-family release` checks the selected
531
+ members' release state. If any selected member has `bump: yes`, the release
532
+ stops before family changelog generation or coverage and reports the members
533
+ that need a version bump. Run `kettle-family bump --execute patch` first, then
534
+ rerun the release.
535
+
530
536
  State checks run concurrently by default, using up to four jobs or the number
531
537
  of available CPU cores, whichever is lower. Use `--jobs N` to set an explicit
532
538
  limit; results remain in family order.
@@ -693,6 +699,13 @@ time. If any members were never started, the report also gives a separate
693
699
  normal-flow command for exactly those members. Use `--start-step` only after
694
700
  the pre-release gate already passed or the failure was intentionally handled:
695
701
 
702
+ The generated command replays the original release's relevant options, such as
703
+ `--secrets-provider`, release skip controls, CI selection, dependency-floor
704
+ mode, explicit workflow environment values, and non-default commit or prompt
705
+ behavior. It replaces member selection and any original recovery position with
706
+ the failed member and its recorded child step; original `--start-step` and
707
+ fast-recovery selections are not replayed.
708
+
696
709
  ```console
697
710
  kettle-family release --publish --execute --start-step 10
698
711
  ```
@@ -1036,7 +1049,7 @@ Thanks for RTFM. ☺️
1036
1049
  [📌gitmoji]: https://gitmoji.dev
1037
1050
  [📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
1038
1051
  [🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
1039
- [🧮kloc-img]: https://img.shields.io/badge/KLOC-5.857-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
1052
+ [🧮kloc-img]: https://img.shields.io/badge/KLOC-5.900-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
1040
1053
  [🔐security]: https://github.com/kettle-dev/kettle-family/blob/main/SECURITY.md
1041
1054
  [🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
1042
1055
  [📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
@@ -691,7 +691,15 @@ module Kettle
691
691
  end
692
692
  state_event_tape = release_state_event_tape(command: command, config: config, options: options)
693
693
  Selection.validate_release_state_only_filter!(effective_only)
694
- release_state_results = release_state_results_for_selection(config: config, members: ordered, only: effective_only, jobs: options[:jobs])
694
+ release_state_results = release_state_results_for_selection(
695
+ command: command,
696
+ config: config,
697
+ members: ordered,
698
+ only: effective_only,
699
+ execute: options[:execute],
700
+ publish: options[:publish],
701
+ jobs: options[:jobs]
702
+ )
695
703
  selected = Selection.new(
696
704
  members: ordered,
697
705
  release_state_results: release_state_results,
@@ -732,6 +740,7 @@ module Kettle
732
740
  release_target_branches: release_target_branches(command: command, config: config, start_at: start_at),
733
741
  member_release_target_branches: member_release_target_branches(command: command, members: selected, config: config, start_at: start_at),
734
742
  release_mode: release_mode(command: command, options: options),
743
+ release_resume_arguments: release_resume_arguments(command: command, options: options),
735
744
  command: command,
736
745
  results: results,
737
746
  warnings: discovery.warnings,
@@ -778,8 +787,10 @@ module Kettle
778
787
  )
779
788
  end
780
789
 
781
- def release_state_results_for_selection(config:, members:, only:, jobs: nil)
782
- return nil unless only.to_s.split(",").map(&:strip).any? { |token| Selection.status_token?(token) }
790
+ def release_state_results_for_selection(command:, config:, members:, only:, execute: false, publish: false, jobs: nil)
791
+ status_filter = only.to_s.split(",").map(&:strip).any? { |token| Selection.status_token?(token) }
792
+ should_check = status_filter || (command == "release" && execute && publish)
793
+ return nil unless should_check
783
794
 
784
795
  ReleaseStateCheck.new(config: config, members: members, jobs: jobs).results
785
796
  end
@@ -869,7 +880,8 @@ module Kettle
869
880
  bup_args: options[:bup_args],
870
881
  bex_args: options[:bex_args],
871
882
  start_member: start_at.member,
872
- start_branch: start_at.branch
883
+ start_branch: start_at.branch,
884
+ release_state_results: release_state_results
873
885
  ).results
874
886
  end
875
887
 
@@ -1273,6 +1285,33 @@ module Kettle
1273
1285
  options[:publish] ? "publish" : "build-only"
1274
1286
  end
1275
1287
 
1288
+ def release_resume_arguments(command:, options:)
1289
+ return [] unless command == "release"
1290
+
1291
+ arguments = []
1292
+ arguments.concat(["--secrets-provider", options[:release_secrets_provider]]) if options[:release_secrets_provider]
1293
+ arguments.concat(["--skip-steps", options[:release_skip_steps]]) if options[:release_skip_steps]
1294
+ arguments << "--skip-ci" if options[:release_skip_ci]
1295
+ arguments << "--skip-changelog" if options[:release_skip_changelog]
1296
+ arguments << "--skip-appraisals" if options[:release_skip_appraisals]
1297
+ arguments << "--local-ci" if options[:release_local_ci]
1298
+ arguments << "--continue-ci-failures" if options[:release_continue_ci_failures]
1299
+ arguments.concat(["--ci-workflows", options[:release_ci_workflows]]) if options[:release_ci_workflows]
1300
+ arguments << "--skip-bundle-audit" if options[:release_skip_bundle_audit]
1301
+ arguments.concat(["--skip-remotes", options[:release_skip_remotes]]) if options[:release_skip_remotes]
1302
+ arguments.concat(["--required-remotes", options[:release_required_remotes]]) if options[:release_required_remotes]
1303
+ arguments << "--no-auto-floors" unless options[:release_auto_dependency_floors]
1304
+ arguments << "--validate-ci-bundles" if options[:release_validate_ci_bundles]
1305
+ arguments << "--no-accept" unless options[:accept]
1306
+ arguments << "--no-commit" unless options[:commit]
1307
+ arguments << "--no-autostash" unless options[:autostash]
1308
+ arguments << "--tag" if options[:tag]
1309
+ arguments << "--push" if options[:push]
1310
+ arguments.concat(["--jobs", options[:jobs].to_s]) if options[:jobs]
1311
+ options[:workflow_env].each { |key, value| arguments.concat(["--env", "#{key}=#{value}"]) }
1312
+ arguments
1313
+ end
1314
+
1276
1315
  def release_target_branches(command:, config:, start_at:)
1277
1316
  branch_targets = BranchTargetConfig.branch_targets_for(command, config.release_target_branches)
1278
1317
  return branch_targets if branch_targets.empty?
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "json"
4
+ require "shellwords"
4
5
 
5
6
  module Kettle
6
7
  module Family
@@ -30,9 +31,9 @@ module Kettle
30
31
  up
31
32
  ].freeze
32
33
 
33
- attr_reader :family_name, :family_mode, :order_mode, :members, :selected_members, :config_path, :command, :results, :branch_lanes, :release_target_branches, :member_release_target_branches, :release_mode, :warnings, :event_log_dirs
34
+ attr_reader :family_name, :family_mode, :order_mode, :members, :selected_members, :config_path, :command, :results, :branch_lanes, :release_target_branches, :member_release_target_branches, :release_mode, :release_resume_arguments, :warnings, :event_log_dirs
34
35
 
35
- def initialize(family_name:, order_mode:, members:, selected_members:, config_path:, family_mode: nil, branch_lanes: {}, release_target_branches: [], member_release_target_branches: {}, release_mode: nil, command: nil, results: [], warnings: [], event_log_dirs: [], elapsed_seconds: nil)
36
+ def initialize(family_name:, order_mode:, members:, selected_members:, config_path:, family_mode: nil, branch_lanes: {}, release_target_branches: [], member_release_target_branches: {}, release_mode: nil, release_resume_arguments: [], command: nil, results: [], warnings: [], event_log_dirs: [], elapsed_seconds: nil)
36
37
  @family_name = family_name
37
38
  @family_mode = family_mode
38
39
  @order_mode = order_mode
@@ -45,6 +46,7 @@ module Kettle
45
46
  @release_target_branches = release_target_branches
46
47
  @member_release_target_branches = member_release_target_branches
47
48
  @release_mode = release_mode
49
+ @release_resume_arguments = release_resume_arguments.dup.freeze
48
50
  @warnings = warnings
49
51
  @event_log_dirs = event_log_dirs
50
52
  @elapsed_seconds = elapsed_seconds
@@ -710,8 +712,16 @@ module Kettle
710
712
  end
711
713
 
712
714
  def release_resume_base
713
- hint = "kettle-family release --execute"
714
- (release_mode == "publish") ? "#{hint} --publish" : hint
715
+ arguments = ["kettle-family", "release", "--execute"]
716
+ arguments << "--publish" if release_mode == "publish"
717
+ shell_join([*arguments, *release_resume_arguments])
718
+ end
719
+
720
+ def shell_join(arguments)
721
+ arguments.map do |argument|
722
+ value = argument.to_s
723
+ value.match?(/\A[A-Za-z0-9_.,:=+\/-]+\z/) ? value : Shellwords.escape(value)
724
+ end.join(" ")
715
725
  end
716
726
  end
717
727
  end
@@ -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.68"
8
+ VERSION = "1.2.69"
9
9
  end
10
10
  # Current gem version exposed at the traditional constant location.
11
11
  VERSION = Version::VERSION # Traditional Constant Location
@@ -106,7 +106,7 @@ module Kettle
106
106
  REGISTRY_WAIT_ATTEMPTS = 15
107
107
  REGISTRY_WAIT_INTERVAL_SECONDS = 15
108
108
 
109
- def initialize(command:, config:, members:, family_members: nil, execute: false, accept: true, commit: true, allow_dirty: false, autostash: true, template_cleanup: true, publish: false, push: false, tag: false, start_step: nil, skip_steps: nil, fast_recovery: nil, fast_recovery_members: nil, skip_ci: false, skip_changelog: false, skip_appraisals: false, local_ci: false, continue_ci_failures: false, ci_workflows: nil, skip_bundle_audit: false, skip_remotes: nil, required_remotes: nil, auto_dependency_floors: nil, validate_ci_bundles: nil, gha_sha_pins_upgrade: "patch", gha_sha_pins_check: false, gha_sha_pins_ttl_days: nil, env_overrides: {}, debug: false, verbose: false, gem_signing_password: nil, secrets_provider: nil, jobs: nil, progress_io: nil, reset_target: nil, bup_args: [], bex_args: [], start_member: nil, start_branch: nil, **options)
109
+ def initialize(command:, config:, members:, family_members: nil, execute: false, accept: true, commit: true, allow_dirty: false, autostash: true, template_cleanup: true, publish: false, push: false, tag: false, start_step: nil, skip_steps: nil, fast_recovery: nil, fast_recovery_members: nil, skip_ci: false, skip_changelog: false, skip_appraisals: false, local_ci: false, continue_ci_failures: false, ci_workflows: nil, skip_bundle_audit: false, skip_remotes: nil, required_remotes: nil, auto_dependency_floors: nil, validate_ci_bundles: nil, gha_sha_pins_upgrade: "patch", gha_sha_pins_check: false, gha_sha_pins_ttl_days: nil, env_overrides: {}, debug: false, verbose: false, gem_signing_password: nil, secrets_provider: nil, jobs: nil, progress_io: nil, reset_target: nil, bup_args: [], bex_args: [], start_member: nil, start_branch: nil, release_state_results: nil, **options)
110
110
  @command = command
111
111
  @config = config
112
112
  @members = members
@@ -160,6 +160,7 @@ module Kettle
160
160
  @bex_args = bex_args
161
161
  @start_member = start_member
162
162
  @start_branch = start_branch
163
+ @release_state_results = Array(release_state_results)
163
164
  @template_commit_mutex = Mutex.new
164
165
  end
165
166
 
@@ -206,7 +207,7 @@ module Kettle
206
207
  execute && release_command_delegates_secrets_to_kettle_release?
207
208
  end
208
209
 
209
- attr_reader :command, :config, :members, :family_members, :execute, :accept, :commit, :allow_dirty, :autostash, :template_cleanup, :publish, :push, :tag, :start_step, :skip_steps, :fast_recovery, :fast_recovery_members, :skip_ci, :skip_changelog, :skip_appraisals, :local_ci, :continue_ci_failures, :ci_workflows, :skip_bundle_audit, :skip_remotes, :required_remotes, :auto_dependency_floors, :validate_ci_bundles, :gha_sha_pins_upgrade, :gha_sha_pins_check, :gha_sha_pins_ttl_days, :env_overrides, :debug, :verbose, :jobs, :progress_io, :reset_target, :bup_args, :bex_args, :start_member, :start_branch
210
+ attr_reader :command, :config, :members, :family_members, :execute, :accept, :commit, :allow_dirty, :autostash, :template_cleanup, :publish, :push, :tag, :start_step, :skip_steps, :fast_recovery, :fast_recovery_members, :skip_ci, :skip_changelog, :skip_appraisals, :local_ci, :continue_ci_failures, :ci_workflows, :skip_bundle_audit, :skip_remotes, :required_remotes, :auto_dependency_floors, :validate_ci_bundles, :gha_sha_pins_upgrade, :gha_sha_pins_check, :gha_sha_pins_ttl_days, :env_overrides, :debug, :verbose, :jobs, :progress_io, :reset_target, :bup_args, :bex_args, :start_member, :start_branch, :release_state_results
210
211
 
211
212
  def template_with_worktree_sync_results
212
213
  runner = command_runner
@@ -1009,12 +1010,33 @@ module Kettle
1009
1010
  end
1010
1011
 
1011
1012
  def release_preflight_phases
1013
+ bump_phase = {label: "release version bump", method: :release_preflight_version_bump_results} unless release_state_results.empty?
1012
1014
  dirty_phase = {label: "branch checkout readiness", method: :release_preflight_branch_checkout_dirty_results}
1013
1015
  signing_phase = {label: "gem signing password", method: :release_preflight_signing_password_results}
1014
1016
  secrets_phase = release_secrets_authorization_required? ? {label: "secrets provider authorization", method: :release_preflight_secrets_authorization_results} : nil
1015
1017
  gha_sha_pins_phase = release_gha_sha_pins_review_required? ? {label: "GitHub Actions SHA pins", method: :release_preflight_gha_sha_pins_results} : nil
1016
1018
 
1017
- [secrets_phase, gha_sha_pins_phase, dirty_phase, signing_phase].compact
1019
+ [bump_phase, secrets_phase, gha_sha_pins_phase, dirty_phase, signing_phase].compact
1020
+ end
1021
+
1022
+ def release_preflight_version_bump_results
1023
+ failed_members = release_state_results.reject(&:ok?).map(&:member_name).compact.uniq
1024
+ unless failed_members.empty?
1025
+ return [release_preflight_error_result(
1026
+ "release_state",
1027
+ "Release blocked because release state could not be determined for: #{failed_members.join(", ")}. Run kettle-family state and resolve the failed probes before retrying."
1028
+ )]
1029
+ end
1030
+
1031
+ bump_members = release_state_results.select do |result|
1032
+ members.any? { |member| member.name == result.member_name } && result.state["bump_release_pending"] == true
1033
+ end.map(&:member_name)
1034
+ return [] if bump_members.empty?
1035
+
1036
+ [release_preflight_error_result(
1037
+ "release_version_bump",
1038
+ "Release blocked: selected member(s) require a version bump: #{bump_members.join(", ")}. Run kettle-family bump --execute patch, then rerun the release."
1039
+ )]
1018
1040
  end
1019
1041
 
1020
1042
  def release_preflight_gha_sha_pins_results
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.68
4
+ version: 1.2.69
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter H. Boling
@@ -441,10 +441,10 @@ licenses:
441
441
  - AGPL-3.0-only
442
442
  metadata:
443
443
  homepage_uri: https://kettle-family.galtzo.com
444
- source_code_uri: https://github.com/kettle-dev/kettle-family/tree/v1.2.68
445
- changelog_uri: https://github.com/kettle-dev/kettle-family/blob/v1.2.68/CHANGELOG.md
444
+ source_code_uri: https://github.com/kettle-dev/kettle-family/tree/v1.2.69
445
+ changelog_uri: https://github.com/kettle-dev/kettle-family/blob/v1.2.69/CHANGELOG.md
446
446
  bug_tracker_uri: https://github.com/kettle-dev/kettle-family/issues
447
- documentation_uri: https://www.rubydoc.info/gems/kettle-family/1.2.68
447
+ documentation_uri: https://www.rubydoc.info/gems/kettle-family/1.2.69
448
448
  funding_uri: https://github.com/sponsors/pboling
449
449
  wiki_uri: https://github.com/kettle-dev/kettle-family/wiki
450
450
  news_uri: https://www.railsbling.com/tags/kettle-family
metadata.gz.sig CHANGED
Binary file