kettle-family 1.3.28 → 1.3.30
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 +30 -1
- data/README.md +1 -1
- data/lib/kettle/family/cli.rb +26 -2
- data/lib/kettle/family/command_runner.rb +9 -37
- data/lib/kettle/family/mise_adapter.rb +123 -0
- data/lib/kettle/family/mise_tasks.rb +47 -28
- data/lib/kettle/family/version.rb +1 -1
- data/lib/kettle/family/workflow.rb +53 -16
- data/lib/kettle/family.rb +20 -0
- data.tar.gz.sig +0 -0
- metadata +7 -6
- 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: e1834021ad7c719f89aee9e9c7408bb2fd772797bf85087620e913f2d0b5cbc5
|
|
4
|
+
data.tar.gz: abcb663c3eaffcebd396befa0443c3d5eb331cfdbcce6de417881cbda9e15679
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fd431e1b40c4c7b7119461eabb4cf55625a2ebea4f37e9c553ee96f3fb7f66af690441f063a33b2118a1d60ed7fdd48be98e9a6c85016cbbc106946206a152b8
|
|
7
|
+
data.tar.gz: b91b8eeb298ec02137d844df600e1ac2fe8ffefc5ff3c94fd055c8f10f57c162499deb1118a2c4034cd7ced3e2b0154b005255f2d95cdafe74744323ae9e6fb1
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
data/CHANGELOG.md
CHANGED
|
@@ -30,6 +30,31 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
|
30
30
|
|
|
31
31
|
### Security
|
|
32
32
|
|
|
33
|
+
## [1.3.30] - 2026-10-22
|
|
34
|
+
|
|
35
|
+
- TAG: [v1.3.30][1.3.30t]
|
|
36
|
+
- COVERAGE: 93.05% -- 7526/8088 lines in 45 files
|
|
37
|
+
- BRANCH COVERAGE: 77.62% -- 3020/3891 branches in 45 files
|
|
38
|
+
- 38.45% documented
|
|
39
|
+
|
|
40
|
+
### Fixed
|
|
41
|
+
|
|
42
|
+
- Family templating and mise-tasks now refresh the generated family task suite and migrate standard task definitions out of mise.toml, preserving custom tasks and family release settings. Generated lint/template commands execute their workflows, and dependency-task env wrappers use valid shell syntax.
|
|
43
|
+
|
|
44
|
+
- Family templating no longer crashes with Errno::ENOENT when the mise executable is unavailable to the spawned command environment: CommandRunner resolves mise to an absolute PATH-derived path for the `mise exec -C` wrapper prefix and the post-template family root trust step (spawned envs strip the orchestrator's Ruby/gem bin dirs from PATH), runs commands UNWRAPPED when mise cannot be resolved at all (no member runtime exists to activate), and skips the trust step when mise is absent (it only enables subsequent nested mise runs).
|
|
45
|
+
+ Mise is now optional everywhere the template flow can reach: the new `Kettle::Family::MiseAdapter` seam resolves the binary at runtime, wraps member commands in `mise exec` when available, and passes them through UNWRAPPED (with `env(1)` injection preserved) when absent — no ENOENT on mise-less CI. The post-template family root trust step and worktree bootstraps skip when unresolvable. The adapter is injectable via `mise_adapter:` kwarg on `CommandRunner` and `Workflow`, with a module-level `Kettle::Family.mise_adapter` default for deep CLI construction. All eight `CommandRunner.new` sites, the family-root trust phase, `worktree_mise_trust_results`, and `CLI.mise_trust_results` delegate to it. Specs default to the nil flavor (hermetic, identical locally and in CI); examples asserting wrapped argv shapes opt into an available adapter locally.
|
|
46
|
+
|
|
47
|
+
## [1.3.29] - 2026-10-21
|
|
48
|
+
|
|
49
|
+
- TAG: [v1.3.29][1.3.29t]
|
|
50
|
+
- COVERAGE: 93.07% -- 7464/8020 lines in 44 files
|
|
51
|
+
- BRANCH COVERAGE: 77.56% -- 2996/3863 branches in 44 files
|
|
52
|
+
- 37.45% documented
|
|
53
|
+
|
|
54
|
+
### Fixed
|
|
55
|
+
|
|
56
|
+
- Release: the closing full-cohort aggregate GitHub Release now runs on execute runs, not only dry-runs. Per-member finalization appends only cover members published in the current run, so a resumed wave (--only on the unpublished remainder) previously never contributed artifacts published by earlier interrupted waves to the shared release. kettle-gh-release skips existing assets, so the full-cohort pass stays cheap on complete waves
|
|
57
|
+
|
|
33
58
|
## [1.3.28] - 2026-10-21
|
|
34
59
|
|
|
35
60
|
- TAG: [v1.3.28][1.3.28t]
|
|
@@ -3189,7 +3214,11 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
|
3189
3214
|
- Fixed CI load failures on engines without compatible `pty` support by falling back to Open3 for interactive release commands.
|
|
3190
3215
|
- Fixed Ruby 3.2 version-bump support by loading Prism lazily and wiring the Prism gem only for MRI versions that need it.
|
|
3191
3216
|
|
|
3192
|
-
[Unreleased]: https://github.com/kettle-dev/kettle-family/compare/v1.3.
|
|
3217
|
+
[Unreleased]: https://github.com/kettle-dev/kettle-family/compare/v1.3.30...HEAD
|
|
3218
|
+
[1.3.30]: https://github.com/kettle-dev/kettle-family/compare/v1.3.29...v1.3.30
|
|
3219
|
+
[1.3.30t]: https://github.com/kettle-dev/kettle-family/releases/tag/v1.3.30
|
|
3220
|
+
[1.3.29]: https://github.com/kettle-dev/kettle-family/compare/v1.3.28...v1.3.29
|
|
3221
|
+
[1.3.29t]: https://github.com/kettle-dev/kettle-family/releases/tag/v1.3.29
|
|
3193
3222
|
[1.3.28]: https://github.com/kettle-dev/kettle-family/compare/v1.3.27...v1.3.28
|
|
3194
3223
|
[1.3.28t]: https://github.com/kettle-dev/kettle-family/releases/tag/v1.3.28
|
|
3195
3224
|
[1.3.27]: https://github.com/kettle-dev/kettle-family/compare/v1.3.26...v1.3.27
|
data/README.md
CHANGED
|
@@ -1225,7 +1225,7 @@ Thanks for RTFM. ☺️
|
|
|
1225
1225
|
[📌gitmoji]: https://gitmoji.dev
|
|
1226
1226
|
[📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
|
|
1227
1227
|
[🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
|
|
1228
|
-
[🧮kloc-img]: https://img.shields.io/badge/KLOC-8.
|
|
1228
|
+
[🧮kloc-img]: https://img.shields.io/badge/KLOC-8.088-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
|
|
1229
1229
|
[🔐security]: https://github.com/kettle-dev/kettle-family/blob/main/SECURITY.md
|
|
1230
1230
|
[🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
|
|
1231
1231
|
[📄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
|
@@ -267,7 +267,7 @@ module Kettle
|
|
|
267
267
|
class MiseTasks < BaseCommand
|
|
268
268
|
command_name "mise-tasks"
|
|
269
269
|
usage "[options]"
|
|
270
|
-
description "
|
|
270
|
+
description "Refresh managed family tasks and migrate standard root definitions; ensure the task-file include."
|
|
271
271
|
|
|
272
272
|
option :task_file, long: "--task-file", value: {type: String, usage: "PATH"},
|
|
273
273
|
desc: "Managed TOML task file name, relative to the root (default: mise-family.tasks.toml)"
|
|
@@ -288,6 +288,13 @@ module Kettle
|
|
|
288
288
|
return 1
|
|
289
289
|
end
|
|
290
290
|
|
|
291
|
+
if File.file?(File.join(root, ".kettle-family.yml"))
|
|
292
|
+
Kettle::Family::MiseTasks.materialize_managed_suite(
|
|
293
|
+
context: {project_root: root}, task_file_name: task_file_name
|
|
294
|
+
)
|
|
295
|
+
stdout.puts("refreshed managed family tasks and migrated standard root definitions")
|
|
296
|
+
end
|
|
297
|
+
|
|
291
298
|
unless File.file?(task_file_path)
|
|
292
299
|
baseline = File.join(__dir__, "templates", "mise-family.tasks.toml")
|
|
293
300
|
FileUtils.cp(baseline, task_file_path)
|
|
@@ -1065,11 +1072,28 @@ module Kettle
|
|
|
1065
1072
|
end
|
|
1066
1073
|
|
|
1067
1074
|
def mise_trust_results(config:, members:)
|
|
1075
|
+
adapter = Kettle::Family.mise_adapter
|
|
1068
1076
|
roots = [config.root, *members.map(&:root)].uniq
|
|
1069
1077
|
runner = CommandRunner.new(execute: true, accept: true)
|
|
1070
1078
|
roots.map.with_index do |root, index|
|
|
1071
1079
|
member = members.find { |candidate| candidate.root == root } || Member.new("family", root, nil, nil, nil, [], [], nil, [], [])
|
|
1072
|
-
|
|
1080
|
+
trust_argv = adapter.trust_argv(root)
|
|
1081
|
+
unless trust_argv
|
|
1082
|
+
next CommandResult.new(
|
|
1083
|
+
member_name: member.name,
|
|
1084
|
+
phase: "mise_trust",
|
|
1085
|
+
command: [],
|
|
1086
|
+
workdir: root,
|
|
1087
|
+
status: nil,
|
|
1088
|
+
success: true,
|
|
1089
|
+
stdout: "",
|
|
1090
|
+
stderr: "",
|
|
1091
|
+
elapsed_seconds: 0.0,
|
|
1092
|
+
skipped: true,
|
|
1093
|
+
reason: "mise executable not available"
|
|
1094
|
+
)
|
|
1095
|
+
end
|
|
1096
|
+
runner.call(member: member, phase: "mise_trust", command: trust_argv, env: {}, raw: true)
|
|
1073
1097
|
end
|
|
1074
1098
|
end
|
|
1075
1099
|
|
|
@@ -11,17 +11,7 @@ module Kettle
|
|
|
11
11
|
"KETTLE_RELEASE_GEM_SIGNING_PASSPHRASE"
|
|
12
12
|
].freeze
|
|
13
13
|
MISE_SESSION_ENV_PREFIX = "__MISE_"
|
|
14
|
-
WINDOWS_ENV_EXEC_SCRIPT =
|
|
15
|
-
unset_count = Integer(ARGV.shift)
|
|
16
|
-
unset_count.times { ENV.delete(ARGV.shift) }
|
|
17
|
-
assignment_count = Integer(ARGV.shift)
|
|
18
|
-
assignment_count.times do
|
|
19
|
-
key, value = ARGV.shift.split("=", 2)
|
|
20
|
-
ENV[key] = value
|
|
21
|
-
end
|
|
22
|
-
abort "missing command after environment arguments" if ARGV.shift != "--"
|
|
23
|
-
exec(*ARGV)
|
|
24
|
-
RUBY
|
|
14
|
+
WINDOWS_ENV_EXEC_SCRIPT = MiseAdapter::WINDOWS_ENV_EXEC_SCRIPT
|
|
25
15
|
|
|
26
16
|
class OtpCoordinator
|
|
27
17
|
def initialize(input: $stdin, output: $stdout, queue_total: nil, secrets_provider: nil, event_handler: nil)
|
|
@@ -235,11 +225,12 @@ module Kettle
|
|
|
235
225
|
end
|
|
236
226
|
private_constant :FailureStatus
|
|
237
227
|
|
|
238
|
-
def initialize(execute: false, accept: true, gem_signing_password: nil, otp_coordinator: nil)
|
|
228
|
+
def initialize(execute: false, accept: true, gem_signing_password: nil, otp_coordinator: nil, mise_adapter: nil)
|
|
239
229
|
@execute = execute
|
|
240
230
|
@accept = accept
|
|
241
231
|
@gem_signing_password = gem_signing_password
|
|
242
232
|
@otp_coordinator = otp_coordinator
|
|
233
|
+
@mise_adapter = mise_adapter || Kettle::Family.mise_adapter
|
|
243
234
|
end
|
|
244
235
|
|
|
245
236
|
def call(member:, phase:, command:, env: {}, interactive: false, raw: false, stdout_line_handler: nil, log_path: nil, passthrough_output: true)
|
|
@@ -688,31 +679,12 @@ module Kettle
|
|
|
688
679
|
|
|
689
680
|
command_env = nonsensitive_env(env)
|
|
690
681
|
unset_env, set_env = command_env.partition { |_key, value| value.nil? }
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
if Gem.win_platform?
|
|
699
|
-
return [
|
|
700
|
-
*mise_argv,
|
|
701
|
-
"ruby",
|
|
702
|
-
"--disable=rubyopt",
|
|
703
|
-
"-e",
|
|
704
|
-
WINDOWS_ENV_EXEC_SCRIPT,
|
|
705
|
-
"--",
|
|
706
|
-
unset_env.length.to_s,
|
|
707
|
-
*unset_env.map { |key, _value| key.to_s },
|
|
708
|
-
set_env.length.to_s,
|
|
709
|
-
*set_env.map { |key, value| "#{key}=#{value}" },
|
|
710
|
-
"--",
|
|
711
|
-
*argv
|
|
712
|
-
]
|
|
713
|
-
end
|
|
714
|
-
|
|
715
|
-
[*mise_argv, "env", *injected_env, *argv]
|
|
682
|
+
@mise_adapter.exec_argv(
|
|
683
|
+
member_root: member.root,
|
|
684
|
+
argv: argv,
|
|
685
|
+
unset_env: unset_env.map { |key, _value| key },
|
|
686
|
+
set_env: set_env.to_h
|
|
687
|
+
)
|
|
716
688
|
end
|
|
717
689
|
|
|
718
690
|
def process_env(member:, env:)
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Kettle
|
|
4
|
+
module Family
|
|
5
|
+
# Adapter seam around the mise binary.
|
|
6
|
+
#
|
|
7
|
+
# Mise is operational glue, not a code dependency: family tooling uses it
|
|
8
|
+
# for `mise trust -C <root>` after materializing managed task files, and
|
|
9
|
+
# for `mise exec -C <member.root> -- <cmd>` when running member commands
|
|
10
|
+
# under the member's declared runtime. It is absent in CI and on mise-less
|
|
11
|
+
# hosts, so every use degrades deliberately:
|
|
12
|
+
#
|
|
13
|
+
# - `trust_argv` returns nil when mise is unavailable (callers skip the
|
|
14
|
+
# trust phase — it only enables subsequent nested mise runs).
|
|
15
|
+
# - `exec_argv` passes the command through unwrapped when mise is
|
|
16
|
+
# unavailable (there is no member runtime to activate), preserving env
|
|
17
|
+
# injection via env(1) (or the portable ruby script on Windows).
|
|
18
|
+
#
|
|
19
|
+
# Specs inject a fake or stubbed adapter rather than spawning the real
|
|
20
|
+
# binary; only these adapter specs exercise the real PATH scan.
|
|
21
|
+
class MiseAdapter
|
|
22
|
+
# Portable env-manipulation wrapper used when commands must run with env
|
|
23
|
+
# changes on Windows (no env(1) there).
|
|
24
|
+
WINDOWS_ENV_EXEC_SCRIPT = <<~RUBY
|
|
25
|
+
unset_count = Integer(ARGV.shift)
|
|
26
|
+
unset_count.times { ENV.delete(ARGV.shift) }
|
|
27
|
+
assignment_count = Integer(ARGV.shift)
|
|
28
|
+
assignment_count.times do
|
|
29
|
+
key, value = ARGV.shift.split("=", 2)
|
|
30
|
+
ENV[key] = value
|
|
31
|
+
end
|
|
32
|
+
abort "missing command after environment arguments" if ARGV.shift != "--"
|
|
33
|
+
exec(*ARGV)
|
|
34
|
+
RUBY
|
|
35
|
+
|
|
36
|
+
# Absolute path to the mise executable resolved from the current PATH,
|
|
37
|
+
# or nil when mise is not installed. The absolute path is required for
|
|
38
|
+
# real spawns: CommandRunner's child env strips the orchestrator's
|
|
39
|
+
# Ruby/gem bin dirs from PATH, so a bare "mise" argv is unresolvable
|
|
40
|
+
# whenever the binary lives in one of those directories.
|
|
41
|
+
#
|
|
42
|
+
# @return [String, nil]
|
|
43
|
+
def executable
|
|
44
|
+
ENV.fetch("PATH", "").split(File::PATH_SEPARATOR).each do |dir|
|
|
45
|
+
path = File.join(dir, "mise")
|
|
46
|
+
return path if File.file?(path) && File.executable?(path)
|
|
47
|
+
end
|
|
48
|
+
nil
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# @return [Boolean] whether mise-wrapping and trust are possible
|
|
52
|
+
def available?
|
|
53
|
+
!executable.nil?
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# argv for `mise trust -C <root>`, or nil when mise is unavailable.
|
|
57
|
+
#
|
|
58
|
+
# @param root [String]
|
|
59
|
+
# @return [Array<String>, nil]
|
|
60
|
+
def trust_argv(root)
|
|
61
|
+
exe = executable
|
|
62
|
+
return nil unless exe
|
|
63
|
+
|
|
64
|
+
[exe, "trust", "-C", root]
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Build the argv for running a member command under the member's
|
|
68
|
+
# mise-declared runtime. Passes through unwrapped (preserving env
|
|
69
|
+
# injection) when mise is unavailable.
|
|
70
|
+
#
|
|
71
|
+
# @param member_root [String]
|
|
72
|
+
# @param argv [Array<String>] the normalized command
|
|
73
|
+
# @param unset_env [Array<String>] env keys to unset in the child
|
|
74
|
+
# @param set_env [Hash{String => String}] env assignments for the child
|
|
75
|
+
# @return [Array<String>]
|
|
76
|
+
def exec_argv(member_root:, argv:, unset_env: [], set_env: {})
|
|
77
|
+
injected_env = [
|
|
78
|
+
*unset_env.flat_map { |key| ["-u", key.to_s] },
|
|
79
|
+
*set_env.map { |key, value| "#{key}=#{value}" }
|
|
80
|
+
]
|
|
81
|
+
|
|
82
|
+
exe = executable
|
|
83
|
+
unless exe
|
|
84
|
+
# No mise executable: there is no member runtime to activate, and a
|
|
85
|
+
# wrapped spawn would be an unresolvable bare "mise" (ENOENT under
|
|
86
|
+
# the filtered child PATH). Run unwrapped, preserving env injection.
|
|
87
|
+
return argv if injected_env.empty?
|
|
88
|
+
|
|
89
|
+
return windows_env_argv(unset_env: unset_env, set_env: set_env, argv: argv) if Gem.win_platform?
|
|
90
|
+
|
|
91
|
+
return ["env", *injected_env, *argv]
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
mise_argv = [exe, "exec", "-C", member_root, "--"]
|
|
95
|
+
return [*mise_argv, *argv] if injected_env.empty?
|
|
96
|
+
|
|
97
|
+
if Gem.win_platform?
|
|
98
|
+
return [*mise_argv, *windows_env_argv(unset_env: unset_env, set_env: set_env, argv: argv)]
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
[*mise_argv, "env", *injected_env, *argv]
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
private
|
|
105
|
+
|
|
106
|
+
def windows_env_argv(unset_env:, set_env:, argv:)
|
|
107
|
+
[
|
|
108
|
+
"ruby",
|
|
109
|
+
"--disable=rubyopt",
|
|
110
|
+
"-e",
|
|
111
|
+
WINDOWS_ENV_EXEC_SCRIPT,
|
|
112
|
+
"--",
|
|
113
|
+
unset_env.length.to_s,
|
|
114
|
+
*unset_env.map { |key| key.to_s },
|
|
115
|
+
set_env.length.to_s,
|
|
116
|
+
*set_env.map { |key, value| "#{key}=#{value}" },
|
|
117
|
+
"--",
|
|
118
|
+
*argv
|
|
119
|
+
]
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
@@ -9,11 +9,9 @@ module Kettle
|
|
|
9
9
|
# Slice-1044 family mise tasks primitive: ensure a destination root
|
|
10
10
|
# `mise.toml` references the kettle-family-managed TOML task file via
|
|
11
11
|
# `[task_config] includes`, and report (optionally clean) task
|
|
12
|
-
# redefinitions between the root file and the managed file.
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
# over the same name from a task file. Redefinition is therefore allowed
|
|
16
|
-
# and only reported; `clean` is always opt-in.
|
|
12
|
+
# redefinitions between the root file and the managed file. Family
|
|
13
|
+
# refreshes migrate managed task names out of the root so old commands
|
|
14
|
+
# cannot shadow generated fixes. Other tasks and settings remain local.
|
|
17
15
|
#
|
|
18
16
|
# All edits go through ast-crispr Actors with the ast-crispr-toml adapter.
|
|
19
17
|
module MiseTasks
|
|
@@ -168,7 +166,7 @@ module Kettle
|
|
|
168
166
|
end
|
|
169
167
|
|
|
170
168
|
# Remove duplicate task definitions from the root mise.toml.
|
|
171
|
-
#
|
|
169
|
+
# Used by family refreshes and the explicit non-family `--clean` path.
|
|
172
170
|
#
|
|
173
171
|
# @param root_content [String] the destination's mise.toml content
|
|
174
172
|
# @param task_file_content [String] managed task file content
|
|
@@ -180,10 +178,11 @@ module Kettle
|
|
|
180
178
|
redefs.each do |name|
|
|
181
179
|
# A task can be defined as a `[tasks.<name>]` table block or as a
|
|
182
180
|
# trivial `name = "…"` pair inside `[tasks]`; try both owners.
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
181
|
+
tables = document_context(content).structural_owners(owner_scope: :tables)
|
|
182
|
+
paths = tables.map(&:name).select { |path| path == "tasks.#{name}" || path.start_with?("tasks.#{name}.") }
|
|
183
|
+
targets = paths.reverse.map { |path| TomlSelectors.table(path: path) }
|
|
184
|
+
targets << TomlSelectors.pair(path: "tasks.#{name}")
|
|
185
|
+
targets.each do |target|
|
|
187
186
|
result = Ast::Crispr::Delete.result(
|
|
188
187
|
content: content,
|
|
189
188
|
target: target,
|
|
@@ -261,6 +260,16 @@ module Kettle
|
|
|
261
260
|
end
|
|
262
261
|
|
|
263
262
|
pairs = table.wrapper.pairs
|
|
263
|
+
if pairs.any? { |pair| pair.key_name.to_s == "includes" }
|
|
264
|
+
entries = includes_entries(context) + [task_file_name]
|
|
265
|
+
result = Ast::Crispr::Replace.result(
|
|
266
|
+
content: content,
|
|
267
|
+
target: TomlSelectors.pair(path: "task_config.includes"),
|
|
268
|
+
replacement: "includes = [#{entries.map(&:inspect).join(", ")}]\n",
|
|
269
|
+
source_label: "mise.toml"
|
|
270
|
+
)
|
|
271
|
+
return fail_or(result)
|
|
272
|
+
end
|
|
264
273
|
result =
|
|
265
274
|
if pairs.empty?
|
|
266
275
|
Ast::Crispr::Replace.result(
|
|
@@ -295,31 +304,30 @@ module Kettle
|
|
|
295
304
|
# .kettle-family.yml).
|
|
296
305
|
#
|
|
297
306
|
# @param context [Hash] kettle-jem plugin context (:project_root)
|
|
298
|
-
def self.materialize_managed_suite(context:)
|
|
307
|
+
def self.materialize_managed_suite(context:, task_file_name: DEFAULT_TASK_FILE_NAME, **options)
|
|
299
308
|
root = context[:project_root].to_s
|
|
300
309
|
return if root.empty?
|
|
301
310
|
|
|
302
311
|
root = File.expand_path(root)
|
|
303
312
|
return unless File.file?(File.join(root, ".kettle-family.yml"))
|
|
304
313
|
|
|
314
|
+
root_mise = File.join(root, "mise.toml")
|
|
315
|
+
return unless File.file?(root_mise)
|
|
316
|
+
|
|
305
317
|
config = Config.load(root: root)
|
|
306
318
|
content = ManagedSuite.new(config).content
|
|
307
319
|
content += "\n" unless content.end_with?("\n")
|
|
308
320
|
|
|
309
|
-
task_file_path = File.join(root,
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
result = ensure_include(
|
|
316
|
-
root_content: File.read(root_mise),
|
|
317
|
-
task_file_name: DEFAULT_TASK_FILE_NAME,
|
|
321
|
+
task_file_path = File.join(root, task_file_name)
|
|
322
|
+
original = File.read(root_mise)
|
|
323
|
+
included = ensure_include(root_content: original, task_file_name: task_file_name)
|
|
324
|
+
result = clean_redefinitions(
|
|
325
|
+
root_content: included.content,
|
|
326
|
+
task_file_name: task_file_name,
|
|
318
327
|
task_file_content: content
|
|
319
328
|
)
|
|
320
|
-
File.write(
|
|
321
|
-
|
|
322
|
-
warn("kettle-family: could not materialize managed mise tasks: #{e.class}: #{e.message}")
|
|
329
|
+
File.write(task_file_path, content) unless File.exist?(task_file_path) && File.read(task_file_path) == content
|
|
330
|
+
File.write(root_mise, result.content) unless result.content == original
|
|
323
331
|
end
|
|
324
332
|
|
|
325
333
|
# Comprehensive managed family mise task suite, generated from family
|
|
@@ -352,16 +360,25 @@ module Kettle
|
|
|
352
360
|
def content
|
|
353
361
|
tasks = {
|
|
354
362
|
"test" => "bundle exec kettle-family test --execute",
|
|
355
|
-
"lint" => "bundle exec kettle-family lint",
|
|
363
|
+
"lint" => "bundle exec kettle-family lint --execute",
|
|
356
364
|
"state" => "bundle exec kettle-family release-state",
|
|
357
365
|
"release-state" => "bundle exec kettle-family release-state",
|
|
358
|
-
"template" => "bundle exec kettle-family template",
|
|
366
|
+
"template" => "bundle exec kettle-family template --execute",
|
|
359
367
|
"bump" => "bundle exec kettle-family bump --execute",
|
|
360
368
|
# Targeting is resolved by kettle-family from the family config:
|
|
361
369
|
# shared-changelog families write the root changelog, member-local
|
|
362
370
|
# families write each member's own.
|
|
363
371
|
"changelog" => "bundle exec kettle-family add-changelog --execute"
|
|
364
372
|
}
|
|
373
|
+
%w[install docs clean-unreleased gha-sha-pins bex branch-lanes discover metadata report pull push up sync reset mise-trust reconcile-releases].each do |command|
|
|
374
|
+
name = {"clean-unreleased" => "clean", "gha-sha-pins" => "pins"}.fetch(command, command)
|
|
375
|
+
flags = %w[branch-lanes discover metadata report mise-trust].include?(command) ? "" : " --execute"
|
|
376
|
+
flags += " --upgrade major" if name == "pins"
|
|
377
|
+
tasks[name] = "bundle exec kettle-family #{command}#{flags}"
|
|
378
|
+
end
|
|
379
|
+
tasks["readiness"] = "bundle exec kettle-family check --execute"
|
|
380
|
+
tasks["deps"] = "bundle exec kettle-family bup --execute --no-commit"
|
|
381
|
+
tasks["lint-fix"] = "bundle exec kettle-family bex --execute --no-commit -- bin/rake rubocop_gradual:autocorrect"
|
|
365
382
|
tasks["bup"] = "bundle exec kettle-family bup --execute --commit"
|
|
366
383
|
tasks["bupb"] = "bundle exec kettle-family update-bundler --execute --commit"
|
|
367
384
|
tasks["update-bundler"] = tasks["bupb"]
|
|
@@ -369,7 +386,7 @@ module Kettle
|
|
|
369
386
|
neutral = neutralize_assignments
|
|
370
387
|
wiring = env_wiring_flags
|
|
371
388
|
%w[bup bupb].each do |name|
|
|
372
|
-
prefix = neutral.empty? ? "" : "env #{neutral}
|
|
389
|
+
prefix = neutral.empty? ? "" : "env -- #{neutral} "
|
|
373
390
|
tasks[name] = "#{prefix}#{tasks[name]}#{wiring}"
|
|
374
391
|
end
|
|
375
392
|
tasks["update-bundler"] = tasks["bupb"]
|
|
@@ -422,11 +439,13 @@ module Kettle
|
|
|
422
439
|
#
|
|
423
440
|
# Family-specific tasks (for example a release task with the
|
|
424
441
|
# family's publish flags and secrets provider) belong in the root
|
|
425
|
-
# mise.toml
|
|
442
|
+
# mise.toml. Standard task names are managed here and migrated out
|
|
443
|
+
# of that file during refreshes.
|
|
426
444
|
HEADER
|
|
445
|
+
out << "\n[check]\ndescription = \"Run readiness, lint, and tests\"\ndepends = [\"readiness\", \"lint\", \"test\"]\nrun = \"true\"\n"
|
|
427
446
|
tasks.each do |name, run|
|
|
428
447
|
out << "\n[#{name}]\n"
|
|
429
|
-
out << "description = #{TASK_DESCRIPTIONS.fetch(name).inspect}\n"
|
|
448
|
+
out << "description = #{TASK_DESCRIPTIONS.fetch(name) { "Run family #{name}" }.inspect}\n"
|
|
430
449
|
out << "raw = true\n"
|
|
431
450
|
out << "run = #{run.inspect}\n"
|
|
432
451
|
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 = "1.3.
|
|
8
|
+
VERSION = "1.3.30"
|
|
9
9
|
end
|
|
10
10
|
# Current gem version exposed at the traditional constant location.
|
|
11
11
|
VERSION = Version::VERSION # Traditional Constant Location
|
|
@@ -109,7 +109,7 @@ module Kettle
|
|
|
109
109
|
REGISTRY_WAIT_INTERVAL_SECONDS = 15
|
|
110
110
|
TEMPLATE_GEMSPEC_RETRY_DELAY_SECONDS = 0.25
|
|
111
111
|
|
|
112
|
-
def initialize(command:, config:, members:, family_members: nil, execute: false, accept: true, commit: true, allow_dirty: false, autostash: true, template_cleanup: true, publish: false, push: false, tag: false, start_step: nil, skip_steps: nil, fast_recovery: nil, fast_recovery_members: nil, skip_ci: false, skip_changelog: false, skip_appraisals: false, local_ci: false, continue_ci_failures: false, ci_workflows: nil, skip_bundle_audit: false, skip_remotes: nil, required_remotes: nil, auto_dependency_floors: nil, validate_ci_bundles: nil, gha_sha_pins_upgrade: "patch", gha_sha_pins_check: false, gha_sha_pins_ttl_days: nil, env_overrides: {}, debug: false, verbose: false, gem_signing_password: nil, secrets_provider: nil, jobs: nil, progress_io: nil, reset_target: nil, bup_args: [], bex_args: [], start_member: nil, start_branch: nil, template_branch_selection: {}, release_state_results: nil, event_tape: nil, **options)
|
|
112
|
+
def initialize(command:, config:, members:, family_members: nil, execute: false, accept: true, commit: true, allow_dirty: false, autostash: true, template_cleanup: true, publish: false, push: false, tag: false, start_step: nil, skip_steps: nil, fast_recovery: nil, fast_recovery_members: nil, skip_ci: false, skip_changelog: false, skip_appraisals: false, local_ci: false, continue_ci_failures: false, ci_workflows: nil, skip_bundle_audit: false, skip_remotes: nil, required_remotes: nil, auto_dependency_floors: nil, validate_ci_bundles: nil, gha_sha_pins_upgrade: "patch", gha_sha_pins_check: false, gha_sha_pins_ttl_days: nil, env_overrides: {}, debug: false, verbose: false, gem_signing_password: nil, secrets_provider: nil, jobs: nil, progress_io: nil, reset_target: nil, bup_args: [], bex_args: [], start_member: nil, start_branch: nil, template_branch_selection: {}, release_state_results: nil, event_tape: nil, mise_adapter: nil, **options)
|
|
113
113
|
@command = command
|
|
114
114
|
@config = config
|
|
115
115
|
@members = members
|
|
@@ -156,6 +156,7 @@ module Kettle
|
|
|
156
156
|
@verbose = verbose
|
|
157
157
|
@gem_signing_password = gem_signing_password
|
|
158
158
|
@secrets_provider = secrets_provider || Secrets::Provider.new
|
|
159
|
+
@mise_adapter = mise_adapter || Kettle::Family.mise_adapter
|
|
159
160
|
@jobs = jobs
|
|
160
161
|
@progress_io = progress_io
|
|
161
162
|
@reset_target = reset_target
|
|
@@ -256,7 +257,30 @@ module Kettle
|
|
|
256
257
|
runner: runner,
|
|
257
258
|
preserve_members: template_cleanup ? [] : failed_members
|
|
258
259
|
)
|
|
259
|
-
checkout_preflight + sync_results + workflow_results + rollback_results + restore_results
|
|
260
|
+
results = checkout_preflight + sync_results + workflow_results + rollback_results + restore_results
|
|
261
|
+
if results.all?(&:ok?)
|
|
262
|
+
MiseTasks.materialize_managed_suite(context: {project_root: config.root})
|
|
263
|
+
# `mise trust` requires the mise executable; spec environments and
|
|
264
|
+
# minimal CI images may not have it installed. Trust is only an
|
|
265
|
+
# enabler for subsequent nested mise runs, so skip when absent.
|
|
266
|
+
trust_argv = @mise_adapter.trust_argv(config.root)
|
|
267
|
+
if trust_argv && File.file?(File.join(config.root, "mise.toml"))
|
|
268
|
+
results << runner.call(
|
|
269
|
+
member: family_member, phase: "family_mise_trust",
|
|
270
|
+
command: trust_argv, raw: true
|
|
271
|
+
)
|
|
272
|
+
end
|
|
273
|
+
if results.all?(&:ok?) && family_root_bundle_commit? && File.file?(File.join(config.root, "mise.toml"))
|
|
274
|
+
results << runner.call(
|
|
275
|
+
member: family_member,
|
|
276
|
+
phase: "commit_family_mise_tasks",
|
|
277
|
+
command: ["sh", "-lc", "files=$(git ls-files --modified --others --exclude-standard -- mise.toml mise-family.tasks.toml); " \
|
|
278
|
+
"if [ -n \"$files\" ]; then git add -- mise.toml mise-family.tasks.toml && " \
|
|
279
|
+
"git commit --only -m '🔧 Refresh managed family mise tasks' -- mise.toml mise-family.tasks.toml; fi"]
|
|
280
|
+
)
|
|
281
|
+
end
|
|
282
|
+
end
|
|
283
|
+
results
|
|
260
284
|
end
|
|
261
285
|
|
|
262
286
|
def template_worktree_sync_results(runner:)
|
|
@@ -535,10 +559,18 @@ module Kettle
|
|
|
535
559
|
return results unless results.all?(&:ok?)
|
|
536
560
|
|
|
537
561
|
results.concat(release_member_results(workflow_members, include_family_changelog: !skip_changelog))
|
|
538
|
-
return results unless
|
|
539
|
-
|
|
562
|
+
return results unless explicit_monorepo_mode? && results.all?(&:ok?)
|
|
563
|
+
|
|
564
|
+
# Per-member appends during finalization only cover members published
|
|
565
|
+
# in THIS run. A resumed wave selects only the unpublished remainder,
|
|
566
|
+
# so the closing aggregate must always span the full shared-version
|
|
567
|
+
# cohort to contribute artifacts published by earlier interrupted
|
|
568
|
+
# waves. Existing assets are skipped by kettle-gh-release, so the
|
|
569
|
+
# full-cohort pass is cheap on a complete wave.
|
|
540
570
|
selected_aggregate_members = aggregate_release_members(workflow_members)
|
|
541
|
-
|
|
571
|
+
if selected_aggregate_members.any? && (!execute || publish)
|
|
572
|
+
results << aggregate_monorepo_github_release(aggregate_github_release_members)
|
|
573
|
+
end
|
|
542
574
|
return results
|
|
543
575
|
end
|
|
544
576
|
return git_sync_results(workflow_members) if GIT_SYNC_COMMANDS.key?(command)
|
|
@@ -548,7 +580,7 @@ module Kettle
|
|
|
548
580
|
|
|
549
581
|
def reset_member_results(workflow_members)
|
|
550
582
|
target = normalized_reset_target
|
|
551
|
-
runner = CommandRunner.new(execute: execute, accept: accept)
|
|
583
|
+
runner = CommandRunner.new(execute: execute, accept: accept, mise_adapter: @mise_adapter)
|
|
552
584
|
workflow_members.each_with_object([]) do |member, memo|
|
|
553
585
|
case target
|
|
554
586
|
when "Gemfile.lock"
|
|
@@ -575,7 +607,7 @@ module Kettle
|
|
|
575
607
|
return template_member_workflow_results(workflow_members) if command == "template" && execute
|
|
576
608
|
return test_member_workflow_results(workflow_members) if command == "test" && execute
|
|
577
609
|
|
|
578
|
-
runner = CommandRunner.new(execute: execute, accept: accept)
|
|
610
|
+
runner = CommandRunner.new(execute: execute, accept: accept, mise_adapter: @mise_adapter)
|
|
579
611
|
results = []
|
|
580
612
|
update_family_root_bundle(runner: runner, memo: results) if %w[bup bupb update-bundler].include?(command)
|
|
581
613
|
return results unless results.all?(&:ok?)
|
|
@@ -682,7 +714,7 @@ module Kettle
|
|
|
682
714
|
|
|
683
715
|
Array.new(wave_jobs) do
|
|
684
716
|
Thread.new do # rubocop:disable ThreadSafety/NewThread -- sibling test suites run in isolated project roots.
|
|
685
|
-
runner = CommandRunner.new(execute: execute, accept: accept)
|
|
717
|
+
runner = CommandRunner.new(execute: execute, accept: accept, mise_adapter: @mise_adapter)
|
|
686
718
|
loop do
|
|
687
719
|
break if mutex.synchronize { stop }
|
|
688
720
|
|
|
@@ -796,7 +828,7 @@ module Kettle
|
|
|
796
828
|
|
|
797
829
|
index, entry = queue.pop(true)
|
|
798
830
|
member = entry.fetch(:member)
|
|
799
|
-
result = CommandRunner.new(execute: execute, accept: accept).call(
|
|
831
|
+
result = CommandRunner.new(execute: execute, accept: accept, mise_adapter: @mise_adapter).call(
|
|
800
832
|
member: member,
|
|
801
833
|
phase: command,
|
|
802
834
|
command: workflow_command(member),
|
|
@@ -1437,7 +1469,7 @@ module Kettle
|
|
|
1437
1469
|
end
|
|
1438
1470
|
|
|
1439
1471
|
bootstrap = NomonoBootstrap.new(latest_version: latest_nomono_version, mode: :execute)
|
|
1440
|
-
runner = CommandRunner.new(execute: execute, accept: accept)
|
|
1472
|
+
runner = CommandRunner.new(execute: execute, accept: accept, mise_adapter: @mise_adapter)
|
|
1441
1473
|
candidate_members.each_with_object([]) do |member, memo|
|
|
1442
1474
|
next unless bootstrap.member_needs_bootstrap?(member)
|
|
1443
1475
|
|
|
@@ -1517,7 +1549,7 @@ module Kettle
|
|
|
1517
1549
|
progress_key ||= member.name
|
|
1518
1550
|
progress_label ||= member.name
|
|
1519
1551
|
start_template_member_progress(progress, member, progress_key: progress_key, progress_label: progress_label) unless progress_started
|
|
1520
|
-
runner = CommandRunner.new(execute: execute, accept: accept)
|
|
1552
|
+
runner = CommandRunner.new(execute: execute, accept: accept, mise_adapter: @mise_adapter)
|
|
1521
1553
|
[].tap do |memo|
|
|
1522
1554
|
if config.normalize_lockfiles?
|
|
1523
1555
|
normalize_lockfiles(member: member, runner: runner, memo: memo, phase: "prepare_lockfiles", commit_changes: commit_changes)
|
|
@@ -1738,16 +1770,20 @@ module Kettle
|
|
|
1738
1770
|
# tracks trust by config path. Trust every active config between the
|
|
1739
1771
|
# worktree root and the member command directory before invoking a
|
|
1740
1772
|
# command there. This bootstrap must run raw: wrapping it in `mise exec`
|
|
1741
|
-
# would require the trust it is establishing.
|
|
1773
|
+
# would require the trust it is establishing. Roots are skipped when the
|
|
1774
|
+
# mise executable is unavailable (mise is operational glue, absent in CI).
|
|
1742
1775
|
def worktree_mise_trust_results(entry, runner:, phase:)
|
|
1743
1776
|
member = entry.fetch(:member)
|
|
1744
1777
|
original_member = entry.fetch(:original_member, member)
|
|
1745
1778
|
worktree_root = entry.fetch(:worktree_root)
|
|
1746
|
-
mise_config_roots_in_worktree(worktree_root, member.root).
|
|
1779
|
+
mise_config_roots_in_worktree(worktree_root, member.root).filter_map do |root|
|
|
1780
|
+
trust_argv = @mise_adapter.trust_argv(root)
|
|
1781
|
+
next unless trust_argv
|
|
1782
|
+
|
|
1747
1783
|
result = runner.call(
|
|
1748
1784
|
member: member,
|
|
1749
1785
|
phase: phase,
|
|
1750
|
-
command:
|
|
1786
|
+
command: trust_argv,
|
|
1751
1787
|
raw: true
|
|
1752
1788
|
)
|
|
1753
1789
|
result.member_name = original_member.name
|
|
@@ -2693,7 +2729,7 @@ module Kettle
|
|
|
2693
2729
|
end
|
|
2694
2730
|
|
|
2695
2731
|
def command_runner
|
|
2696
|
-
CommandRunner.new(execute: execute, accept: accept, gem_signing_password: @gem_signing_password)
|
|
2732
|
+
CommandRunner.new(execute: execute, accept: accept, gem_signing_password: @gem_signing_password, mise_adapter: @mise_adapter)
|
|
2697
2733
|
end
|
|
2698
2734
|
|
|
2699
2735
|
def release_command_runner
|
|
@@ -2704,7 +2740,8 @@ module Kettle
|
|
|
2704
2740
|
# RubyGems MFA belongs to the child release command. Keeping an OTP
|
|
2705
2741
|
# coordinator here can make a family-level gem retry look successful
|
|
2706
2742
|
# while skipping the child's checksums and GitHub release steps.
|
|
2707
|
-
otp_coordinator: nil
|
|
2743
|
+
otp_coordinator: nil,
|
|
2744
|
+
mise_adapter: @mise_adapter
|
|
2708
2745
|
)
|
|
2709
2746
|
end
|
|
2710
2747
|
|
data/lib/kettle/family.rb
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require_relative "family/member"
|
|
4
4
|
require_relative "family/command_result"
|
|
5
5
|
require_relative "family/release_state_result"
|
|
6
|
+
require_relative "family/mise_adapter"
|
|
6
7
|
require_relative "family/command_runner"
|
|
7
8
|
require_relative "family/readiness_check"
|
|
8
9
|
require_relative "family/published_version_check"
|
|
@@ -43,6 +44,25 @@ module Kettle
|
|
|
43
44
|
module Family
|
|
44
45
|
class Error < StandardError; end
|
|
45
46
|
|
|
47
|
+
# Default MiseAdapter for the whole family stack. CommandRunner, Workflow,
|
|
48
|
+
# and CLI use this when no adapter is injected; specs swap it to control
|
|
49
|
+
# mise availability without spawning the real binary (mise is operational
|
|
50
|
+
# glue, absent in CI).
|
|
51
|
+
#
|
|
52
|
+
# @return [MiseAdapter]
|
|
53
|
+
# rubocop:disable ThreadSafety/ClassInstanceVariable
|
|
54
|
+
def self.mise_adapter
|
|
55
|
+
@mise_adapter ||= MiseAdapter.new
|
|
56
|
+
end
|
|
57
|
+
# rubocop:enable ThreadSafety/ClassInstanceVariable
|
|
58
|
+
|
|
59
|
+
# @param adapter [MiseAdapter]
|
|
60
|
+
# rubocop:disable ThreadSafety/ClassInstanceVariable
|
|
61
|
+
def self.mise_adapter=(adapter)
|
|
62
|
+
@mise_adapter = adapter
|
|
63
|
+
end
|
|
64
|
+
# rubocop:enable ThreadSafety/ClassInstanceVariable
|
|
65
|
+
|
|
46
66
|
# kettle-jem plugin registration (kettle-jem-appraisals pattern). The gem
|
|
47
67
|
# name "kettle-family" resolves to this module as the plugin handle, and
|
|
48
68
|
# kettle-jem calls +register_kettle_jem_plugin(registrar)+ on it when the
|
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.3.
|
|
4
|
+
version: 1.3.30
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Peter H. Boling
|
|
@@ -134,7 +134,7 @@ dependencies:
|
|
|
134
134
|
version: '3.1'
|
|
135
135
|
- - ">="
|
|
136
136
|
- !ruby/object:Gem::Version
|
|
137
|
-
version: 3.1.
|
|
137
|
+
version: 3.1.23
|
|
138
138
|
type: :runtime
|
|
139
139
|
prerelease: false
|
|
140
140
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -144,7 +144,7 @@ dependencies:
|
|
|
144
144
|
version: '3.1'
|
|
145
145
|
- - ">="
|
|
146
146
|
- !ruby/object:Gem::Version
|
|
147
|
-
version: 3.1.
|
|
147
|
+
version: 3.1.23
|
|
148
148
|
- !ruby/object:Gem::Dependency
|
|
149
149
|
name: kettle-gha-pins
|
|
150
150
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -537,6 +537,7 @@ files:
|
|
|
537
537
|
- lib/kettle/family/local_install.rb
|
|
538
538
|
- lib/kettle/family/member.rb
|
|
539
539
|
- lib/kettle/family/member_loader.rb
|
|
540
|
+
- lib/kettle/family/mise_adapter.rb
|
|
540
541
|
- lib/kettle/family/mise_tasks.rb
|
|
541
542
|
- lib/kettle/family/nomono_bootstrap.rb
|
|
542
543
|
- lib/kettle/family/orderer.rb
|
|
@@ -567,10 +568,10 @@ licenses:
|
|
|
567
568
|
- AGPL-3.0-only
|
|
568
569
|
metadata:
|
|
569
570
|
homepage_uri: https://kettle-family.galtzo.com
|
|
570
|
-
source_code_uri: https://github.com/kettle-dev/kettle-family/tree/v1.3.
|
|
571
|
-
changelog_uri: https://github.com/kettle-dev/kettle-family/blob/v1.3.
|
|
571
|
+
source_code_uri: https://github.com/kettle-dev/kettle-family/tree/v1.3.30
|
|
572
|
+
changelog_uri: https://github.com/kettle-dev/kettle-family/blob/v1.3.30/CHANGELOG.md
|
|
572
573
|
bug_tracker_uri: https://github.com/kettle-dev/kettle-family/issues
|
|
573
|
-
documentation_uri: https://www.rubydoc.info/gems/kettle-family/1.3.
|
|
574
|
+
documentation_uri: https://www.rubydoc.info/gems/kettle-family/1.3.30
|
|
574
575
|
funding_uri: https://github.com/sponsors/pboling
|
|
575
576
|
wiki_uri: https://github.com/kettle-dev/kettle-family/wiki
|
|
576
577
|
news_uri: https://www.railsbling.com/tags/kettle-family
|
metadata.gz.sig
CHANGED
|
Binary file
|