kettle-dev 2.3.5 → 2.3.7

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.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +55 -11
  4. data/README.md +2 -2
  5. data/exe/kettle-release +26 -2
  6. data/lib/kettle/dev/ci_monitor.rb +4 -4
  7. data/lib/kettle/dev/gha_sha_pins_cli.rb +49 -6
  8. data/lib/kettle/dev/release_cli.rb +8 -2
  9. data/lib/kettle/dev/version.rb +1 -1
  10. data/sig/kettle/dev.rbs +583 -1
  11. data.tar.gz.sig +0 -0
  12. metadata +15 -59
  13. metadata.gz.sig +0 -0
  14. data/AGPL-3.0-only.md +0 -235
  15. data/CITATION.cff +0 -20
  16. data/CODE_OF_CONDUCT.md +0 -134
  17. data/CONTRIBUTING.md +0 -275
  18. data/FUNDING.md +0 -70
  19. data/RUBOCOP.md +0 -71
  20. data/SECURITY.md +0 -21
  21. data/certs/pboling.pem +0 -27
  22. data/sig/kettle/dev/appraisals_ast_merger.rbs +0 -72
  23. data/sig/kettle/dev/changelog_cli.rbs +0 -69
  24. data/sig/kettle/dev/ci_helpers.rbs +0 -42
  25. data/sig/kettle/dev/ci_monitor.rbs +0 -17
  26. data/sig/kettle/dev/commit_msg.rbs +0 -8
  27. data/sig/kettle/dev/dvcs_cli.rbs +0 -8
  28. data/sig/kettle/dev/exit_adapter.rbs +0 -8
  29. data/sig/kettle/dev/gem_spec_reader.rbs +0 -33
  30. data/sig/kettle/dev/git_adapter.rbs +0 -17
  31. data/sig/kettle/dev/git_commit_footer.rbs +0 -16
  32. data/sig/kettle/dev/input_adapter.rbs +0 -8
  33. data/sig/kettle/dev/modular_gemfiles.rbs +0 -12
  34. data/sig/kettle/dev/open_collective_config.rbs +0 -8
  35. data/sig/kettle/dev/pre_release_cli.rbs +0 -34
  36. data/sig/kettle/dev/prism_utils.rbs +0 -56
  37. data/sig/kettle/dev/readme_backers.rbs +0 -21
  38. data/sig/kettle/dev/release_cli.rbs +0 -20
  39. data/sig/kettle/dev/setup_cli.rbs +0 -8
  40. data/sig/kettle/dev/source_merger.rbs +0 -70
  41. data/sig/kettle/dev/tasks/ci_task.rbs +0 -9
  42. data/sig/kettle/dev/tasks/install_task.rbs +0 -10
  43. data/sig/kettle/dev/tasks/template_task.rbs +0 -10
  44. data/sig/kettle/dev/tasks.rbs +0 -7
  45. data/sig/kettle/dev/template_helpers.rbs +0 -84
  46. data/sig/kettle/dev/version.rbs +0 -8
  47. data/sig/kettle/dev/versioning.rbs +0 -21
  48. data/sig/kettle/emoji_regex.rbs +0 -5
  49. data/sig/kettle-dev.rbs +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d92e30cac83dbcad9d7d975f1daf19bb98eb61e57753c0e2816e2176d810a326
4
- data.tar.gz: 1dd743a5f4e788f2564de31c57a143f2a6df4bdd1198013d8f340cce4e829fce
3
+ metadata.gz: 4e582c50d05608c5e338caeac74f7c339fb2d66010b58c8cce836a78d8e4ded5
4
+ data.tar.gz: e9ce2e0857dbf506017c8ddab46c5049ffc5003af5778a2e2954dd759cee8183
5
5
  SHA512:
