kettle-family 0.1.27 → 0.1.28
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 +0 -0
- data/CHANGELOG.md +15 -1
- data/README.md +1 -1
- data/lib/kettle/family/cli.rb +64 -20
- data/lib/kettle/family/command_result.rb +3 -1
- data/lib/kettle/family/version.rb +1 -1
- data/lib/kettle/family/workflow.rb +35 -6
- 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: 064f3f14703f9a178aba7cb549a0c55139f52397caa413adafa1137e44e504bb
|
|
4
|
+
data.tar.gz: c1c7ae833d6b815d7f7a52ba287fa186d51be53b09ab4e91d442b2cc6e94ab44
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9c71cc770c2d719561d0d6ef91d4c43a329ac75559cebaaf62732efbc0dd02f03e52684d9fa60ff26ac5ea1ad785c51af7e33e56573dc270b6def694d9bfec39
|
|
7
|
+
data.tar.gz: 9a4bc82e5d51c3ff52ccc5b93243c6c36a55e4769b29c0f17f320f1386f1336908acddca9e7dcf508e04680717262a63e6e80c47d5d5aaafdd569ba87fc0d12a
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
data/CHANGELOG.md
CHANGED
|
@@ -30,6 +30,18 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
|
30
30
|
|
|
31
31
|
### Security
|
|
32
32
|
|
|
33
|
+
## [0.1.28] - 2026-06-28
|
|
34
|
+
|
|
35
|
+
- TAG: [v0.1.28][0.1.28t]
|
|
36
|
+
- COVERAGE: 95.24% -- 1899/1994 lines in 21 files
|
|
37
|
+
- BRANCH COVERAGE: 74.86% -- 658/879 branches in 21 files
|
|
38
|
+
- 38.37% documented
|
|
39
|
+
|
|
40
|
+
### Added
|
|
41
|
+
|
|
42
|
+
- `kettle-family --start-at MEMBER@BRANCH` now resumes member-local and family
|
|
43
|
+
branch-stack workflows at a specific release target branch.
|
|
44
|
+
|
|
33
45
|
## [0.1.27] - 2026-06-28
|
|
34
46
|
|
|
35
47
|
- TAG: [v0.1.27][0.1.27t]
|
|
@@ -483,7 +495,9 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
|
483
495
|
- Fixed CI load failures on engines without compatible `pty` support by falling back to Open3 for interactive release commands.
|
|
484
496
|
- Fixed Ruby 3.2 version-bump support by loading Prism lazily and wiring the Prism gem only for MRI versions that need it.
|
|
485
497
|
|
|
486
|
-
[Unreleased]: https://github.com/kettle-dev/kettle-family/compare/v0.1.
|
|
498
|
+
[Unreleased]: https://github.com/kettle-dev/kettle-family/compare/v0.1.28...HEAD
|
|
499
|
+
[0.1.28]: https://github.com/kettle-dev/kettle-family/compare/v0.1.27...v0.1.28
|
|
500
|
+
[0.1.28t]: https://github.com/kettle-dev/kettle-family/releases/tag/v0.1.28
|
|
487
501
|
[0.1.27]: https://github.com/kettle-dev/kettle-family/compare/v0.1.26...v0.1.27
|
|
488
502
|
[0.1.27t]: https://github.com/kettle-dev/kettle-family/releases/tag/v0.1.27
|
|
489
503
|
[0.1.26]: https://github.com/kettle-dev/kettle-family/compare/v0.1.25...v0.1.26
|
data/README.md
CHANGED
|
@@ -571,7 +571,7 @@ Thanks for RTFM. ☺️
|
|
|
571
571
|
[📌gitmoji]: https://gitmoji.dev
|
|
572
572
|
[📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
|
|
573
573
|
[🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
|
|
574
|
-
[🧮kloc-img]: https://img.shields.io/badge/KLOC-1.
|
|
574
|
+
[🧮kloc-img]: https://img.shields.io/badge/KLOC-1.994-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
|
|
575
575
|
[🔐security]: https://github.com/kettle-dev/kettle-family/blob/main/SECURITY.md
|
|
576
576
|
[🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
|
|
577
577
|
[📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
|
data/lib/kettle/family/cli.rb
CHANGED
|
@@ -81,7 +81,7 @@ module Kettle
|
|
|
81
81
|
--root PATH Workspace or family root (default: current directory)
|
|
82
82
|
--config PATH Family config path
|
|
83
83
|
--only MEMBER Select exactly one member
|
|
84
|
-
--start-at NAME Select from member through the end of order
|
|
84
|
+
--start-at NAME Select from member through the end of order; use MEMBER@BRANCH for branch stacks
|
|
85
85
|
--json Print JSON report to stdout
|
|
86
86
|
--report PATH Write JSON report to PATH
|
|
87
87
|
--execute Execute external workflow commands
|
|
@@ -145,7 +145,7 @@ module Kettle
|
|
|
145
145
|
parser.on("--root PATH") { |value| options[:root] = value }
|
|
146
146
|
parser.on("--config PATH") { |value| options[:config] = value }
|
|
147
147
|
parser.on("--only MEMBER") { |value| options[:only] = value }
|
|
148
|
-
parser.on("--start-at MEMBER") { |value| options[:start_at] = value }
|
|
148
|
+
parser.on("--start-at MEMBER[@BRANCH]") { |value| options[:start_at] = value }
|
|
149
149
|
parser.on("--json") { options[:json] = true }
|
|
150
150
|
parser.on("--report PATH") { |value| options[:report] = value }
|
|
151
151
|
parser.on("--execute") { options[:execute] = true }
|
|
@@ -180,6 +180,7 @@ module Kettle
|
|
|
180
180
|
|
|
181
181
|
def build_report(command, options)
|
|
182
182
|
config = Config.load(root: options[:root], path: options[:config])
|
|
183
|
+
start_at = parse_start_at(options[:start_at])
|
|
183
184
|
members = Discovery.new(config: config).members
|
|
184
185
|
ordered = if command == "install"
|
|
185
186
|
install_order(members, config)
|
|
@@ -188,13 +189,13 @@ module Kettle
|
|
|
188
189
|
else
|
|
189
190
|
Orderer.new(members: members, mode: config.order_mode, hints: config.order_hints).ordered
|
|
190
191
|
end
|
|
191
|
-
selected = Selection.new(members: ordered).apply(only: options[:only], start_at:
|
|
192
|
+
selected = Selection.new(members: ordered).apply(only: options[:only], start_at: start_at.member)
|
|
192
193
|
result_members = if command == "branch-lanes"
|
|
193
194
|
ordered
|
|
194
195
|
else
|
|
195
196
|
selected
|
|
196
197
|
end
|
|
197
|
-
results = command_results(command: command, config: config, members: result_members, options: options)
|
|
198
|
+
results = command_results(command: command, config: config, members: result_members, options: options, start_at: start_at)
|
|
198
199
|
Report.new(
|
|
199
200
|
family_name: config.family_name,
|
|
200
201
|
family_mode: config.family_mode,
|
|
@@ -203,22 +204,24 @@ module Kettle
|
|
|
203
204
|
selected_members: selected,
|
|
204
205
|
config_path: config.path,
|
|
205
206
|
branch_lanes: config.branch_lanes,
|
|
206
|
-
release_target_branches:
|
|
207
|
-
member_release_target_branches: member_release_target_branches(command: command, members: selected, config: config),
|
|
207
|
+
release_target_branches: release_target_branches(command: command, config: config, start_at: start_at),
|
|
208
|
+
member_release_target_branches: member_release_target_branches(command: command, members: selected, config: config, start_at: start_at),
|
|
208
209
|
release_mode: release_mode(command: command, options: options),
|
|
209
210
|
command: command,
|
|
210
211
|
results: results
|
|
211
212
|
)
|
|
212
213
|
end
|
|
213
214
|
|
|
214
|
-
|
|
215
|
-
return branch_target_command_results(command: command, config: config, members: members, options: options) if branch_target_command?(command, config)
|
|
216
|
-
return member_local_branch_target_command_results(command: command, config: config, members: members, options: options) if member_local_branch_target_command?(command, config, members)
|
|
215
|
+
StartAt = Struct.new(:member, :branch)
|
|
217
216
|
|
|
218
|
-
|
|
217
|
+
def command_results(command:, config:, members:, options:, start_at:)
|
|
218
|
+
return branch_target_command_results(command: command, config: config, members: members, options: options, start_at: start_at) if branch_target_command?(command, config)
|
|
219
|
+
return member_local_branch_target_command_results(command: command, config: config, members: members, options: options, start_at: start_at) if member_local_branch_target_command?(command, config, members)
|
|
220
|
+
|
|
221
|
+
command_results_for_current_branch(command: command, config: config, members: members, options: options, start_at: start_at)
|
|
219
222
|
end
|
|
220
223
|
|
|
221
|
-
def command_results_for_current_branch(command:, config:, members:, options:)
|
|
224
|
+
def command_results_for_current_branch(command:, config:, members:, options:, start_at: StartAt.new(nil, nil))
|
|
222
225
|
return bump_version_results(members: members, options: options) if command == "bump-version"
|
|
223
226
|
return add_changelog_results(members: members, options: options) if command == "add-changelog"
|
|
224
227
|
return branch_lane_results(config: config, members: members) if command == "branch-lanes"
|
|
@@ -247,7 +250,9 @@ module Kettle
|
|
|
247
250
|
debug: options[:debug],
|
|
248
251
|
jobs: options[:jobs],
|
|
249
252
|
progress_io: progress_io(command, options),
|
|
250
|
-
bup_args: options[:bup_args]
|
|
253
|
+
bup_args: options[:bup_args],
|
|
254
|
+
start_member: start_at.member,
|
|
255
|
+
start_branch: start_at.branch
|
|
251
256
|
).results
|
|
252
257
|
end
|
|
253
258
|
|
|
@@ -283,20 +288,23 @@ module Kettle
|
|
|
283
288
|
members.any? { |member| member_local_release_config(member: member, config: config) }
|
|
284
289
|
end
|
|
285
290
|
|
|
286
|
-
def branch_target_command_results(command:, config:, members:, options:)
|
|
291
|
+
def branch_target_command_results(command:, config:, members:, options:, start_at:)
|
|
287
292
|
runner = CommandRunner.new(execute: options[:execute])
|
|
288
293
|
selected_names = members.map(&:name)
|
|
289
|
-
|
|
294
|
+
release_target_branches(command: command, config: config, start_at: start_at).each_with_object([]) do |branch, memo|
|
|
290
295
|
memo << runner.call(
|
|
291
296
|
member: family_member(config),
|
|
292
297
|
phase: "release_checkout",
|
|
293
298
|
command: ["git", "checkout", branch]
|
|
294
299
|
)
|
|
300
|
+
memo.last.branch = branch
|
|
295
301
|
break memo unless memo.last.ok?
|
|
296
302
|
|
|
297
303
|
branch_members = rediscovered_selected_members(config: config, selected_names: selected_names, command: command)
|
|
298
304
|
branch_members = members if branch_members.empty?
|
|
299
|
-
|
|
305
|
+
branch_results = command_results_for_current_branch(command: command, config: config, members: branch_members, options: options)
|
|
306
|
+
branch_results.each { |result| result.branch = branch if result.respond_to?(:branch=) }
|
|
307
|
+
memo.concat(branch_results)
|
|
300
308
|
break memo unless memo.last&.ok?
|
|
301
309
|
|
|
302
310
|
commit_changelog_entries(branch_members: branch_members, runner: runner, memo: memo) if command == "add-changelog"
|
|
@@ -304,7 +312,7 @@ module Kettle
|
|
|
304
312
|
end
|
|
305
313
|
end
|
|
306
314
|
|
|
307
|
-
def member_local_branch_target_command_results(command:, config:, members:, options:)
|
|
315
|
+
def member_local_branch_target_command_results(command:, config:, members:, options:, start_at:)
|
|
308
316
|
runner = CommandRunner.new(execute: options[:execute])
|
|
309
317
|
members.each_with_object([]) do |member, memo|
|
|
310
318
|
member_config = member_local_release_config(member: member, config: config)
|
|
@@ -314,17 +322,20 @@ module Kettle
|
|
|
314
322
|
next
|
|
315
323
|
end
|
|
316
324
|
|
|
317
|
-
|
|
325
|
+
member_branch_targets(command: command, member: member, member_config: member_config, start_at: start_at).each do |branch|
|
|
318
326
|
memo << runner.call(
|
|
319
327
|
member: member,
|
|
320
328
|
phase: "release_checkout",
|
|
321
329
|
command: ["git", "checkout", branch]
|
|
322
330
|
)
|
|
331
|
+
memo.last.branch = branch
|
|
323
332
|
break unless memo.last.ok?
|
|
324
333
|
|
|
325
334
|
branch_members = rediscovered_selected_members(config: member_config, selected_names: [member.name], command: command)
|
|
326
335
|
branch_members = [member] if branch_members.empty?
|
|
327
|
-
|
|
336
|
+
branch_results = command_results_for_current_branch(command: command, config: member_config, members: branch_members, options: options)
|
|
337
|
+
branch_results.each { |result| result.branch = branch if result.respond_to?(:branch=) }
|
|
338
|
+
memo.concat(branch_results)
|
|
328
339
|
break unless memo.last&.ok?
|
|
329
340
|
end
|
|
330
341
|
break memo unless memo.last&.ok?
|
|
@@ -363,6 +374,16 @@ module Kettle
|
|
|
363
374
|
raise OptionParser::InvalidArgument, "--upgrade must be one of: major, minor, patch"
|
|
364
375
|
end
|
|
365
376
|
|
|
377
|
+
def parse_start_at(value)
|
|
378
|
+
return StartAt.new(nil, nil) unless value
|
|
379
|
+
|
|
380
|
+
member, branch = value.split("@", 2)
|
|
381
|
+
raise Error, "--start-at requires MEMBER before @BRANCH" if member.to_s.empty?
|
|
382
|
+
raise Error, "--start-at requires BRANCH after MEMBER@" if value.include?("@") && branch.to_s.empty?
|
|
383
|
+
|
|
384
|
+
StartAt.new(member, branch)
|
|
385
|
+
end
|
|
386
|
+
|
|
366
387
|
def bump_version_results(members:, options:)
|
|
367
388
|
results = VersionBump.new(
|
|
368
389
|
members: members,
|
|
@@ -449,13 +470,36 @@ module Kettle
|
|
|
449
470
|
options[:publish] ? "publish" : "build-only"
|
|
450
471
|
end
|
|
451
472
|
|
|
452
|
-
def
|
|
473
|
+
def release_target_branches(command:, config:, start_at:)
|
|
474
|
+
branch_targets = BranchTargetConfig.branch_targets_for(command, config.release_target_branches)
|
|
475
|
+
return branch_targets if branch_targets.empty?
|
|
476
|
+
|
|
477
|
+
slice_branch_targets(branch_targets, start_at.branch)
|
|
478
|
+
end
|
|
479
|
+
|
|
480
|
+
def member_release_target_branches(command:, members:, config:, start_at:)
|
|
453
481
|
members.each_with_object({}) do |member, memo|
|
|
454
482
|
member_config = member_local_release_config(member: member, config: config)
|
|
455
|
-
memo[member.name] =
|
|
483
|
+
memo[member.name] = member_branch_targets(command: command, member: member, member_config: member_config, start_at: start_at) if member_config
|
|
456
484
|
end
|
|
457
485
|
end
|
|
458
486
|
|
|
487
|
+
def member_branch_targets(command:, member:, member_config:, start_at:)
|
|
488
|
+
branch_targets = BranchTargetConfig.branch_targets_for(command, member_config.release_target_branches)
|
|
489
|
+
return branch_targets unless start_at.branch && start_at.member == member.name
|
|
490
|
+
|
|
491
|
+
slice_branch_targets(branch_targets, start_at.branch)
|
|
492
|
+
end
|
|
493
|
+
|
|
494
|
+
def slice_branch_targets(branch_targets, start_branch)
|
|
495
|
+
return branch_targets unless start_branch
|
|
496
|
+
|
|
497
|
+
index = branch_targets.index(start_branch)
|
|
498
|
+
raise Error, "unknown branch target #{start_branch.inspect}" unless index
|
|
499
|
+
|
|
500
|
+
branch_targets.drop(index)
|
|
501
|
+
end
|
|
502
|
+
|
|
459
503
|
def member_local_release_config(member:, config:)
|
|
460
504
|
BranchTargetConfig.member_local_release_config(member: member, config: config)
|
|
461
505
|
end
|
|
@@ -44,7 +44,7 @@ module Kettle
|
|
|
44
44
|
"BUNDLE_SUPPRESS_INSTALL_USING_MESSAGES" => "true"
|
|
45
45
|
}.freeze
|
|
46
46
|
|
|
47
|
-
def initialize(command:, config:, members:, execute: false, accept: true, commit: true, allow_dirty: false, publish: false, push: false, tag: false, start_step: nil, skip_steps: nil, local_ci: false, continue_ci_failures: false, gha_sha_pins_upgrade: "patch", gha_sha_pins_check: false, env_overrides: {}, debug: false, gem_signing_password: nil, jobs: nil, progress_io: nil, bup_args: [])
|
|
47
|
+
def initialize(command:, config:, members:, execute: false, accept: true, commit: true, allow_dirty: false, publish: false, push: false, tag: false, start_step: nil, skip_steps: nil, local_ci: false, continue_ci_failures: false, gha_sha_pins_upgrade: "patch", gha_sha_pins_check: false, env_overrides: {}, debug: false, gem_signing_password: nil, jobs: nil, progress_io: nil, bup_args: [], start_member: nil, start_branch: nil)
|
|
48
48
|
@command = command
|
|
49
49
|
@config = config
|
|
50
50
|
@members = members
|
|
@@ -67,6 +67,8 @@ module Kettle
|
|
|
67
67
|
@jobs = jobs
|
|
68
68
|
@progress_io = progress_io
|
|
69
69
|
@bup_args = bup_args
|
|
70
|
+
@start_member = start_member
|
|
71
|
+
@start_branch = start_branch
|
|
70
72
|
end
|
|
71
73
|
|
|
72
74
|
def results
|
|
@@ -79,7 +81,7 @@ module Kettle
|
|
|
79
81
|
|
|
80
82
|
private
|
|
81
83
|
|
|
82
|
-
attr_reader :command, :config, :members, :execute, :accept, :commit, :allow_dirty, :publish, :push, :tag, :start_step, :skip_steps, :local_ci, :continue_ci_failures, :gha_sha_pins_upgrade, :gha_sha_pins_check, :env_overrides, :debug, :jobs, :progress_io, :bup_args
|
|
84
|
+
attr_reader :command, :config, :members, :execute, :accept, :commit, :allow_dirty, :publish, :push, :tag, :start_step, :skip_steps, :local_ci, :continue_ci_failures, :gha_sha_pins_upgrade, :gha_sha_pins_check, :env_overrides, :debug, :jobs, :progress_io, :bup_args, :start_member, :start_branch
|
|
83
85
|
|
|
84
86
|
def current_branch_results(workflow_members)
|
|
85
87
|
return check_results(workflow_members) if command == "check"
|
|
@@ -175,10 +177,13 @@ module Kettle
|
|
|
175
177
|
|
|
176
178
|
branch_members = rediscovered_selected_members(selected_names)
|
|
177
179
|
branch_members = members if branch_members.empty?
|
|
178
|
-
|
|
180
|
+
branch_results = current_branch_results(branch_members)
|
|
181
|
+
tag_branch_results(branch_results, branch)
|
|
182
|
+
memo.concat(branch_results)
|
|
179
183
|
break memo unless memo.last&.ok?
|
|
180
184
|
|
|
181
185
|
commit_normalized_lockfiles(branch_members: branch_members, runner: runner, memo: memo)
|
|
186
|
+
tag_branch_results(memo.last(1), branch)
|
|
182
187
|
break memo unless memo.last&.ok?
|
|
183
188
|
end
|
|
184
189
|
end
|
|
@@ -236,10 +241,18 @@ module Kettle
|
|
|
236
241
|
gem_signing_password: @gem_signing_password,
|
|
237
242
|
jobs: jobs,
|
|
238
243
|
progress_io: progress_io,
|
|
239
|
-
bup_args: bup_args
|
|
244
|
+
bup_args: bup_args,
|
|
245
|
+
start_member: start_member,
|
|
246
|
+
start_branch: start_branch_for_member(member)
|
|
240
247
|
)
|
|
241
248
|
end
|
|
242
249
|
|
|
250
|
+
def start_branch_for_member(member)
|
|
251
|
+
return unless member.name == start_member
|
|
252
|
+
|
|
253
|
+
start_branch
|
|
254
|
+
end
|
|
255
|
+
|
|
243
256
|
def release_member_results(release_members, include_family_changelog: false)
|
|
244
257
|
runner = release_command_runner
|
|
245
258
|
results = []
|
|
@@ -400,7 +413,17 @@ module Kettle
|
|
|
400
413
|
end
|
|
401
414
|
|
|
402
415
|
def branch_targets
|
|
403
|
-
BranchTargetConfig.branch_targets_for(command, config.release_target_branches)
|
|
416
|
+
targets = BranchTargetConfig.branch_targets_for(command, config.release_target_branches)
|
|
417
|
+
slice_branch_targets(targets, start_branch)
|
|
418
|
+
end
|
|
419
|
+
|
|
420
|
+
def slice_branch_targets(targets, branch)
|
|
421
|
+
return targets unless branch
|
|
422
|
+
|
|
423
|
+
index = targets.index(branch)
|
|
424
|
+
raise Error, "unknown branch target #{branch.inspect}" unless index
|
|
425
|
+
|
|
426
|
+
targets.drop(index)
|
|
404
427
|
end
|
|
405
428
|
|
|
406
429
|
def member_local_release_config(member)
|
|
@@ -408,11 +431,17 @@ module Kettle
|
|
|
408
431
|
end
|
|
409
432
|
|
|
410
433
|
def checkout_branch_result(branch:, runner:)
|
|
411
|
-
runner.call(
|
|
434
|
+
result = runner.call(
|
|
412
435
|
member: family_member,
|
|
413
436
|
phase: "release_checkout",
|
|
414
437
|
command: ["git", "checkout", branch]
|
|
415
438
|
)
|
|
439
|
+
result.branch = branch
|
|
440
|
+
result
|
|
441
|
+
end
|
|
442
|
+
|
|
443
|
+
def tag_branch_results(results, branch)
|
|
444
|
+
results.each { |result| result.branch = branch if result.respond_to?(:branch=) }
|
|
416
445
|
end
|
|
417
446
|
|
|
418
447
|
def append_release_internal_checks(member:, memo:)
|
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: 0.1.
|
|
4
|
+
version: 0.1.28
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Peter H. Boling
|
|
@@ -310,10 +310,10 @@ licenses:
|
|
|
310
310
|
- AGPL-3.0-only
|
|
311
311
|
metadata:
|
|
312
312
|
homepage_uri: https://kettle-family.galtzo.com
|
|
313
|
-
source_code_uri: https://github.com/kettle-dev/kettle-family/tree/v0.1.
|
|
314
|
-
changelog_uri: https://github.com/kettle-dev/kettle-family/blob/v0.1.
|
|
313
|
+
source_code_uri: https://github.com/kettle-dev/kettle-family/tree/v0.1.28
|
|
314
|
+
changelog_uri: https://github.com/kettle-dev/kettle-family/blob/v0.1.28/CHANGELOG.md
|
|
315
315
|
bug_tracker_uri: https://github.com/kettle-dev/kettle-family/issues
|
|
316
|
-
documentation_uri: https://www.rubydoc.info/gems/kettle-family/0.1.
|
|
316
|
+
documentation_uri: https://www.rubydoc.info/gems/kettle-family/0.1.28
|
|
317
317
|
funding_uri: https://github.com/sponsors/pboling
|
|
318
318
|
wiki_uri: https://github.com/kettle-dev/kettle-family/wiki
|
|
319
319
|
news_uri: https://www.railsbling.com/tags/kettle-family
|
metadata.gz.sig
CHANGED
|
Binary file
|