kettle-family 1.3.0 → 1.3.1

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: c2e7e86419a5d960e83f3e8f7cb5aa1348f5acbe217b02b43e27ca479b9dafd9
4
- data.tar.gz: cb5de478d104da8759b0746db6a58f415afb768aae9cd6622e3b4d2a42cdbd09
3
+ metadata.gz: ce61863e305027b86eef8097ce594d8a9b77ba0e9e043ecb1617be9722a5ae38
4
+ data.tar.gz: 2b61292cbe3fcabb567c8f47ab7bac6170782dcedf75366452bb171b29b5a96a
5
5
  SHA512:
6
- metadata.gz: a60488bf1fc40699a0317e52d6b62318bf0eb243cc42f6950b39b1f7e2e785e7be4de6163a436057d2fcef5a602446dd1acbce249f6ecad7912ccfbc947d7526
7
- data.tar.gz: 7c35f5fb09c6edbd5dc63235c0e3a97b69e9aa21a2dffff7c453fa557ab54f9383b7d1d69a9d08972bd1a7f078352dff5cc32991e203d588765570eaecc3ed18
6
+ metadata.gz: 47d6f2b5ebe4cbb0480c75037f702aba4eacf8185758df0724922d5cf2780d15a6c742d92e4d0bbdb55e64d3272c41a9ee3db8d46ad4e3bb39fedcc82427c25e
7
+ data.tar.gz: 1b0db917fd48cfe90aee4f6d00909ea667b9aab0bd9ac13704039a0117878f0f46d6ef6a5f1ef3f7e23a81858ef6f3aa2966d219127826a664c7c640f15da160
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.3.1] - 2026-09-10
34
+
35
+ - TAG: [v1.3.1][1.3.1t]
36
+ - COVERAGE: 93.48% -- 6352/6795 lines in 36 files
37
+ - BRANCH COVERAGE: 77.98% -- 2582/3311 branches in 36 files
38
+ - 33.49% documented
39
+
40
+ ### Fixed
41
+
42
+ - Honor configured ordering in release-state reports, emit all five phases for shared-changelog members, and distinguish missing exact GitHub releases from lookup errors.
43
+
44
+ - Publish shared monorepo GitHub releases incrementally after each finalized member, retain successful workers from interrupted waves, attach both checksum formats, and report redundant family state cells once.
45
+
46
+ - Keep independent monorepo GitHub release identities exact and avoid false unlisted-member warnings during filtered state inspection.
47
+
33
48
  ## [1.3.0] - 2026-09-10
34
49
 
35
50
  - TAG: [v1.3.0][1.3.0t]
@@ -2731,7 +2746,9 @@ Please file a bug if you notice a violation of semantic versioning.
2731
2746
  - Fixed CI load failures on engines without compatible `pty` support by falling back to Open3 for interactive release commands.
2732
2747
  - Fixed Ruby 3.2 version-bump support by loading Prism lazily and wiring the Prism gem only for MRI versions that need it.
2733
2748
 
2734
- [Unreleased]: https://github.com/kettle-dev/kettle-family/compare/v1.3.0...HEAD
2749
+ [Unreleased]: https://github.com/kettle-dev/kettle-family/compare/v1.3.1...HEAD
2750
+ [1.3.1]: https://github.com/kettle-dev/kettle-family/compare/v1.3.0...v1.3.1
2751
+ [1.3.1t]: https://github.com/kettle-dev/kettle-family/releases/tag/v1.3.1
2735
2752
  [1.3.0]: https://github.com/kettle-dev/kettle-family/compare/v1.2.100...v1.3.0
2736
2753
  [1.3.0t]: https://github.com/kettle-dev/kettle-family/releases/tag/v1.3.0
2737
2754
  [1.2.100]: https://github.com/kettle-dev/kettle-family/compare/v1.2.99...v1.2.100
data/README.md CHANGED
@@ -1186,7 +1186,7 @@ Thanks for RTFM. ☺️
1186
1186
  [📌gitmoji]: https://gitmoji.dev