6
- metadata.gz: 434c23b1f327e1707a49d461485a99699e4102e4a067289c5e490ed4df076eb5477827a369cad2c09190f88158255bbaf3b76decaa2114f5f239d7cd92bcfa47
7
- data.tar.gz: fed2def55fc0799c88a14ba0b6bf8d095ca53b7d1d76718676557f4a3560be7e2643e66f9b2a0d047ea969f5c0dfa52e3c2b2d91393560308e44d2d7a361c04b
6
+ metadata.gz: cea8e2be14321cc1e70534197cd2b01dea382a62f6de651ebfb35ccf1025acdfb0a11ee74c31e7c5c78dfe216ec51fdbe21a02f4f1358b6e8b526365b9a5f5af
7
+ data.tar.gz: 47dada022728fd8414d252df3d01ecb992f18ccea69ed20ed8670dbd87ab3cf7f205bb488a48ab95039a4548a0b278c5e8aaf7099b7d94248539db5e7630c26b
checksums.yaml.gz.sig CHANGED
Binary file
data/CHANGELOG.md CHANGED
@@ -30,6 +30,46 @@ Please file a bug if you notice a violation of semantic versioning.
30
30
 
31
31
  ### Security
32
32
 
33
+ ## [2.3.7] - 2026-07-18
34
+
35
+ - TAG: [v2.3.7][2.3.7t]
36
+ - COVERAGE: 91.84% -- 4311/4694 lines in 36 files
37
+ - BRANCH COVERAGE: 74.20% -- 1694/2283 branches in 36 files
38
+ - 56.25% documented
39
+
40
+ ### Fixed
41
+
42
+ - `kettle-gha-sha-pins` now canonicalizes duplicate equivalent action tags,
43
+ preferring explicit release tags such as `v7.0.0` over major-line aliases
44
+ such as `v7`, so adjacent version comments do not flip between spellings.
45
+
46
+ ## [2.3.6] - 2026-07-17
47
+
48
+ - TAG: [v2.3.6][2.3.6t]
49
+ - COVERAGE: 91.85% -- 4292/4673 lines in 36 files
50
+ - BRANCH COVERAGE: 73.94% -- 1685/2279 branches in 36 files
51
+ - 56.67% documented
52
+
53
+ ### Added
54
+
55
+ - `kettle-release` now accepts `--ci-workflows` and
56
+ `K_RELEASE_CI_WORKFLOWS` to monitor an explicit workflow subset at the CI
57
+ wait step while retaining the default behavior of waiting for all applicable
58
+ workflows.
59
+
60
+ ### Changed
61
+
62
+ - kettle-jem-template-20260716-001 - Shim gemspec manifests now include
63
+ `LICENSE.md` instead of nonexistent `LICENSE.txt`.
64
+ - kettle-jem-template-20260716-002 - Generated gemspec manifests now ship fewer
65
+ repository-only files by default to reduce downstream distro packaging churn.
66
+
67
+ ### Fixed
68
+
69
+ - `kettle-release --ci-workflows` now rejects a missing value when the next
70
+ token is another flag, and the release CI workflow subset APIs now have
71
+ matching RBS signatures.
72
+
33
73
  ## [2.3.5] - 2026-07-16
34
74
 
35
75
  - TAG: [v2.3.5][2.3.5t]
@@ -2496,7 +2536,11 @@ Please file a bug if you notice a violation of semantic versioning.
2496
2536
  - Selecting will run the selected workflow via `act`
2497
2537
  - This may move to its own gem in the future.
2498
2538
 
