kettle-dev 3.0.15 → 3.0.17

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: a56a00d70fc1cd4ddea4cd5ed4c5eb1eae1b74789430acfa0d21a2c3baad0f92
4
- data.tar.gz: 1ff16f0d28c5f12cd182d1539e09c4af04cf19e2971f47124d9581f182c45460
3
+ metadata.gz: f66f871d88afeaa31ae017c4160572849be5c60b352b956d03392e87c513b4b9
4
+ data.tar.gz: bf62e022d4fbfa4b5aaa30c90d5468c0c931ea815819f3f966958efcf2c4831e
5
5
  SHA512:
6
- metadata.gz: ccfa73d99e87b3a0d21af3d0224b84a9d9a39cbb739f58ddc57de095f4fdf4e8232656d10869f26d5125acd111a42813ce2ab7e9cb8200dac693ad1865365124
7
- data.tar.gz: d8438b12b9e9bd77dc5fb45c9e0cbbdbb31aeeb3cb611511671265525c36b755664ca45350eae8967c4209fdd797463021b69ee4c6d2bbb5efe8db6e250ada34
6
+ metadata.gz: 7c886d799dc0a7f3fb65c065e638b478bc4a81653028c57e5cf59aed0e92098065c85c14147b061f29f9177ea56523803ad87586f20fabb62bba5efdddf83332
7
+ data.tar.gz: cf5748d69de40fa374e3ec36b7a79cf4315ae29b61104c9f1a6b44ff4d4df08baf9ff16be06ffead8ac806b46cc9881cdae6b2f6d03ca1d5d6b47485edf0f994
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.17] - 2026-08-29
34
+
35
+ - TAG: [v3.0.17][3.0.17t]
36
+ - COVERAGE: 91.48% -- 5839/6383 lines in 47 files
37
+ - BRANCH COVERAGE: 76.16% -- 2240/2941 branches in 47 files
38
+ - 50.97% documented
39
+
40
+ ### Fixed
41
+
42
+ - Stage Bundler update lockfiles correctly when releasing a monorepo subgem.
43
+
44
+ - Bound RubyGems version lookups so release reconciliation cannot wait indefinitely on a live registry request.
45
+
46
+ - Keep release child commands and commit hooks on the canonical registry-backed lockfile environment.
47
+
48
+ ## [3.0.16] - 2026-08-28
49
+
50
+ - TAG: [v3.0.16][3.0.16t]
51
+ - COVERAGE: 91.20% -- 5807/6367 lines in 47 files
52
+ - BRANCH COVERAGE: 75.93% -- 2227/2933 branches in 47 files
53
+ - 51.10% documented
54
+
55
+ ### Fixed
56
+
57
+ - Retry release lockfile resets while newly published workspace gems propagate to the configured source.
58
+
33
59
  ## [3.0.15] - 2026-08-28
34
60
 
35
61
  - TAG: [v3.0.15][3.0.15t]
@@ -3608,7 +3634,11 @@ Please file a bug if you notice a violation of semantic versioning.
3608
3634
  - Selecting will run the selected workflow via `act`
3609
3635
  - This may move to its own gem in the future.
3610
3636
 
