kettle-dev 2.4.0 → 2.4.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: dc6dd6b412d11d659d2f5ed0916372e599642a82640335700f3e723937638cba
4
- data.tar.gz: 86114a4e096dd7da0934477c06aee521372d6eeb5f2114377d0a035b32be42f1
3
+ metadata.gz: 77a7621fa0d906b716e933205ff585081b8746345530f540a8c83f6e67d3f347
4
+ data.tar.gz: ae54a1e1f33347caa8c6d07eae632db0b88c95583a838fece942bd9bb1d84bfb
5
5
  SHA512:
6
- metadata.gz: f056c2d67dee284c734c2b0bf5cb06ce957d981cc7c8f922108b2cf1c3b3a8acf5c0c2a1fe8b7b3347ae92c85f780f82ab1e14cf677e12591ece125522bdf967
7
- data.tar.gz: 1c5db4b16afe9840dca06f5a6a1528fe3afa3dadb68b727c2b95c43bfa3240d19625aad892a792000841b42640d07451136f0f87a18f2e711aba5f7107721368
6
+ metadata.gz: 03b528fd8d85c047d18606f023a0f9f217ca88556ed26ddbc62504a282bceda6a42ea315c0cd0fdd0e2e4307fefeda357d34fcf4fab98d83dc5214c9d202bbb2
7
+ data.tar.gz: d630c32d5f8cfbb28b74cdc552a9d331aa73d25de2d80298736f759f2bfe3181649c845a1d812c5ead41f9792a3169091f07ae33a2afb1610028b191effb08e7
checksums.yaml.gz.sig CHANGED
Binary file
data/CHANGELOG.md CHANGED
@@ -30,6 +30,20 @@ Please file a bug if you notice a violation of semantic versioning.
30
30
 
31
31
  ### Security
32
32
 
33
+ ## [2.4.1] - 2026-07-24
34
+
35
+ - TAG: [v2.4.1][2.4.1t]
36
+ - COVERAGE: 92.29% -- 3928/4256 lines in 38 files
37
+ - BRANCH COVERAGE: 76.09% -- 1550/2037 branches in 38 files
38
+ - 58.66% documented
39
+
40
+ ### Fixed
41
+
42
+ - `kettle-release` now normalizes and revalidates release lockfiles after
43
+ mutating setup/appraisal/doc steps, before committing or pushing, so local
44
+ path remotes and locally installed registry gems with empty lockfile
45
+ checksums cannot leak into CI.
46
+
33
47
  ## [2.4.0] - 2026-07-23
34
48
 
35
49
  - TAG: [v2.4.0][2.4.0t]
@@ -2646,7 +2660,9 @@ Please file a bug if you notice a violation of semantic versioning.
2646
2660
  - Selecting will run the selected workflow via `act`
2647
2661
  - This may move to its own gem in the future.
2648
2662
 
