kettle-dev 2.2.19 → 2.2.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 +0 -0
- data/CHANGELOG.md +31 -1
- data/README.md +1 -1
- data/exe/kettle-release +25 -3
- data/lib/kettle/dev/gha_sha_pins_cli.rb +24 -20
- data/lib/kettle/dev/git_adapter.rb +6 -4
- data/lib/kettle/dev/pre_release_cli.rb +6 -4
- data/lib/kettle/dev/rakelib/appraisal.rake +47 -19
- data/lib/kettle/dev/release_cli.rb +121 -23
- data/lib/kettle/dev/tasks/ci_task.rb +85 -79
- data/lib/kettle/dev/version.rb +1 -1
- data.tar.gz.sig +0 -0
- metadata +24 -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: 22a0bb59de4bca05c100302f2050a300c2a60a90a2124f2f5aa07c215c6b6919
|
|
4
|
+
data.tar.gz: 6b314236d27b59baa482317413c5b5c95303b9530b33693ee03841491ed00bc6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1f8a2d831b26d101a1ea8e381ff3cfc7bbce6d88682e70ec43c22a37b3ba047da5376247b5f32b1184f088514da8a1377f54ffcbe4def383b249515c70c3c518
|
|
7
|
+
data.tar.gz: 1aa2b1ceb5886238f9034491256e3c7fbdd5cbba121c27393288bced653f92051e43fec7f242a35b4cab7e316731e422a46c73c054548c96ee4b1537c6b371ac
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
data/CHANGELOG.md
CHANGED
|
@@ -30,6 +30,34 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
|
30
30
|
|
|
31
31
|
### Security
|
|
32
32
|
|
|
33
|
+
## [2.2.20] - 2026-06-27
|
|
34
|
+
|
|
35
|
+
- TAG: [v2.2.20][2.2.20t]
|
|
36
|
+
- COVERAGE: 91.82% -- 4131/4499 lines in 33 files
|
|
37
|
+
- BRANCH COVERAGE: 72.73% -- 1632/2244 branches in 33 files
|
|
38
|
+
- 61.04% documented
|
|
39
|
+
|
|
40
|
+
### Added
|
|
41
|
+
|
|
42
|
+
- `kettle-release` now accepts `skip_steps=...` / `--skip-steps ...` to skip
|
|
43
|
+
selected numbered release steps while running the rest of the release flow.
|
|
44
|
+
|
|
45
|
+
### Fixed
|
|
46
|
+
|
|
47
|
+
- `kettle-release` now suppresses inherited Bundler/debug verbosity when running
|
|
48
|
+
release child commands and Appraisal bundle installs.
|
|
49
|
+
|
|
50
|
+
- `kettle-release` now switches a local `RUBOCOP_LTS_LOCAL` checkout to the
|
|
51
|
+
branch matching the project's selected `rubocop-rubyN_N` style gem before
|
|
52
|
+
running setup and default rake tasks.
|
|
53
|
+
|
|
54
|
+
- Restored Ruby 2.4 parser compatibility for recent release and CI helper code.
|
|
55
|
+
|
|
56
|
+
### Changed
|
|
57
|
+
|
|
58
|
+
- `kettle-release` now reads RuboCop LTS branch selection from
|
|
59
|
+
`Kettle::Rb::CompatMatrix`.
|
|
60
|
+
|
|
33
61
|
## [2.2.19] - 2026-06-26
|
|
34
62
|
|
|
35
63
|
- TAG: [v2.2.19][2.2.19t]
|
|
@@ -2293,7 +2321,9 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
|
2293
2321
|
- Selecting will run the selected workflow via `act`
|
|
2294
2322
|
- This may move to its own gem in the future.
|
|
2295
2323
|
|
|
2296
|
-
[Unreleased]: https://github.com/kettle-dev/kettle-dev/compare/v2.2.
|
|
2324
|
+
[Unreleased]: https://github.com/kettle-dev/kettle-dev/compare/v2.2.20...HEAD
|
|
2325
|
+
[2.2.20]: https://github.com/kettle-dev/kettle-dev/compare/v2.2.19...v2.2.20
|
|
2326
|
+
[2.2.20t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v2.2.20
|
|
2297
2327
|
[2.2.19]: https://github.com/kettle-dev/kettle-dev/compare/v2.2.18...v2.2.19
|
|
2298
2328
|
[2.2.19t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v2.2.19
|
|
2299
2329
|
[2.2.18]: https://github.com/kettle-dev/kettle-dev/compare/v2.2.17...v2.2.18
|
data/README.md
CHANGED
|
@@ -874,7 +874,7 @@ Thanks for RTFM. ☺️
|
|
|
874
874
|
[📌gitmoji]: https://gitmoji.dev
|
|
875
875
|
[📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
|
|
876
876
|
[🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
|
|
877
|
-
[🧮kloc-img]: https://img.shields.io/badge/KLOC-4.
|
|
877
|
+
[🧮kloc-img]: https://img.shields.io/badge/KLOC-4.499-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
|
|
878
878
|
[🔐security]: https://github.com/kettle-dev/kettle-dev/blob/main/SECURITY.md
|
|
879
879
|
[🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
|
|
880
880
|
[📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
|
data/exe/kettle-release
CHANGED
|
@@ -43,7 +43,7 @@ end
|
|
|
43
43
|
# Do not guard with __FILE__ == $PROGRAM_NAME because binstubs use Kernel.load.
|
|
44
44
|
if ARGV.include?("-h") || ARGV.include?("--help")
|
|
45
45
|
puts <<~USAGE
|
|
46
|
-
Usage: kettle-release [--version VERSION] [--local-ci] [--appraisal-update] [start_step=<0-19>]
|
|
46
|
+
Usage: kettle-release [--version VERSION] [--local-ci] [--appraisal-update] [--skip-steps STEPS] [start_step=<0-19>]
|
|
47
47
|
|
|
48
48
|
Automates the release flow for a Ruby gem in the host project.
|
|
49
49
|
|
|
@@ -76,6 +76,8 @@ if ARGV.include?("-h") || ARGV.include?("--help")
|
|
|
76
76
|
|
|
77
77
|
Options:
|
|
78
78
|
start_step=<number> # Begin at the numbered step above (e.g., 10 to resume at CI monitoring)
|
|
79
|
+
skip_steps=<numbers> # Comma-separated numbered steps to skip while running the rest
|
|
80
|
+
--skip-steps NUMBERS # Alias for skip_steps=NUMBERS (e.g., --skip-steps 10 or --skip-steps 10,18)
|
|
79
81
|
--version VERSION # Use this version instead of detecting VERSION from lib/**/version.rb
|
|
80
82
|
--appraisal-update # Use slower appraisal:update instead of default appraisal:generate
|
|
81
83
|
--local-ci # Sensitive release mode: run act locally, publish before any git push,
|
|
@@ -97,12 +99,13 @@ if ARGV.include?("-h") || ARGV.include?("--help")
|
|
|
97
99
|
kettle-release --local-ci # run local act CI, publish gem, then push commits/tags
|
|
98
100
|
kettle-release start_step=1 # skip pre-release checks and start numbered release steps
|
|
99
101
|
kettle-release start_step=10 # resume by monitoring CI for the current branch
|
|
102
|
+
kettle-release skip_steps=10 # run the release but skip remote CI monitoring
|
|
100
103
|
SKIP_GEM_SIGNING=true kettle-release start_step=14 # build+release without signing
|
|
101
104
|
USAGE
|
|
102
105
|
exit 0
|
|
103
106
|
end
|
|
104
107
|
|
|
105
|
-
# Parse
|
|
108
|
+
# Parse release options from ARGV
|
|
106
109
|
def extract_version_arg!(argv)
|
|
107
110
|
version = nil
|
|
108
111
|
if (idx = argv.index("--version"))
|
|
@@ -121,14 +124,33 @@ def extract_version_arg!(argv)
|
|
|
121
124
|
Kettle::Dev::Versioning.normalize_explicit_version(version)
|
|
122
125
|
end
|
|
123
126
|
|
|
127
|
+
def extract_skip_steps_arg!(argv)
|
|
128
|
+
skip_steps = nil
|
|
129
|
+
if (idx = argv.index("--skip-steps"))
|
|
130
|
+
skip_steps = argv[idx + 1]
|
|
131
|
+
Kettle::Dev::ExitAdapter.abort("--skip-steps requires a comma-separated step list") if skip_steps.to_s.empty?
|
|
132
|
+
argv.slice!(idx, 2)
|
|
133
|
+
end
|
|
134
|
+
argv.delete_if do |arg|
|
|
135
|
+
if arg.start_with?("--skip-steps=", "skip_steps=")
|
|
136
|
+
skip_steps = arg.split("=", 2)[1]
|
|
137
|
+
true
|
|
138
|
+
else
|
|
139
|
+
false
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
skip_steps
|
|
143
|
+
end
|
|
144
|
+
|
|
124
145
|
local_ci = ARGV.include?("--local-ci")
|
|
125
146
|
appraisal_task = ARGV.delete("--appraisal-update") ? "appraisal:update" : nil
|
|
126
147
|
start_step_arg = ARGV.find { |a| a.start_with?("start_step=") }
|
|
127
148
|
start_step = start_step_arg ? start_step_arg.split("=", 2)[1].to_i : 0
|
|
128
149
|
version_override = extract_version_arg!(ARGV)
|
|
150
|
+
skip_steps = extract_skip_steps_arg!(ARGV)
|
|
129
151
|
|
|
130
152
|
begin
|
|
131
|
-
Kettle::Dev::ReleaseCLI.new(start_step: start_step, local_ci: local_ci, version: version_override, appraisal_task: appraisal_task).run
|
|
153
|
+
Kettle::Dev::ReleaseCLI.new(start_step: start_step, local_ci: local_ci, version: version_override, appraisal_task: appraisal_task, skip_steps: skip_steps).run
|
|
132
154
|
rescue LoadError => e
|
|
133
155
|
warn("#{script_basename}: could not load dependency: #{e.class}: #{e.message}")
|
|
134
156
|
warn(Array(e.backtrace).join("\n")) if ENV["DEBUG"]
|
|
@@ -264,9 +264,11 @@ module Kettle
|
|
|
264
264
|
@options[:progress] = bool
|
|
265
265
|
end
|
|
266
266
|
opt.on("--skip-pattern PATTERN", "Skip workflow paths matching pattern (repeatable)") do |pattern|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
267
|
+
begin
|
|
268
|
+
@options[:reject_patterns] << Regexp.new(pattern)
|
|
269
|
+
rescue RegexpError => e
|
|
270
|
+
Kettle::Dev::ExitAdapter.abort("Invalid --skip-pattern #{pattern.inspect}: #{e.message}")
|
|
271
|
+
end
|
|
270
272
|
end
|
|
271
273
|
opt.on("--[no-]validate", "Validate YAML after editing") do |bool|
|
|
272
274
|
@options[:validate] = bool
|
|
@@ -282,25 +284,27 @@ module Kettle
|
|
|
282
284
|
def load_workflows(paths, state)
|
|
283
285
|
file_progress = progress_bar(title: "Files", total: paths.length)
|
|
284
286
|
paths.each_with_object([]) do |path, workflows|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
287
|
+
begin
|
|
288
|
+
state[:files_scanned] += 1
|
|
289
|
+
text = begin
|
|
290
|
+
File.read(path)
|
|
291
|
+
rescue Errno::EACCES => e
|
|
292
|
+
record_failure(state, path: path, error: "read_error: #{e.message}")
|
|
293
|
+
next
|
|
294
|
+
end
|
|
292
295
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
296
|
+
parsed = begin
|
|
297
|
+
Psych.parse_stream(text)
|
|
298
|
+
rescue Psych::Exception => e
|
|
299
|
+
record_failure(state, path: path, error: "yaml_parse_error: #{e.message}")
|
|
300
|
+
next
|
|
301
|
+
end
|
|
299
302
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
303
|
+
uses_nodes = extract_uses_nodes(parsed, text)
|
|
304
|
+
workflows << {path: path, text: text, uses_nodes: uses_nodes} unless uses_nodes.empty?
|
|
305
|
+
ensure
|
|
306
|
+
file_progress&.increment
|
|
307
|
+
end
|
|
304
308
|
end
|
|
305
309
|
end
|
|
306
310
|
|
|
@@ -198,10 +198,12 @@ module Kettle
|
|
|
198
198
|
def remotes_with_urls
|
|
199
199
|
if @backend == :gem
|
|
200
200
|
@git.remotes.each_with_object({}) do |r, h|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
201
|
+
begin
|
|
202
|
+
h[r.name] = r.url
|
|
203
|
+
rescue => e
|
|
204
|
+
Kettle::Dev.debug_error(e, __method__)
|
|
205
|
+
# ignore
|
|
206
|
+
end
|
|
205
207
|
end
|
|
206
208
|
else
|
|
207
209
|
out, status = Open3.capture2("git", "remote", "-v")
|
|
@@ -253,10 +253,12 @@ module Kettle
|
|
|
253
253
|
Array(glob_pattern)
|
|
254
254
|
end
|
|
255
255
|
urls = files.flat_map do |f|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
256
|
+
begin
|
|
257
|
+
extract_image_urls_from_text(File.read(f))
|
|
258
|
+
rescue => e
|
|
259
|
+
warn("[kettle-pre-release] Could not read #{Kettle::Dev.display_path(f)}: #{e.class}: #{e.message}")
|
|
260
|
+
[]
|
|
261
|
+
end
|
|
260
262
|
end
|
|
261
263
|
urls.uniq
|
|
262
264
|
end
|
|
@@ -5,7 +5,27 @@ begin
|
|
|
5
5
|
require "appraisal/task"
|
|
6
6
|
|
|
7
7
|
bundle = "bundle"
|
|
8
|
-
|
|
8
|
+
quiet_env = {
|
|
9
|
+
"KETTLE_JEM_QUIET" => "true",
|
|
10
|
+
"KETTLE_JEM_DEBUG" => "false",
|
|
11
|
+
"KETTLE_DEV_DEBUG" => "false",
|
|
12
|
+
"SMORG_RB_DEBUG" => "false",
|
|
13
|
+
"DEBUG" => nil,
|
|
14
|
+
"BUNDLE_QUIET" => "true",
|
|
15
|
+
"BUNDLE_DEBUG" => "false",
|
|
16
|
+
"BUNDLER_DEBUG" => "false",
|
|
17
|
+
"BUNDLE_VERBOSE" => "false",
|
|
18
|
+
"DEBUG_RESOLVER" => nil,
|
|
19
|
+
"DEBUG_RESOLVER_TREE" => nil,
|
|
20
|
+
"BUNDLER_DEBUG_RESOLVER" => nil,
|
|
21
|
+
"BUNDLER_DEBUG_RESOLVER_TREE" => nil,
|
|
22
|
+
"DEBUG_COMPACT_INDEX" => nil,
|
|
23
|
+
"MOLINILLO_DEBUG" => nil,
|
|
24
|
+
"BUNDLE_SILENCE_DEPRECATIONS" => "true",
|
|
25
|
+
"BUNDLE_SILENCE_ROOT_WARNING" => "true",
|
|
26
|
+
"BUNDLE_SUPPRESS_INSTALL_USING_MESSAGES" => "true"
|
|
27
|
+
}
|
|
28
|
+
appraisal_env = quiet_env.merge("BUNDLE_GEMFILE" => "Appraisal.root.gemfile")
|
|
9
29
|
|
|
10
30
|
run_command = lambda do |failure_message, *args|
|
|
11
31
|
ok = system(*args)
|
|
@@ -18,7 +38,8 @@ begin
|
|
|
18
38
|
"appraisal:generate failed: BUNDLE_GEMFILE=Appraisal.root.gemfile bundle install",
|
|
19
39
|
appraisal_env,
|
|
20
40
|
bundle,
|
|
21
|
-
"install"
|
|
41
|
+
"install",
|
|
42
|
+
"--quiet"
|
|
22
43
|
)
|
|
23
44
|
|
|
24
45
|
# 2) BUNDLE_GEMFILE=Appraisal.root.gemfile bundle exec appraisal generate
|
|
@@ -33,18 +54,20 @@ begin
|
|
|
33
54
|
end
|
|
34
55
|
|
|
35
56
|
run_appraisal_task = lambda do |task_name, primary_steps = nil|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
57
|
+
begin
|
|
58
|
+
if primary_steps
|
|
59
|
+
begin
|
|
60
|
+
primary_steps.call
|
|
61
|
+
rescue RuntimeError => e
|
|
62
|
+
warn("[kettle-dev][#{task_name}] #{e.message}; falling back to appraisal:generate")
|
|
63
|
+
run_generate_steps.call
|
|
64
|
+
end
|
|
65
|
+
else
|
|
41
66
|
run_generate_steps.call
|
|
42
67
|
end
|
|
43
|
-
|
|
44
|
-
|
|
68
|
+
rescue RuntimeError => e
|
|
69
|
+
abort(e.message)
|
|
45
70
|
end
|
|
46
|
-
rescue RuntimeError => e
|
|
47
|
-
abort(e.message)
|
|
48
71
|
end
|
|
49
72
|
|
|
50
73
|
desc("Install Appraisal gemfiles (initial setup for projects that didn't previously use Appraisal)")
|
|
@@ -58,7 +81,8 @@ begin
|
|
|
58
81
|
"appraisal:install failed: BUNDLE_GEMFILE=Appraisal.root.gemfile bundle install",
|
|
59
82
|
appraisal_env,
|
|
60
83
|
bundle,
|
|
61
|
-
"install"
|
|
84
|
+
"install",
|
|
85
|
+
"--quiet"
|
|
62
86
|
)
|
|
63
87
|
|
|
64
88
|
# 2) BUNDLE_GEMFILE=Appraisal.root.gemfile bundle exec appraisal generate-install
|
|
@@ -105,7 +129,8 @@ begin
|
|
|
105
129
|
"appraisal:update failed: BUNDLE_GEMFILE=Appraisal.root.gemfile bundle install",
|
|
106
130
|
appraisal_env,
|
|
107
131
|
bundle,
|
|
108
|
-
"install"
|
|
132
|
+
"install",
|
|
133
|
+
"--quiet"
|
|
109
134
|
)
|
|
110
135
|
|
|
111
136
|
# 2) BUNDLE_GEMFILE=Appraisal.root.gemfile bundle update --bundler
|
|
@@ -122,7 +147,8 @@ begin
|
|
|
122
147
|
"appraisal:update failed: BUNDLE_GEMFILE=Appraisal.root.gemfile bundle install",
|
|
123
148
|
appraisal_env,
|
|
124
149
|
bundle,
|
|
125
|
-
"install"
|
|
150
|
+
"install",
|
|
151
|
+
"--quiet"
|
|
126
152
|
)
|
|
127
153
|
|
|
128
154
|
# 4) BUNDLE_GEMFILE=Appraisal.root.gemfile bundle exec appraisal generate-update
|
|
@@ -157,11 +183,13 @@ begin
|
|
|
157
183
|
else
|
|
158
184
|
failures = []
|
|
159
185
|
locks.each do |f|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
186
|
+
begin
|
|
187
|
+
File.delete(f)
|
|
188
|
+
rescue Errno::ENOENT
|
|
189
|
+
# Ignore if already gone
|
|
190
|
+
rescue => e
|
|
191
|
+
failures << [f, e]
|
|
192
|
+
end
|
|
165
193
|
end
|
|
166
194
|
|
|
167
195
|
unless failures.empty?
|
|
@@ -11,11 +11,33 @@ require "json"
|
|
|
11
11
|
require "uri"
|
|
12
12
|
|
|
13
13
|
# External gems
|
|
14
|
+
require "kettle/rb/compat_matrix"
|
|
14
15
|
require "ruby-progressbar"
|
|
15
16
|
|
|
16
17
|
module Kettle
|
|
17
18
|
module Dev
|
|
18
19
|
class ReleaseCLI
|
|
20
|
+
QUIET_ENV = {
|
|
21
|
+
"KETTLE_JEM_QUIET" => "true",
|
|
22
|
+
"KETTLE_JEM_DEBUG" => "false",
|
|
23
|
+
"KETTLE_DEV_DEBUG" => "false",
|
|
24
|
+
"SMORG_RB_DEBUG" => "false",
|
|
25
|
+
"DEBUG" => nil,
|
|
26
|
+
"BUNDLE_QUIET" => "true",
|
|
27
|
+
"BUNDLE_DEBUG" => "false",
|
|
28
|
+
"BUNDLER_DEBUG" => "false",
|
|
29
|
+
"BUNDLE_VERBOSE" => "false",
|
|
30
|
+
"DEBUG_RESOLVER" => nil,
|
|
31
|
+
"DEBUG_RESOLVER_TREE" => nil,
|
|
32
|
+
"BUNDLER_DEBUG_RESOLVER" => nil,
|
|
33
|
+
"BUNDLER_DEBUG_RESOLVER_TREE" => nil,
|
|
34
|
+
"DEBUG_COMPACT_INDEX" => nil,
|
|
35
|
+
"MOLINILLO_DEBUG" => nil,
|
|
36
|
+
"BUNDLE_SILENCE_DEPRECATIONS" => "true",
|
|
37
|
+
"BUNDLE_SILENCE_ROOT_WARNING" => "true",
|
|
38
|
+
"BUNDLE_SUPPRESS_INSTALL_USING_MESSAGES" => "true"
|
|
39
|
+
}.freeze
|
|
40
|
+
DEBUG_TRUE_VALUES = %w[1 true yes on].freeze
|
|
19
41
|
class << self
|
|
20
42
|
def run_cmd!(cmd)
|
|
21
43
|
# For Bundler-invoked build/release, explicitly prefix SKIP_GEM_SIGNING so
|
|
@@ -26,7 +48,7 @@ module Kettle
|
|
|
26
48
|
end
|
|
27
49
|
puts "$ #{cmd}"
|
|
28
50
|
# Pass a plain Hash for the environment to satisfy tests and avoid ENV object oddities
|
|
29
|
-
env_hash =
|
|
51
|
+
env_hash = command_env
|
|
30
52
|
|
|
31
53
|
# Some commands are interactive (e.g., `bundle exec rake release` prompting for RubyGems MFA).
|
|
32
54
|
# Using capture3 detaches STDIN, preventing prompts from working. For such commands, use system
|
|
@@ -62,6 +84,19 @@ module Kettle
|
|
|
62
84
|
abort("Command failed: #{cmd} (exit #{exit_code})#{diag}")
|
|
63
85
|
end
|
|
64
86
|
end
|
|
87
|
+
|
|
88
|
+
private
|
|
89
|
+
|
|
90
|
+
def command_env
|
|
91
|
+
env_hash = ENV.respond_to?(:to_hash) ? ENV.to_hash : ENV.to_h
|
|
92
|
+
return env_hash if debug_env_enabled?
|
|
93
|
+
|
|
94
|
+
env_hash.merge(QUIET_ENV)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def debug_env_enabled?
|
|
98
|
+
DEBUG_TRUE_VALUES.include?(ENV.fetch("KETTLE_DEV_DEBUG", "").downcase)
|
|
99
|
+
end
|
|
65
100
|
end
|
|
66
101
|
|
|
67
102
|
private
|
|
@@ -72,21 +107,22 @@ module Kettle
|
|
|
72
107
|
|
|
73
108
|
public
|
|
74
109
|
|
|
75
|
-
def initialize(start_step: 0, local_ci: false, version: nil, appraisal_task: nil)
|
|
110
|
+
def initialize(start_step: 0, local_ci: false, version: nil, appraisal_task: nil, skip_steps: nil)
|
|
76
111
|
@root = Kettle::Dev::CIHelpers.project_root
|
|
77
112
|
@git = Kettle::Dev::GitAdapter.new
|
|
78
113
|
@start_step = (start_step || 0).to_i
|
|
79
114
|
@start_step = 0 if @start_step < 0
|
|
115
|
+
@skip_steps = normalize_skip_steps(skip_steps)
|
|
80
116
|
@local_ci = !!local_ci
|
|
81
117
|
@version_override = Kettle::Dev::Versioning.normalize_explicit_version(version)
|
|
82
118
|
@appraisal_task = normalize_appraisal_task(appraisal_task || ENV["KETTLE_RELEASE_APPRAISAL_TASK"])
|
|
83
119
|
end
|
|
84
120
|
|
|
85
121
|
def run
|
|
86
|
-
run_pre_release_checks! if
|
|
122
|
+
run_pre_release_checks! if run_step?(0)
|
|
87
123
|
|
|
88
124
|
# 1. Ensure Bundler version ✓
|
|
89
|
-
ensure_bundler_2_7_plus!
|
|
125
|
+
ensure_bundler_2_7_plus! if run_step?(1)
|
|
90
126
|
|
|
91
127
|
version = nil
|
|
92
128
|
committed = nil
|
|
@@ -94,7 +130,7 @@ module Kettle
|
|
|
94
130
|
feature = nil
|
|
95
131
|
|
|
96
132
|
# 2. Version detection and sanity checks + prompt
|
|
97
|
-
if
|
|
133
|
+
if run_step?(2)
|
|
98
134
|
version = detect_version
|
|
99
135
|
puts "Detected version: #{version.inspect}"
|
|
100
136
|
|
|
@@ -186,13 +222,15 @@ module Kettle
|
|
|
186
222
|
end
|
|
187
223
|
end
|
|
188
224
|
|
|
225
|
+
prepare_rubocop_lts_local_branch! if rubocop_lts_release_preflight_needed?
|
|
226
|
+
|
|
189
227
|
# 3. bin/setup
|
|
190
|
-
run_cmd!("bin/setup") if
|
|
228
|
+
run_cmd!("bin/setup") if run_step?(3)
|
|
191
229
|
# 4. bin/rake
|
|
192
|
-
run_cmd!("bin/rake") if
|
|
230
|
+
run_cmd!("bin/rake") if run_step?(4)
|
|
193
231
|
|
|
194
232
|
# 5. appraisal:generate (optional) + canonical docs build
|
|
195
|
-
if
|
|
233
|
+
if run_step?(5)
|
|
196
234
|
appraisals_path = File.join(@root, "Appraisals")
|
|
197
235
|
if File.file?(appraisals_path)
|
|
198
236
|
puts "Appraisals detected at #{Kettle::Dev.display_path(appraisals_path)}. Running: bin/rake #{@appraisal_task}"
|
|
@@ -206,47 +244,47 @@ module Kettle
|
|
|
206
244
|
end
|
|
207
245
|
|
|
208
246
|
# 6. git user + commit release prep
|
|
209
|
-
if
|
|
247
|
+
if run_step?(6)
|
|
210
248
|
ensure_git_user!
|
|
211
249
|
version ||= detect_version
|
|
212
250
|
committed = commit_release_prep!(version)
|
|
213
251
|
end
|
|
214
252
|
|
|
215
253
|
# 7. optional local CI via act
|
|
216
|
-
maybe_run_local_ci_before_push!(committed, force: local_ci?) if
|
|
254
|
+
maybe_run_local_ci_before_push!(committed, force: local_ci?) if run_step?(7)
|
|
217
255
|
|
|
218
256
|
# 8. ensure trunk synced
|
|
219
|
-
if
|
|
257
|
+
if run_step?(8) && !local_ci?
|
|
220
258
|
trunk = detect_trunk_branch
|
|
221
259
|
feature = current_branch
|
|
222
260
|
puts "Trunk branch detected: #{trunk}"
|
|
223
261
|
ensure_trunk_synced_before_push!(trunk, feature)
|
|
224
|
-
elsif
|
|
262
|
+
elsif run_step?(8)
|
|
225
263
|
puts "Local CI release mode: skipping remote trunk sync before publishing."
|
|
226
264
|
end
|
|
227
265
|
|
|
228
266
|
# 9. push branches
|
|
229
|
-
push! if
|
|
267
|
+
push! if run_step?(9) && !local_ci?
|
|
230
268
|
|
|
231
269
|
# 10. monitor CI after push
|
|
232
|
-
monitor_workflows_after_push! if
|
|
270
|
+
monitor_workflows_after_push! if run_step?(10) && !local_ci?
|
|
233
271
|
|
|
234
272
|
# 11. merge feature into trunk and push
|
|
235
|
-
if
|
|
273
|
+
if run_step?(11) && !local_ci?
|
|
236
274
|
trunk ||= detect_trunk_branch
|
|
237
275
|
feature ||= current_branch
|
|
238
276
|
merge_feature_into_trunk_and_push!(trunk, feature)
|
|
239
277
|
end
|
|
240
278
|
|
|
241
279
|
# 12. checkout trunk and pull
|
|
242
|
-
if
|
|
280
|
+
if run_step?(12) && !local_ci?
|
|
243
281
|
trunk ||= detect_trunk_branch
|
|
244
282
|
checkout!(trunk)
|
|
245
283
|
pull!(trunk)
|
|
246
284
|
end
|
|
247
285
|
|
|
248
286
|
# 13. signing guidance and checks
|
|
249
|
-
if
|
|
287
|
+
if run_step?(13)
|
|
250
288
|
if ENV.fetch("SKIP_GEM_SIGNING", "false").casecmp("false").zero?
|
|
251
289
|
puts "TIP: For local dry-runs or testing the release workflow, set SKIP_GEM_SIGNING=true to avoid PEM password prompts."
|
|
252
290
|
if Kettle::Dev::InputAdapter.tty?
|
|
@@ -267,13 +305,13 @@ module Kettle
|
|
|
267
305
|
end
|
|
268
306
|
|
|
269
307
|
# 14. build
|
|
270
|
-
if
|
|
308
|
+
if run_step?(14)
|
|
271
309
|
puts "Running build (you may be prompted for the signing key password)..."
|
|
272
310
|
run_cmd!("bundle exec rake build")
|
|
273
311
|
end
|
|
274
312
|
|
|
275
313
|
# 15. release and tag
|
|
276
|
-
if
|
|
314
|
+
if run_step?(15)
|
|
277
315
|
if local_ci?
|
|
278
316
|
version ||= detect_version
|
|
279
317
|
release_gem_and_tag_locally!(version)
|
|
@@ -287,7 +325,7 @@ module Kettle
|
|
|
287
325
|
# Checksums are generated after release to avoid including checksums/ in gem package
|
|
288
326
|
# Rationale: Running gem_checksums before release may commit checksums/ and cause Bundler's
|
|
289
327
|
# release build to include them in the gem, thus altering the artifact, and invalidating the checksums.
|
|
290
|
-
if
|
|
328
|
+
if run_step?(16)
|
|
291
329
|
# Generate checksums for the just-built artifact, commit them, then validate
|
|
292
330
|
run_cmd!("bin/gem_checksums")
|
|
293
331
|
version ||= detect_version
|
|
@@ -295,19 +333,19 @@ module Kettle
|
|
|
295
333
|
end
|
|
296
334
|
|
|
297
335
|
# 17. push checksum commit (gem_checksums already commits)
|
|
298
|
-
if
|
|
336
|
+
if run_step?(17)
|
|
299
337
|
push!
|
|
300
338
|
push_tags! if local_ci?
|
|
301
339
|
end
|
|
302
340
|
|
|
303
341
|
# 18. create GitHub release (optional)
|
|
304
|
-
if
|
|
342
|
+
if run_step?(18)
|
|
305
343
|
version ||= detect_version
|
|
306
344
|
maybe_create_github_release!(version)
|
|
307
345
|
end
|
|
308
346
|
|
|
309
347
|
# 19. push tags to remotes (final step)
|
|
310
|
-
push_tags! if
|
|
348
|
+
push_tags! if run_step?(19) && !local_ci?
|
|
311
349
|
|
|
312
350
|
# Final success message
|
|
313
351
|
begin
|
|
@@ -330,12 +368,72 @@ module Kettle
|
|
|
330
368
|
abort("Unsupported appraisal task #{value.inspect}; use appraisal:generate or appraisal:update.")
|
|
331
369
|
end
|
|
332
370
|
|
|
371
|
+
def normalize_skip_steps(value)
|
|
372
|
+
raw_steps = Array(value).flat_map { |part| part.to_s.split(",") }.map(&:strip).reject(&:empty?)
|
|
373
|
+
raw_steps.map do |raw|
|
|
374
|
+
abort("Invalid skip_steps value #{raw.inspect}; use comma-separated release step numbers from 0 to 19.") unless raw.match?(/\A\d+\z/)
|
|
375
|
+
|
|
376
|
+
step = raw.to_i
|
|
377
|
+
abort("Invalid skip_steps value #{raw.inspect}; release steps are numbered 0 to 19.") unless step.between?(0, 19)
|
|
378
|
+
|
|
379
|
+
step
|
|
380
|
+
end.uniq
|
|
381
|
+
end
|
|
382
|
+
|
|
333
383
|
private
|
|
334
384
|
|
|
335
385
|
def local_ci?
|
|
336
386
|
@local_ci
|
|
337
387
|
end
|
|
338
388
|
|
|
389
|
+
def run_step?(step)
|
|
390
|
+
@start_step <= step && !@skip_steps.include?(step)
|
|
391
|
+
end
|
|
392
|
+
|
|
393
|
+
def rubocop_lts_release_preflight_needed?
|
|
394
|
+
(3..5).any? { |step| run_step?(step) }
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
def prepare_rubocop_lts_local_branch!
|
|
398
|
+
local_root = rubocop_lts_local_root
|
|
399
|
+
return unless local_root
|
|
400
|
+
|
|
401
|
+
ruby_gem = selected_rubocop_lts_ruby_gem
|
|
402
|
+
return unless ruby_gem
|
|
403
|
+
|
|
404
|
+
branch = Kettle::Rb::CompatMatrix.rubocop_lts_branch_for_gem(ruby_gem)
|
|
405
|
+
abort("Cannot select RUBOCOP_LTS_LOCAL branch for #{ruby_gem.inspect}.") unless branch
|
|
406
|
+
|
|
407
|
+
checkout = File.join(local_root, "rubocop-lts")
|
|
408
|
+
current, ok = git_output(["-C", checkout, "branch", "--show-current"])
|
|
409
|
+
abort("Cannot inspect RUBOCOP_LTS_LOCAL checkout at #{checkout}.") unless ok
|
|
410
|
+
return if current == branch
|
|
411
|
+
|
|
412
|
+
puts "Switching RUBOCOP_LTS_LOCAL checkout #{checkout} to #{branch} for #{ruby_gem}."
|
|
413
|
+
_stdout, switched = git_output(["-C", checkout, "switch", branch])
|
|
414
|
+
abort("Cannot switch RUBOCOP_LTS_LOCAL checkout at #{checkout} to #{branch}. Commit or stash local changes, then retry.") unless switched
|
|
415
|
+
end
|
|
416
|
+
|
|
417
|
+
def rubocop_lts_local_root
|
|
418
|
+
value = ENV["RUBOCOP_LTS_LOCAL"].to_s.strip
|
|
419
|
+
return nil if value.empty? || %w[false 0 no off].include?(value.downcase)
|
|
420
|
+
return File.join(Dir.home, "src", "rubocop-lts") if %w[true 1 yes on].include?(value.downcase)
|
|
421
|
+
return value if value.start_with?("/")
|
|
422
|
+
|
|
423
|
+
File.join(Dir.home, value)
|
|
424
|
+
end
|
|
425
|
+
|
|
426
|
+
def selected_rubocop_lts_ruby_gem
|
|
427
|
+
path = File.join(@root, "gemfiles", "modular", "style_local.gemfile")
|
|
428
|
+
return nil unless File.file?(path)
|
|
429
|
+
|
|
430
|
+
content = File.read(path)
|
|
431
|
+
# This reads the generated kettle-jem style_local.gemfile declaration
|
|
432
|
+
# without evaluating the Gemfile during release preflight.
|
|
433
|
+
local_gems = content[/\blocal_gems\s*=\s*%w\[(.*?)\]/m, 1].to_s.split
|
|
434
|
+
local_gems.find { |gem_name| Kettle::Rb::CompatMatrix.rubocop_ruby_gem?(gem_name) }
|
|
435
|
+
end
|
|
436
|
+
|
|
339
437
|
def run_pre_release_checks!
|
|
340
438
|
puts "Running pre-release checks via kettle-pre-release..."
|
|
341
439
|
Kettle::Dev::PreReleaseCLI.new(check_num: 1).run
|
|
@@ -91,46 +91,48 @@ module Kettle
|
|
|
91
91
|
|
|
92
92
|
# Print GitLab pipeline status (if configured) for the current branch.
|
|
93
93
|
print_gitlab_status = proc do
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
94
|
+
begin
|
|
95
|
+
branch = Kettle::Dev::CIHelpers.current_branch
|
|
96
|
+
# Detect any GitLab remote (not just origin), mirroring CIMonitor behavior
|
|
97
|
+
gl_remotes = Kettle::Dev::CIMonitor.gitlab_remote_candidates
|
|
98
|
+
if gl_remotes.nil? || gl_remotes.empty? || branch.nil?
|
|
99
|
+
puts "Latest GL (#{branch || "n/a"}) pipeline: n/a"
|
|
100
|
+
next
|
|
101
|
+
end
|
|
101
102
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
103
|
+
# Parse owner/repo from the first GitLab remote URL
|
|
104
|
+
gl_url = Kettle::Dev::CIMonitor.remote_url(gl_remotes.first)
|
|
105
|
+
owner = repo = nil
|
|
106
|
+
if gl_url =~ %r{git@gitlab.com:(.+?)/(.+?)(\.git)?$}
|
|
107
|
+
owner = Regexp.last_match(1)
|
|
108
|
+
repo = Regexp.last_match(2).sub(/\.git\z/, "")
|
|
109
|
+
elsif gl_url =~ %r{https://gitlab.com/(.+?)/(.+?)(\.git)?$}
|
|
110
|
+
owner = Regexp.last_match(1)
|
|
111
|
+
repo = Regexp.last_match(2).sub(/\.git\z/, "")
|
|
112
|
+
end
|
|
112
113
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
114
|
+
unless owner && repo
|
|
115
|
+
puts "Latest GL (#{branch}) pipeline: n/a"
|
|
116
|
+
next
|
|
117
|
+
end
|
|
117
118
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
119
|
+
pipe = Kettle::Dev::CIHelpers.gitlab_latest_pipeline(owner: owner, repo: repo, branch: branch)
|
|
120
|
+
if pipe
|
|
121
|
+
st = pipe["status"].to_s
|
|
122
|
+
status = if st == "success"
|
|
123
|
+
"success"
|
|
124
|
+
else
|
|
125
|
+
((st == "failed") ? "failure" : nil)
|
|
126
|
+
end
|
|
127
|
+
emoji = Kettle::Dev::CIMonitor.status_emoji(st, status)
|
|
128
|
+
details = [st, pipe["failure_reason"]].compact.join("/")
|
|
129
|
+
puts "Latest GL (#{branch}) pipeline: #{emoji} (#{details})"
|
|
123
130
|
else
|
|
124
|
-
|
|
131
|
+
puts "Latest GL (#{branch}) pipeline: none"
|
|
125
132
|
end
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
puts "Latest GL (#{branch}) pipeline: #{emoji} (#{details})"
|
|
129
|
-
else
|
|
130
|
-
puts "Latest GL (#{branch}) pipeline: none"
|
|
133
|
+
rescue => e
|
|
134
|
+
puts "GL status: error #{e.class}: #{e.message}"
|
|
131
135
|
end
|
|
132
|
-
rescue => e
|
|
133
|
-
puts "GL status: error #{e.class}: #{e.message}"
|
|
134
136
|
end
|
|
135
137
|
|
|
136
138
|
run_act_for = proc do |file_path|
|
|
@@ -262,10 +264,12 @@ module Kettle
|
|
|
262
264
|
selected = nil
|
|
263
265
|
input_thread = nil
|
|
264
266
|
read_input = proc do
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
267
|
+
begin
|
|
268
|
+
selected = Kettle::Dev::InputAdapter.gets&.strip
|
|
269
|
+
rescue StandardError, SystemExit, Interrupt => error
|
|
270
|
+
puts "Error reading input: #{error.class}: #{error.message}" if Kettle::Dev::DEBUGGING
|
|
271
|
+
selected = :input_error
|
|
272
|
+
end
|
|
269
273
|
end
|
|
270
274
|
if tty
|
|
271
275
|
input_thread = Thread.new(&read_input) # rubocop:disable ThreadSafety/NewThread
|
|
@@ -279,52 +283,54 @@ module Kettle
|
|
|
279
283
|
|
|
280
284
|
options.each do |code, file|
|
|
281
285
|
workers << Thread.new(code, file, owner, repo, branch, token, start_at) do |c, f, ow, rp, br, tk, st_at| # rubocop:disable ThreadSafety/NewThread
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
286
|
+
begin
|
|
287
|
+
now = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
288
|
+
delay = 0.12 - (now - st_at)
|
|
289
|
+
sleep(delay) if delay && delay > 0
|
|
290
|
+
|
|
291
|
+
if ow.nil? || rp.nil? || br.nil?
|
|
292
|
+
status_q << [c, f, "n/a"]
|
|
293
|
+
Thread.exit
|
|
294
|
+
end
|
|
295
|
+
uri = URI("https://api.github.com/repos/#{ow}/#{rp}/actions/workflows/#{f}/runs?branch=#{URI.encode_www_form_component(br)}&per_page=1")
|
|
296
|
+
poll_interval = Integer(ENV["CI_ACT_POLL_INTERVAL"] || 5)
|
|
297
|
+
loop do
|
|
298
|
+
begin
|
|
299
|
+
req = Net::HTTP::Get.new(uri)
|
|
300
|
+
req["User-Agent"] = "ci:act rake task"
|
|
301
|
+
req["Authorization"] = "token #{tk}" if tk && !tk.empty?
|
|
302
|
+
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
|
|
303
|
+
if res.is_a?(Net::HTTPSuccess)
|
|
304
|
+
data = JSON.parse(res.body)
|
|
305
|
+
run = data["workflow_runs"]&.first
|
|
306
|
+
if run
|
|
307
|
+
st = run["status"]
|
|
308
|
+
con = run["conclusion"]
|
|
309
|
+
emoji = Kettle::Dev::CIMonitor.status_emoji(st, con)
|
|
310
|
+
details = [st, con].compact.join("/")
|
|
311
|
+
status_q << [c, f, "#{emoji} (#{details})"]
|
|
312
|
+
break if st == "completed"
|
|
313
|
+
else
|
|
314
|
+
status_q << [c, f, "none"]
|
|
315
|
+
break
|
|
316
|
+
end
|
|
308
317
|
else
|
|
309
|
-
status_q << [c, f, "
|
|
310
|
-
break
|
|
318
|
+
status_q << [c, f, "fail #{res.code}"]
|
|
311
319
|
end
|
|
312
|
-
|
|
313
|
-
|
|
320
|
+
rescue Exception => e # rubocop:disable Lint/RescueException
|
|
321
|
+
Kettle::Dev.debug_error(e, __method__)
|
|
322
|
+
# Catch all exceptions to prevent crashing the process from a worker thread
|
|
323
|
+
status_q << [c, f, "err"]
|
|
314
324
|
end
|
|
315
|
-
|
|
316
|
-
Kettle::Dev.debug_error(e, __method__)
|
|
317
|
-
# Catch all exceptions to prevent crashing the process from a worker thread
|
|
318
|
-
status_q << [c, f, "err"]
|
|
325
|
+
sleep(poll_interval)
|
|
319
326
|
end
|
|
320
|
-
|
|
327
|
+
rescue Exception => e # rubocop:disable Lint/RescueException
|
|
328
|
+
Kettle::Dev.debug_error(e, __method__)
|
|
329
|
+
# simplecov:disable
|
|
330
|
+
# Catch all exceptions in the worker thread boundary, including SystemExit
|
|
331
|
+
status_q << [c, f, "err"]
|
|
332
|
+
# simplecov:enable
|
|
321
333
|
end
|
|
322
|
-
rescue Exception => e # rubocop:disable Lint/RescueException
|
|
323
|
-
Kettle::Dev.debug_error(e, __method__)
|
|
324
|
-
# simplecov:disable
|
|
325
|
-
# Catch all exceptions in the worker thread boundary, including SystemExit
|
|
326
|
-
status_q << [c, f, "err"]
|
|
327
|
-
# simplecov:enable
|
|
328
334
|
end
|
|
329
335
|
end
|
|
330
336
|
|
data/lib/kettle/dev/version.rb
CHANGED
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: 2.2.
|
|
4
|
+
version: 2.2.20
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Peter H. Boling
|
|
@@ -37,6 +37,26 @@ cert_chain:
|
|
|
37
37
|
-----END CERTIFICATE-----
|
|
38
38
|
date: 1980-01-02 00:00:00.000000000 Z
|
|
39
39
|
dependencies:
|
|
40
|
+
- !ruby/object:Gem::Dependency
|
|
41
|
+
name: kettle-rb
|
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - "~>"
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '0.1'
|
|
47
|
+
- - ">="
|
|
48
|
+
- !ruby/object:Gem::Version
|
|
49
|
+
version: 0.1.0
|
|
50
|
+
type: :runtime
|
|
51
|
+
prerelease: false
|
|
52
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
53
|
+
requirements:
|
|
54
|
+
- - "~>"
|
|
55
|
+
- !ruby/object:Gem::Version
|
|
56
|
+
version: '0.1'
|
|
57
|
+
- - ">="
|
|
58
|
+
- !ruby/object:Gem::Version
|
|
59
|
+
version: 0.1.0
|
|
40
60
|
- !ruby/object:Gem::Dependency
|
|
41
61
|
name: kettle-test
|
|
42
62
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -339,10 +359,10 @@ licenses:
|
|
|
339
359
|
- AGPL-3.0-only
|
|
340
360
|
metadata:
|
|
341
361
|
homepage_uri: https://kettle-dev.galtzo.com
|
|
342
|
-
source_code_uri: https://github.com/kettle-dev/kettle-dev/tree/v2.2.
|
|
343
|
-
changelog_uri: https://github.com/kettle-dev/kettle-dev/blob/v2.2.
|
|
362
|
+
source_code_uri: https://github.com/kettle-dev/kettle-dev/tree/v2.2.20
|
|
363
|
+
changelog_uri: https://github.com/kettle-dev/kettle-dev/blob/v2.2.20/CHANGELOG.md
|
|
344
364
|
bug_tracker_uri: https://github.com/kettle-dev/kettle-dev/issues
|
|
345
|
-
documentation_uri: https://www.rubydoc.info/gems/kettle-dev/2.2.
|
|
365
|
+
documentation_uri: https://www.rubydoc.info/gems/kettle-dev/2.2.20
|
|
346
366
|
funding_uri: https://github.com/sponsors/pboling
|
|
347
367
|
wiki_uri: https://github.com/kettle-dev/kettle-dev/wiki
|
|
348
368
|
news_uri: https://www.railsbling.com/tags/kettle-dev
|
metadata.gz.sig
CHANGED
|
Binary file
|