kettle-family 1.2.11 → 1.2.12

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: 1f0da4c8794762df47df980870cdafa4ccbe25e6e1e0faae8b1b2ab13e512097
4
- data.tar.gz: a8ad81e87f95aa544d51a21b3ba8b3cfa875d413939560ae603678e1ae9f64a1
3
+ metadata.gz: 8ba0934fc9a3cb13405a2d6546e64f6542df7972983eb22b881981c71fde5af4
4
+ data.tar.gz: dca77905dae036ee7d9ea4a71c6d52fd9ebc7689f4981005bc9b317f278c2d2a
5
5
  SHA512:
6
- metadata.gz: d48cba6cd03e39932c805252a16d2f60bae16130b4ef2b3bba0ed650d35fea4a628e6be48a0ca33d6a8f625ef3f81e074aca43d16587f4a97ff2da2cb3533d0b
7
- data.tar.gz: 577b907ce129337f155bfb0d498f00d14d8dcfb70ac3835ba57c62cf0d69431ba70e4cd81ce6a04463724e420ed36c7580e27fb08474752ca4e7eeb140cfce34
6
+ metadata.gz: a8652fa19d9f51210fd3eef7d206f7299db43e05688f8e1e09b0d5acc6b05969efa1303e4e47ae9fd98cfb31391b5ea1ab48ce506181ae577f4db88e534988f6
7
+ data.tar.gz: 1f1bb5c5677b5d870114678d5ab569f238e2e00d4ab0c5d713801135bdfd40941596dcd356313ad974c05967b9fe47e47b34c88583b02e2631c36b37c31e60f6
checksums.yaml.gz.sig CHANGED
Binary file
data/CHANGELOG.md CHANGED
@@ -30,6 +30,24 @@ Please file a bug if you notice a violation of semantic versioning.
30
30
 
31
31
  ### Security
32
32
 
33
+ ## [1.2.12] - 2026-07-30
34
+
35
+ - TAG: [v1.2.12][1.2.12t]
36
+ - COVERAGE: 93.90% -- 3846/4096 lines in 27 files
37
+ - BRANCH COVERAGE: 76.54% -- 1475/1927 branches in 27 files
38
+ - 27.83% documented
39
+
40
+ ### Fixed
41
+
42
+ - Publish release skip checks now use `kettle-dev`'s shared RubyGems version
43
+ cache instead of a direct `gem.coop` HTTP request, matching the cached
44
+ release-state path used by `kettle-family state`.
45
+
46
+ - Family release dependency-floor readiness now validates CI-facing direct
47
+ appraisal Gemfiles, so generated workflows such as `dep-heads.yml` cannot fail
48
+ after a just-published family dependency was only checked through release
49
+ lockfiles.
50
+
33
51
  ## [1.2.11] - 2026-07-30
34
52
 
35
53
  - TAG: [v1.2.11][1.2.11t]
@@ -1358,7 +1376,9 @@ Please file a bug if you notice a violation of semantic versioning.
1358
1376
  - Fixed CI load failures on engines without compatible `pty` support by falling back to Open3 for interactive release commands.
1359
1377
  - Fixed Ruby 3.2 version-bump support by loading Prism lazily and wiring the Prism gem only for MRI versions that need it.
1360
1378
 
1361
- [Unreleased]: https://github.com/kettle-dev/kettle-family/compare/v1.2.11...HEAD
1379
+ [Unreleased]: https://github.com/kettle-dev/kettle-family/compare/v1.2.12...HEAD
1380
+ [1.2.12]: https://github.com/kettle-dev/kettle-family/compare/v1.2.11...v1.2.12
1381
+ [1.2.12t]: https://github.com/kettle-dev/kettle-family/releases/tag/v1.2.12
1362
1382
  [1.2.11]: https://github.com/kettle-dev/kettle-family/compare/v1.2.10...v1.2.11
1363
1383
  [1.2.11t]: https://github.com/kettle-dev/kettle-family/releases/tag/v1.2.11
1364
1384
  [1.2.10]: https://github.com/kettle-dev/kettle-family/compare/v1.2.9...v1.2.10
data/README.md CHANGED
@@ -814,7 +814,7 @@ Thanks for RTFM. ☺️
814
814
  [📌gitmoji]: https://gitmoji.dev