2649
- [Unreleased]: https://github.com/kettle-dev/kettle-dev/compare/v2.4.0...HEAD
2663
+ [Unreleased]: https://github.com/kettle-dev/kettle-dev/compare/v2.4.1...HEAD
2664
+ [2.4.1]: https://github.com/kettle-dev/kettle-dev/compare/v2.4.0...v2.4.1
2665
+ [2.4.1t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v2.4.1
2650
2666
  [2.4.0]: https://github.com/kettle-dev/kettle-dev/compare/v2.3.11...v2.4.0
2651
2667
  [2.4.0t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v2.4.0
2652
2668
  [2.3.11]: https://github.com/kettle-dev/kettle-dev/compare/v2.3.10...v2.3.11
data/README.md CHANGED
@@ -891,7 +891,7 @@ Thanks for RTFM. ☺️
891
891
  [📌gitmoji]: https://gitmoji.dev
892
892
  [📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
893
893
  [🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
894
- [🧮kloc-img]: https://img.shields.io/badge/KLOC-4.141-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
894
+ [🧮kloc-img]: https://img.shields.io/badge/KLOC-4.256-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
895
895
  [🔐security]: https://github.com/kettle-dev/kettle-dev/blob/main/SECURITY.md
896
896
  [🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
897
897
  [📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
@@ -10,6 +10,7 @@ require "net/http"
10
10
  require "json"
11
11
  require "uri"
12
12
  require "yaml"
13
+ require "set"
13
14
 
14
15
  # External gems
15
16
  require "kettle/rb/compat_matrix"
@@ -256,6 +257,7 @@ module Kettle
256
257
 
257
258
  # 6. git user + commit release prep
258
259
  if run_step?(6)
260
+ prepare_release_lockfiles_for_commit!
259
261
  ensure_git_user!
260
262
  version ||= detect_version
261
263
  committed = commit_release_prep!(version)
@@ -279,10 +281,16 @@ module Kettle
279
281
  end
280
282
 
281
283
  # 9. push branches
282
- push! if run_step?(9) && !local_ci?
284
+ if run_step?(9) && !local_ci?
285
+ validate_release_lockfiles!(stage: "before push")
286
+ push!
287
+ end
283
288
 
284
289
  # 10. monitor CI after push
285
- monitor_workflows_after_push! if run_step?(10) && !local_ci?
290
+ if run_step?(10) && !local_ci?
291
+ validate_release_lockfiles!(stage: "before CI monitoring")
292
+ monitor_workflows_after_push!
293
+ end
286
294
 
287
295
  # 11. merge feature into trunk and push
288
296
  if run_step?(11) && !local_ci?
@@ -505,6 +513,187 @@ module Kettle
505
513
  run_changelog!
506
514
  end
507
515
 
516
+ def prepare_release_lockfiles_for_commit!
517
+ dirty_lockfiles = release_lockfile_paths.select { |path| release_lockfile_normalization_needed?(path) }
518
+ unless dirty_lockfiles.empty?
519
+ puts "Normalizing release lockfiles with local path dependencies disabled..."
520
+ dirty_lockfiles.each { |path| normalize_release_lockfile!(path) }
521
+ end
522
+
523
+ validate_release_lockfiles!(stage: "before release prep commit")
524
+ end
525
+
526
+ def validate_release_lockfiles!(stage:)
527
+ diagnostics = release_lockfile_paths.flat_map { |path| release_lockfile_diagnostics(path) }
528
+ return if diagnostics.empty?
529
+
530
+ abort(<<~MSG)
531
+ Release lockfile validation failed #{stage}:
532
+ #{diagnostics.map { |diagnostic| " - #{diagnostic}" }.join("\n")}
533
+ Re-run bundle lock/update with local path development env disabled before releasing.
534
+ MSG
535
+ end
536
+
537
+ def release_lockfile_paths
538
+ candidates = [
539
+ File.join(@root, "Gemfile.lock"),
540
+ File.join(@root, "Appraisal.root.gemfile.lock")
541
+ ]
542
+ candidates.select { |path| File.file?(path) }.sort
543
+ end
544
+
545
+ def release_lockfile_normalization_needed?(path)
546
+ release_lockfile_has_local_path_remote?(path) || !release_lockfile_empty_registry_checksums(path).empty?
547
+ end
548
+
549
+ def normalize_release_lockfile!(path)
550
+ gemfile = release_gemfile_for_lockfile(path)
551
+ unless gemfile && File.file?(gemfile)
552
+ warn("Cannot normalize #{Kettle::Dev.display_path(path)} because its Gemfile was not found.")
553
+ return
554
+ end
555
+
556
+ update_gems = release_lockfile_empty_registry_checksums(path).map(&:first).uniq.sort
557
+ env = release_lockfile_normalization_env.merge("BUNDLE_GEMFILE" => gemfile)
558
+ command = +"env"
559
+ env.each do |key, value|
560
+ command << " #{key}=#{Shellwords.escape(value)}"
561
+ end
562
+ command << " bundle lock"
563
+ command << " --update #{update_gems.map { |gem_name| Shellwords.escape(gem_name) }.join(" ")}" unless update_gems.empty?
564
+ run_cmd!(command)
565
+ end
566
+
567
+ def release_gemfile_for_lockfile(path)
568
+ basename = File.basename(path)
569
+ return File.join(@root, "Gemfile") if basename == "Gemfile.lock"
570
+
571
+ path.delete_suffix(".lock")
572
+ end
573
+
574
+ def release_lockfile_normalization_env
575
+ {
576
+ "KETTLE_DEV_DEV" => "false",
577
+ "K_JEM_TEMPLATING" => "false",
578
+ "STRUCTUREDMERGE_DEV" => "false",
579
+ "TREE_SITTER_LANGUAGE_PACK_DEV" => "false",
580
+ "RUBOCOP_LTS_LOCAL" => "false",
581
+ "GALTZO_FLOSS_DEV" => "false",
582
+ "UR_BRAIN_DEV" => "false"
583
+ }
584
+ end
585
+
586
+ def release_lockfile_diagnostics(path)
587
+ diagnostics = []
588
+ release_lockfile_local_path_remote_lines(path).each do |line_number|
589
+ diagnostics << "#{release_lockfile_label(path)} has local path remote at line #{line_number}"
590
+ end
591
+ release_lockfile_empty_registry_checksums(path).each do |name, version, line_number|
592
+ diagnostics << "#{release_lockfile_label(path)} CHECKSUMS has no sha256 for #{name} #{version} at line #{line_number}"
593
+ end
594
+ diagnostics
595
+ end
596
+
597
+ def release_lockfile_has_local_path_remote?(path)
598
+ !release_lockfile_local_path_remote_lines(path).empty?
599
+ end
600
+
601
+ def release_lockfile_local_path_remote_lines(path)
602
+ File.readlines(path).filter_map.with_index(1) do |line, index|
603
+ next unless line.start_with?(" remote: /", " remote: ./", " remote: ../")
604
+
605
+ index
606
+ end
607
+ end
608
+
609
+ def release_lockfile_empty_registry_checksums(path)
610
+ path_gems = release_lockfile_path_source_gems(path) | release_lockfile_path_dependency_gems(path)
611
+ in_checksums = false
612
+ entries = File.readlines(path).filter_map.with_index(1) do |line, index|
613
+ stripped = line.strip
614
+ if stripped == "CHECKSUMS"
615
+ in_checksums = true
616
+ next
617
+ end
618
+ next unless in_checksums
619
+ next if stripped.empty?
620
+ next if stripped == "BUNDLED WITH"
621
+
622
+ match = stripped.match(/\A([A-Za-z0-9_.-]+) \(([^)]+)\)(?:\s+(sha256=.*))?\z/)
623
+ next unless match
624
+
625
+ name = match[1]
626
+ checksum = match[3].to_s
627
+ next if !checksum.empty?
628
+ next if path_gems.include?(name)
629
+
630
+ [name, match[2], index]
631
+ end
632
+ return [] unless release_lockfile_has_any_sha_checksum?(path)
633
+
634
+ entries
635
+ end
636
+
637
+ def release_lockfile_has_any_sha_checksum?(path)
638
+ in_checksums = false
639
+ File.readlines(path).any? do |line|
640
+ stripped = line.strip
641
+ if stripped == "CHECKSUMS"
642
+ in_checksums = true
643
+ next false
644
+ end
645
+ next false unless in_checksums
646
+
647
+ stripped.include?("sha256=")
648
+ end
649
+ end
650
+
651
+ def release_lockfile_path_source_gems(path)
652
+ gems = Set.new
653
+ in_path = false
654
+ in_specs = false
655
+ File.readlines(path).each do |line|
656
+ header = line.strip
657
+ if header.match?(/\A[A-Z][A-Z ]*\z/)
658
+ in_path = header == "PATH"
659
+ in_specs = false
660
+ next
661
+ end
662
+ next unless in_path
663
+
664
+ if header == "specs:"
665
+ in_specs = true
666
+ next
667
+ end
668
+ next unless in_specs
669
+
670
+ match = line.match(/\A ([A-Za-z0-9_.-]+) \([^)]+\)/)
671
+ gems << match[1] if match
672
+ end
673
+ gems
674
+ end
675
+
676
+ def release_lockfile_path_dependency_gems(path)
677
+ gems = Set.new
678
+ in_dependencies = false
679
+ File.readlines(path).each do |line|
680
+ header = line.strip
681
+ if header.match?(/\A[A-Z][A-Z ]*\z/)
682
+ in_dependencies = header == "DEPENDENCIES"
683
+ next
684
+ end
685
+ next unless in_dependencies
686
+
687
+ match = line.match(/\A ([A-Za-z0-9_.-]+)!\z/)
688
+ gems << match[1] if match
689
+ end
690
+ gems
691
+ end
692
+
693
+ def release_lockfile_label(path)
694
+ Kettle::Dev.display_path(path)
695
+ end
696
+
508
697
  def run_changelog!
509
698
  cmd = "bundle exec kettle-changelog"
510
699
  cmd = "#{cmd} --version #{Shellwords.escape(@version_override)}" if @version_override
@@ -3,7 +3,7 @@
3
3
  module Kettle
4
4
  module Dev
5
5
  module Version
6
- VERSION = "2.4.0"
6
+ VERSION = "2.4.1"
7
7
  end
8
8
  VERSION = Version::VERSION # Traditional Constant Location
9
9
  end
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: 2.4.0
4
+ version: 2.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter H. Boling
@@ -349,10 +349,10 @@ licenses:
349
349
  - AGPL-3.0-only
350
350
  metadata:
351
351
  homepage_uri: https://kettle-dev.galtzo.com
352
- source_code_uri: https://github.com/kettle-dev/kettle-dev/tree/v2.4.0
353
- changelog_uri: https://github.com/kettle-dev/kettle-dev/blob/v2.4.0/CHANGELOG.md
352
+ source_code_uri: https://github.com/kettle-dev/kettle-dev/tree/v2.4.1
353
+ changelog_uri: https://github.com/kettle-dev/kettle-dev/blob/v2.4.1/CHANGELOG.md
354
354
  bug_tracker_uri: https://github.com/kettle-dev/kettle-dev/issues
355
- documentation_uri: https://www.rubydoc.info/gems/kettle-dev/2.4.0
355
+ documentation_uri: https://www.rubydoc.info/gems/kettle-dev/2.4.1
356
356
  funding_uri: https://github.com/sponsors/pboling
357
357
  wiki_uri: https://github.com/kettle-dev/kettle-dev/wiki
358
358
  news_uri: https://www.railsbling.com/tags/kettle-dev
metadata.gz.sig CHANGED
Binary file