1187
1187
  [📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
1188
1188
  [🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
1189
- [🧮kloc-img]: https://img.shields.io/badge/KLOC-6.764-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
1189
+ [🧮kloc-img]: https://img.shields.io/badge/KLOC-6.795-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
1190
1190
  [🔐security]: https://github.com/kettle-dev/kettle-family/blob/main/SECURITY.md
1191
1191
  [🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
1192
1192
  [📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
@@ -684,10 +684,10 @@ module Kettle
684
684
  members = discovery.members
685
685
  ordered = if command == "install"
686
686
  install_order(members, config)
687
- elsif %w[metadata release-state].include?(command)
687
+ elsif command == "metadata"
688
688
  members.sort_by(&:name)
689
689
  else
690
- Orderer.new(members: members, mode: config.order_mode, hints: config.order_hints).ordered
690
+ Orderer.new(members: members, mode: config.order_mode, hints: config.order_hints).ordered(allow_cycles: command == "release-state")
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)
@@ -92,7 +92,9 @@ module Kettle
92
92
  def warn_unlisted_discovered_members(discovered, configured)
93
93
  return unless config.configured_member_roots? || config.explicit_members.any?
94
94
 
95
- configured_roots = configured.map { |member| normalized_path(member.root) }
95
+ # Selection limits evaluation, not membership in the configuration.
96
+ roots = configured.map(&:root) + config.configured_member_roots + config.explicit_members.map { |entry| entry.fetch("root") }
97
+ configured_roots = roots.map { |root| normalized_path(root) }
96
98
  discovered.each do |member|
97
99
  next if configured_roots.include?(normalized_path(member.root))
98
100
 
@@ -14,7 +14,7 @@ module Kettle
14
14
  @by_name = members.to_h { |member| [member.name, member] }
15
15
  end
16
16
 
17
- def ordered
17
+ def ordered(allow_cycles: false)
18
18
  case mode
19
19
  when "dependency"
20
20
  tsort
@@ -24,6 +24,9 @@ module Kettle
24
24
  raise Error, "unknown order mode #{mode.inspect}"
25
25
  end
26
26
  rescue TSort::Cyclic => error
27
+ # Read-only state inspection must remain available to diagnose cycles.
28
+ return hinted_members if allow_cycles
29
+
27
30
  raise Error, "dependency cycle detected: #{error.message}"
28
31
  end
29
32
 
@@ -152,8 +152,11 @@ module Kettle
152
152
  success = status.success?
153
153
  emit_event(event_handler, member: member, branch: branch, action: "changelog_command", status: success ? "ok" : "failed", elapsed_seconds: elapsed, status_code: status.exitstatus)
154
154
  state = success ? JSON.parse(stdout) : {}
155
+ emit_event(event_handler, member: member, branch: branch, action: "computed_booleans", status: "running") if success
155
156
  state = state_with_computed_booleans(state) if success
157
+ state["shared_changelog_root"] = File.expand_path(config.root) if success
156
158
  state = branch_filtered_state(member, state, branch) if success && branch
159
+ emit_event(event_handler, member: member, branch: branch, action: "computed_booleans", status: "ok") if success
157
160
  emit_event(event_handler, member: member, branch: branch, action: "git_state", status: "running") if success
158
161
  state = enrich_git_state(member.root, state, branch: branch) if success
159
162
  emit_event(event_handler, member: member, branch: branch, action: "git_state", status: "ok") if success
@@ -391,11 +394,12 @@ module Kettle
391
394
  end
392
395
 
393
396
  def enrich_github_release(root, state, branch: nil, member: nil)
394
- tag = if branch || shared_root_member?(member)
395
- github_release_for_version(root, state["latest_released"])
396
- else
397
- github_latest_release(root)
397
+ # A shared repository can publish an independent member after (or
398
+ # before) the cohort. Repository-wide "latest" cannot identify either.
399
+ if branch || shared_changelog?
400
+ return state.merge(github_release_for_version(root, state["latest_released"]))
398
401
  end
402
+ tag = github_latest_release(root)
399
403
  return state unless tag
400
404
 
401
405
  state.merge("github_latest_release" => tag)
@@ -406,16 +410,24 @@ module Kettle
406
410
  end
407
411
 
408
412
  def github_release_for_version(root, version)
409
- return nil if version.to_s.empty?
413
+ return {} if version.to_s.empty?
410
414
 
411
415
  repo = github_repo_slug(root)
412
- return nil unless repo
416
+ return {} unless repo
413
417
 
414
418
  tag = "v#{version.to_s.delete_prefix("v")}"
415
- stdout, _stderr, status = Open3.capture3("gh", "release", "view", tag, "--repo", repo, "--json", "tagName", "--jq", ".tagName")
416
- status.success? ? normalize_github_release_tag(stdout) : nil
417
- rescue SystemCallError
418
- nil
419
+ stdout, stderr, status = Open3.capture3("gh", "release", "view", tag, "--repo", repo, "--json", "tagName", "--jq", ".tagName")
420
+ return {"github_latest_release" => normalize_github_release_tag(stdout)} if status.success?
421
+
422
+ # A missing exact release is not a failed lookup, nor permission to
423
+ # substitute an independently versioned member's latest release.
424
+ {
425
+ "github_release_status" => (stderr.strip == "release not found") ? "missing" : "error",
426
+ "github_expected_release" => tag,
427
+ "github_release_error" => stderr.strip
428
+ }
429
+ rescue SystemCallError => error
430
+ {"github_release_status" => "error", "github_release_error" => error.message}
419
431
  end
420
432
 
421
433
  def enrich_transfer_changelog_lag(root, state)
@@ -554,9 +554,28 @@ module Kettle
554
554
  lines << " count columns:"
555
555
  lines << " T(n): filter-aware kettle-jem transfer changelog lag; n is the total source entry count and row values are missing / applicable (x excluded-present)"
556
556
  rows = release_state_header
557
+ shared_rows = {}
557
558
  results.each do |result|
558
- rows << release_state_row(result)
559
+ row = release_state_row(result)
560
+ state = result.state || {}
561
+ shared_root = state["shared_changelog_root"]
562
+ if shared_root
563
+ # Only explicit shared-changelog cohorts share presentation. Keep
564
+ # member versions, registry state, transfer filters and flags intact.
565
+ key = [shared_root, result.branch, state["latest_released"]]
566
+ offset = release_state_has_branches? ? 1 : 0
567
+ shared_columns = [1, 3, 5, 7]
568
+ if shared_rows.key?(key)
569
+ shared_columns.each do |column|
570
+ row[column + offset] = "-" if row[column + offset] == shared_rows[key][column + offset]
571
+ end
572
+ else
573
+ shared_rows[key] = row.dup
574
+ end
575
+ end
576
+ rows << row
559
577
  end
578
+ lines << " -: shared family value reported on the first matching cohort row" unless shared_rows.empty?
560
579
  lines.concat(format_table(rows).map { |line| " #{line}" })
561
580
  failures = results.reject(&:ok?)
562
581
  return if failures.empty?
@@ -615,6 +634,9 @@ module Kettle
615
634
  end
616
635
 
617
636
  def release_state_github_release(state)
637
+ lookup_status = state["github_release_status"]
638
+ return lookup_status if %w[missing error].include?(lookup_status)
639
+
618
640
  github_release = state.fetch("github_latest_release", nil).to_s
619
641
  return "unknown" if github_release.empty?
620
642
 
@@ -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.0"
8
+ VERSION = "1.3.1"
9
9
  end
10
10
  # Current gem version exposed at the traditional constant location.
11
11
  VERSION = Version::VERSION # Traditional Constant Location
@@ -533,7 +533,7 @@ module Kettle
533
533
  return results unless results.all?(&:ok?)
534
534
 
535
535
  results.concat(release_member_results(workflow_members, include_family_changelog: !skip_changelog))
536
- return results unless explicit_monorepo_mode? && results.all?(&:ok?)
536
+ return results unless !execute && explicit_monorepo_mode? && results.all?(&:ok?)
537
537
 
538
538
  selected_aggregate_members = aggregate_release_members(workflow_members)
539
539
  results << aggregate_monorepo_github_release(aggregate_github_release_members) unless selected_aggregate_members.empty?
@@ -2128,6 +2128,9 @@ module Kettle
2128
2128
  results.concat(release_results_for_member(member, runner: runner, wave_jobs: 1))
2129
2129
  break unless results.last.ok?
2130
2130
 
2131
+ append_member_github_release(member, results)
2132
+ break unless results.last.ok?
2133
+
2131
2134
  remaining_members = ordered_members.drop(ordered_members.index(member) + 1)
2132
2135
  @release_completed_member_names << member.name
2133
2136
  append_dependency_floor_results(released_members: [member], dependent_members: remaining_members, runner: runner, memo: results)
@@ -2217,10 +2220,15 @@ module Kettle
2217
2220
  unless aggregate_members.empty?
2218
2221
  worker_results = run_monorepo_release_wave(aggregate_members, wave_jobs: release_jobs(aggregate_members))
2219
2222
  results.concat(worker_results.flatten)
2220
- break unless worker_results.all? { |member_results| member_results.all?(&:ok?) }
2221
-
2222
- finalization_results = finalize_monorepo_release_wave(aggregate_members)
2223
+ # Finalize published successes even when another worker failed.
2224
+ # Otherwise interruption strands registry gems without GH assets.
2225
+ successful_members = aggregate_members.select do |member|
2226
+ member_results = worker_results.flatten.select { |result| result.member_name == member.name }
2227
+ member_results.any? { |result| result.phase == "release_publish" && result.ok? } && member_results.all?(&:ok?)
2228
+ end
2229
+ finalization_results = finalize_monorepo_release_wave(successful_members)
2223
2230
  results.concat(finalization_results)
2231
+ break unless worker_results.all? { |member_results| member_results.all?(&:ok?) }
2224
2232
  break unless finalization_results.all?(&:ok?)
2225
2233
  end
2226
2234
 
@@ -2425,17 +2433,28 @@ module Kettle
2425
2433
  passthrough_output: release_command_passthrough_output?
2426
2434
  )
2427
2435
  break unless results.last.ok?
2428
- end
2429
- return results unless results.all?(&:ok?)
2430
2436
 
2431
- results << runner.call(
2432
- member: monorepo_release_control_member,
2433
- phase: "release_shared_push",
2434
- command: config.release_push_command
2435
- )
2437
+ results << runner.call(
2438
+ member: monorepo_release_control_member,
2439
+ phase: "release_shared_push",
2440
+ command: config.release_push_command
2441
+ )
2442
+ break unless results.last.ok?
2443
+
2444
+ append_member_github_release(member, results)
2445
+ break unless results.last.ok?
2446
+ end
2436
2447
  results
2437
2448
  end
2438
2449
 
2450
+ def append_member_github_release(member, results)
2451
+ return unless execute && publish && aggregate_monorepo_github_release? && aggregate_release_member?(member)
2452
+
2453
+ # Existing assets are retained by kettle-gh-release. Only contribute
2454
+ # this successfully published member, never a merely built future gem.
2455
+ results << aggregate_monorepo_github_release([member])
2456
+ end
2457
+
2439
2458
  def ensure_monorepo_release_tag(member, runner:)
2440
2459
  version = member.version.to_s
2441
2460
  tag = release_tag_name(version)
@@ -3762,8 +3781,8 @@ module Kettle
3762
3781
 
3763
3782
  assets = members.flat_map do |member|
3764
3783
  gem_path = Dir[File.join(member.root, "pkg", "*.gem")].select { |path| File.basename(path).end_with?("-#{version.first}.gem") }
3765
- checksum_path = File.join(member.root, "checksums", "#{member.name}-#{version.first}.gem.sha256")
3766
- gem_path + (File.file?(checksum_path) ? [checksum_path] : [])
3784
+ checksum_paths = %w[sha256 sha512].map { |algorithm| File.join(member.root, "checksums", "#{member.name}-#{version.first}.gem.#{algorithm}") }
3785
+ gem_path + checksum_paths.select { |path| File.file?(path) }
3767
3786
  end
3768
3787
  command = ["bundle", "exec", "kettle-gh-release", "--allow-unpublished", "--events", "--release-version", version.first]
3769
3788
  assets.each { |asset| command.concat(["--asset", asset]) }
data.tar.gz.sig CHANGED
@@ -1,3 +1 @@
1
- ]ez��h(F>Lb��1 ��_��ޭ��&2V����1�����m�����4_C�M�W�����`8��7�� x7XF����`;�MD��!����2��D`!р�����JV\�� ��"�>�T7 ´۱b����n¯�
2
- K������f�j6�/;kA�z���T�^%m�qOJ�L�e��K2(`Q��"��C�AdM��9$Ȍ/�����*�
3
- �Ҙ#�+C)�p?)�á�%(*�:��M�p���T��CZv�Iw��}���:y��w1�&ُ:{H�׫��]d~��6G�g=� ԃ2&ZL���0[�b��)P��7�����W�u�y�\jNes�w�rK�ePN����
1
+ ������փw54|���5\3�™�}%�sA���K&��yTt�U� �[�ZV}x�����Ao��1��°QW;8��}b�yoau�\���O:4��ތК? �E(��4��~�ܶZ��Nr��plu4�M�Qf�&^�Y��j��K�]5!�`Y�“X?;�wD�;1j��S��X*oЍ�������F�*VU0�]��ע���F������R�QA��|4��7��$��&�2F*di���C��s�����rB�
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.0
4
+ version: 1.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter H. Boling
@@ -444,10 +444,10 @@ licenses:
444
444
  - AGPL-3.0-only
445
445
  metadata:
446
446
  homepage_uri: https://kettle-family.galtzo.com
447
- source_code_uri: https://github.com/kettle-dev/kettle-family/tree/v1.3.0
448
- changelog_uri: https://github.com/kettle-dev/kettle-family/blob/v1.3.0/CHANGELOG.md
447
+ source_code_uri: https://github.com/kettle-dev/kettle-family/tree/v1.3.1
448
+ changelog_uri: https://github.com/kettle-dev/kettle-family/blob/v1.3.1/CHANGELOG.md
449
449
  bug_tracker_uri: https://github.com/kettle-dev/kettle-family/issues
450
- documentation_uri: https://www.rubydoc.info/gems/kettle-family/1.3.0
450
+ documentation_uri: https://www.rubydoc.info/gems/kettle-family/1.3.1
451
451
  funding_uri: https://github.com/sponsors/pboling
452
452
  wiki_uri: https://github.com/kettle-dev/kettle-family/wiki
453
453
  news_uri: https://www.railsbling.com/tags/kettle-family
metadata.gz.sig CHANGED
Binary file