kettle-dev 3.0.23 → 3.0.24

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: b985d06999d067d64979c99918110a0203d706c53392e498ab667126e9388d68
4
- data.tar.gz: 73b20adeb029d70f67152d6ae8ee4377629c846c851ac1a6c484fc2ff6add583
3
+ metadata.gz: d210f4626dc19b866996b80ae87c61627e94a7b5c5844262f7b6178fbbacf056
4
+ data.tar.gz: d4d1775405e309dc934d5258cb9ca9fc0503047188f19c5c04e0e878e172216c
5
5
  SHA512:
6
- metadata.gz: 4af9b35a01651eb7eab623ea2f7d1a2829fee953467fd92f3fe27886333dc417397ddb430485b74dc1413d2aeb5553d840636fef9cab83425f32eaccd283ce99
7
- data.tar.gz: 8d73396e1a95de0eac8a19ec6625830779505144d9dc7bb4852de362e9f3f83bcbc2190b221b971687459e6b7e2b2a3aa7c6453b71e87479a4b14d5ec805d2e1
6
+ metadata.gz: bc3c91ff5678b13f405174b3400aa45cd6d1536e844ec4180762d44455b30e7fc72bd0ca0fcf6d1c07c911ab9a2c02e7593da9b71126efa7f1d4b1f5977fbeb2
7
+ data.tar.gz: f725c2f04abcc0b1c3127d9bc86dac6e853aabdcd85a026819fc18dee8246f2ab614d4089588aeb89bca8713c2f589cde03394e0939d806fc5d897ae4335fd18
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
+ ## [3.0.24] - 2026-08-31
34
+
35
+ - TAG: [v3.0.24][3.0.24t]
36
+ - COVERAGE: 91.38% -- 5934/6494 lines in 47 files
37
+ - BRANCH COVERAGE: 75.98% -- 2271/2989 branches in 47 files
38
+ - 50.47% documented
39
+
40
+ ### Fixed
41
+
42
+ - Keep Gemfile bootstrap dependencies available while resetting explicitly allowed monorepo release lockfiles.
43
+
44
+ - Keep installed Gemfile bootstrap dependencies available for every release lockfile reset.
45
+
46
+ - Emit explicit logical release resume-step metadata instead of relying on command-event ordering.
47
+
33
48
  ## [3.0.23] - 2026-08-30
34
49
 
35
50
  - TAG: [v3.0.23][3.0.23t]
@@ -3710,7 +3725,9 @@ Please file a bug if you notice a violation of semantic versioning.
3710
3725
  - Selecting will run the selected workflow via `act`
3711
3726
  - This may move to its own gem in the future.
3712
3727
 