3611
- [Unreleased]: https://github.com/kettle-dev/kettle-dev/compare/v3.0.15...HEAD
3637
+ [Unreleased]: https://github.com/kettle-dev/kettle-dev/compare/v3.0.17...HEAD
3638
+ [3.0.17]: https://github.com/kettle-dev/kettle-dev/compare/v3.0.16...v3.0.17
3639
+ [3.0.17t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v3.0.17
3640
+ [3.0.16]: https://github.com/kettle-dev/kettle-dev/compare/v3.0.15...v3.0.16
3641
+ [3.0.16t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v3.0.16
3612
3642
  [3.0.15]: https://github.com/kettle-dev/kettle-dev/compare/v3.0.14...v3.0.15
3613
3643
  [3.0.15t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v3.0.15
3614
3644
  [3.0.14]: https://github.com/kettle-dev/kettle-dev/compare/v3.0.13...v3.0.14
data/README.md CHANGED
@@ -503,6 +503,21 @@ What it does:
503
503
  removed when the release process exits. `BUNDLE_FROZEN=true` is not a
504
504
  substitute because it converts the same reconciliation into a failure
505
505
  when Bundler needs to write its resolved lockfile.
506
+ - Lockfile roles are explicit during a release:
507
+
508
+ | Role | Lockfile | Used by |
509
+ | --- | --- | --- |
510
+ | Family runner | The family/orchestrator bundle | May resolve local sibling gems to run `kettle-family`; it never becomes the target project's lockfile. |
511
+ | 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. |
512
+ | 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. |
513
+ | 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. |
514
+ | 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. |
515
+
516
+ A command must select one of these roles. Do not construct an ad hoc
517
+ `BUNDLE_GEMFILE`, `BUNDLE_LOCKFILE`, or local-development environment in
518
+ a release phase. `ReleaseCLI#release_child_command` owns canonical/tool
519
+ command construction; `ReleaseCLI#release_project_command` selects the
520
+ disposable task lock only for build and publish.
506
521
  - Tips:
507
522
  - The commit message helper `exe/kettle-commit-msg` prefers project-local `.git-hooks` (then falls back to `~/.git-hooks`).
508
523
  - The goalie file `commit-subjects-goalie.txt` controls when a footer is appended; customize `footer-template.erb.txt` as you like.
@@ -1033,7 +1048,7 @@ Thanks for RTFM. ☺️
1033
1048
  [📌gitmoji]: https://gitmoji.dev
1034
1049
  [📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
1035
1050
  [🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
1036
- [🧮kloc-img]: https://img.shields.io/badge/KLOC-6.361-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
1051
+ [🧮kloc-img]: https://img.shields.io/badge/KLOC-6.383-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
1037
1052
  [🔐security]: https://github.com/kettle-dev/kettle-dev/blob/main/SECURITY.md
1038
1053
  [🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
1039
1054
  [📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
@@ -71,12 +71,28 @@ module Kettle
71
71
  false
72
72
  end
73
73
 
74
+ # Stage paths reported by Git commands such as `git diff --name-only`.
75
+ # Git reports these paths relative to the repository root, even when this
76
+ # adapter operates from a monorepo subdirectory. `:(top)` keeps the
77
+ # pathspec rooted at that repository root in either topology.
78
+ #
79
+ # @param paths [Array<String>] repository-root-relative paths
80
+ # @return [Boolean] true when Git stages every path
81
+ def add_repository_paths(paths)
82
+ pathspecs = Array(paths).map { |path| ":(top)#{path}" }
83
+ git_system("add", "--", *pathspecs)
84
+ rescue => e
85
+ Kettle::Dev.debug_error(e, __method__)
86
+ false
87
+ end
88
+
74
89
  # Commit all staged/tracked changes with a message.
75
90
  #
76
91
  # @param message [String]
92
+ # @param env [Hash{String => String, nil}] environment overrides for Git hooks
77
93
  # @return [Boolean]
78
- def commit_all(message)
79
- git_system("commit", "-am", message.to_s)
94
+ def commit_all(message, env: {})
95
+ git_system("commit", "-am", message.to_s, env: env)
80
96
  rescue => e
81
97
  Kettle::Dev.debug_error(e, __method__)
82
98
  false
@@ -89,9 +105,10 @@ module Kettle
89
105
  # atomic commit.
90
106
  #
91
107
  # @param message [String]
108
+ # @param env [Hash{String => String, nil}] environment overrides for Git hooks
92
109
  # @return [Boolean]
93
- def commit_staged(message)
94
- git_system("commit", "-m", message.to_s)
110
+ def commit_staged(message, env: {})
111
+ git_system("commit", "-m", message.to_s, env: env)
95
112
  rescue => e
96
113
  Kettle::Dev.debug_error(e, __method__)
97
114
  false
@@ -99,9 +116,10 @@ module Kettle
99
116
 
100
117
  # Amend the current commit without changing its message.
101
118
  #
119
+ # @param env [Hash{String => String, nil}] environment overrides for Git hooks
102
120
  # @return [Boolean]
103
- def commit_amend_no_edit
104
- git_system("commit", "--amend", "--no-edit")
121
+ def commit_amend_no_edit(env: {})
122
+ git_system("commit", "--amend", "--no-edit", env: env)
105
123
  rescue => e
106
124
  Kettle::Dev.debug_error(e, __method__)
107
125
  false
@@ -406,11 +424,15 @@ module Kettle
406
424
  end
407
425
  end
408
426
 
409
- def git_system(*args)
427
+ def git_system(*args, env: {})
428
+ command = ["git", *args]
429
+ return system(*command) if env.empty? && @root == Dir.pwd
430
+ return system(*command, chdir: @root) if env.empty?
431
+
410
432
  if @root == Dir.pwd
411
- system("git", *args)
433
+ system(env, *command)
412
434
  else
413
- system("git", *args, chdir: @root)
435
+ system(env, *command, chdir: @root)
414
436
  end
415
437
  end
416
438
  end
@@ -506,7 +506,7 @@ module Kettle
506
506
  # Generate checksums for the just-built artifact, commit them, then validate
507
507
  version ||= detect_version
508
508
  gem_path = checksum_gem_path_for_version!(version)
509
- run_cmd!("bin/gem_checksums #{Shellwords.escape(gem_path)}")
509
+ run_cmd!(release_child_command("bin/gem_checksums #{Shellwords.escape(gem_path)}"))
510
510
  validate_checksums!(version, stage: "after release")
511
511
  end
512
512
 
@@ -702,17 +702,24 @@ module Kettle
702
702
  rescue Kettle::Dev::Error => error
703
703
  raise unless error.message.start_with?("Reset #{Kettle::Dev::LockfileReset::RELEASE_LOCKFILES_TARGET} failed validation:")
704
704
 
705
- # Keep release-facing failures shaped like the lockfile validation
706
- # guard, even when the shared reset helper is the component that
707
- # detects the unrepaired lockfile.
705
+ retryable = retryable_release_lockfile_reset_error?(error) && attempt < attempts
708
706
  emit_release_lockfile_event(
709
707
  action: "reset",
710
- status: "blocked",
708
+ status: retryable ? "retrying" : "blocked",
711
709
  stage: stage,
712
710
  attempt: attempt,
713
711
  attempts: attempts,
714
712
  reason: error.message
715
713
  )
714
+ if retryable
715
+ puts "Release lockfile reset could not resolve a newly published workspace gem from #{RELEASE_VALIDATION_SOURCE}; waiting before retry #{attempt + 1}/#{attempts}."
716
+ sleep(release_availability_probe_interval)
717
+ next
718
+ end
719
+
720
+ # Keep non-transient release-facing failures shaped like the
721
+ # lockfile validation guard, even when the shared reset helper
722
+ # detects the unrepaired lockfile.
716
723
  break
717
724
  rescue => error
718
725
  retryable = retryable_release_lockfile_reset_error?(error) && attempt < attempts
@@ -755,7 +762,9 @@ module Kettle
755
762
  message = error.message.to_s
756
763
  message.include?("Bundler::GemNotFound") ||
757
764
  message.include?("Could not find gem") ||
758
- message.include?("can no longer be found in that source")
765
+ message.include?("can no longer be found in that source") ||
766
+ message.include?("locks local workspace gem") &&
767
+ message.include?("not resolvable from the configured gem source")
759
768
  end
760
769
 
761
770
  def validate_release_lockfiles!(stage:)
@@ -793,6 +802,20 @@ module Kettle
793
802
  lockfile_reset.normalization_env
794
803
  end
795
804
 
805
+ # The release process has three distinct lockfile roles:
806
+ #
807
+ # - canonical: tracked project lockfiles, always registry-backed;
808
+ # - task: a disposable Gemfile.lock copy for build and publication; and
809
+ # - tool: a tool-owned Gemfile, such as kettle-changelog's release bundle.
810
+ #
811
+ # A family may use local sibling gems to launch this process, but no
812
+ # release child may inherit that graph. Git hooks are release children
813
+ # too: they commonly load project tooling and otherwise can silently
814
+ # rewrite the canonical lockfile with local PATH sources.
815
+ def release_git_hook_environment
816
+ release_child_environment
817
+ end
818
+
796
819
  def release_lockfile_diagnostics(path)
797
820
  lockfile_reset.diagnostics(path)
798
821
  end
@@ -860,7 +883,7 @@ module Kettle
860
883
 
861
884
  puts "Fallback release lockfile reset result: diagnostics cleared; amending release prep commit with #{paths.length} lockfile(s)."
862
885
  abort("Failed to stage reset release lockfiles.") unless @git.add_paths(paths)
863
- abort("Failed to amend release prep commit with reset lockfiles.") unless @git.commit_amend_no_edit
886
+ abort("Failed to amend release prep commit with reset lockfiles.") unless @git.commit_amend_no_edit(env: release_git_hook_environment)
864
887
  end
865
888
 
866
889
  def changed_release_lockfile_paths
@@ -901,18 +924,13 @@ module Kettle
901
924
  # of relying on an ambient installed executable.
902
925
  def release_changelog_command
903
926
  gemfile = release_changelog_gemfile
904
- return "bundle exec kettle-changelog" unless gemfile
927
+ return release_child_command("bundle exec kettle-changelog") unless gemfile
905
928
 
906
- escaped_gemfile = Shellwords.escape(gemfile)
907
- command = +"env -u BUNDLE_GEMFILE -u BUNDLE_LOCKFILE"
929
+ environment = {"BUNDLE_GEMFILE" => gemfile}
908
930
  if (local_root = release_changelog_local_root)
909
- # Changelog coverage runs before the release lockfile reset. Keep it
910
- # on the registry-backed release graph instead of reintroducing local
911
- # sibling paths through the inherited templating switch.
912
- command << " KETTLE_DEV_DEV=false K_JEM_TEMPLATING=false KETTLE_CHANGELOG_DEV_ROOT=#{Shellwords.escape(local_root)}"
931
+ environment["KETTLE_CHANGELOG_DEV_ROOT"] = local_root
913
932
  end
914
- command << " BUNDLE_GEMFILE=#{escaped_gemfile} bundle exec kettle-changelog"
915
- command
933
+ release_child_command("bundle exec kettle-changelog", environment: environment)
916
934
  end
917
935
 
918
936
  def release_changelog_gemfile
@@ -972,29 +990,44 @@ module Kettle
972
990
  release_project_command("bin/setup")
973
991
  end
974
992
 
975
- # Every command that loads the project bundle must run outside the
976
- # release tool's bundle and with local workspace dependency switches
977
- # disabled. The default task may carry a leading environment assignment,
978
- # so relying on BundlerEnvGuard's command classification alone is not
979
- # sufficient.
993
+ # Canonical release commands use the tracked project lockfiles. These
994
+ # lockfiles are shared state and are normalized/committed before release
995
+ # prep; they must never contain sibling PATH sources.
980
996
  def release_project_command(command)
981
- project_command = command
982
- unbundled_keys = (BundlerEnvGuard::RESET_ENV_KEYS + %w[RUBYLIB RUBYOPT]).uniq
983
- command = +"env #{unbundled_keys.map { |key| "-u #{Shellwords.escape(key)}" }.join(" ")}"
984
- release_lockfile_normalization_env.each do |key, value|
985
- command << " #{key}=#{Shellwords.escape(value)}"
997
+ release_child_command(command, lockfile: release_task_command?(command) ? release_task_lockfile_path : nil)
998
+ end
999
+
1000
+ def release_task_command?(command)
1001
+ ["bundle exec rake build", "bundle exec rake release"].include?(command.to_s.strip)
1002
+ end
1003
+
1004
+ # Every release child runs outside the release tool's Bundler context and
1005
+ # with local sibling switches disabled. The optional lockfile identifies
1006
+ # a disposable task lockfile; omitting it deliberately selects the
1007
+ # canonical tracked lockfile for setup, checks, docs, and checksums.
1008
+ def release_child_command(command, environment: {}, lockfile: nil)
1009
+ command_body = command
1010
+ command = +"env"
1011
+ release_child_environment.each do |key, value|
1012
+ command << " -u #{Shellwords.escape(key)}" if value.nil?
986
1013
  end
987
- if release_task_command?(project_command)
988
- if (lockfile = release_task_lockfile_path)
989
- command << " BUNDLE_LOCKFILE=#{Shellwords.escape(lockfile)}"
990
- end
1014
+ release_child_environment.each do |key, value|
1015
+ command << " #{key}=#{Shellwords.escape(value)}" unless value.nil?
991
1016
  end
992
- command << " #{project_command}"
1017
+ environment.each do |key, value|
1018
+ command << " #{key}=#{Shellwords.escape(value)}"
1019
+ end
1020
+ command << " BUNDLE_LOCKFILE=#{Shellwords.escape(lockfile)}" if lockfile
1021
+ command << " #{command_body}"
993
1022
  command
994
1023
  end
995
1024
 
996
- def release_task_command?(command)
997
- ["bundle exec rake build", "bundle exec rake release"].include?(command.to_s.strip)
1025
+ def release_child_environment
1026
+ @release_child_environment ||= begin
1027
+ release_lockfile_normalization_env
1028
+ .merge(BundlerEnvGuard.unbundled_env)
1029
+ .merge("RUBYLIB" => nil, "RUBYOPT" => nil)
1030
+ end
998
1031
  end
999
1032
 
1000
1033
  # Bundler may reconcile the current machine's platform while loading a
@@ -1638,8 +1671,8 @@ module Kettle
1638
1671
  end
1639
1672
 
1640
1673
  puts "Committing Bundler update in #{paths.length} lockfile(s)."
1641
- abort("Failed to stage Bundler update lockfiles.") unless @git.add_paths(paths)
1642
- abort("Failed to commit Bundler update lockfiles.") unless @git.commit_staged("🔒️ Update bundle")
1674
+ abort("Failed to stage Bundler update lockfiles.") unless @git.add_repository_paths(paths)
1675
+ abort("Failed to commit Bundler update lockfiles.") unless @git.commit_staged("🔒️ Update bundle", env: release_git_hook_environment)
1643
1676
  reconcile_bundle_update_commit!
1644
1677
  true
1645
1678
  end
@@ -1669,8 +1702,8 @@ module Kettle
1669
1702
  return if paths.empty?
1670
1703
 
1671
1704
  puts "Bundler changed lockfiles while committing; amending the bundle update commit."
1672
- abort("Failed to stage post-commit Bundler lockfile changes.") unless @git.add_paths(paths)
1673
- abort("Failed to amend the bundle update commit.") unless @git.commit_amend_no_edit
1705
+ abort("Failed to stage post-commit Bundler lockfile changes.") unless @git.add_repository_paths(paths)
1706
+ abort("Failed to amend the bundle update commit.") unless @git.commit_amend_no_edit(env: release_git_hook_environment)
1674
1707
  end
1675
1708
 
1676
1709
  abort("Bundler continued changing lockfiles after the bundle update commit.") unless changed_bundle_lockfile_paths.empty?
@@ -1683,7 +1716,7 @@ module Kettle
1683
1716
 
1684
1717
  puts "Release commit hooks changed tracked files; amending the release preparation commit."
1685
1718
  abort("Failed to stage post-commit release changes.") unless @git.add_all
1686
- abort("Failed to amend the release preparation commit.") unless @git.commit_amend_no_edit
1719
+ abort("Failed to amend the release preparation commit.") unless @git.commit_amend_no_edit(env: release_git_hook_environment)
1687
1720
  end
1688
1721
 
1689
1722
  output, = git_output(["status", "--porcelain"])
@@ -1985,7 +2018,7 @@ module Kettle
1985
2018
  puts "No changes to commit for release prep (continuing)."
1986
2019
  false
1987
2020
  else
1988
- abort("Failed to commit release prep changes.") unless @git.commit_all(msg)
2021
+ abort("Failed to commit release prep changes.") unless @git.commit_all(msg, env: release_git_hook_environment)
1989
2022
  reconcile_release_prep_commit!
1990
2023
  true
1991
2024
  end
@@ -14,6 +14,8 @@ module Kettle
14
14
  module RubyGemsVersions
15
15
  CACHE_BUST_TTL_SECONDS = 30 * 24 * 60 * 60
16
16
  VERSION_CACHE_TTL_SECONDS = 30 * 24 * 60 * 60
17
+ HTTP_OPEN_TIMEOUT_SECONDS = 5
18
+ HTTP_READ_TIMEOUT_SECONDS = 10
17
19
  ENV_REFRESH = "KETTLE_RUBYGEMS_REFRESH"
18
20
  ENV_MARKER_PATH = "KETTLE_RUBYGEMS_CACHE_BUST_PATH"
19
21
  ENV_VERSION_CACHE_PATH = "KETTLE_RUBYGEMS_VERSION_CACHE_PATH"
@@ -32,7 +34,13 @@ module Kettle
32
34
  request["Cache-Control"] = "no-cache"
33
35
  request["Pragma"] = "no-cache"
34
36
  end
35
- response = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == "https") do |http|
37
+ response = Net::HTTP.start(
38
+ uri.host,
39
+ uri.port,
40
+ use_ssl: uri.scheme == "https",
41
+ open_timeout: HTTP_OPEN_TIMEOUT_SECONDS,
42
+ read_timeout: HTTP_READ_TIMEOUT_SECONDS
43
+ ) do |http|
36
44
  http.request(request)
37
45
  end
38
46
  if response.code.to_i == 404
@@ -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.15"
8
+ VERSION = "3.0.17"
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.15
4
+ version: 3.0.17
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.15
404
- changelog_uri: https://github.com/kettle-dev/kettle-dev/blob/v3.0.15/CHANGELOG.md
403
+ source_code_uri: https://github.com/kettle-dev/kettle-dev/tree/v3.0.17
404
+ changelog_uri: https://github.com/kettle-dev/kettle-dev/blob/v3.0.17/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.15
406
+ documentation_uri: https://www.rubydoc.info/gems/kettle-dev/3.0.17
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