kettle-dev 2.2.19 → 2.2.21
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 +46 -1
- data/README.md +1 -1
- data/exe/kettle-release +25 -3
- data/lib/kettle/dev/gem_spec_reader.rb +1 -1
- 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 +180 -27
- 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: 5c84739dfdebb3ae9c5c6fd438c7cc1db6e5707d9cecfe7a3e2e754e41390301
|
|
4
|
+
data.tar.gz: 9e1f2b9e2f3c842c218977027c6cf69c1a753072f2d281e39239dc3e7097e9ee
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 287be3949983f25366e89ec2de3058bc63cf14dee7ff5b45a5da6a49a09d524493e91318788a370bb6ff92d4bed313771596368638f5026802850523be74f4df
|
|
7
|
+
data.tar.gz: 20bf852b21d4fa605b151e9ee4fe91b50921fa7320ded4ec937951e3cfcc4177ae653246448139ede0188d4741d70f0b5d1b7afce04ed042442d31cbbbb4f98b
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
data/CHANGELOG.md
CHANGED
|
@@ -30,6 +30,47 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
|
30
30
|
|
|
31
31
|
### Security
|
|
32
32
|
|
|
33
|
+
## [2.2.21] - 2026-06-28
|
|
34
|
+
|
|
35
|
+
- TAG: [v2.2.21][2.2.21t]
|
|
36
|
+
- COVERAGE: 92.34% -- 4182/4529 lines in 33 files
|
|
37
|
+
- BRANCH COVERAGE: 73.34% -- 1659/2262 branches in 33 files
|
|
38
|
+
- 61.04% documented
|
|
39
|
+
|
|
40
|
+
### Fixed
|
|
41
|
+
|
|
42
|
+
- `kettle-release` now detects local `.kettle-family.yml` branch-stack release
|
|
43
|
+
targets and skips trunk sync, trunk merge, and trunk checkout for those release
|
|
44
|
+
branches.
|
|
45
|
+
|
|
46
|
+
## [2.2.20] - 2026-06-27
|
|
47
|
+
|
|
48
|
+
- TAG: [v2.2.20][2.2.20t]
|
|
49
|
+
- COVERAGE: 91.82% -- 4131/4499 lines in 33 files
|
|
50
|
+
- BRANCH COVERAGE: 72.73% -- 1632/2244 branches in 33 files
|
|
51
|
+
- 61.04% documented
|
|
52
|
+
|
|
53
|
+
### Added
|
|
54
|
+
|
|
55
|
+
- `kettle-release` now accepts `skip_steps=...` / `--skip-steps ...` to skip
|
|
56
|
+
selected numbered release steps while running the rest of the release flow.
|
|
57
|
+
|
|
58
|
+
### Fixed
|
|
59
|
+
|
|
60
|
+
- `kettle-release` now suppresses inherited Bundler/debug verbosity when running
|
|
61
|
+
release child commands and Appraisal bundle installs.
|
|
62
|
+
|
|
63
|
+
- `kettle-release` now switches a local `RUBOCOP_LTS_LOCAL` checkout to the
|
|
64
|
+
branch matching the project's selected `rubocop-rubyN_N` style gem before
|
|
65
|
+
running setup and default rake tasks.
|
|
66
|
+
|
|
67
|
+
- Restored Ruby 2.4 parser compatibility for recent release and CI helper code.
|
|
68
|
+
|
|
69
|
+
### Changed
|
|
70
|
+
|
|
71
|
+
- `kettle-release` now reads RuboCop LTS branch selection from
|
|
72
|
+
`Kettle::Rb::CompatMatrix`.
|
|
73
|
+
|
|
33
74
|
## [2.2.19] - 2026-06-26
|
|
34
75
|
|
|
35
76
|
- TAG: [v2.2.19][2.2.19t]
|
|
@@ -2293,7 +2334,11 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
|
2293
2334
|
- Selecting will run the selected workflow via `act`
|
|
2294
2335
|
- This may move to its own gem in the future.
|
|
2295
2336
|
|
|
2296
|
-
[Unreleased]: https://github.com/kettle-dev/kettle-dev/compare/v2.2.
|
|
2337
|
+
[Unreleased]: https://github.com/kettle-dev/kettle-dev/compare/v2.2.21...HEAD
|
|
2338
|
+
[2.2.21]: https://github.com/kettle-dev/kettle-dev/compare/v2.2.20...v2.2.21
|
|
2339
|
+
[2.2.21t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v2.2.21
|
|
2340
|
+
[2.2.20]: https://github.com/kettle-dev/kettle-dev/compare/v2.2.19...v2.2.20
|
|
2341
|
+
[2.2.20t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v2.2.20
|
|
2297
2342
|
[2.2.19]: https://github.com/kettle-dev/kettle-dev/compare/v2.2.18...v2.2.19
|
|
2298
2343
|
[2.2.19t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v2.2.19
|
|
2299
2344
|
[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.529-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"]
|
|
@@ -196,7 +196,7 @@ module Kettle
|
|
|
196
196
|
end
|
|
197
197
|
|
|
198
198
|
def declared_version_file_path(root)
|
|
199
|
-
gemspec_path = Dir.glob(File.join(root.to_s, "*.gemspec")).
|
|
199
|
+
gemspec_path = Dir.glob(File.join(root.to_s, "*.gemspec")).min
|
|
200
200
|
return unless gemspec_path && File.file?(gemspec_path)
|
|
201
201
|
|
|
202
202
|
gemspec_source = File.read(gemspec_path)
|
|
@@ -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?
|
|
@@ -9,13 +9,36 @@ require "fileutils"
|
|
|
9
9
|
require "net/http"
|
|
10
10
|
require "json"
|
|
11
11
|
require "uri"
|
|
12
|
+
require "yaml"
|
|
12
13
|
|
|
13
14
|
# External gems
|
|
15
|
+
require "kettle/rb/compat_matrix"
|
|
14
16
|
require "ruby-progressbar"
|
|
15
17
|
|
|
16
18
|
module Kettle
|
|
17
19
|
module Dev
|
|
18
20
|
class ReleaseCLI
|
|
21
|
+
QUIET_ENV = {
|
|
22
|
+
"KETTLE_JEM_QUIET" => "true",
|
|
23
|
+
"KETTLE_JEM_DEBUG" => "false",
|
|
24
|
+
"KETTLE_DEV_DEBUG" => "false",
|
|
25
|
+
"SMORG_RB_DEBUG" => "false",
|
|
26
|
+
"DEBUG" => nil,
|
|
27
|
+
"BUNDLE_QUIET" => "true",
|
|
28
|
+
"BUNDLE_DEBUG" => "false",
|
|
29
|
+
"BUNDLER_DEBUG" => "false",
|
|
30
|
+
"BUNDLE_VERBOSE" => "false",
|
|
31
|
+
"DEBUG_RESOLVER" => nil,
|
|
32
|
+
"DEBUG_RESOLVER_TREE" => nil,
|
|
33
|
+
"BUNDLER_DEBUG_RESOLVER" => nil,
|
|
34
|
+
"BUNDLER_DEBUG_RESOLVER_TREE" => nil,
|
|
35
|
+
"DEBUG_COMPACT_INDEX" => nil,
|
|
36
|
+
"MOLINILLO_DEBUG" => nil,
|
|
37
|
+
"BUNDLE_SILENCE_DEPRECATIONS" => "true",
|
|
38
|
+
"BUNDLE_SILENCE_ROOT_WARNING" => "true",
|
|
39
|
+
"BUNDLE_SUPPRESS_INSTALL_USING_MESSAGES" => "true"
|
|
40
|
+
}.freeze
|
|
41
|
+
DEBUG_TRUE_VALUES = %w[1 true yes on].freeze
|
|
19
42
|
class << self
|
|
20
43
|
def run_cmd!(cmd)
|
|
21
44
|
# For Bundler-invoked build/release, explicitly prefix SKIP_GEM_SIGNING so
|
|
@@ -26,7 +49,7 @@ module Kettle
|
|
|
26
49
|
end
|
|
27
50
|
puts "$ #{cmd}"
|
|
28
51
|
# Pass a plain Hash for the environment to satisfy tests and avoid ENV object oddities
|
|
29
|
-
env_hash =
|
|
52
|
+
env_hash = command_env
|
|
30
53
|
|
|
31
54
|
# Some commands are interactive (e.g., `bundle exec rake release` prompting for RubyGems MFA).
|
|
32
55
|
# Using capture3 detaches STDIN, preventing prompts from working. For such commands, use system
|
|
@@ -62,6 +85,19 @@ module Kettle
|
|
|
62
85
|
abort("Command failed: #{cmd} (exit #{exit_code})#{diag}")
|
|
63
86
|
end
|
|
64
87
|
end
|
|
88
|
+
|
|
89
|
+
private
|
|
90
|
+
|
|
91
|
+
def command_env
|
|
92
|
+
env_hash = ENV.respond_to?(:to_hash) ? ENV.to_hash : ENV.to_h
|
|
93
|
+
return env_hash if debug_env_enabled?
|
|
94
|
+
|
|
95
|
+
env_hash.merge(QUIET_ENV)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def debug_env_enabled?
|
|
99
|
+
DEBUG_TRUE_VALUES.include?(ENV.fetch("KETTLE_DEV_DEBUG", "").downcase)
|
|
100
|
+
end
|
|
65
101
|
end
|
|
66
102
|
|
|
67
103
|
private
|
|
@@ -72,29 +108,31 @@ module Kettle
|
|
|
72
108
|
|
|
73
109
|
public
|
|
74
110
|
|
|
75
|
-
def initialize(start_step: 0, local_ci: false, version: nil, appraisal_task: nil)
|
|
111
|
+
def initialize(start_step: 0, local_ci: false, version: nil, appraisal_task: nil, skip_steps: nil)
|
|
76
112
|
@root = Kettle::Dev::CIHelpers.project_root
|
|
77
113
|
@git = Kettle::Dev::GitAdapter.new
|
|
78
114
|
@start_step = (start_step || 0).to_i
|
|
79
115
|
@start_step = 0 if @start_step < 0
|
|
116
|
+
@skip_steps = normalize_skip_steps(skip_steps)
|
|
80
117
|
@local_ci = !!local_ci
|
|
81
118
|
@version_override = Kettle::Dev::Versioning.normalize_explicit_version(version)
|
|
82
119
|
@appraisal_task = normalize_appraisal_task(appraisal_task || ENV["KETTLE_RELEASE_APPRAISAL_TASK"])
|
|
83
120
|
end
|
|
84
121
|
|
|
85
122
|
def run
|
|
86
|
-
run_pre_release_checks! if
|
|
123
|
+
run_pre_release_checks! if run_step?(0)
|
|
87
124
|
|
|
88
125
|
# 1. Ensure Bundler version ✓
|
|
89
|
-
ensure_bundler_2_7_plus!
|
|
126
|
+
ensure_bundler_2_7_plus! if run_step?(1)
|
|
90
127
|
|
|
91
128
|
version = nil
|
|
92
129
|
committed = nil
|
|
93
130
|
trunk = nil
|
|
94
131
|
feature = nil
|
|
132
|
+
branch_stack_release = false
|
|
95
133
|
|
|
96
134
|
# 2. Version detection and sanity checks + prompt
|
|
97
|
-
if
|
|
135
|
+
if run_step?(2)
|
|
98
136
|
version = detect_version
|
|
99
137
|
puts "Detected version: #{version.inspect}"
|
|
100
138
|
|
|
@@ -186,13 +224,15 @@ module Kettle
|
|
|
186
224
|
end
|
|
187
225
|
end
|
|
188
226
|
|
|
227
|
+
prepare_rubocop_lts_local_branch! if rubocop_lts_release_preflight_needed?
|
|
228
|
+
|
|
189
229
|
# 3. bin/setup
|
|
190
|
-
run_cmd!("bin/setup") if
|
|
230
|
+
run_cmd!("bin/setup") if run_step?(3)
|
|
191
231
|
# 4. bin/rake
|
|
192
|
-
run_cmd!("bin/rake") if
|
|
232
|
+
run_cmd!("bin/rake") if run_step?(4)
|
|
193
233
|
|
|
194
234
|
# 5. appraisal:generate (optional) + canonical docs build
|
|
195
|
-
if
|
|
235
|
+
if run_step?(5)
|
|
196
236
|
appraisals_path = File.join(@root, "Appraisals")
|
|
197
237
|
if File.file?(appraisals_path)
|
|
198
238
|
puts "Appraisals detected at #{Kettle::Dev.display_path(appraisals_path)}. Running: bin/rake #{@appraisal_task}"
|
|
@@ -206,47 +246,62 @@ module Kettle
|
|
|
206
246
|
end
|
|
207
247
|
|
|
208
248
|
# 6. git user + commit release prep
|
|
209
|
-
if
|
|
249
|
+
if run_step?(6)
|
|
210
250
|
ensure_git_user!
|
|
211
251
|
version ||= detect_version
|
|
212
252
|
committed = commit_release_prep!(version)
|
|
213
253
|
end
|
|
214
254
|
|
|
215
255
|
# 7. optional local CI via act
|
|
216
|
-
maybe_run_local_ci_before_push!(committed, force: local_ci?) if
|
|
256
|
+
maybe_run_local_ci_before_push!(committed, force: local_ci?) if run_step?(7)
|
|
217
257
|
|
|
218
258
|
# 8. ensure trunk synced
|
|
219
|
-
if
|
|
259
|
+
if run_step?(8) && !local_ci?
|
|
220
260
|
trunk = detect_trunk_branch
|
|
221
261
|
feature = current_branch
|
|
262
|
+
branch_stack_release = branch_stack_release_branch?(feature, trunk)
|
|
263
|
+
if branch_stack_release
|
|
264
|
+
puts "Kettle-family branch stack release branch detected: #{feature}; skipping trunk sync/rebase."
|
|
265
|
+
end
|
|
222
266
|
puts "Trunk branch detected: #{trunk}"
|
|
223
|
-
ensure_trunk_synced_before_push!(trunk, feature)
|
|
224
|
-
elsif
|
|
267
|
+
ensure_trunk_synced_before_push!(trunk, feature) unless branch_stack_release
|
|
268
|
+
elsif run_step?(8)
|
|
225
269
|
puts "Local CI release mode: skipping remote trunk sync before publishing."
|
|
226
270
|
end
|
|
227
271
|
|
|
228
272
|
# 9. push branches
|
|
229
|
-
push! if
|
|
273
|
+
push! if run_step?(9) && !local_ci?
|
|
230
274
|
|
|
231
275
|
# 10. monitor CI after push
|
|
232
|
-
monitor_workflows_after_push! if
|
|
276
|
+
monitor_workflows_after_push! if run_step?(10) && !local_ci?
|
|
233
277
|
|
|
234
278
|
# 11. merge feature into trunk and push
|
|
235
|
-
if
|
|
279
|
+
if run_step?(11) && !local_ci?
|
|
236
280
|
trunk ||= detect_trunk_branch
|
|
237
281
|
feature ||= current_branch
|
|
238
|
-
|
|
282
|
+
branch_stack_release ||= branch_stack_release_branch?(feature, trunk)
|
|
283
|
+
if branch_stack_release
|
|
284
|
+
puts "Kettle-family branch stack release branch detected: #{feature}; skipping merge into #{trunk}."
|
|
285
|
+
else
|
|
286
|
+
merge_feature_into_trunk_and_push!(trunk, feature)
|
|
287
|
+
end
|
|
239
288
|
end
|
|
240
289
|
|
|
241
290
|
# 12. checkout trunk and pull
|
|
242
|
-
if
|
|
291
|
+
if run_step?(12) && !local_ci?
|
|
243
292
|
trunk ||= detect_trunk_branch
|
|
244
|
-
|
|
245
|
-
|
|
293
|
+
feature ||= current_branch
|
|
294
|
+
branch_stack_release ||= branch_stack_release_branch?(feature, trunk)
|
|
295
|
+
if branch_stack_release
|
|
296
|
+
puts "Kettle-family branch stack release branch detected: #{feature}; staying on release branch."
|
|
297
|
+
else
|
|
298
|
+
checkout!(trunk)
|
|
299
|
+
pull!(trunk)
|
|
300
|
+
end
|
|
246
301
|
end
|
|
247
302
|
|
|
248
303
|
# 13. signing guidance and checks
|
|
249
|
-
if
|
|
304
|
+
if run_step?(13)
|
|
250
305
|
if ENV.fetch("SKIP_GEM_SIGNING", "false").casecmp("false").zero?
|
|
251
306
|
puts "TIP: For local dry-runs or testing the release workflow, set SKIP_GEM_SIGNING=true to avoid PEM password prompts."
|
|
252
307
|
if Kettle::Dev::InputAdapter.tty?
|
|
@@ -267,13 +322,13 @@ module Kettle
|
|
|
267
322
|
end
|
|
268
323
|
|
|
269
324
|
# 14. build
|
|
270
|
-
if
|
|
325
|
+
if run_step?(14)
|
|
271
326
|
puts "Running build (you may be prompted for the signing key password)..."
|
|
272
327
|
run_cmd!("bundle exec rake build")
|
|
273
328
|
end
|
|
274
329
|
|
|
275
330
|
# 15. release and tag
|
|
276
|
-
if
|
|
331
|
+
if run_step?(15)
|
|
277
332
|
if local_ci?
|
|
278
333
|
version ||= detect_version
|
|
279
334
|
release_gem_and_tag_locally!(version)
|
|
@@ -287,7 +342,7 @@ module Kettle
|
|
|
287
342
|
# Checksums are generated after release to avoid including checksums/ in gem package
|
|
288
343
|
# Rationale: Running gem_checksums before release may commit checksums/ and cause Bundler's
|
|
289
344
|
# release build to include them in the gem, thus altering the artifact, and invalidating the checksums.
|
|
290
|
-
if
|
|
345
|
+
if run_step?(16)
|
|
291
346
|
# Generate checksums for the just-built artifact, commit them, then validate
|
|
292
347
|
run_cmd!("bin/gem_checksums")
|
|
293
348
|
version ||= detect_version
|
|
@@ -295,19 +350,19 @@ module Kettle
|
|
|
295
350
|
end
|
|
296
351
|
|
|
297
352
|
# 17. push checksum commit (gem_checksums already commits)
|
|
298
|
-
if
|
|
353
|
+
if run_step?(17)
|
|
299
354
|
push!
|
|
300
355
|
push_tags! if local_ci?
|
|
301
356
|
end
|
|
302
357
|
|
|
303
358
|
# 18. create GitHub release (optional)
|
|
304
|
-
if
|
|
359
|
+
if run_step?(18)
|
|
305
360
|
version ||= detect_version
|
|
306
361
|
maybe_create_github_release!(version)
|
|
307
362
|
end
|
|
308
363
|
|
|
309
364
|
# 19. push tags to remotes (final step)
|
|
310
|
-
push_tags! if
|
|
365
|
+
push_tags! if run_step?(19) && !local_ci?
|
|
311
366
|
|
|
312
367
|
# Final success message
|
|
313
368
|
begin
|
|
@@ -330,12 +385,72 @@ module Kettle
|
|
|
330
385
|
abort("Unsupported appraisal task #{value.inspect}; use appraisal:generate or appraisal:update.")
|
|
331
386
|
end
|
|
332
387
|
|
|
388
|
+
def normalize_skip_steps(value)
|
|
389
|
+
raw_steps = Array(value).flat_map { |part| part.to_s.split(",") }.map(&:strip).reject(&:empty?)
|
|
390
|
+
raw_steps.map do |raw|
|
|
391
|
+
abort("Invalid skip_steps value #{raw.inspect}; use comma-separated release step numbers from 0 to 19.") unless raw.match?(/\A\d+\z/)
|
|
392
|
+
|
|
393
|
+
step = raw.to_i
|
|
394
|
+
abort("Invalid skip_steps value #{raw.inspect}; release steps are numbered 0 to 19.") unless step.between?(0, 19)
|
|
395
|
+
|
|
396
|
+
step
|
|
397
|
+
end.uniq
|
|
398
|
+
end
|
|
399
|
+
|
|
333
400
|
private
|
|
334
401
|
|
|
335
402
|
def local_ci?
|
|
336
403
|
@local_ci
|
|
337
404
|
end
|
|
338
405
|
|
|
406
|
+
def run_step?(step)
|
|
407
|
+
@start_step <= step && !@skip_steps.include?(step)
|
|
408
|
+
end
|
|
409
|
+
|
|
410
|
+
def rubocop_lts_release_preflight_needed?
|
|
411
|
+
(3..5).any? { |step| run_step?(step) }
|
|
412
|
+
end
|
|
413
|
+
|
|
414
|
+
def prepare_rubocop_lts_local_branch!
|
|
415
|
+
local_root = rubocop_lts_local_root
|
|
416
|
+
return unless local_root
|
|
417
|
+
|
|
418
|
+
ruby_gem = selected_rubocop_lts_ruby_gem
|
|
419
|
+
return unless ruby_gem
|
|
420
|
+
|
|
421
|
+
branch = Kettle::Rb::CompatMatrix.rubocop_lts_branch_for_gem(ruby_gem)
|
|
422
|
+
abort("Cannot select RUBOCOP_LTS_LOCAL branch for #{ruby_gem.inspect}.") unless branch
|
|
423
|
+
|
|
424
|
+
checkout = File.join(local_root, "rubocop-lts")
|
|
425
|
+
current, ok = git_output(["-C", checkout, "branch", "--show-current"])
|
|
426
|
+
abort("Cannot inspect RUBOCOP_LTS_LOCAL checkout at #{checkout}.") unless ok
|
|
427
|
+
return if current == branch
|
|
428
|
+
|
|
429
|
+
puts "Switching RUBOCOP_LTS_LOCAL checkout #{checkout} to #{branch} for #{ruby_gem}."
|
|
430
|
+
_stdout, switched = git_output(["-C", checkout, "switch", branch])
|
|
431
|
+
abort("Cannot switch RUBOCOP_LTS_LOCAL checkout at #{checkout} to #{branch}. Commit or stash local changes, then retry.") unless switched
|
|
432
|
+
end
|
|
433
|
+
|
|
434
|
+
def rubocop_lts_local_root
|
|
435
|
+
value = ENV["RUBOCOP_LTS_LOCAL"].to_s.strip
|
|
436
|
+
return nil if value.empty? || %w[false 0 no off].include?(value.downcase)
|
|
437
|
+
return File.join(Dir.home, "src", "rubocop-lts") if %w[true 1 yes on].include?(value.downcase)
|
|
438
|
+
return value if value.start_with?("/")
|
|
439
|
+
|
|
440
|
+
File.join(Dir.home, value)
|
|
441
|
+
end
|
|
442
|
+
|
|
443
|
+
def selected_rubocop_lts_ruby_gem
|
|
444
|
+
path = File.join(@root, "gemfiles", "modular", "style_local.gemfile")
|
|
445
|
+
return nil unless File.file?(path)
|
|
446
|
+
|
|
447
|
+
content = File.read(path)
|
|
448
|
+
# This reads the generated kettle-jem style_local.gemfile declaration
|
|
449
|
+
# without evaluating the Gemfile during release preflight.
|
|
450
|
+
local_gems = content[/\blocal_gems\s*=\s*%w\[(.*?)\]/m, 1].to_s.split
|
|
451
|
+
local_gems.find { |gem_name| Kettle::Rb::CompatMatrix.rubocop_ruby_gem?(gem_name) }
|
|
452
|
+
end
|
|
453
|
+
|
|
339
454
|
def run_pre_release_checks!
|
|
340
455
|
puts "Running pre-release checks via kettle-pre-release..."
|
|
341
456
|
Kettle::Dev::PreReleaseCLI.new(check_num: 1).run
|
|
@@ -988,6 +1103,44 @@ module Kettle
|
|
|
988
1103
|
puts "Merged #{feature} into #{trunk} and pushed. The PR (if any) should auto-close."
|
|
989
1104
|
end
|
|
990
1105
|
|
|
1106
|
+
def branch_stack_release_branch?(branch, trunk = nil)
|
|
1107
|
+
return false if branch.to_s.empty?
|
|
1108
|
+
return false if trunk && branch == trunk
|
|
1109
|
+
|
|
1110
|
+
local_kettle_family_release_target_branches.include?(branch)
|
|
1111
|
+
end
|
|
1112
|
+
|
|
1113
|
+
def local_kettle_family_release_target_branches
|
|
1114
|
+
local_kettle_family_config_paths.each do |path|
|
|
1115
|
+
next unless File.file?(path)
|
|
1116
|
+
|
|
1117
|
+
begin
|
|
1118
|
+
data = YAML.safe_load(File.read(path), permitted_classes: [], aliases: false) || {}
|
|
1119
|
+
branches = Array(dig_string_keys(data, "release", "target_branches")) +
|
|
1120
|
+
Array(dig_string_keys(data, "branches", "release_targets"))
|
|
1121
|
+
return branches.map(&:to_s).reject(&:empty?) unless branches.empty?
|
|
1122
|
+
rescue Psych::Exception => e
|
|
1123
|
+
warn("Ignoring invalid kettle-family config #{Kettle::Dev.display_path(path)}: #{e.message}")
|
|
1124
|
+
end
|
|
1125
|
+
end
|
|
1126
|
+
[]
|
|
1127
|
+
end
|
|
1128
|
+
|
|
1129
|
+
def local_kettle_family_config_paths
|
|
1130
|
+
[
|
|
1131
|
+
File.join(@root, ".kettle-family.yml"),
|
|
1132
|
+
File.join(@root, ".structuredmerge", "kettle-family.yml")
|
|
1133
|
+
]
|
|
1134
|
+
end
|
|
1135
|
+
|
|
1136
|
+
def dig_string_keys(data, *keys)
|
|
1137
|
+
keys.reduce(data) do |memo, key|
|
|
1138
|
+
break nil unless memo.is_a?(Hash)
|
|
1139
|
+
|
|
1140
|
+
memo[key] || memo[key.to_sym]
|
|
1141
|
+
end
|
|
1142
|
+
end
|
|
1143
|
+
|
|
991
1144
|
def ensure_signing_setup_or_skip!
|
|
992
1145
|
# Treat any non-/true/i value as an explicit skip signal
|
|
993
1146
|
return if ENV.fetch("SKIP_GEM_SIGNING", "").casecmp("true").zero?
|
|
@@ -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.21
|
|
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.21
|
|
363
|
+
changelog_uri: https://github.com/kettle-dev/kettle-dev/blob/v2.2.21/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.21
|
|
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
|