kettle-dev 3.0.28 → 3.0.30

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: dda94d3be88afd70177ebf10e5272e19ade1b64468e8c44479145949382a954f
4
- data.tar.gz: cc4a9f69fef74faad9f592909bfdc58caf913c6a7e3f52fde4a70101840b47ed
3
+ metadata.gz: d32d5afad3273769c6866465e43835b68691702c67e7de114aa0c641e5ba98e4
4
+ data.tar.gz: 182991a2de8eb82855285724435c3430a2dd52759838efbf11543061eb4336b4
5
5
  SHA512:
6
- metadata.gz: b8c9a7f9b079a7c040dd025ff7093bcf74ac30a37163b32a5460353bf1d1c4cf4a0cff964f14d11eb126343e8d5eb8ef3413e580eb33605d850f23863e25639c
7
- data.tar.gz: 7da28d9024ac1c4ae381ae97d6331ee21eb1bda66b720ba09c6d7af5eaf8fcd973cc98eeead7b9710884f056c63a7a981ffd6423ec4389aebbf4bc9a1a2fbf70
6
+ metadata.gz: 29ad4b57bc12dc971e7132a46c52a6c33492838673d53f35c4dafb7a30c915383002365ab65fc7cf0350e35a5d8bb35ce0764c2cc33913f859c9fad49e9b467a
7
+ data.tar.gz: 82ab1755611b6d7f645ab573554f18030766a76a07f93e8e2a9af866ec2eadb2b36426d104142de457ca6af26b4eb05df4516978a77b19de2209057de315f508
checksums.yaml.gz.sig CHANGED
Binary file
data/CHANGELOG.md CHANGED
@@ -30,6 +30,32 @@ Please file a bug if you notice a violation of semantic versioning.
30
30
 
31
31
  ### Security
32
32
 
33
+ ## [3.0.30] - 2026-09-01
34
+
35
+ - TAG: [v3.0.30][3.0.30t]
36
+ - COVERAGE: 91.68% -- 6038/6586 lines in 47 files
37
+ - BRANCH COVERAGE: 76.31% -- 2310/3027 branches in 47 files
38
+ - 50.00% documented
39
+
40
+ ### Fixed
41
+
42
+ - Add an isolated family-member publish mode for concurrent monorepo releases.
43
+
44
+ - Add serialized family-member checksum finalization for concurrent monorepo releases.
45
+
46
+ ## [3.0.29] - 2026-09-01
47
+
48
+ - TAG: [v3.0.29][3.0.29t]
49
+ - COVERAGE: 91.58% -- 6003/6555 lines in 47 files
50
+ - BRANCH COVERAGE: 76.25% -- 2302/3019 branches in 47 files
51
+ - 50.24% documented
52
+
53
+ ### Fixed
54
+
55
+ - Install bootstrap gems required by statically evaluated Gemfiles before isolated release lockfile resolution.
56
+
57
+ - Ignore inactive nested Gemfile bootstrap requirements when their appraisal lockfile does not include the bootstrap gem.
58
+
33
59
  ## [3.0.28] - 2026-09-01
34
60
 
35
61
  - TAG: [v3.0.28][3.0.28t]
@@ -3773,7 +3799,11 @@ Please file a bug if you notice a violation of semantic versioning.
3773
3799
  - Selecting will run the selected workflow via `act`
3774
3800
  - This may move to its own gem in the future.
3775
3801
 