3713
- [Unreleased]: https://github.com/kettle-dev/kettle-dev/compare/v3.0.23...HEAD
3728
+ [Unreleased]: https://github.com/kettle-dev/kettle-dev/compare/v3.0.24...HEAD
3729
+ [3.0.24]: https://github.com/kettle-dev/kettle-dev/compare/v3.0.23...v3.0.24
3730
+ [3.0.24t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v3.0.24
3714
3731
  [3.0.23]: https://github.com/kettle-dev/kettle-dev/compare/v3.0.22...v3.0.23
3715
3732
  [3.0.23t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v3.0.23
3716
3733
  [3.0.22]: https://github.com/kettle-dev/kettle-dev/compare/v3.0.21...v3.0.22
data/README.md CHANGED
@@ -467,6 +467,14 @@ What it does:
467
467
  variables, known local-template toggles, and writes checksums while
468
468
  updating path-sourced and checksum-gap gems back to released registry
469
469
  versions.
470
+ - Gemfile bootstrap dependencies are separate from dependency resolution.
471
+ A generated Gemfile can require `nomono/bundler` while it is being
472
+ evaluated, before Bundler has resolved its declared `nomono` gem.
473
+ `kettle-reset` detects that literal bootstrap require and installs the
474
+ locked registry version of `nomono` into its temporary `GEM_HOME` before
475
+ invoking Bundler. Its `GEM_PATH` contains only that reset sandbox: no
476
+ unrelated gems installed for the invoking Ruby can affect lockfile
477
+ resolution.
470
478
  - Release lockfile resets normally keep the complete development Gemfile
471
479
  graph, including the development-only `kettle-changelog` dependency.
472
480
  `kettle-changelog` depends on `kettle-dev`, so including it in
@@ -510,7 +518,7 @@ What it does:
510
518
  | Role | Lockfile | Used by |
511
519
  | --- | --- | --- |
512
520
  | Family runner | The family/orchestrator bundle | May resolve local sibling gems to run `kettle-family`; it never becomes the target project's lockfile. |
513
- | Canonical release state | Tracked `Gemfile.lock` and, when present, `Appraisal.root.gemfile.lock` | Step 1 Bundler update, steps 3-6 setup/checks/appraisals/docs/prep commit, and step 16 checksums. These commands disable local `*_DEV`/`*_LOCAL` switches, except a narrow member-root policy supplied by `kettle-family` for an explicit monorepo. |
521
+ | Canonical release state | Tracked `Gemfile.lock` and, when present, `Appraisal.root.gemfile.lock` | Step 1 Bundler update, steps 3-6 setup/checks/appraisals/docs/prep commit, and step 16 checksums. These commands disable local `*_DEV`/`*_LOCAL` switches, except an explicitly allowed monorepo member-root policy supplied by `kettle-family`. Reset `GEM_HOME` and `GEM_PATH` are isolated; direct Gemfile bootstrap requirements are installed from their locked registry source into that sandbox before Bundler evaluates the Gemfile. |
514
522
  | Release task state | `tmp/kettle-release/lockfiles/Gemfile-<pid>.lock` | Steps 14-15 build and publish only. It begins as a copy of canonical `Gemfile.lock` and is deleted at process exit. |
515
523
  | Tool state | A tool-owned Gemfile such as `kettle-changelog/gemfiles/release.gemfile` | The tool's own dependencies. The command still disables local dependency switches before it can trigger target-project work. |
516
524
  | Git-hook state | Canonical release environment | Every release-created commit and amend. Hooks remain enabled, but cannot inherit the family runner's local sibling graph. |
@@ -1058,7 +1066,7 @@ Thanks for RTFM. ☺️
1058
1066
  [📌gitmoji]: https://gitmoji.dev
1059
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
1060
1068
  [🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
1061
- [🧮kloc-img]: https://img.shields.io/badge/KLOC-6.438-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
1069
+ [🧮kloc-img]: https://img.shields.io/badge/KLOC-6.494-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
1062
1070
  [🔐security]: https://github.com/kettle-dev/kettle-dev/blob/main/SECURITY.md
1063
1071
  [🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
1064
1072
  [📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
@@ -6,6 +6,7 @@ require "fileutils"
6
6
  require "open3"
7
7
  require "tmpdir"
8
8
  require "bundler"
9
+ require "ripper"
9
10
 
10
11
  require_relative "bundler_env_guard"
11
12
 
@@ -162,6 +163,7 @@ module Kettle
162
163
  end
163
164
 
164
165
  with_isolated_gem_paths do |gem_home|
166
+ install_gemfile_bootstrap_gems!(gemfile: gemfile, lockfile: path, gem_home: gem_home)
165
167
  command = reset_command(
166
168
  path: path,
167
169
  gemfile: gemfile,
@@ -179,7 +181,7 @@ module Kettle
179
181
  end
180
182
  end
181
183
 
182
- def reset_command(path:, gemfile:, full_update: false, platforms: nil, skip_changelog_dependency: false, update_bundler: false, isolated_gem_home: nil)
184
+ def reset_command(path:, gemfile:, full_update: false, platforms: nil, skip_changelog_dependency: false, update_bundler: false, isolated_gem_home: nil, isolated_gem_path: nil)
183
185
  update_gems = (full_update || has_local_path_remote?(path)) ? [] : reset_update_gems(path)
184
186
  platforms ||= reset_platforms(path)
185
187
  removed_platforms = full_update ? [] : lockfile_platforms(path) - platforms
@@ -190,7 +192,7 @@ module Kettle
190
192
  env["KETTLE_DEV_SKIP_CHANGELOG_DEPENDENCY"] = "true" if skip_changelog_dependency
191
193
  if isolated_gem_home
192
194
  env["GEM_HOME"] = isolated_gem_home
193
- env["GEM_PATH"] = isolated_gem_home
195
+ env["GEM_PATH"] = isolated_gem_path || isolated_gem_home
194
196
  end
195
197
  command = +"env"
196
198
  UNBUNDLED_ENV_KEYS.each do |key|
@@ -469,7 +471,83 @@ module Kettle
469
471
  def with_isolated_gem_paths
470
472
  base = File.join(root, "tmp", "kettle-reset")
471
473
  FileUtils.mkdir_p(base)
472
- Dir.mktmpdir("gem-home-", base) { |gem_home| yield(gem_home) }
474
+ Dir.mktmpdir("gem-home-", base) do |gem_home|
475
+ yield(gem_home)
476
+ end
477
+ end
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.
482
+ def install_gemfile_bootstrap_gems!(gemfile:, lockfile:, gem_home:)
483
+ gemfile_bootstrap_gem_names(gemfile).each do |name|
484
+ version = locked_registry_gem_version(lockfile, name)
485
+ source_url = registry_source_urls(lockfile).first
486
+ unless version && source_url
487
+ raise Error, "Cannot isolate Gemfile bootstrap #{name.inspect}: #{display_path(lockfile)} does not lock it from a registry source"
488
+ end
489
+
490
+ command_runner.call(bootstrap_gem_install_command(name, version, source_url, gem_home))
491
+ end
492
+ end
493
+
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
497
+ end
498
+
499
+ def require_calls_from_ripper(node, calls = [])
500
+ return calls unless node.is_a?(Array)
501
+
502
+ case node.first
503
+ when :command
504
+ calls << [node.dig(1, 1), string_literal_value(node[2])]
505
+ when :method_add_arg
506
+ calls << [node.dig(1, 1, 1), string_literal_value(node[2])]
507
+ end
508
+ node.each { |child| require_calls_from_ripper(child, calls) if child.is_a?(Array) }
509
+ calls
510
+ end
511
+
512
+ def string_literal_value(node)
513
+ return unless node.is_a?(Array)
514
+
515
+ parts = []
516
+ collect_string_content(node, parts)
517
+ parts.join unless parts.empty?
518
+ end
519
+
520
+ def collect_string_content(node, parts)
521
+ return unless node.is_a?(Array)
522
+
523
+ parts << node[1] if node.first == :@tstring_content
524
+ node.each { |child| collect_string_content(child, parts) if child.is_a?(Array) }
525
+ end
526
+
527
+ def bootstrap_gem_name(method_name, argument)
528
+ return unless method_name == "require" && argument == "nomono/bundler"
529
+
530
+ "nomono"
531
+ end
532
+
533
+ def locked_registry_gem_version(lockfile, name)
534
+ lockfile_parser(lockfile).specs.find do |spec|
535
+ spec.name == name && registry_source?(spec.source)
536
+ end&.version&.to_s
537
+ end
538
+
539
+ def bootstrap_gem_install_command(name, version, source_url, gem_home)
540
+ env = unbundled_env.merge("GEM_HOME" => gem_home, "GEM_PATH" => gem_home)
541
+ command = +"env"
542
+ env.each do |key, value|
543
+ assignment = value.nil? ? " -u #{key}" : " #{key}=#{Shellwords.escape(value)}"
544
+ command << assignment
545
+ end
546
+ command << " gem install #{Shellwords.escape(name)}"
547
+ command << " -v #{Shellwords.escape("= #{version}")}"
548
+ command << " --source #{Shellwords.escape(source_url)} --clear-sources --no-document"
549
+ command << " --install-dir #{Shellwords.escape(gem_home)}"
550
+ command
473
551
  end
474
552
 
475
553
  def lockfile_parser(path)
@@ -365,24 +365,26 @@ module Kettle
365
365
  prepare_rubocop_lts_local_branch! if rubocop_lts_release_preflight_needed?
366
366
 
367
367
  # 3. bin/setup
368
- run_cmd!(release_setup_command) if run_step?(3)
368
+ with_release_resume_step(3) { run_cmd!(release_setup_command) } if run_step?(3)
369
369
  # 4. bin/rake
370
- run_cmd!(release_default_task_command) if run_step?(4)
370
+ with_release_resume_step(4) { run_cmd!(release_default_task_command) } if run_step?(4)
371
371
 
372
372
  # 5. appraisal:generate (optional) + canonical docs build
373
- if run_step?(5)
374
- appraisals_path = File.join(@root, "Appraisals")
375
- if skip_appraisals?
376
- puts "Skipping #{@appraisal_task} because --skip-appraisals was provided."
377
- elsif File.file?(appraisals_path)
378
- puts "Appraisals detected at #{Kettle::Dev.display_path(appraisals_path)}. Running: bin/rake #{@appraisal_task}"
379
- run_cmd!(release_project_command("bin/rake #{@appraisal_task}"))
380
- else
381
- puts "No Appraisals file found; skipping #{@appraisal_task}"
382
- end
373
+ with_release_resume_step(5) do
374
+ if run_step?(5)
375
+ appraisals_path = File.join(@root, "Appraisals")
376
+ if skip_appraisals?
377
+ puts "Skipping #{@appraisal_task} because --skip-appraisals was provided."
378
+ elsif File.file?(appraisals_path)
379
+ puts "Appraisals detected at #{Kettle::Dev.display_path(appraisals_path)}. Running: bin/rake #{@appraisal_task}"
380
+ run_cmd!(release_project_command("bin/rake #{@appraisal_task}"))
381
+ else
382
+ puts "No Appraisals file found; skipping #{@appraisal_task}"
383
+ end
383
384
 
384
- puts "Generating docs site via canonical task: bin/rake yard"
385
- run_cmd!(release_project_command("bin/rake yard"))
385
+ puts "Generating docs site via canonical task: bin/rake yard"
386
+ run_cmd!(release_project_command("bin/rake yard"))
387
+ end
386
388
  end
387
389
 
388
390
  # 6. git user + commit release prep
@@ -472,36 +474,40 @@ module Kettle
472
474
  end
473
475
 
474
476
  # 14. build
475
- if run_step?(14)
476
- ensure_release_secrets_ready_for_signing! if signing_enabled? && release_secrets_configured?
477
- if signing_enabled? && release_secrets_configured?
478
- puts "Running build with gem signing passphrase from configured secrets provider (#{release_secrets_provider_label})..."
479
- else
480
- puts "Running build (you may be prompted for the signing key password)..."
477
+ with_release_resume_step(14) do
478
+ if run_step?(14)
479
+ ensure_release_secrets_ready_for_signing! if signing_enabled? && release_secrets_configured?
480
+ if signing_enabled? && release_secrets_configured?
481
+ puts "Running build with gem signing passphrase from configured secrets provider (#{release_secrets_provider_label})..."
482
+ else
483
+ puts "Running build (you may be prompted for the signing key password)..."
484
+ end
485
+ run_cmd!(release_project_command("bundle exec rake build"))
481
486
  end
482
- run_cmd!(release_project_command("bundle exec rake build"))
483
487
  end
484
488
 
485
489
  # 15. release and tag
486
- if run_step?(15)
487
- version ||= detect_version
488
- gem_name = detect_gem_name
489
- @release_candidate = build_release_candidate(gem_name, version)
490
- if local_ci?
491
- with_unpublished_candidate_cleanup { release_gem_and_tag_locally!(version) }
492
- else
493
- ensure_release_secrets_ready_for_signing! if signing_enabled? && release_secrets_configured?
494
- if release_secrets_configured?
495
- puts "Running release with configured secrets provider (#{release_secrets_provider_label}) for signing and RubyGems MFA prompts..."
490
+ with_release_resume_step(15) do
491
+ if run_step?(15)
492
+ version ||= detect_version
493
+ gem_name = detect_gem_name
494
+ @release_candidate = build_release_candidate(gem_name, version)
495
+ if local_ci?
496
+ with_unpublished_candidate_cleanup { release_gem_and_tag_locally!(version) }
496
497
  else
497
- puts "Running release (you may be prompted for signing key password and RubyGems MFA OTP)..."
498
- end
499
- with_unpublished_candidate_cleanup do
500
- run_cmd!(release_project_command("bundle exec rake release"))
501
- @release_candidate.published = true
502
- confirm_release_candidate_available!(@release_candidate)
498
+ ensure_release_secrets_ready_for_signing! if signing_enabled? && release_secrets_configured?
499
+ if release_secrets_configured?
500
+ puts "Running release with configured secrets provider (#{release_secrets_provider_label}) for signing and RubyGems MFA prompts..."
501
+ else
502
+ puts "Running release (you may be prompted for signing key password and RubyGems MFA OTP)..."
503
+ end
504
+ with_unpublished_candidate_cleanup do
505
+ run_cmd!(release_project_command("bundle exec rake release"))
506
+ @release_candidate.published = true
507
+ confirm_release_candidate_available!(@release_candidate)
508
+ end
509
+ mark_rubygems_release_cache_bust(version)
503
510
  end
504
- mark_rubygems_release_cache_bust(version)
505
511
  end
506
512
  end
507
513
 
@@ -509,12 +515,14 @@ module Kettle
509
515
  # Checksums are generated after release to avoid including checksums/ in gem package
510
516
  # Rationale: Running gem_checksums before release may commit checksums/ and cause Bundler's
511
517
  # release build to include them in the gem, thus altering the artifact, and invalidating the checksums.
512
- if run_step?(16)
513
- # Generate checksums for the just-built artifact, commit them, then validate
514
- version ||= detect_version
515
- gem_path = checksum_gem_path_for_version!(version)
516
- run_cmd!(release_child_command("bin/gem_checksums #{Shellwords.escape(gem_path)}"))
517
- validate_checksums!(version, stage: "after release")
518
+ with_release_resume_step(16) do
519
+ if run_step?(16)
520
+ # Generate checksums for the just-built artifact, commit them, then validate
521
+ version ||= detect_version
522
+ gem_path = checksum_gem_path_for_version!(version)
523
+ run_cmd!(release_child_command("bin/gem_checksums #{Shellwords.escape(gem_path)}"))
524
+ validate_checksums!(version, stage: "after release")
525
+ end
518
526
  end
519
527
 
520
528
  # 17. push checksum commit (gem_checksums already commits)
@@ -1429,20 +1437,20 @@ module Kettle
1429
1437
  abort("GitHub pull request setup failed: gh CLI is required to create or find the release PR.")
1430
1438
  end
1431
1439
 
1432
- def run_cmd!(cmd)
1440
+ def run_cmd!(cmd, resume_step: @release_resume_step)
1433
1441
  cmd = bundle_audit_skip_command(cmd)
1434
- emit_command_event(cmd, "started")
1442
+ emit_command_event(cmd, "started", resume_step: resume_step)
1435
1443
  with_bundle_audit_skip_env do
1436
1444
  with_machine_stdout_redirect do
1437
1445
  run_command_with_release_secrets!(cmd)
1438
1446
  end
1439
1447
  end
1440
- emit_command_event(cmd, "ok")
1448
+ emit_command_event(cmd, "ok", resume_step: resume_step)
1441
1449
  rescue SystemExit => e
1442
- emit_command_event(cmd, "failed", reason: e.message)
1450
+ emit_command_event(cmd, "failed", reason: e.message, resume_step: resume_step)
1443
1451
  raise
1444
1452
  rescue => e
1445
- emit_command_event(cmd, "failed", reason: "#{e.class}: #{e.message}")
1453
+ emit_command_event(cmd, "failed", reason: "#{e.class}: #{e.message}", resume_step: resume_step)
1446
1454
  raise
1447
1455
  end
1448
1456
 
@@ -1454,6 +1462,14 @@ module Kettle
1454
1462
  "KETTLE_DEV_SKIP_BUNDLE_AUDIT=true #{cmd}"
1455
1463
  end
1456
1464
 
1465
+ def with_release_resume_step(step)
1466
+ previous_step = @release_resume_step
1467
+ @release_resume_step = step
1468
+ yield
1469
+ ensure
1470
+ @release_resume_step = previous_step
1471
+ end
1472
+
1457
1473
  def run_command_with_release_secrets!(cmd)
1458
1474
  return self.class.run_cmd!(cmd) unless release_secret_command?(cmd) && release_secrets_configured?
1459
1475
 
@@ -2124,7 +2140,7 @@ module Kettle
2124
2140
  )
2125
2141
  end
2126
2142
 
2127
- def emit_command_event(command, status, reason: nil)
2143
+ def emit_command_event(command, status, reason: nil, resume_step: nil)
2128
2144
  event = {
2129
2145
  phase: "release",
2130
2146
  index: @command_events.length + 1,
@@ -2135,6 +2151,7 @@ module Kettle
2135
2151
  command: command,
2136
2152
  changed_files: []
2137
2153
  }
2154
+ event[:resume_step] = resume_step if resume_step
2138
2155
  @command_events << event unless status == "started"
2139
2156
  Kettle::Ndjson.emit_step_event(@event_recorder, "command_step", event, phase: "release", index: event[:index])
2140
2157
  end
@@ -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.23"
8
+ VERSION = "3.0.24"
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.23
4
+ version: 3.0.24
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter H. Boling
@@ -80,7 +80,7 @@ dependencies:
80
80
  version: '0.1'
81
81
  - - ">="
82
82
  - !ruby/object:Gem::Version
83
- version: 0.1.13
83
+ version: 0.1.14
84
84
  type: :runtime
85
85
  prerelease: false
86
86
  version_requirements: !ruby/object:Gem::Requirement
@@ -90,7 +90,7 @@ dependencies:
90
90
  version: '0.1'
91
91
  - - ">="
92
92
  - !ruby/object:Gem::Version
93
- version: 0.1.13
93
+ version: 0.1.14
94
94
  - !ruby/object:Gem::Dependency
95
95
  name: kettle-rb
96
96
  requirement: !ruby/object:Gem::Requirement
@@ -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.23
404
- changelog_uri: https://github.com/kettle-dev/kettle-dev/blob/v3.0.23/CHANGELOG.md
403
+ source_code_uri: https://github.com/kettle-dev/kettle-dev/tree/v3.0.24
404
+ changelog_uri: https://github.com/kettle-dev/kettle-dev/blob/v3.0.24/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.23
406
+ documentation_uri: https://www.rubydoc.info/gems/kettle-dev/3.0.24
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