815
815
  [📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
816
816
  [🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
817
- [🧮kloc-img]: https://img.shields.io/badge/KLOC-4.035-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
817
+ [🧮kloc-img]: https://img.shields.io/badge/KLOC-4.096-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
818
818
  [🔐security]: https://github.com/kettle-dev/kettle-family/blob/main/SECURITY.md
819
819
  [🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
820
820
  [📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
@@ -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.11"
8
+ VERSION = "1.2.12"
9
9
  end
10
10
  # Current gem version exposed at the traditional constant location.
11
11
  VERSION = Version::VERSION # Traditional Constant Location
@@ -3,13 +3,13 @@
3
3
  require "io/console"
4
4
  require "fileutils"
5
5
  require "json"
6
- require "net/http"
7
6
  require "etc"
8
7
  require "open3"
8
+ require "pathname"
9
9
  require "rbconfig"
10
10
  require "shellwords"
11
- require "uri"
12
11
  require "yaml"
12
+ require "kettle/dev/ruby_gems_versions"
13
13
 
14
14
  require_relative "workflow_progress"
15
15
 
@@ -729,6 +729,9 @@ module Kettle
729
729
  append_dependency_floor_lockfile_results(released_members: released_members, dependent_members: affected_dependent_members, runner: runner, memo: memo)
730
730
  return if memo.any? && !memo.last.ok?
731
731
 
732
+ append_dependency_floor_ci_bundle_results(released_members: released_members, dependent_members: affected_dependent_members, runner: runner, memo: memo)
733
+ return if memo.any? && !memo.last.ok?
734
+
732
735
  commit_dependency_floor_changes(dependent_members: floor_results.map(&:member_name), runner: runner, memo: memo) if floor_results.any? && execute && commit
733
736
  end
734
737
 
@@ -753,6 +756,19 @@ module Kettle
753
756
  end
754
757
  end
755
758
 
759
+ def append_dependency_floor_ci_bundle_results(released_members:, dependent_members:, runner:, memo:)
760
+ return unless execute && publish
761
+ return if dependent_members.empty?
762
+
763
+ dependent_members.each do |member|
764
+ dependency_floor_ci_bundle_gemfiles(member).each do |gemfile|
765
+ memo << wait_for_dependency_floor_ci_bundle_result(member: member, gemfile: gemfile, released_members: released_members, runner: runner)
766
+ break unless memo.last.ok?
767
+ end
768
+ break if memo.any? && !memo.last.ok?
769
+ end
770
+ end
771
+
756
772
  def wait_for_dependency_floor_lockfiles_result(member:, released_members:, runner:)
757
773
  result = nil
758
774
  REGISTRY_WAIT_ATTEMPTS.times do |index|
@@ -772,6 +788,25 @@ module Kettle
772
788
  result
773
789
  end
774
790
 
791
+ def wait_for_dependency_floor_ci_bundle_result(member:, gemfile:, released_members:, runner:)
792
+ result = nil
793
+ REGISTRY_WAIT_ATTEMPTS.times do |index|
794
+ emit_dependency_floor_ci_bundle_progress(member: member, gemfile: gemfile, attempt: index + 1)
795
+ FileUtils.mkdir_p(File.dirname(dependency_floor_ci_bundle_lockfile_path(member: member, gemfile: gemfile)))
796
+ result = runner.call(
797
+ member: member,
798
+ phase: "dependency_floor_ci_bundle",
799
+ command: dependency_floor_ci_bundle_command(released_members),
800
+ env: dependency_floor_ci_bundle_env(member: member, gemfile: gemfile)
801
+ )
802
+ annotate_dependency_floor_ci_bundle_result(result, index + 1, gemfile: gemfile)
803
+ break if result.ok?
804
+
805
+ sleep(REGISTRY_WAIT_INTERVAL_SECONDS) if index + 1 < REGISTRY_WAIT_ATTEMPTS
806
+ end
807
+ result
808
+ end
809
+
775
810
  def validate_dependency_floor_lockfile_result(result:, member:, released_members:)
776
811
  diagnostics = dependency_floor_lockfile_diagnostics(member: member, released_members: released_members)
777
812
  return if diagnostics.empty?
@@ -804,6 +839,64 @@ module Kettle
804
839
  ["bundle", "lock", "--update", *released_members.map(&:name), "--add-checksums"]
805
840
  end
806
841
 
842
+ def dependency_floor_ci_bundle_command(released_members)
843
+ ["bundle", "lock", "--update", *released_members.map(&:name), "--add-checksums"]
844
+ end
845
+
846
+ def dependency_floor_ci_bundle_env(member:, gemfile:)
847
+ release_lockfile_env(member).merge(
848
+ "BUNDLE_GEMFILE" => gemfile,
849
+ "BUNDLE_LOCKFILE" => dependency_floor_ci_bundle_lockfile_path(member: member, gemfile: gemfile)
850
+ )
851
+ end
852
+
853
+ def dependency_floor_ci_bundle_lockfile_path(member:, gemfile:)
854
+ relative = relative_path_from_member_root(member: member, path: gemfile)
855
+ safe_name = relative.gsub(%r{[^A-Za-z0-9_.-]+}, "_")
856
+ File.join(member.root, "tmp", "kettle-family", "dependency-floor-ci-bundles", "#{safe_name}.lock")
857
+ end
858
+
859
+ def dependency_floor_ci_bundle_gemfiles(member)
860
+ workflow_bundle_gemfiles(member).select do |gemfile|
861
+ File.file?(gemfile)
862
+ end.uniq.sort
863
+ end
864
+
865
+ def workflow_bundle_gemfiles(member)
866
+ Dir.glob(File.join(member.root, ".github", "workflows", "*.{yml,yaml}")).flat_map do |path|
867
+ workflow_bundle_gemfile_entries(path).map do |entry|
868
+ File.expand_path(entry, member.root)
869
+ end
870
+ end
871
+ end
872
+
873
+ def workflow_bundle_gemfile_entries(path)
874
+ data = YAML.safe_load_file(path, permitted_classes: [], permitted_symbols: [], aliases: true) || {}
875
+ recursive_values_for_key(data, "bundle_gemfile").map(&:to_s).reject(&:empty?)
876
+ rescue Psych::Exception
877
+ []
878
+ end
879
+
880
+ def recursive_values_for_key(value, key)
881
+ case value
882
+ when Hash
883
+ value.flat_map do |entry_key, entry_value|
884
+ matches = (entry_key.to_s == key) ? [entry_value] : []
885
+ matches.concat(recursive_values_for_key(entry_value, key))
886
+ end
887
+ when Array
888
+ value.flat_map { |entry| recursive_values_for_key(entry, key) }
889
+ else
890
+ []
891
+ end
892
+ end
893
+
894
+ def relative_path_from_member_root(member:, path:)
895
+ Pathname.new(path).relative_path_from(Pathname.new(member.root)).to_s
896
+ rescue ArgumentError
897
+ path.to_s
898
+ end
899
+
807
900
  def reset_gemfile_lock(member:, runner:, memo:)
808
901
  result = runner.call(
809
902
  member: member,
@@ -987,6 +1080,18 @@ module Kettle
987
1080
  end
988
1081
  end
989
1082
 
1083
+ def annotate_dependency_floor_ci_bundle_result(result, attempts, gemfile:)
1084
+ return unless result
1085
+
1086
+ relative = File.basename(gemfile)
1087
+ if result.ok?
1088
+ message = "validated CI bundle #{relative} after #{attempts} attempt(s)"
1089
+ result.stdout = [result.stdout, message].reject(&:empty?).join("\n")
1090
+ else
1091
+ result.reason = "dependency floor CI bundle validation failed for #{relative} after #{attempts} attempt(s)"
1092
+ end
1093
+ end
1094
+
990
1095
  def commit_dependency_floor_changes(dependent_members:, runner:, memo:)
991
1096
  by_name = members.to_h { |member| [member.name, member] }
992
1097
  dependent_members.each do |member_name|
@@ -1283,19 +1388,25 @@ module Kettle
1283
1388
  end
1284
1389
 
1285
1390
  def released_version?(gem_name, version)
1286
- uri = URI("https://gem.coop/api/v1/versions/#{gem_name}.json")
1287
- response = Net::HTTP.get_response(uri)
1288
- raise Error, "could not check published versions for #{gem_name}: HTTP #{response.code}" unless response.is_a?(Net::HTTPSuccess)
1391
+ data = Kettle::Dev::RubyGemsVersions.fetch(gem_name, version_hint: version)
1392
+ raise Error, "could not check published versions for #{gem_name}" unless data.is_a?(Array)
1289
1393
 
1290
- JSON.parse(response.body).any? { |entry| entry["number"].to_s == version.to_s }
1394
+ data.any? { |entry| entry["number"].to_s == version.to_s }
1291
1395
  rescue JSON::ParserError => error
1292
1396
  raise Error, "could not parse published versions for #{gem_name}: #{error.message}"
1397
+ rescue => error
1398
+ raise Error, "could not check published versions for #{gem_name}: #{error.message}"
1293
1399
  end
1294
1400
 
1295
1401
  def emit_dependency_floor_lockfile_progress(member:, attempt:)
1296
1402
  @release_progress&.update(member, status: "lockfiles #{attempt}/#{REGISTRY_WAIT_ATTEMPTS}", mark: ">")
1297
1403
  end
1298
1404
 
1405
+ def emit_dependency_floor_ci_bundle_progress(member:, gemfile:, attempt:)
1406
+ relative = relative_path_from_member_root(member: member, path: gemfile)
1407
+ @release_progress&.update(member, status: "ci bundle #{relative} #{attempt}/#{REGISTRY_WAIT_ATTEMPTS}", mark: ">")
1408
+ end
1409
+
1299
1410
  def already_released_result(member)
1300
1411
  tag = release_tag_name(member.version)
1301
1412
  current_release_head = released_version_current_head?(member, tag)
@@ -2140,10 +2251,18 @@ module Kettle
2140
2251
 
2141
2252
  def release_lockfile_env(member = nil)
2142
2253
  base_release_env
2254
+ .merge(release_lockfile_bundler_env_resets)
2143
2255
  .merge(env_overrides)
2144
2256
  .merge(release_lockfile_local_path_env_overrides(member))
2145
2257
  end
2146
2258
 
2259
+ def release_lockfile_bundler_env_resets
2260
+ {
2261
+ "BUNDLE_GEMFILE" => nil,
2262
+ "BUNDLE_LOCKFILE" => nil
2263
+ }
2264
+ end
2265
+
2147
2266
  def release_allowed_local_path_roots
2148
2267
  release_local_path_env_sources.filter_map do |key, value|
2149
2268
  next unless key.end_with?("_LOCAL", "_DEV")
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.11
4
+ version: 1.2.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter H. Boling
@@ -74,7 +74,7 @@ dependencies:
74
74
  version: '2.3'
75
75
  - - ">="
76
76
  - !ruby/object:Gem::Version
77
- version: 2.5.8
77
+ version: 2.5.11
78
78
  type: :runtime
79
79
  prerelease: false
80
80
  version_requirements: !ruby/object:Gem::Requirement
@@ -84,7 +84,7 @@ dependencies:
84
84
  version: '2.3'
85
85
  - - ">="
86
86
  - !ruby/object:Gem::Version
87
- version: 2.5.8
87
+ version: 2.5.11
88
88
  - !ruby/object:Gem::Dependency
89
89
  name: kettle-test
90
90
  requirement: !ruby/object:Gem::Requirement
@@ -341,10 +341,10 @@ licenses:
341
341
  - AGPL-3.0-only
342
342
  metadata:
343
343
  homepage_uri: https://kettle-family.galtzo.com
344
- source_code_uri: https://github.com/kettle-dev/kettle-family/tree/v1.2.11
345
- changelog_uri: https://github.com/kettle-dev/kettle-family/blob/v1.2.11/CHANGELOG.md
344
+ source_code_uri: https://github.com/kettle-dev/kettle-family/tree/v1.2.12
345
+ changelog_uri: https://github.com/kettle-dev/kettle-family/blob/v1.2.12/CHANGELOG.md
346
346
  bug_tracker_uri: https://github.com/kettle-dev/kettle-family/issues
347
- documentation_uri: https://www.rubydoc.info/gems/kettle-family/1.2.11
347
+ documentation_uri: https://www.rubydoc.info/gems/kettle-family/1.2.12
348
348
  funding_uri: https://github.com/sponsors/pboling
349
349
  wiki_uri: https://github.com/kettle-dev/kettle-family/wiki
350
350
  news_uri: https://www.railsbling.com/tags/kettle-family
metadata.gz.sig CHANGED
Binary file