3776
- [Unreleased]: https://github.com/kettle-dev/kettle-dev/compare/v3.0.28...HEAD
3802
+ [Unreleased]: https://github.com/kettle-dev/kettle-dev/compare/v3.0.30...HEAD
3803
+ [3.0.30]: https://github.com/kettle-dev/kettle-dev/compare/v3.0.29...v3.0.30
3804
+ [3.0.30t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v3.0.30
3805
+ [3.0.29]: https://github.com/kettle-dev/kettle-dev/compare/v3.0.28...v3.0.29
3806
+ [3.0.29t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v3.0.29
3777
3807
  [3.0.28]: https://github.com/kettle-dev/kettle-dev/compare/v3.0.27...v3.0.28
3778
3808
  [3.0.28t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v3.0.28
3779
3809
  [3.0.27]: https://github.com/kettle-dev/kettle-dev/compare/v3.0.26...v3.0.27
data/README.md CHANGED
@@ -1066,7 +1066,7 @@ Thanks for RTFM. ☺️
1066
1066
  [📌gitmoji]: https://gitmoji.dev
1067
1067
  [📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
1068
1068
  [🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
1069
- [🧮kloc-img]: https://img.shields.io/badge/KLOC-6.542-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
1069
+ [🧮kloc-img]: https://img.shields.io/badge/KLOC-6.586-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
1070
1070
  [🔐security]: https://github.com/kettle-dev/kettle-dev/blob/main/SECURITY.md
1071
1071
  [🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
1072
1072
  [📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
@@ -476,14 +476,18 @@ module Kettle
476
476
  end
477
477
  end
478
478
 
479
- # Bundler evaluates a Gemfile before it resolves the gems declared in it.
480
- # Install only direct, literal bootstrap requires into the reset sandbox so
481
- # unrelated gems from the invoking Ruby cannot influence resolution.
479
+ # Bundler evaluates a Gemfile and its static eval_gemfile inputs before it
480
+ # resolves declared gems. Install only literal bootstrap requires into the
481
+ # reset sandbox so unrelated gems from the invoking Ruby cannot influence
482
+ # resolution.
482
483
  def install_gemfile_bootstrap_gems!(gemfile:, lockfile:, gem_home:)
483
- gemfile_bootstrap_gem_names(gemfile).each do |name|
484
+ gemfile_bootstrap_gems(gemfile).each do |name, required_by_root_gemfile|
484
485
  version = locked_registry_gem_version(lockfile, name)
485
486
  source_url = registry_source_urls(lockfile).first
486
- unless version && source_url
487
+ needs_install = required_by_root_gemfile || (version && source_url)
488
+ next unless needs_install
489
+
490
+ if !version || !source_url
487
491
  raise Error, "Cannot isolate Gemfile bootstrap #{name.inspect}: #{display_path(lockfile)} does not lock it from a registry source"
488
492
  end
489
493
 
@@ -491,9 +495,27 @@ module Kettle
491
495
  end
492
496
  end
493
497
 
494
- def gemfile_bootstrap_gem_names(gemfile)
495
- calls = require_calls_from_ripper(Ripper.sexp(File.read(gemfile)))
496
- calls.filter_map { |method_name, argument| bootstrap_gem_name(method_name, argument) }.uniq
498
+ def gemfile_bootstrap_gems(gemfile)
499
+ gemfile_source_paths(gemfile).each_with_index.each_with_object({}) do |(path, index), gems|
500
+ calls = require_calls_from_ripper(Ripper.sexp(File.read(path)))
501
+ calls.filter_map { |method_name, argument| bootstrap_gem_name(method_name, argument) }.each do |name|
502
+ gems[name] = gems.fetch(name, false) || index.zero?
503
+ end
504
+ end
505
+ end
506
+
507
+ def gemfile_source_paths(gemfile, seen = Set.new)
508
+ path = File.expand_path(gemfile)
509
+ return [] if seen.include?(path) || !File.file?(path)
510
+
511
+ seen << path
512
+ calls = require_calls_from_ripper(Ripper.sexp(File.read(path)))
513
+ nested_paths = calls.filter_map do |method_name, argument|
514
+ next unless method_name == "eval_gemfile" && argument
515
+
516
+ File.expand_path(argument, File.dirname(path))
517
+ end
518
+ [path, *nested_paths.flat_map { |nested_path| gemfile_source_paths(nested_path, seen) }]
497
519
  end
498
520
 
499
521
  def require_calls_from_ripper(node, calls = [])
@@ -69,6 +69,8 @@ module Kettle
69
69
  ].freeze
70
70
  DEBUG_TRUE_VALUES = %w[1 true yes on].freeze
71
71
  RELEASE_VALIDATION_SOURCE = "https://gem.coop"
72
+ FAMILY_MEMBER_PUBLISH_MODE_ENV = "KETTLE_RELEASE_FAMILY_MEMBER_PUBLISH"
73
+ FAMILY_MEMBER_FINALIZE_MODE_ENV = "KETTLE_RELEASE_FAMILY_MEMBER_FINALIZE"
72
74
 
73
75
  class << self
74
76
  def run_cmd!(cmd)
@@ -223,6 +225,8 @@ module Kettle
223
225
  @finished_report = nil
224
226
  @changelog_generated_coverage = false
225
227
  @release_task_lockfile_paths = {}
228
+ @family_member_publish = truthy_value?(ENV[FAMILY_MEMBER_PUBLISH_MODE_ENV])
229
+ @family_member_finalize = truthy_value?(ENV[FAMILY_MEMBER_FINALIZE_MODE_ENV])
226
230
  end
227
231
 
228
232
  def run
@@ -255,6 +259,9 @@ module Kettle
255
259
  attr_reader :finished_report
256
260
 
257
261
  def run_with_release_environment
262
+ return run_family_member_publish if family_member_publish?
263
+ return run_family_member_finalize if family_member_finalize?
264
+
258
265
  # Changelog generation at step 0 runs the target project's test bundle
259
266
  # to collect coverage. Normalize its canonical release lockfile before
260
267
  # that subprocess starts; otherwise a local development PATH lock can
@@ -605,6 +612,41 @@ module Kettle
605
612
  @skip_bundle_audit
606
613
  end
607
614
 
615
+ # Kettle Family uses this mode only after it has prepared and validated
616
+ # the shared monorepo release commit. A member may build and publish its
617
+ # gem, but it must never alter the shared Git repository or release it.
618
+ def family_member_publish?
619
+ @family_member_publish
620
+ end
621
+
622
+ def family_member_finalize?
623
+ @family_member_finalize
624
+ end
625
+
626
+ def run_family_member_publish
627
+ version = detect_version
628
+ prepare_release_lockfiles_for_release_tasks!
629
+ ensure_signing_setup_or_skip!
630
+ ensure_release_secrets_ready_for_signing! if signing_enabled? && release_secrets_configured?
631
+ run_cmd!(release_project_command("bundle exec rake build"))
632
+
633
+ gem_name = detect_gem_name
634
+ @release_candidate = build_release_candidate(gem_name, version)
635
+ with_unpublished_candidate_cleanup { publish_built_gem!(version) }
636
+ human_output.puts "\n🚀 Published #{gem_name} v#{version} from family member mode 🚀"
637
+ end
638
+
639
+ # Kettle Family invokes this serially in the primary checkout after
640
+ # concurrent member publication. bin/gem_checksums owns its checksum
641
+ # commit; the family owns the one shared tag, pushes, and GitHub Release.
642
+ def run_family_member_finalize
643
+ version = detect_version
644
+ gem_path = checksum_gem_path_for_version!(version)
645
+ run_cmd!(release_child_command("bin/gem_checksums #{Shellwords.escape(gem_path)}"))
646
+ validate_checksums!(version, stage: "after family member publish")
647
+ human_output.puts "\n🔒 Finalized checksums for #{detect_gem_name} v#{version} from family member mode 🔒"
648
+ end
649
+
608
650
  def truthy_value?(value)
609
651
  return true if value == true
610
652
 
@@ -1868,6 +1910,15 @@ module Kettle
1868
1910
  abort("Failed to create local tag #{tag}.") unless @git.tag_annotated(tag, tag)
1869
1911
  end
1870
1912
 
1913
+ publish_built_gem!(version)
1914
+ end
1915
+
1916
+ def publish_built_gem!(version)
1917
+ gem_path = gem_file_for_version(version)
1918
+ unless gem_path && File.file?(gem_path)
1919
+ abort("Unable to locate built gem for version #{version} in pkg/. Did the build succeed?")
1920
+ end
1921
+
1871
1922
  puts "Publishing #{File.basename(gem_path)} to RubyGems without pushing git refs..."
1872
1923
  run_cmd!("gem push #{Shellwords.escape(gem_path)}")
1873
1924
  gem_name = gem_name_from_gem_path(gem_path, version)
@@ -5,7 +5,7 @@ module Kettle
5
5
  # Version namespace for this gem.
6
6
  module Version
7
7
  # Current gem version.
8
- VERSION = "3.0.28"
8
+ VERSION = "3.0.30"
9
9
  end
10
10
  # Current gem version exposed at the traditional constant location.
11
11
  VERSION = Version::VERSION # Traditional Constant Location
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kettle-dev
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.28
4
+ version: 3.0.30
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter H. Boling
@@ -400,10 +400,10 @@ licenses:
400
400
  - AGPL-3.0-only
401
401
  metadata:
402
402
  homepage_uri: https://kettle-dev.galtzo.com
403
- source_code_uri: https://github.com/kettle-dev/kettle-dev/tree/v3.0.28
404
- changelog_uri: https://github.com/kettle-dev/kettle-dev/blob/v3.0.28/CHANGELOG.md
403
+ source_code_uri: https://github.com/kettle-dev/kettle-dev/tree/v3.0.30
404
+ changelog_uri: https://github.com/kettle-dev/kettle-dev/blob/v3.0.30/CHANGELOG.md
405
405
  bug_tracker_uri: https://github.com/kettle-dev/kettle-dev/issues
406
- documentation_uri: https://www.rubydoc.info/gems/kettle-dev/3.0.28
406
+ documentation_uri: https://www.rubydoc.info/gems/kettle-dev/3.0.30
407
407
  funding_uri: https://github.com/sponsors/pboling
408
408
  wiki_uri: https://github.com/kettle-dev/kettle-dev/wiki
409
409
  news_uri: https://www.railsbling.com/tags/kettle-dev
metadata.gz.sig CHANGED
Binary file