kettle-dev 3.0.18 → 3.0.20
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 +4 -4
- checksums.yaml.gz.sig +1 -5
- data/CHANGELOG.md +31 -1
- data/README.md +10 -2
- data/lib/kettle/dev/lockfile_reset.rb +51 -4
- data/lib/kettle/dev/release_cli.rb +39 -12
- data/lib/kettle/dev/version.rb +1 -1
- data.tar.gz.sig +0 -0
- metadata +4 -4
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 20e87802965f21d08fce4a1bb8eaab16a950611e67268f55284610c9e7601d6a
|
|
4
|
+
data.tar.gz: 26d1ac30a1bba63404ec8463290e20effd4039393c179842e61cf98ed5e89760
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d6d0157c9bd6b22580c9c4304ed9ec0d2a87f55d8e8afe33cf4e81e14a3905f979e30397143047979bfed0c795b321acfaa9739988c9fb6f8546c1e45ceffa17
|
|
7
|
+
data.tar.gz: cf6a29d466ad157170224b8aca7cb9569e2de56711825487d18f8e68ef3ca5e5d546b215d2b00d34d9e9dbe49d49e2a326c37883b9eab66cc0835f97420732c0
|
checksums.yaml.gz.sig
CHANGED
|
@@ -1,5 +1 @@
|
|
|
1
|
-
|
|
2
|
-
i��$7�(^�a��YM�o
|
|
3
|
-
;�6���x����2ĕ��{-�mM��df��S���x%nSt���ݓ�%�=f�O5l�=�w\D�THw%�����
|
|
4
|
-
�k�$7�sЛϸ���wjʞu���8���,��4��T�G��5�m���L��ëV�4?�3.V���0��}ב��_�Y��rM�v]��<�%��%�§:q/��^�)����<��@̎�ڧ�Nټu��������D�s��侊B���Mo������zĉ=$���ט��)F%@��g�j
|
|
5
|
-
s}`Z{�J��
|
|
1
|
+
,8����ۆ����n�tр���aV�8�^�*¼zo�:t�`�m$'���c@
|
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.20] - 2026-08-30
|
|
34
|
+
|
|
35
|
+
- TAG: [v3.0.20][3.0.20t]
|
|
36
|
+
- COVERAGE: 91.44% -- 5875/6425 lines in 47 files
|
|
37
|
+
- BRANCH COVERAGE: 76.07% -- 2248/2955 branches in 47 files
|
|
38
|
+
- 50.47% documented
|
|
39
|
+
|
|
40
|
+
### Fixed
|
|
41
|
+
|
|
42
|
+
- Preserve configured monorepo member-path lockfiles during release while rejecting unapproved local paths.
|
|
43
|
+
|
|
44
|
+
## [3.0.19] - 2026-08-30
|
|
45
|
+
|
|
46
|
+
- TAG: [v3.0.19][3.0.19t]
|
|
47
|
+
- COVERAGE: 91.50% -- 5855/6399 lines in 47 files
|
|
48
|
+
- BRANCH COVERAGE: 76.21% -- 2249/2951 branches in 47 files
|
|
49
|
+
- 50.97% documented
|
|
50
|
+
|
|
51
|
+
### Fixed
|
|
52
|
+
|
|
53
|
+
- Run changelog coverage with the disposable release lockfile so host platform reconciliation cannot dirty a release.
|
|
54
|
+
|
|
55
|
+
- Normalize release lockfiles before changelog coverage runs.
|
|
56
|
+
|
|
57
|
+
- Isolate changelog coverage with the selected coverage Gemfile lockfile during release.
|
|
58
|
+
|
|
33
59
|
## [3.0.18] - 2026-08-30
|
|
34
60
|
|
|
35
61
|
- TAG: [v3.0.18][3.0.18t]
|
|
@@ -3651,7 +3677,11 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
|
3651
3677
|
- Selecting will run the selected workflow via `act`
|
|
3652
3678
|
- This may move to its own gem in the future.
|
|
3653
3679
|
|
|
3654
|
-
[Unreleased]: https://github.com/kettle-dev/kettle-dev/compare/v3.0.
|
|
3680
|
+
[Unreleased]: https://github.com/kettle-dev/kettle-dev/compare/v3.0.20...HEAD
|
|
3681
|
+
[3.0.20]: https://github.com/kettle-dev/kettle-dev/compare/v3.0.19...v3.0.20
|
|
3682
|
+
[3.0.20t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v3.0.20
|
|
3683
|
+
[3.0.19]: https://github.com/kettle-dev/kettle-dev/compare/v3.0.18...v3.0.19
|
|
3684
|
+
[3.0.19t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v3.0.19
|
|
3655
3685
|
[3.0.18]: https://github.com/kettle-dev/kettle-dev/compare/v3.0.17...v3.0.18
|
|
3656
3686
|
[3.0.18t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v3.0.18
|
|
3657
3687
|
[3.0.17]: https://github.com/kettle-dev/kettle-dev/compare/v3.0.16...v3.0.17
|
data/README.md
CHANGED
|
@@ -508,7 +508,7 @@ What it does:
|
|
|
508
508
|
| Role | Lockfile | Used by |
|
|
509
509
|
| --- | --- | --- |
|
|
510
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. |
|
|
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, except a narrow member-root policy supplied by `kettle-family` for an explicit monorepo. |
|
|
512
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
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
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. |
|
|
@@ -518,6 +518,14 @@ What it does:
|
|
|
518
518
|
a release phase. `ReleaseCLI#release_child_command` owns canonical/tool
|
|
519
519
|
command construction; `ReleaseCLI#release_project_command` selects the
|
|
520
520
|
disposable task lock only for build and publish.
|
|
521
|
+
|
|
522
|
+
The monorepo exception is intentionally narrow. `kettle-family` derives
|
|
523
|
+
it only from `family.mode: monorepo` and its configured members root, then
|
|
524
|
+
passes the allowed root and activating environment name to
|
|
525
|
+
`kettle-release`. A sibling Kettle Dev checkout is not covered: normal
|
|
526
|
+
releases must use the released `kettle-family`, `kettle-changelog`, and
|
|
527
|
+
other Kettle dependencies. Local Kettle Dev integration is an explicit
|
|
528
|
+
development opt-in, never a canonical release-lock default.
|
|
521
529
|
- Tips:
|
|
522
530
|
- The commit message helper `exe/kettle-commit-msg` prefers project-local `.git-hooks` (then falls back to `~/.git-hooks`).
|
|
523
531
|
- The goalie file `commit-subjects-goalie.txt` controls when a footer is appended; customize `footer-template.erb.txt` as you like.
|
|
@@ -1048,7 +1056,7 @@ Thanks for RTFM. ☺️
|
|
|
1048
1056
|
[📌gitmoji]: https://gitmoji.dev
|
|
1049
1057
|
[📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
|
|
1050
1058
|
[🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
|
|
1051
|
-
[🧮kloc-img]: https://img.shields.io/badge/KLOC-6.
|
|
1059
|
+
[🧮kloc-img]: https://img.shields.io/badge/KLOC-6.425-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
|
|
1052
1060
|
[🔐security]: https://github.com/kettle-dev/kettle-dev/blob/main/SECURITY.md
|
|
1053
1061
|
[🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
|
|
1054
1062
|
[📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
|
|
@@ -21,6 +21,8 @@ module Kettle
|
|
|
21
21
|
"GALTZO_FLOSS_DEV" => "false",
|
|
22
22
|
"UR_BRAIN_DEV" => "false"
|
|
23
23
|
}.freeze
|
|
24
|
+
ALLOWED_LOCAL_PATH_ROOTS_ENV = "KETTLE_RELEASE_ALLOWED_LOCAL_PATH_ROOTS"
|
|
25
|
+
ALLOWED_LOCAL_PATH_ENVS_ENV = "KETTLE_RELEASE_ALLOWED_LOCAL_PATH_ENVS"
|
|
24
26
|
RELEASE_LOCKFILES_TARGET = "release-lockfiles"
|
|
25
27
|
SUPPORTED_TARGETS = ["Gemfile.lock", "Appraisal.root.gemfile.lock", RELEASE_LOCKFILES_TARGET].freeze
|
|
26
28
|
UNBUNDLED_ENV_KEYS = (BundlerEnvGuard::RESET_ENV_KEYS + %w[
|
|
@@ -110,12 +112,18 @@ module Kettle
|
|
|
110
112
|
@root = root
|
|
111
113
|
@command_runner = command_runner
|
|
112
114
|
@release_platforms = {}
|
|
115
|
+
@allowed_local_path_roots = configured_allowed_local_path_roots
|
|
116
|
+
@allowed_local_path_env_names = configured_allowed_local_path_env_names
|
|
113
117
|
end
|
|
114
118
|
|
|
115
119
|
def reset(target, skip_changelog_dependency: false)
|
|
116
120
|
BundlerEnvGuard.warn_unexpected_env!
|
|
117
121
|
paths = lockfile_paths_for(target)
|
|
118
|
-
|
|
122
|
+
# A monorepo lockfile may deliberately use paths rooted in the
|
|
123
|
+
# repository's members directory. Keep that valid development graph;
|
|
124
|
+
# only rebuild when an unapproved path or other diagnostic remains.
|
|
125
|
+
force_full_update = release_lockfiles_target?(target) &&
|
|
126
|
+
(allowed_local_path_roots.empty? || paths.any? { |path| normalization_needed?(path) })
|
|
119
127
|
platforms = release_platforms_for(paths) if force_full_update
|
|
120
128
|
uninstall_unreleased_local_gems(paths) if force_full_update
|
|
121
129
|
paths.each do |path|
|
|
@@ -251,7 +259,7 @@ module Kettle
|
|
|
251
259
|
|
|
252
260
|
def diagnostics(path)
|
|
253
261
|
diagnostics = []
|
|
254
|
-
|
|
262
|
+
disallowed_local_path_remote_lines(path).each do |line_number|
|
|
255
263
|
diagnostics << "#{display_path(path)} has local path remote at line #{line_number}"
|
|
256
264
|
end
|
|
257
265
|
empty_registry_checksums(path).each do |name, version, line_number|
|
|
@@ -308,13 +316,16 @@ module Kettle
|
|
|
308
316
|
end
|
|
309
317
|
|
|
310
318
|
def normalization_env
|
|
311
|
-
DEFAULT_DISABLED_ENV
|
|
319
|
+
DEFAULT_DISABLED_ENV
|
|
320
|
+
.reject { |name, _| allowed_local_path_env_names.include?(name) }
|
|
321
|
+
.merge(dynamic_local_path_env)
|
|
312
322
|
end
|
|
313
323
|
|
|
314
324
|
def dynamic_local_path_env
|
|
315
325
|
ENV.each_with_object({}) do |(key, value), env|
|
|
316
326
|
next unless key.end_with?("_DEV", "_LOCAL")
|
|
317
327
|
next unless local_path_env_value?(value)
|
|
328
|
+
next if allowed_local_path_env_names.include?(key)
|
|
318
329
|
|
|
319
330
|
env[key] = "false"
|
|
320
331
|
end
|
|
@@ -329,13 +340,49 @@ module Kettle
|
|
|
329
340
|
end
|
|
330
341
|
|
|
331
342
|
def has_local_path_remote?(path)
|
|
332
|
-
!
|
|
343
|
+
!disallowed_local_path_remote_lines(path).empty?
|
|
333
344
|
end
|
|
334
345
|
|
|
335
346
|
def local_path_remote_lines(path)
|
|
336
347
|
self.class.local_path_remote_lines_from_source(File.read(path))
|
|
337
348
|
end
|
|
338
349
|
|
|
350
|
+
attr_reader :allowed_local_path_roots, :allowed_local_path_env_names
|
|
351
|
+
|
|
352
|
+
def disallowed_local_path_remote_lines(path)
|
|
353
|
+
local_path_remote_lines(path).reject do |line_number|
|
|
354
|
+
allowed_local_path?(local_path_remote_at(path, line_number))
|
|
355
|
+
end
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
def configured_allowed_local_path_roots
|
|
359
|
+
ENV.fetch(ALLOWED_LOCAL_PATH_ROOTS_ENV, "").split(File::PATH_SEPARATOR).filter_map do |value|
|
|
360
|
+
next if value.strip.empty?
|
|
361
|
+
|
|
362
|
+
canonical_path(value)
|
|
363
|
+
end.uniq
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
def configured_allowed_local_path_env_names
|
|
367
|
+
ENV.fetch(ALLOWED_LOCAL_PATH_ENVS_ENV, "").split(",").map(&:strip).reject(&:empty?).uniq
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
def local_path_remote_at(path, line_number)
|
|
371
|
+
File.readlines(path)[line_number - 1].to_s.split("remote:", 2).last.to_s.strip
|
|
372
|
+
end
|
|
373
|
+
|
|
374
|
+
def allowed_local_path?(path)
|
|
375
|
+
remote = canonical_path(path)
|
|
376
|
+
allowed_local_path_roots.any? { |root| remote == root || remote.start_with?("#{root}/") }
|
|
377
|
+
end
|
|
378
|
+
|
|
379
|
+
def canonical_path(path)
|
|
380
|
+
expanded = File.expand_path(path, root)
|
|
381
|
+
File.realpath(expanded)
|
|
382
|
+
rescue Errno::ENOENT
|
|
383
|
+
expanded
|
|
384
|
+
end
|
|
385
|
+
|
|
339
386
|
def empty_registry_checksums(path)
|
|
340
387
|
non_registry_gems = non_registry_source_gems(path) | path_dependency_gems(path)
|
|
341
388
|
in_checksums = false
|
|
@@ -218,7 +218,7 @@ module Kettle
|
|
|
218
218
|
@started_at = nil
|
|
219
219
|
@finished_report = nil
|
|
220
220
|
@changelog_generated_coverage = false
|
|
221
|
-
@
|
|
221
|
+
@release_task_lockfile_paths = {}
|
|
222
222
|
end
|
|
223
223
|
|
|
224
224
|
def run
|
|
@@ -251,6 +251,11 @@ module Kettle
|
|
|
251
251
|
attr_reader :finished_report
|
|
252
252
|
|
|
253
253
|
def run_with_release_environment
|
|
254
|
+
# Changelog generation at step 0 runs the target project's test bundle
|
|
255
|
+
# to collect coverage. Normalize its canonical release lockfile before
|
|
256
|
+
# that subprocess starts; otherwise a local development PATH lock can
|
|
257
|
+
# force Bundler to resolve an invalid mixed local/released graph.
|
|
258
|
+
prepare_release_lockfiles_for_release_tasks! if release_lockfile_preflight_needed?
|
|
254
259
|
run_pre_release_checks! if run_step?(0)
|
|
255
260
|
|
|
256
261
|
# 1. Ensure Bundler version and record its current release in the
|
|
@@ -357,7 +362,6 @@ module Kettle
|
|
|
357
362
|
end
|
|
358
363
|
|
|
359
364
|
prepare_rubocop_lts_local_branch! if rubocop_lts_release_preflight_needed?
|
|
360
|
-
prepare_release_lockfiles_for_release_tasks! if release_lockfile_preflight_needed?
|
|
361
365
|
|
|
362
366
|
# 3. bin/setup
|
|
363
367
|
run_cmd!(release_setup_command) if run_step?(3)
|
|
@@ -602,7 +606,10 @@ module Kettle
|
|
|
602
606
|
end
|
|
603
607
|
|
|
604
608
|
def release_lockfile_preflight_needed?
|
|
605
|
-
|
|
609
|
+
# Step 0 invokes kettle-changelog, which runs `bundle exec kettle-test`
|
|
610
|
+
# for fresh coverage. It therefore needs the same registry-backed
|
|
611
|
+
# release lockfile as later setup, task, and documentation steps.
|
|
612
|
+
run_step?(0) || (3..5).any? { |step| run_step?(step) }
|
|
606
613
|
end
|
|
607
614
|
|
|
608
615
|
def prepare_rubocop_lts_local_branch!
|
|
@@ -927,6 +934,14 @@ module Kettle
|
|
|
927
934
|
return release_child_command("bundle exec kettle-changelog") unless gemfile
|
|
928
935
|
|
|
929
936
|
environment = {"BUNDLE_GEMFILE" => gemfile}
|
|
937
|
+
coverage_gemfile = changelog_coverage_gemfile
|
|
938
|
+
environment["K_CHANGELOG_COVERAGE_GEMFILE"] = coverage_gemfile if coverage_gemfile
|
|
939
|
+
# Changelog coverage runs the target project's bundle. Give that nested
|
|
940
|
+
# invocation a disposable lockfile for its selected coverage Gemfile so
|
|
941
|
+
# Bundler's host-platform reconciliation cannot dirty the prep commit.
|
|
942
|
+
if (lockfile = release_task_lockfile_path(gemfile: coverage_gemfile || File.join(@root, "Gemfile")))
|
|
943
|
+
environment["KETTLE_CHANGELOG_COVERAGE_LOCKFILE"] = lockfile
|
|
944
|
+
end
|
|
930
945
|
if (local_root = release_changelog_local_root)
|
|
931
946
|
environment["KETTLE_CHANGELOG_DEV_ROOT"] = local_root
|
|
932
947
|
end
|
|
@@ -960,6 +975,18 @@ module Kettle
|
|
|
960
975
|
File.expand_path(local_root)
|
|
961
976
|
end
|
|
962
977
|
|
|
978
|
+
# A generated coverage appraisal is intentionally smaller than the root
|
|
979
|
+
# development bundle and therefore avoids release-only tool dependency
|
|
980
|
+
# conflicts. Let kettle-changelog retain the root-Gemfile fallback when
|
|
981
|
+
# a project has not generated this optional bundle.
|
|
982
|
+
def changelog_coverage_gemfile
|
|
983
|
+
configured = ENV["K_CHANGELOG_COVERAGE_GEMFILE"].to_s.strip
|
|
984
|
+
return File.expand_path(configured, @root) unless configured.empty?
|
|
985
|
+
|
|
986
|
+
generated = File.join(@root, "gemfiles", "coverage.gemfile")
|
|
987
|
+
generated if File.file?(generated)
|
|
988
|
+
end
|
|
989
|
+
|
|
963
990
|
# Monorepo subprojects commonly disable their local hard coverage gate
|
|
964
991
|
# because their narrow test suite cannot satisfy the aggregate root
|
|
965
992
|
# thresholds. Preserve an explicit changelog policy, otherwise derive
|
|
@@ -1036,26 +1063,26 @@ module Kettle
|
|
|
1036
1063
|
# bundler/gem_tasks' release:guard_clean check. Keep that reconciliation
|
|
1037
1064
|
# in a disposable lockfile so the committed, normalized lockfile remains
|
|
1038
1065
|
# unchanged throughout build and publication.
|
|
1039
|
-
def release_task_lockfile_path
|
|
1040
|
-
return @
|
|
1066
|
+
def release_task_lockfile_path(gemfile: File.join(@root, "Gemfile"))
|
|
1067
|
+
return @release_task_lockfile_paths[gemfile] if @release_task_lockfile_paths.key?(gemfile)
|
|
1041
1068
|
|
|
1042
|
-
source =
|
|
1069
|
+
source = "#{gemfile}.lock"
|
|
1043
1070
|
return unless File.file?(source)
|
|
1044
1071
|
|
|
1045
1072
|
directory = File.join(@root, "tmp", "kettle-release", "lockfiles")
|
|
1046
1073
|
FileUtils.mkdir_p(directory)
|
|
1047
|
-
|
|
1048
|
-
FileUtils.cp(source,
|
|
1049
|
-
@
|
|
1074
|
+
path = File.join(directory, "#{File.basename(gemfile)}-#{$$}.lock")
|
|
1075
|
+
FileUtils.cp(source, path)
|
|
1076
|
+
@release_task_lockfile_paths[gemfile] = path
|
|
1050
1077
|
rescue SystemCallError => error
|
|
1051
1078
|
abort("Unable to isolate the release task lockfile: #{error.message}")
|
|
1052
1079
|
end
|
|
1053
1080
|
|
|
1054
1081
|
def cleanup_release_task_lockfile!
|
|
1055
|
-
return
|
|
1082
|
+
return if @release_task_lockfile_paths.empty?
|
|
1056
1083
|
|
|
1057
|
-
FileUtils.rm_f(
|
|
1058
|
-
@
|
|
1084
|
+
@release_task_lockfile_paths.each_value { |path| FileUtils.rm_f(path) }
|
|
1085
|
+
@release_task_lockfile_paths.clear
|
|
1059
1086
|
end
|
|
1060
1087
|
|
|
1061
1088
|
def confirm_yes!(message, prompt, abort_message)
|
data/lib/kettle/dev/version.rb
CHANGED
|
@@ -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.
|
|
8
|
+
VERSION = "3.0.20"
|
|
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.
|
|
4
|
+
version: 3.0.20
|
|
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.
|
|
404
|
-
changelog_uri: https://github.com/kettle-dev/kettle-dev/blob/v3.0.
|
|
403
|
+
source_code_uri: https://github.com/kettle-dev/kettle-dev/tree/v3.0.20
|
|
404
|
+
changelog_uri: https://github.com/kettle-dev/kettle-dev/blob/v3.0.20/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.
|
|
406
|
+
documentation_uri: https://www.rubydoc.info/gems/kettle-dev/3.0.20
|
|
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
|