2499
- [Unreleased]: https://github.com/kettle-dev/kettle-dev/compare/v2.3.5...HEAD
2539
+ [Unreleased]: https://github.com/kettle-dev/kettle-dev/compare/v2.3.7...HEAD
2540
+ [2.3.7]: https://github.com/kettle-dev/kettle-dev/compare/v2.3.6...v2.3.7
2541
+ [2.3.7t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v2.3.7
2542
+ [2.3.6]: https://github.com/kettle-dev/kettle-dev/compare/v2.3.5...v2.3.6
2543
+ [2.3.6t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v2.3.6
2500
2544
  [2.3.5]: https://github.com/kettle-dev/kettle-dev/compare/v2.3.4...v2.3.5
2501
2545
  [2.3.5t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v2.3.5
2502
2546
  [2.3.4]: https://github.com/kettle-dev/kettle-dev/compare/v2.3.3...v2.3.4
@@ -2749,25 +2793,25 @@ Please file a bug if you notice a violation of semantic versioning.
2749
2793
  [1.0.12t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v1.0.12
2750
2794
  [1.0.11]: https://github.com/kettle-dev/kettle-dev/compare/v1.0.10...v1.0.11
2751
2795
  [1.0.11t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v1.0.11
2752
- [1.0.10]: https://gitlab.com/kettle-rb/kettle-dev/-/compare/v1.0.9...v1.0.10
2796
+ [1.0.10]: https://gitlab.com/kettle-dev/kettle-dev/-/compare/v1.0.9...v1.0.10
2753
2797
  [1.0.10t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v1.0.10
2754
- [1.0.9]: https://gitlab.com/kettle-rb/kettle-dev/-/compare/v1.0.8...v1.0.9
2798
+ [1.0.9]: https://gitlab.com/kettle-dev/kettle-dev/-/compare/v1.0.8...v1.0.9
2755
2799
  [1.0.9t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v1.0.9
2756
- [1.0.8]: https://gitlab.com/kettle-rb/kettle-dev/-/compare/v1.0.7...v1.0.8
2800
+ [1.0.8]: https://gitlab.com/kettle-dev/kettle-dev/-/compare/v1.0.7...v1.0.8
2757
2801
  [1.0.8t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v1.0.8
2758
- [1.0.7]: https://gitlab.com/kettle-rb/kettle-dev/-/compare/v1.0.6...v1.0.7
2802
+ [1.0.7]: https://gitlab.com/kettle-dev/kettle-dev/-/compare/v1.0.6...v1.0.7
2759
2803
  [1.0.7t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v1.0.7
2760
- [1.0.6]: https://gitlab.com/kettle-rb/kettle-dev/-/compare/v1.0.5...v1.0.6
2804
+ [1.0.6]: https://gitlab.com/kettle-dev/kettle-dev/-/compare/v1.0.5...v1.0.6
2761
2805
  [1.0.6t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v1.0.6
2762
- [1.0.5]: https://gitlab.com/kettle-rb/kettle-dev/-/compare/v1.0.4...v1.0.5
2806
+ [1.0.5]: https://gitlab.com/kettle-dev/kettle-dev/-/compare/v1.0.4...v1.0.5
2763
2807
  [1.0.5t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v1.0.5
2764
- [1.0.4]: https://gitlab.com/kettle-rb/kettle-dev/-/compare/v1.0.3...v1.0.4
2808
+ [1.0.4]: https://gitlab.com/kettle-dev/kettle-dev/-/compare/v1.0.3...v1.0.4
2765
2809
  [1.0.4t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v1.0.4
2766
- [1.0.3]: https://gitlab.com/kettle-rb/kettle-dev/-/compare/v1.0.2...v1.0.3
2810
+ [1.0.3]: https://gitlab.com/kettle-dev/kettle-dev/-/compare/v1.0.2...v1.0.3
2767
2811
  [1.0.3t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v1.0.3
2768
- [1.0.2]: https://gitlab.com/kettle-rb/kettle-dev/-/compare/v1.0.1...v1.0.2
2812
+ [1.0.2]: https://gitlab.com/kettle-dev/kettle-dev/-/compare/v1.0.1...v1.0.2
2769
2813
  [1.0.2t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v1.0.2
2770
- [1.0.1]: https://gitlab.com/kettle-rb/kettle-dev/-/compare/v1.0.0...v1.0.1
2814
+ [1.0.1]: https://gitlab.com/kettle-dev/kettle-dev/-/compare/v1.0.0...v1.0.1
2771
2815
  [1.0.1t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v1.0.1
2772
2816
  [1.0.0]: https://github.com/kettle-dev/kettle-dev/compare/a427c302df09cfe4253a7c8d400333f9a4c1a208...v1.0.0
2773
2817
  [1.0.0t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v1.0.0
data/README.md CHANGED
@@ -887,7 +887,7 @@ Thanks for RTFM. ☺️
887
887
  [📌gitmoji]: https://gitmoji.dev
888
888
  [📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
889
889
  [🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
890
- [🧮kloc-img]: https://img.shields.io/badge/KLOC-4.669-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
890
+ [🧮kloc-img]: https://img.shields.io/badge/KLOC-4.694-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
891
891
  [🔐security]: https://github.com/kettle-dev/kettle-dev/blob/main/SECURITY.md
892
892
  [🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
893
893
  [📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
@@ -913,7 +913,7 @@ Thanks for RTFM. ☺️
913
913
  | Field | Value |
914
914
  |---|---|
915
915
  | Package | kettle-dev |
916
- | Description | 🍲 Kettle::Dev is a meta tool from kettle-rb to streamline development and testing. Acts as a shim dependency, pulling in many other dependencies, to give you OOTB productivity with a RubyGem, or Ruby app project. Configures a complete set of Rake tasks, for all the libraries is brings in, so they arrive ready to go. Fund overlooked open source projects - bottom of stack, dev/test dependencies: floss-funding.dev |
916
+ | Description | 🍲 Kettle::Dev is a meta tool from kettle-dev to streamline development and testing. Acts as a shim dependency, pulling in many other dependencies, to give you OOTB productivity with a RubyGem, or Ruby app project. Configures a complete set of Rake tasks, for all the libraries is brings in, so they arrive ready to go. Fund overlooked open source projects - bottom of stack, dev/test dependencies: floss-funding.dev |
917
917
  | Homepage | https://github.com/kettle-dev/kettle-dev |
918
918
  | Source | https://github.com/kettle-dev/kettle-dev |
919
919
  | License | `AGPL-3.0-only` |
data/exe/kettle-release CHANGED
@@ -43,7 +43,7 @@ end
43
43
  # Do not guard with __FILE__ == $PROGRAM_NAME because binstubs use Kernel.load.
44
44
  if ARGV.include?("-h") || ARGV.include?("--help")
45
45
  puts <<~USAGE
46
- Usage: kettle-release [--version VERSION] [--local-ci] [--appraisal-update] [--skip-bundle-audit] [--skip-steps STEPS] [start_step=<0-19>]
46
+ Usage: kettle-release [--version VERSION] [--local-ci] [--appraisal-update] [--skip-bundle-audit] [--skip-steps STEPS] [--ci-workflows WORKFLOWS] [start_step=<0-19>]
47
47
 
48
48
  Automates the release flow for a Ruby gem in the host project.
49
49
 
@@ -81,6 +81,7 @@ if ARGV.include?("-h") || ARGV.include?("--help")
81
81
  --version VERSION # Use this version instead of detecting VERSION from lib/**/version.rb
82
82
  --appraisal-update # Use slower appraisal:update instead of default appraisal:generate
83
83
  --skip-bundle-audit # Skip bundle:audit/update during release rake checks
84
+ --ci-workflows WORKFLOWS # Comma-separated workflow files or stems to monitor at CI step 10
84
85
  --local-ci # Sensitive release mode: run act locally, publish before any git push,
85
86
  # create the git tag locally, then push commits and tags after publish
86
87
 
@@ -89,6 +90,7 @@ if ARGV.include?("-h") || ARGV.include?("--help")
89
90
  GEM_CERT_USER=<user> # Select certs/<user>.pem for signing
90
91
  K_RELEASE_LOCAL_CI=ask|1|0 # Use 'act' locally before push; 'ask' prompts, '1' forces, default off
91
92
  K_RELEASE_LOCAL_CI_WORKFLOW # Name of workflow (without .yml) for local CI; defaults to locked_deps or first
93
+ K_RELEASE_CI_WORKFLOWS # Comma-separated workflow files or stems to monitor at CI step 10
92
94
  KETTLE_RELEASE_APPRAISAL_TASK=appraisal:update
93
95
  # Use slower appraisal:update instead of default appraisal:generate
94
96
  KETTLE_DEV_SKIP_BUNDLE_AUDIT=true
@@ -145,6 +147,27 @@ def extract_skip_steps_arg!(argv)
145
147
  skip_steps
146
148
  end
147
149
 
150
+ def extract_ci_workflows_arg!(argv)
151
+ workflows = nil
152
+ if (idx = argv.index("--ci-workflows"))
153
+ workflows = argv[idx + 1]
154
+ if workflows.to_s.empty? || workflows.to_s.start_with?("-")
155
+ Kettle::Dev::ExitAdapter.abort("--ci-workflows requires a comma-separated workflow list")
156
+ end
157
+ argv.slice!(idx, 2)
158
+ end
159
+ argv.delete_if do |arg|
160
+ if arg.start_with?("--ci-workflows=", "ci_workflows=")
161
+ workflows = arg.split("=", 2)[1]
162
+ Kettle::Dev::ExitAdapter.abort("--ci-workflows requires a comma-separated workflow list") if workflows.to_s.empty?
163
+ true
164
+ else
165
+ false
166
+ end
167
+ end
168
+ workflows
169
+ end
170
+
148
171
  local_ci = ARGV.include?("--local-ci")
149
172
  appraisal_task = ARGV.delete("--appraisal-update") ? "appraisal:update" : nil
150
173
  skip_bundle_audit = !!ARGV.delete("--skip-bundle-audit")
@@ -152,9 +175,10 @@ start_step_arg = ARGV.find { |a| a.start_with?("start_step=") }
152
175
  start_step = start_step_arg ? start_step_arg.split("=", 2)[1].to_i : 0
153
176
  version_override = extract_version_arg!(ARGV)
154
177
  skip_steps = extract_skip_steps_arg!(ARGV)
178
+ ci_workflows = extract_ci_workflows_arg!(ARGV)
155
179
 
156
180
  begin
157
- Kettle::Dev::ReleaseCLI.new(start_step: start_step, local_ci: local_ci, version: version_override, appraisal_task: appraisal_task, skip_steps: skip_steps, skip_bundle_audit: skip_bundle_audit).run
181
+ Kettle::Dev::ReleaseCLI.new(start_step: start_step, local_ci: local_ci, version: version_override, appraisal_task: appraisal_task, skip_steps: skip_steps, skip_bundle_audit: skip_bundle_audit, ci_workflows: ci_workflows).run
158
182
  rescue LoadError => e
159
183
  warn("#{script_basename}: could not load dependency: #{e.class}: #{e.message}")
160
184
  warn(Array(e.backtrace).join("\n")) if ENV["DEBUG"]
@@ -47,9 +47,9 @@ module Kettle
47
47
  #
48
48
  # @param restart_hint [String] guidance command shown on failure
49
49
  # @return [void]
50
- def monitor_all!(restart_hint: "bundle exec kettle-release start_step=10")
50
+ def monitor_all!(restart_hint: "bundle exec kettle-release start_step=10", workflows: nil, **options)
51
51
  checks_any = false
52
- checks_any |= monitor_github_internal!(restart_hint: restart_hint)
52
+ checks_any |= monitor_github_internal!(restart_hint: restart_hint, workflows: workflows)
53
53
  checks_any |= monitor_gitlab_internal!(restart_hint: restart_hint)
54
54
  abort("CI configuration not detected (GitHub or GitLab). Ensure CI is configured and remotes point to the correct hosts.") unless checks_any
55
55
  end
@@ -269,9 +269,9 @@ module Kettle
269
269
 
270
270
  # -- internals (abort-on-failure legacy paths used elsewhere) --
271
271
 
272
- def monitor_github_internal!(restart_hint:)
272
+ def monitor_github_internal!(restart_hint:, workflows: nil)
273
273
  root = Kettle::Dev::CIHelpers.project_root
274
- workflows = Kettle::Dev::CIHelpers.workflows_list(root)
274
+ workflows = Array(workflows).empty? ? Kettle::Dev::CIHelpers.workflows_list(root) : Array(workflows)
275
275
  gh_remote = preferred_github_remote
276
276
  return false unless gh_remote && !workflows.empty?
277
277
 
@@ -35,6 +35,23 @@ module Kettle
35
35
  VERSION_COMMENT_SUFFIX_RE = /\A\s+#\s*v?(?<version>\d+(?:\.\d+\.\d+(?:[-.]?[0-9A-Za-z.-]+)?)?)/
36
36
  VERSION_COMMENT_REPLACEMENT_RE = /\A(?<prefix>\s+#\s*)v?\d+(?:\.\d+\.\d+(?:[-.]?[0-9A-Za-z.-]+)?)?/
37
37
 
38
+ def self.release_version_sort_key(entry)
39
+ [entry.fetch(:version_obj), *release_version_specificity(entry)]
40
+ end
41
+
42
+ def self.release_version_specificity(entry)
43
+ text = entry.fetch(:tag).to_s.sub(/\A[vV]/, "")
44
+ release_text, suffix = text.split(/[-.](?=[A-Za-z])/, 2)
45
+ numeric_segments = release_text.to_s.split(".").take_while { |part| part.match?(/\A\d+\z/) }
46
+
47
+ [
48
+ numeric_segments.length,
49
+ suffix ? 0 : 1,
50
+ text.length,
51
+ entry.fetch(:tag).to_s
52
+ ]
53
+ end
54
+
38
55
  def initialize(argv, err: $stderr)
39
56
  @argv = argv
40
57
  @err = err
@@ -521,7 +538,7 @@ module Kettle
521
538
  end
522
539
  end
523
540
 
524
- candidates.max_by { |entry| entry[:version_obj] }
541
+ candidates.max_by { |entry| release_version_sort_key(entry) }
525
542
  end
526
543
 
527
544
  def major_line_version?(value)
@@ -538,7 +555,7 @@ module Kettle
538
555
  entry[:version_obj] > current &&
539
556
  (!entry[:version_obj].prerelease? || current.prerelease?)
540
557
  end
541
- .max_by { |entry| entry[:version_obj] }
558
+ .max_by { |entry| release_version_sort_key(entry) }
542
559
  end
543
560
 
544
561
  def determine_upgrade_plan(old_ref:, repo_ref:, versions:, upgrade_level:, client:)
@@ -645,6 +662,10 @@ module Kettle
645
662
  sha
646
663
  end
647
664
 
665
+ def release_version_sort_key(entry)
666
+ self.class.release_version_sort_key(entry)
667
+ end
668
+
648
669
  def short_sha?(candidate)
649
670
  return false unless candidate
650
671
  WEAK_SHA_RE.match?(candidate)
@@ -1061,10 +1082,10 @@ module Kettle
1061
1082
  full_semver_entries = entries.reject { |entry| major_line_version?(entry[:version]) }
1062
1083
  {
1063
1084
  "patch" => full_semver_entries.group_by { |entry| entry[:version_obj].segments[0, 2].join(".") }
1064
- .transform_values { |group| serialize_target(group.max_by { |entry| entry[:version_obj] }) },
1085
+ .transform_values { |group| serialize_target(group.max_by { |entry| GhaShaPinsCLI.release_version_sort_key(entry) }) },
1065
1086
  "minor" => full_semver_entries.group_by { |entry| entry[:version_obj].segments[0].to_s }
1066
- .transform_values { |group| serialize_target(group.max_by { |entry| entry[:version_obj] }) },
1067
- "major" => {"*" => serialize_target(entries.max_by { |entry| entry[:version_obj] })}
1087
+ .transform_values { |group| serialize_target(group.max_by { |entry| GhaShaPinsCLI.release_version_sort_key(entry) }) },
1088
+ "major" => {"*" => serialize_target(entries.max_by { |entry| GhaShaPinsCLI.release_version_sort_key(entry) })}
1068
1089
  }
1069
1090
  end
1070
1091
 
@@ -1212,12 +1233,34 @@ module Kettle
1212
1233
  }
1213
1234
  end
1214
1235
  releases.concat(tag_versions)
1236
+ releases = canonicalize_equivalent_release_versions(releases)
1215
1237
 
1216
- releases.sort_by! { |release| release[:version_obj] }
1238
+ releases.sort_by! { |release| GhaShaPinsCLI.release_version_sort_key(release) }
1217
1239
  releases.reverse!
1218
1240
  releases
1219
1241
  end
1220
1242
 
1243
+ def canonicalize_equivalent_release_versions(releases)
1244
+ groups = []
1245
+ releases.each do |release|
1246
+ group = groups.find { |entries| equivalent_release_tag?(entries.first, release) }
1247
+ if group
1248
+ group << release
1249
+ else
1250
+ groups << [release]
1251
+ end
1252
+ end
1253
+
1254
+ groups.map { |entries| entries.max_by { |entry| GhaShaPinsCLI.release_version_sort_key(entry) } }
1255
+ end
1256
+
1257
+ def equivalent_release_tag?(left, right)
1258
+ left[:version_obj] == right[:version_obj] &&
1259
+ left[:sha] &&
1260
+ right[:sha] &&
1261
+ left[:sha] == right[:sha]
1262
+ end
1263
+
1221
1264
  def parse_release_version_text(value)
1222
1265
  normalized = value.to_s.sub(/\A[vV]/, "")
1223
1266
  return nil unless normalized.match?(/\A(?:\d+|\d+\.\d+\.\d+(?:[-.]?[0-9A-Za-z.-]+)?)\z/)
@@ -108,12 +108,13 @@ module Kettle
108
108
 
109
109
  public
110
110
 
111
- def initialize(start_step: 0, local_ci: false, version: nil, appraisal_task: nil, skip_steps: nil, skip_bundle_audit: nil)
111
+ def initialize(start_step: 0, local_ci: false, version: nil, appraisal_task: nil, skip_steps: nil, skip_bundle_audit: nil, ci_workflows: nil, **options)
112
112
  @root = Kettle::Dev::CIHelpers.project_root
113
113
  @git = Kettle::Dev::GitAdapter.new
114
114
  @start_step = (start_step || 0).to_i
115
115
  @start_step = 0 if @start_step < 0
116
116
  @skip_steps = normalize_skip_steps(skip_steps)
117
+ @ci_workflows = normalize_ci_workflows(ci_workflows || ENV["K_RELEASE_CI_WORKFLOWS"])
117
118
  @local_ci = !!local_ci
118
119
  @skip_bundle_audit = truthy_value?(skip_bundle_audit) || truthy_value?(ENV["KETTLE_DEV_SKIP_BUNDLE_AUDIT"])
119
120
  @version_override = Kettle::Dev::Versioning.normalize_explicit_version(version)
@@ -405,6 +406,11 @@ module Kettle
405
406
  end.uniq
406
407
  end
407
408
 
409
+ def normalize_ci_workflows(value)
410
+ workflows = Array(value).flat_map { |part| part.to_s.split(",") }.map(&:strip).reject(&:empty?)
411
+ workflows.map { |workflow| workflow.match?(/\.ya?ml\z/) ? workflow : "#{workflow}.yml" }.uniq
412
+ end
413
+
408
414
  private
409
415
 
410
416
  def local_ci?
@@ -714,7 +720,7 @@ module Kettle
714
720
 
715
721
  def monitor_workflows_after_push!
716
722
  # Use abort-on-failure CI monitor to match historical behavior and specs
717
- Kettle::Dev::CIMonitor.monitor_all!(restart_hint: "bundle exec kettle-release start_step=10")
723
+ Kettle::Dev::CIMonitor.monitor_all!(restart_hint: "bundle exec kettle-release start_step=10", workflows: @ci_workflows)
718
724
  end
719
725
 
720
726
  def run_cmd!(cmd)
@@ -3,7 +3,7 @@
3
3
  module Kettle
4
4
  module Dev
5
5
  module Version
6
- VERSION = "2.3.5"
6
+ VERSION = "2.3.7"
7
7
  end
8
8
  VERSION = Version::VERSION # Traditional Constant Location
9
9
  end