kettle-family 1.2.13 → 1.2.14
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 +59 -1
- data/README.md +1 -1
- data/lib/kettle/family/cli.rb +4 -0
- data/lib/kettle/family/command_result.rb +4 -2
- data/lib/kettle/family/command_runner.rb +85 -41
- data/lib/kettle/family/config.rb +4 -0
- data/lib/kettle/family/report.rb +21 -1
- data/lib/kettle/family/secrets.rb +11 -1
- data/lib/kettle/family/version.rb +1 -1
- data/lib/kettle/family/workflow.rb +179 -45
- data/lib/kettle/family/workflow_progress.rb +3 -2
- data.tar.gz.sig +0 -0
- metadata +6 -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: 417f2f02e871abec85184783775b1449c32b0caac52e7b18b4744840af2ac17d
|
|
4
|
+
data.tar.gz: c5013fc308ed12715d2184edf21ad6dea41dea2a5ae5df0bc521d6aba53b6c4a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: '091796994cdd4db8bb7e50d5cd8104e42a4680eaba541aa0897675ab835a3a51eed13ba63adbdd4fd1b8d099d426424d39f5b0a3b09e83235fba18f8dac63a65'
|
|
7
|
+
data.tar.gz: e744049cdd349d806bf4f14db21781e94a57b1e8a0b4fcb71e132637d6dedbc80e389b82031e9871f8ae82473836f9e0e1dce8e75aa1a3bf9c2bb1e79a61e68f
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
data/CHANGELOG.md
CHANGED
|
@@ -30,6 +30,62 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
|
30
30
|
|
|
31
31
|
### Security
|
|
32
32
|
|
|
33
|
+
## [1.2.14] - 2026-07-31
|
|
34
|
+
|
|
35
|
+
- TAG: [v1.2.14][1.2.14t]
|
|
36
|
+
- COVERAGE: 94.22% -- 4175/4431 lines in 28 files
|
|
37
|
+
- BRANCH COVERAGE: 76.69% -- 1622/2115 branches in 28 files
|
|
38
|
+
- 28.88% documented
|
|
39
|
+
|
|
40
|
+
### Added
|
|
41
|
+
|
|
42
|
+
- Release publish/build commands now write per-member transcript logs under
|
|
43
|
+
`tmp/kettle-family/release-*`, and failure summaries include the log path.
|
|
44
|
+
|
|
45
|
+
- Release progress now renders child `kettle-release` `remote_parity` events,
|
|
46
|
+
keeping remote fetch, skip, failure, and completion activity visible without
|
|
47
|
+
scraping raw command output.
|
|
48
|
+
|
|
49
|
+
- Release progress now renders child `kettle-release` `ci_monitor` events with
|
|
50
|
+
provider and workflow or pipeline context, so CI activity is visible as
|
|
51
|
+
structured progress.
|
|
52
|
+
|
|
53
|
+
- Release progress now renders child `kettle-release` `pre_release` events, so
|
|
54
|
+
pre-release checks are visible as structured progress while raw output stays
|
|
55
|
+
in the transcript log.
|
|
56
|
+
|
|
57
|
+
- Release progress now renders child `kettle-changelog` `changelog` events, so
|
|
58
|
+
release plan, coverage, and changelog update activity is visible as structured
|
|
59
|
+
progress.
|
|
60
|
+
|
|
61
|
+
### Changed
|
|
62
|
+
|
|
63
|
+
- Family release now keeps raw child `kettle-release` output in the per-member
|
|
64
|
+
transcript log by default and renders structured NDJSON progress in the
|
|
65
|
+
terminal, with raw passthrough still available under verbose/debug output.
|
|
66
|
+
- Release summary footers now include the transcript log directory when release
|
|
67
|
+
logs were written, including successful runs where raw output stayed quiet.
|
|
68
|
+
- Release progress now renders child `command_step` summaries, so phases can
|
|
69
|
+
show context such as `release:bundle_lock:Gemfile` or
|
|
70
|
+
`release:yard:documentation`.
|
|
71
|
+
- Release progress now renders child `release_lockfile` and `release_probe`
|
|
72
|
+
events, so lockfile reset retries and published-gem availability probes show
|
|
73
|
+
as structured progress.
|
|
74
|
+
- Release progress now renders GitHub CI wait/start/tick events with completion
|
|
75
|
+
counts, so CI monitoring no longer appears stuck while waiting for workflows.
|
|
76
|
+
- Release preflight now renders through the shared progress event tape instead
|
|
77
|
+
of printing separate start and finish lines for each successful phase.
|
|
78
|
+
|
|
79
|
+
### Fixed
|
|
80
|
+
|
|
81
|
+
- Release preflight no longer prints a nested 1Password authorization alert
|
|
82
|
+
between the phase start and finish lines; the preflight phase itself is the
|
|
83
|
+
user-facing authorization notice.
|
|
84
|
+
|
|
85
|
+
- Family release runs can now pass configured required release remotes through
|
|
86
|
+
to `kettle-release`, allowing mirrors to remain optional while primary remotes
|
|
87
|
+
still block release parity failures.
|
|
88
|
+
|
|
33
89
|
## [1.2.13] - 2026-07-31
|
|
34
90
|
|
|
35
91
|
- TAG: [v1.2.13][1.2.13t]
|
|
@@ -1443,7 +1499,9 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
|
1443
1499
|
- Fixed CI load failures on engines without compatible `pty` support by falling back to Open3 for interactive release commands.
|
|
1444
1500
|
- Fixed Ruby 3.2 version-bump support by loading Prism lazily and wiring the Prism gem only for MRI versions that need it.
|
|
1445
1501
|
|
|
1446
|
-
[Unreleased]: https://github.com/kettle-dev/kettle-family/compare/v1.2.
|
|
1502
|
+
[Unreleased]: https://github.com/kettle-dev/kettle-family/compare/v1.2.14...HEAD
|
|
1503
|
+
[1.2.14]: https://github.com/kettle-dev/kettle-family/compare/v1.2.13...v1.2.14
|
|
1504
|
+
[1.2.14t]: https://github.com/kettle-dev/kettle-family/releases/tag/v1.2.14
|
|
1447
1505
|
[1.2.13]: https://github.com/kettle-dev/kettle-family/compare/v1.2.12...v1.2.13
|
|
1448
1506
|
[1.2.13t]: https://github.com/kettle-dev/kettle-family/releases/tag/v1.2.13
|
|
1449
1507
|
[1.2.12]: https://github.com/kettle-dev/kettle-family/compare/v1.2.11...v1.2.12
|
data/README.md
CHANGED
|
@@ -819,7 +819,7 @@ Thanks for RTFM. ☺️
|
|
|
819
819
|
[📌gitmoji]: https://gitmoji.dev
|
|
820
820
|
[📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
|
|
821
821
|
[🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
|
|
822
|
-
[🧮kloc-img]: https://img.shields.io/badge/KLOC-4.
|
|
822
|
+
[🧮kloc-img]: https://img.shields.io/badge/KLOC-4.431-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
|
|
823
823
|
[🔐security]: https://github.com/kettle-dev/kettle-family/blob/main/SECURITY.md
|
|
824
824
|
[🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
|
|
825
825
|
[📄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
|
@@ -151,6 +151,7 @@ module Kettle
|
|
|
151
151
|
release_ci_workflows: nil,
|
|
152
152
|
release_skip_bundle_audit: false,
|
|
153
153
|
release_skip_remotes: nil,
|
|
154
|
+
release_required_remotes: nil,
|
|
154
155
|
release_secrets_provider: nil,
|
|
155
156
|
accept: true,
|
|
156
157
|
tag: false,
|
|
@@ -464,6 +465,7 @@ module Kettle
|
|
|
464
465
|
option :ci_workflows, long: "--ci-workflows", value: {type: String, usage: "LIST"}, desc: "Pass a comma-separated CI workflow monitor subset through to kettle-release commands"
|
|
465
466
|
option :skip_bundle_audit, long: "--skip-bundle-audit", desc: "Skip bundle:audit/update during release rake checks"
|
|
466
467
|
option :skip_remotes, long: "--skip-remotes", value: {type: String, usage: "LIST"}, desc: "Pass a comma-separated git remote skip list through to kettle-release commands"
|
|
468
|
+
option :required_remotes, long: "--required-remotes", value: {type: String, usage: "LIST"}, desc: "Pass a comma-separated required git remote list through to kettle-release commands"
|
|
467
469
|
option :secrets_provider, long: "--secrets-provider", value: {type: String, usage: "NAME"}, desc: "Release secrets provider: interactive, 1password"
|
|
468
470
|
option :no_auto_floors, long: "--no-auto-floors", desc: "Do not raise family dependency floors between member releases" do
|
|
469
471
|
options[:no_auto_floors] = true
|
|
@@ -487,6 +489,7 @@ module Kettle
|
|
|
487
489
|
release_ci_workflows: options[:ci_workflows],
|
|
488
490
|
release_skip_bundle_audit: truthy_option?(:skip_bundle_audit),
|
|
489
491
|
release_skip_remotes: options[:skip_remotes],
|
|
492
|
+
release_required_remotes: options[:required_remotes],
|
|
490
493
|
release_secrets_provider: options[:secrets_provider],
|
|
491
494
|
release_auto_dependency_floors: !truthy_option?(:no_auto_floors),
|
|
492
495
|
accept: !options.key?(:accept) || options[:accept],
|
|
@@ -662,6 +665,7 @@ module Kettle
|
|
|
662
665
|
ci_workflows: options[:release_ci_workflows],
|
|
663
666
|
skip_bundle_audit: options[:release_skip_bundle_audit],
|
|
664
667
|
skip_remotes: options[:release_skip_remotes],
|
|
668
|
+
required_remotes: options[:release_required_remotes],
|
|
665
669
|
secrets_provider: release_secrets_provider(command: command, config: config, options: options),
|
|
666
670
|
auto_dependency_floors: options[:release_auto_dependency_floors],
|
|
667
671
|
gha_sha_pins_upgrade: options[:gha_sha_pins_upgrade],
|
|
@@ -15,7 +15,8 @@ module Kettle
|
|
|
15
15
|
:skipped,
|
|
16
16
|
:reason,
|
|
17
17
|
:branch,
|
|
18
|
-
:output_streamed
|
|
18
|
+
:output_streamed,
|
|
19
|
+
:log_path
|
|
19
20
|
) do
|
|
20
21
|
def to_h
|
|
21
22
|
{
|
|
@@ -31,7 +32,8 @@ module Kettle
|
|
|
31
32
|
"elapsed_seconds" => elapsed_seconds,
|
|
32
33
|
"skipped" => skipped,
|
|
33
34
|
"reason" => reason,
|
|
34
|
-
"output_streamed" => output_streamed
|
|
35
|
+
"output_streamed" => output_streamed?,
|
|
36
|
+
"log_path" => log_path
|
|
35
37
|
}
|
|
36
38
|
end
|
|
37
39
|
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require "open3"
|
|
4
4
|
require "io/console"
|
|
5
|
+
require "fileutils"
|
|
5
6
|
|
|
6
7
|
module Kettle
|
|
7
8
|
module Family
|
|
@@ -143,26 +144,33 @@ module Kettle
|
|
|
143
144
|
@otp_coordinator = otp_coordinator
|
|
144
145
|
end
|
|
145
146
|
|
|
146
|
-
def call(member:, phase:, command:, env: {}, interactive: false, stdout_line_handler: nil)
|
|
147
|
+
def call(member:, phase:, command:, env: {}, interactive: false, stdout_line_handler: nil, log_path: nil, passthrough_output: true)
|
|
147
148
|
argv = command_argv(member: member, command: command, env: env)
|
|
148
149
|
process_env = process_env(member: member, env: env)
|
|
149
150
|
spawn_options = process_options
|
|
150
151
|
return skipped_result(member: member, phase: phase, argv: argv) unless execute
|
|
151
152
|
|
|
152
153
|
started = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
153
|
-
stdout, stderr, status =
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
154
|
+
stdout, stderr, status = with_transcript(log_path, argv: argv, chdir: member.root) do |log_io|
|
|
155
|
+
if interactive
|
|
156
|
+
run_interactive(
|
|
157
|
+
env: process_env,
|
|
158
|
+
argv: argv,
|
|
159
|
+
chdir: member.root,
|
|
160
|
+
member_name: member.name,
|
|
161
|
+
process_options: spawn_options,
|
|
162
|
+
stdout_line_handler: stdout_line_handler,
|
|
163
|
+
log_io: log_io,
|
|
164
|
+
passthrough_output: passthrough_output
|
|
165
|
+
)
|
|
166
|
+
elsif stdout_line_handler
|
|
167
|
+
run_streaming(env: process_env, argv: argv, chdir: member.root, process_options: spawn_options, stdout_line_handler: stdout_line_handler, log_io: log_io)
|
|
168
|
+
else
|
|
169
|
+
result = Open3.capture3(process_env, *argv, chdir: member.root, **spawn_options)
|
|
170
|
+
transcript_write(log_io, result[0])
|
|
171
|
+
transcript_write(log_io, result[1])
|
|
172
|
+
result
|
|
173
|
+
end
|
|
166
174
|
end
|
|
167
175
|
stdout = normalize_output(stdout)
|
|
168
176
|
stderr = normalize_output(stderr)
|
|
@@ -179,7 +187,8 @@ module Kettle
|
|
|
179
187
|
elapsed_seconds: elapsed.round(3),
|
|
180
188
|
skipped: false,
|
|
181
189
|
reason: status.success? ? nil : "command failed",
|
|
182
|
-
output_streamed: interactive
|
|
190
|
+
output_streamed: interactive,
|
|
191
|
+
log_path: log_path
|
|
183
192
|
)
|
|
184
193
|
end
|
|
185
194
|
|
|
@@ -187,7 +196,7 @@ module Kettle
|
|
|
187
196
|
|
|
188
197
|
attr_reader :execute, :accept, :gem_signing_password, :otp_coordinator
|
|
189
198
|
|
|
190
|
-
def run_streaming(env:, argv:, chdir:, process_options:, stdout_line_handler:)
|
|
199
|
+
def run_streaming(env:, argv:, chdir:, process_options:, stdout_line_handler:, log_io: nil)
|
|
191
200
|
captured_stdout = +""
|
|
192
201
|
captured_stderr = +""
|
|
193
202
|
stdout_line_buffer = +""
|
|
@@ -197,12 +206,14 @@ module Kettle
|
|
|
197
206
|
until readers.empty?
|
|
198
207
|
ready = IO.select(readers)
|
|
199
208
|
ready.first.each do |reader|
|
|
209
|
+
chunk = reader.readpartial(1024)
|
|
200
210
|
if reader.equal?(output)
|
|
201
|
-
chunk = reader.readpartial(1024)
|
|
202
211
|
captured_stdout << chunk
|
|
212
|
+
transcript_write(log_io, chunk)
|
|
203
213
|
stdout_line_buffer = stream_stdout_lines(stdout_line_buffer, chunk, stdout_line_handler)
|
|
204
214
|
else
|
|
205
|
-
captured_stderr <<
|
|
215
|
+
captured_stderr << chunk
|
|
216
|
+
transcript_write(log_io, chunk)
|
|
206
217
|
end
|
|
207
218
|
rescue EOFError
|
|
208
219
|
readers.delete(reader)
|
|
@@ -222,7 +233,7 @@ module Kettle
|
|
|
222
233
|
remainder
|
|
223
234
|
end
|
|
224
235
|
|
|
225
|
-
def run_interactive(env:, argv:, chdir:, member_name:, process_options:, stdout_line_handler:)
|
|
236
|
+
def run_interactive(env:, argv:, chdir:, member_name:, process_options:, stdout_line_handler:, log_io: nil, passthrough_output: true)
|
|
226
237
|
if pty_available?
|
|
227
238
|
return run_interactive_pty(
|
|
228
239
|
env: env,
|
|
@@ -230,7 +241,9 @@ module Kettle
|
|
|
230
241
|
chdir: chdir,
|
|
231
242
|
member_name: member_name,
|
|
232
243
|
process_options: process_options,
|
|
233
|
-
stdout_line_handler: stdout_line_handler
|
|
244
|
+
stdout_line_handler: stdout_line_handler,
|
|
245
|
+
log_io: log_io,
|
|
246
|
+
passthrough_output: passthrough_output
|
|
234
247
|
)
|
|
235
248
|
end
|
|
236
249
|
|
|
@@ -240,11 +253,13 @@ module Kettle
|
|
|
240
253
|
chdir: chdir,
|
|
241
254
|
member_name: member_name,
|
|
242
255
|
process_options: process_options,
|
|
243
|
-
stdout_line_handler: stdout_line_handler
|
|
256
|
+
stdout_line_handler: stdout_line_handler,
|
|
257
|
+
log_io: log_io,
|
|
258
|
+
passthrough_output: passthrough_output
|
|
244
259
|
)
|
|
245
260
|
end
|
|
246
261
|
|
|
247
|
-
def run_interactive_pty(env:, argv:, chdir:, member_name:, process_options:, stdout_line_handler:)
|
|
262
|
+
def run_interactive_pty(env:, argv:, chdir:, member_name:, process_options:, stdout_line_handler:, log_io: nil, passthrough_output: true)
|
|
248
263
|
stdout = +""
|
|
249
264
|
stderr = +""
|
|
250
265
|
stdout_line_buffer = +""
|
|
@@ -259,10 +274,12 @@ module Kettle
|
|
|
259
274
|
if reader.equal?(output)
|
|
260
275
|
chunk = output.readpartial(1024)
|
|
261
276
|
stdout << chunk
|
|
262
|
-
|
|
277
|
+
transcript_write(log_io, chunk)
|
|
278
|
+
stdout_line_buffer = print_interactive_stdout(stdout_line_buffer, chunk, stdout_line_handler, passthrough_output: passthrough_output)
|
|
263
279
|
handle_interactive_prompt(input, chunk, member_name: member_name)
|
|
264
280
|
else
|
|
265
|
-
|
|
281
|
+
chunk = $stdin.readpartial(1024)
|
|
282
|
+
input.write(chunk)
|
|
266
283
|
end
|
|
267
284
|
end
|
|
268
285
|
end
|
|
@@ -270,16 +287,17 @@ module Kettle
|
|
|
270
287
|
# PTY raises EIO when the child process exits after closing the slave.
|
|
271
288
|
rescue Error => error
|
|
272
289
|
stderr << "#{error.message}\n"
|
|
290
|
+
transcript_write(log_io, "#{error.message}\n")
|
|
273
291
|
terminate_process(pid)
|
|
274
292
|
end
|
|
275
|
-
flush_interactive_stdout(stdout_line_buffer, stdout_line_handler)
|
|
293
|
+
flush_interactive_stdout(stdout_line_buffer, stdout_line_handler, passthrough_output: passthrough_output)
|
|
276
294
|
_, status = Process.wait2(pid)
|
|
277
295
|
status = failure_status if !stderr.empty? && status.success?
|
|
278
296
|
end
|
|
279
297
|
[stdout, stderr, status]
|
|
280
298
|
end
|
|
281
299
|
|
|
282
|
-
def run_interactive_open3(env:, argv:, chdir:, member_name:, process_options:, stdout_line_handler:)
|
|
300
|
+
def run_interactive_open3(env:, argv:, chdir:, member_name:, process_options:, stdout_line_handler:, log_io: nil, passthrough_output: true)
|
|
283
301
|
captured_stdout = +""
|
|
284
302
|
captured_stderr = +""
|
|
285
303
|
stdout_line_buffer = +""
|
|
@@ -303,19 +321,22 @@ module Kettle
|
|
|
303
321
|
readers,
|
|
304
322
|
member_name: member_name,
|
|
305
323
|
stdout_line_buffer: stdout_line_buffer,
|
|
306
|
-
stdout_line_handler: stdout_line_handler
|
|
324
|
+
stdout_line_handler: stdout_line_handler,
|
|
325
|
+
log_io: log_io,
|
|
326
|
+
passthrough_output: passthrough_output
|
|
307
327
|
)
|
|
308
328
|
end
|
|
309
329
|
end
|
|
310
330
|
end
|
|
311
331
|
rescue Error => error
|
|
312
332
|
captured_stderr << "#{error.message}\n"
|
|
333
|
+
transcript_write(log_io, "#{error.message}\n")
|
|
313
334
|
terminate_process(wait_thread.pid)
|
|
314
335
|
status = failure_status
|
|
315
336
|
else
|
|
316
337
|
status = wait_thread.value
|
|
317
338
|
end
|
|
318
|
-
flush_interactive_stdout(stdout_line_buffer, stdout_line_handler)
|
|
339
|
+
flush_interactive_stdout(stdout_line_buffer, stdout_line_handler, passthrough_output: passthrough_output)
|
|
319
340
|
end
|
|
320
341
|
[captured_stdout, captured_stderr, status]
|
|
321
342
|
end
|
|
@@ -329,15 +350,19 @@ module Kettle
|
|
|
329
350
|
readers,
|
|
330
351
|
member_name:,
|
|
331
352
|
stdout_line_buffer:,
|
|
332
|
-
stdout_line_handler
|
|
353
|
+
stdout_line_handler:,
|
|
354
|
+
log_io: nil,
|
|
355
|
+
passthrough_output: true
|
|
333
356
|
)
|
|
334
357
|
chunk = reader.readpartial(1024)
|
|
335
358
|
if reader.equal?(output)
|
|
336
359
|
captured_stdout << chunk
|
|
337
|
-
|
|
360
|
+
transcript_write(log_io, chunk)
|
|
361
|
+
stdout_line_buffer = print_interactive_stdout(stdout_line_buffer, chunk, stdout_line_handler, passthrough_output: passthrough_output)
|
|
338
362
|
else
|
|
339
363
|
captured_stderr << chunk
|
|
340
|
-
|
|
364
|
+
transcript_write(log_io, chunk)
|
|
365
|
+
$stderr.print(chunk) if passthrough_output
|
|
341
366
|
end
|
|
342
367
|
handle_interactive_prompt(input, chunk, member_name: member_name)
|
|
343
368
|
stdout_line_buffer
|
|
@@ -346,36 +371,55 @@ module Kettle
|
|
|
346
371
|
stdout_line_buffer
|
|
347
372
|
end
|
|
348
373
|
|
|
349
|
-
def
|
|
350
|
-
return
|
|
374
|
+
def with_transcript(log_path, argv:, chdir:)
|
|
375
|
+
return yield(nil) if log_path.to_s.empty?
|
|
376
|
+
|
|
377
|
+
FileUtils.mkdir_p(File.dirname(log_path))
|
|
378
|
+
File.open(log_path, "wb") do |log_io|
|
|
379
|
+
log_io.sync = true
|
|
380
|
+
log_io.puts("$ #{argv.join(" ")}")
|
|
381
|
+
log_io.puts("workdir: #{chdir}")
|
|
382
|
+
log_io.puts
|
|
383
|
+
yield(log_io)
|
|
384
|
+
end
|
|
385
|
+
end
|
|
386
|
+
|
|
387
|
+
def transcript_write(log_io, chunk)
|
|
388
|
+
return if log_io.nil? || chunk.to_s.empty?
|
|
389
|
+
|
|
390
|
+
log_io.write(chunk)
|
|
391
|
+
end
|
|
392
|
+
|
|
393
|
+
def print_interactive_stdout(buffer, chunk, stdout_line_handler, passthrough_output: true)
|
|
394
|
+
return print_interactive_chunk(chunk, passthrough_output: passthrough_output) unless stdout_line_handler
|
|
351
395
|
|
|
352
396
|
pending = buffer + chunk
|
|
353
397
|
lines = pending.lines
|
|
354
398
|
remainder = pending.end_with?("\n") ? +"" : lines.pop.to_s
|
|
355
|
-
lines.each { |line| print_interactive_line(line, stdout_line_handler) }
|
|
399
|
+
lines.each { |line| print_interactive_line(line, stdout_line_handler, passthrough_output: passthrough_output) }
|
|
356
400
|
return +"" if remainder.empty?
|
|
357
401
|
unless possible_event_line?(remainder)
|
|
358
|
-
$stdout.print(remainder)
|
|
402
|
+
$stdout.print(remainder) if passthrough_output
|
|
359
403
|
return +""
|
|
360
404
|
end
|
|
361
405
|
|
|
362
406
|
remainder
|
|
363
407
|
end
|
|
364
408
|
|
|
365
|
-
def flush_interactive_stdout(buffer, stdout_line_handler)
|
|
409
|
+
def flush_interactive_stdout(buffer, stdout_line_handler, passthrough_output: true)
|
|
366
410
|
return if buffer.empty?
|
|
367
411
|
|
|
368
|
-
print_interactive_line(buffer, stdout_line_handler)
|
|
412
|
+
print_interactive_line(buffer, stdout_line_handler, passthrough_output: passthrough_output)
|
|
369
413
|
end
|
|
370
414
|
|
|
371
|
-
def print_interactive_chunk(chunk)
|
|
372
|
-
$stdout.print(chunk)
|
|
415
|
+
def print_interactive_chunk(chunk, passthrough_output: true)
|
|
416
|
+
$stdout.print(chunk) if passthrough_output
|
|
373
417
|
+""
|
|
374
418
|
end
|
|
375
419
|
|
|
376
|
-
def print_interactive_line(line, stdout_line_handler)
|
|
420
|
+
def print_interactive_line(line, stdout_line_handler, passthrough_output: true)
|
|
377
421
|
consumed = possible_event_line?(line) && stdout_line_handler.call(line.chomp)
|
|
378
|
-
$stdout.print(line)
|
|
422
|
+
$stdout.print(line) if !consumed && passthrough_output
|
|
379
423
|
end
|
|
380
424
|
|
|
381
425
|
def possible_event_line?(line)
|
data/lib/kettle/family/config.rb
CHANGED
|
@@ -249,6 +249,10 @@ module Kettle
|
|
|
249
249
|
fetch_path("release", "publish_command") || command_for("release_publish") || "bundle exec kettle-release"
|
|
250
250
|
end
|
|
251
251
|
|
|
252
|
+
def release_required_remotes
|
|
253
|
+
fetch_path("release", "required_remotes")
|
|
254
|
+
end
|
|
255
|
+
|
|
252
256
|
def release_env
|
|
253
257
|
stringify_env(fetch_path("release", "env") || {})
|
|
254
258
|
end
|
data/lib/kettle/family/report.rb
CHANGED
|
@@ -134,6 +134,7 @@ module Kettle
|
|
|
134
134
|
lines << "summary:"
|
|
135
135
|
lines << " outcome: #{data.fetch("outcome")}"
|
|
136
136
|
lines << " elapsed: #{format_elapsed(data.fetch("elapsed_seconds"))}"
|
|
137
|
+
lines << " logs: #{data.fetch("release_log_dirs").join(", ")}" unless data.fetch("release_log_dirs").empty?
|
|
137
138
|
lines << " selected: #{data.fetch("selected_count")}"
|
|
138
139
|
lines << " results: #{data.fetch("result_count")}"
|
|
139
140
|
lines << " succeeded: #{summary_list(data.fetch("succeeded"))}"
|
|
@@ -164,10 +165,20 @@ module Kettle
|
|
|
164
165
|
"skipped" => summary_skipped,
|
|
165
166
|
"failed" => summary_failed,
|
|
166
167
|
"pending" => summary_pending,
|
|
168
|
+
"release_log_dirs" => release_log_dirs,
|
|
167
169
|
"resume_hint" => resume_hint
|
|
168
170
|
}
|
|
169
171
|
end
|
|
170
172
|
|
|
173
|
+
def release_log_dirs
|
|
174
|
+
return [] unless command == "release"
|
|
175
|
+
|
|
176
|
+
visible_results.filter_map do |result|
|
|
177
|
+
path = result.log_path.to_s if result.respond_to?(:log_path)
|
|
178
|
+
File.dirname(path) unless path.to_s.empty?
|
|
179
|
+
end.uniq
|
|
180
|
+
end
|
|
181
|
+
|
|
171
182
|
def append_release_waves(lines)
|
|
172
183
|
wave_results = results.select { |result| release_wave_result?(result) }
|
|
173
184
|
return if wave_results.empty?
|
|
@@ -205,7 +216,10 @@ module Kettle
|
|
|
205
216
|
end
|
|
206
217
|
|
|
207
218
|
def append_result_stdout(lines, result)
|
|
208
|
-
|
|
219
|
+
if suppress_success_output?(result)
|
|
220
|
+
append_result_log_path(lines, result) unless result.ok?
|
|
221
|
+
return
|
|
222
|
+
end
|
|
209
223
|
|
|
210
224
|
if output_streamed?(result)
|
|
211
225
|
append_streamed_output_summary(lines, result) unless result.ok?
|
|
@@ -216,6 +230,11 @@ module Kettle
|
|
|
216
230
|
else
|
|
217
231
|
append_indented_output(lines, result.stdout)
|
|
218
232
|
end
|
|
233
|
+
append_result_log_path(lines, result) unless result.ok? || output_streamed?(result)
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
def append_result_log_path(lines, result)
|
|
237
|
+
lines << " log: #{result.log_path}" if result.respond_to?(:log_path) && !result.log_path.to_s.empty?
|
|
219
238
|
end
|
|
220
239
|
|
|
221
240
|
def suppress_success_output?(result)
|
|
@@ -239,6 +258,7 @@ module Kettle
|
|
|
239
258
|
lines << " summary: #{summary}" if summary
|
|
240
259
|
recommended_fix = streamed_recommended_fix(result)
|
|
241
260
|
lines << " recommended fix: #{recommended_fix}" if recommended_fix
|
|
261
|
+
append_result_log_path(lines, result)
|
|
242
262
|
lines << " output: omitted because it was already streamed"
|
|
243
263
|
end
|
|
244
264
|
|
|
@@ -19,7 +19,7 @@ module Kettle
|
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
def authorize!
|
|
22
|
-
gem_signing_passphrase
|
|
22
|
+
with_release_secret_alert_suppressed { gem_signing_passphrase }
|
|
23
23
|
rescue => error
|
|
24
24
|
raise Error, error.message
|
|
25
25
|
end
|
|
@@ -35,6 +35,16 @@ module Kettle
|
|
|
35
35
|
rescue => error
|
|
36
36
|
raise Error, error.message
|
|
37
37
|
end
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
def with_release_secret_alert_suppressed
|
|
42
|
+
previous = ENV.fetch("KETTLE_RELEASE_SECRET_ALERT", nil)
|
|
43
|
+
ENV["KETTLE_RELEASE_SECRET_ALERT"] = "false"
|
|
44
|
+
yield
|
|
45
|
+
ensure
|
|
46
|
+
previous.nil? ? ENV.delete("KETTLE_RELEASE_SECRET_ALERT") : ENV["KETTLE_RELEASE_SECRET_ALERT"] = previous
|
|
47
|
+
end
|
|
38
48
|
end
|
|
39
49
|
else
|
|
40
50
|
class Provider
|
|
@@ -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.2.
|
|
8
|
+
VERSION = "1.2.14"
|
|
9
9
|
end
|
|
10
10
|
# Current gem version exposed at the traditional constant location.
|
|
11
11
|
VERSION = Version::VERSION # Traditional Constant Location
|
|
@@ -16,6 +16,8 @@ require_relative "workflow_progress"
|
|
|
16
16
|
module Kettle
|
|
17
17
|
module Family
|
|
18
18
|
class Workflow
|
|
19
|
+
PreflightProgressMember = Struct.new(:name)
|
|
20
|
+
|
|
19
21
|
DEFAULT_COMMANDS = {
|
|
20
22
|
"template" => "bundle exec kettle-jem install",
|
|
21
23
|
"test" => "bundle exec kettle-test",
|
|
@@ -100,7 +102,7 @@ module Kettle
|
|
|
100
102
|
REGISTRY_WAIT_ATTEMPTS = 15
|
|
101
103
|
REGISTRY_WAIT_INTERVAL_SECONDS = 15
|
|
102
104
|
|
|
103
|
-
def initialize(command:, config:, members:, execute: false, accept: true, commit: true, allow_dirty: false, publish: false, push: false, tag: false, start_step: nil, skip_steps: nil, local_ci: false, continue_ci_failures: false, ci_workflows: nil, skip_bundle_audit: false, skip_remotes: nil, auto_dependency_floors: nil, gha_sha_pins_upgrade: "patch", gha_sha_pins_check: false, 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, **options)
|
|
105
|
+
def initialize(command:, config:, members:, execute: false, accept: true, commit: true, allow_dirty: false, publish: false, push: false, tag: false, start_step: nil, skip_steps: nil, local_ci: false, continue_ci_failures: false, ci_workflows: nil, skip_bundle_audit: false, skip_remotes: nil, required_remotes: nil, auto_dependency_floors: nil, gha_sha_pins_upgrade: "patch", gha_sha_pins_check: false, 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, **options)
|
|
104
106
|
@command = command
|
|
105
107
|
@config = config
|
|
106
108
|
@members = members
|
|
@@ -117,7 +119,8 @@ module Kettle
|
|
|
117
119
|
@continue_ci_failures = continue_ci_failures
|
|
118
120
|
@ci_workflows = validate_ci_workflows(ci_workflows)
|
|
119
121
|
@skip_bundle_audit = skip_bundle_audit
|
|
120
|
-
@skip_remotes =
|
|
122
|
+
@skip_remotes = validate_remote_list(skip_remotes, "--skip-remotes")
|
|
123
|
+
@required_remotes = validate_remote_list(required_remotes.nil? ? config.release_required_remotes : required_remotes, "--required-remotes")
|
|
121
124
|
@auto_dependency_floors = auto_dependency_floors.nil? ? config.release_auto_dependency_floors? : auto_dependency_floors
|
|
122
125
|
@gha_sha_pins_upgrade = gha_sha_pins_upgrade
|
|
123
126
|
@gha_sha_pins_check = gha_sha_pins_check
|
|
@@ -159,7 +162,7 @@ module Kettle
|
|
|
159
162
|
|
|
160
163
|
private
|
|
161
164
|
|
|
162
|
-
attr_reader :command, :config, :members, :execute, :accept, :commit, :allow_dirty, :publish, :push, :tag, :start_step, :skip_steps, :local_ci, :continue_ci_failures, :ci_workflows, :skip_bundle_audit, :skip_remotes, :auto_dependency_floors, :gha_sha_pins_upgrade, :gha_sha_pins_check, :env_overrides, :debug, :verbose, :jobs, :progress_io, :reset_target, :bup_args, :bex_args, :start_member, :start_branch
|
|
165
|
+
attr_reader :command, :config, :members, :execute, :accept, :commit, :allow_dirty, :publish, :push, :tag, :start_step, :skip_steps, :local_ci, :continue_ci_failures, :ci_workflows, :skip_bundle_audit, :skip_remotes, :required_remotes, :auto_dependency_floors, :gha_sha_pins_upgrade, :gha_sha_pins_check, :env_overrides, :debug, :verbose, :jobs, :progress_io, :reset_target, :bup_args, :bex_args, :start_member, :start_branch
|
|
163
166
|
|
|
164
167
|
def current_branch_results(workflow_members)
|
|
165
168
|
return check_results(workflow_members) if command == "check"
|
|
@@ -421,14 +424,23 @@ module Kettle
|
|
|
421
424
|
|
|
422
425
|
def release_preflight_results
|
|
423
426
|
phases = release_preflight_phases
|
|
424
|
-
|
|
427
|
+
progress = start_release_preflight_progress(phases)
|
|
428
|
+
progress&.start
|
|
429
|
+
preflight_member = release_preflight_progress_member
|
|
430
|
+
progress&.start_member(preflight_member, total: phases.length, status: phases.first.fetch(:label))
|
|
425
431
|
phases.each_with_index do |phase, index|
|
|
426
|
-
|
|
432
|
+
label = phase.fetch(:label)
|
|
433
|
+
progress&.update(preflight_member, status: label, mark: ">")
|
|
427
434
|
result = send(phase.fetch(:method))
|
|
428
|
-
|
|
435
|
+
progress&.advance(preflight_member, status: label, success: result.empty?, mark: result.empty? ? "." : "F")
|
|
436
|
+
unless result.empty?
|
|
437
|
+
progress&.finish_member(preflight_member, success: false, status: label)
|
|
438
|
+
progress&.stop
|
|
439
|
+
end
|
|
429
440
|
return result unless result.empty?
|
|
430
441
|
end
|
|
431
|
-
|
|
442
|
+
progress&.finish_member(preflight_member, success: true, status: "ok")
|
|
443
|
+
progress&.stop
|
|
432
444
|
[]
|
|
433
445
|
end
|
|
434
446
|
|
|
@@ -745,7 +757,9 @@ module Kettle
|
|
|
745
757
|
command: release_command,
|
|
746
758
|
env: release_env,
|
|
747
759
|
interactive: release_command_interactive?,
|
|
748
|
-
stdout_line_handler: release_event_line_handler(member, progress: progress)
|
|
760
|
+
stdout_line_handler: release_event_line_handler(member, progress: progress),
|
|
761
|
+
log_path: release_command_log_path(member, release_phase),
|
|
762
|
+
passthrough_output: release_command_passthrough_output?
|
|
749
763
|
)
|
|
750
764
|
emit_member_result_progress(member, memo.last, progress: progress)
|
|
751
765
|
return memo unless memo.last.ok?
|
|
@@ -1378,6 +1392,10 @@ module Kettle
|
|
|
1378
1392
|
publish || !!@gem_signing_password
|
|
1379
1393
|
end
|
|
1380
1394
|
|
|
1395
|
+
def release_command_passthrough_output?
|
|
1396
|
+
verbose || debug
|
|
1397
|
+
end
|
|
1398
|
+
|
|
1381
1399
|
def kettle_release_command?(command)
|
|
1382
1400
|
case command
|
|
1383
1401
|
when Array
|
|
@@ -1408,6 +1426,7 @@ module Kettle
|
|
|
1408
1426
|
args << "--local-ci" if local_ci
|
|
1409
1427
|
args << "--skip-bundle-audit" if skip_bundle_audit
|
|
1410
1428
|
args << "--skip-remotes=#{skip_remotes}" if skip_remotes && !skip_remotes.to_s.empty?
|
|
1429
|
+
args << "--required-remotes=#{required_remotes}" if required_remotes && !required_remotes.to_s.empty?
|
|
1411
1430
|
args << "--yes" if release_command_uses_kettle_release_yes? && !command_includes_arg?(command, "--yes")
|
|
1412
1431
|
args << "--events" unless command_includes_arg?(command, "--events")
|
|
1413
1432
|
return command if args.empty?
|
|
@@ -1436,12 +1455,14 @@ module Kettle
|
|
|
1436
1455
|
workflows.join(",")
|
|
1437
1456
|
end
|
|
1438
1457
|
|
|
1439
|
-
def
|
|
1440
|
-
return nil if value.nil?
|
|
1458
|
+
def validate_remote_list(value, option_name)
|
|
1459
|
+
return nil if value.nil?
|
|
1460
|
+
|
|
1461
|
+
remotes = Array(value).flat_map { |entry| entry.to_s.split(",") }.map(&:strip)
|
|
1462
|
+
return nil if remotes.all?(&:empty?)
|
|
1441
1463
|
|
|
1442
|
-
remotes = value.to_s.split(",").map(&:strip)
|
|
1443
1464
|
invalid = remotes.find { |remote| remote.empty? || !remote.match?(/\A[A-Za-z0-9_.-]+\z/) }
|
|
1444
|
-
raise Error, "invalid
|
|
1465
|
+
raise Error, "invalid #{option_name} value #{value.inspect}" if invalid
|
|
1445
1466
|
|
|
1446
1467
|
remotes.join(",")
|
|
1447
1468
|
end
|
|
@@ -1460,6 +1481,7 @@ module Kettle
|
|
|
1460
1481
|
env["K_RELEASE_CI_WORKFLOWS"] = ci_workflows if ci_workflows && !ci_workflows.to_s.empty?
|
|
1461
1482
|
env["KETTLE_DEV_SKIP_BUNDLE_AUDIT"] = "true" if skip_bundle_audit
|
|
1462
1483
|
env["K_RELEASE_SKIP_REMOTES"] = skip_remotes if skip_remotes && !skip_remotes.to_s.empty?
|
|
1484
|
+
env["K_RELEASE_REQUIRED_REMOTES"] = required_remotes if required_remotes && !required_remotes.to_s.empty?
|
|
1463
1485
|
env.merge!(kettle_release_secrets_env)
|
|
1464
1486
|
env
|
|
1465
1487
|
end
|
|
@@ -1903,6 +1925,24 @@ module Kettle
|
|
|
1903
1925
|
progress
|
|
1904
1926
|
end
|
|
1905
1927
|
|
|
1928
|
+
def start_release_preflight_progress(phases)
|
|
1929
|
+
return nil unless progress_io
|
|
1930
|
+
|
|
1931
|
+
phase_label = (phases.length == 1) ? "phase" : "phases"
|
|
1932
|
+
WorkflowProgress.new(
|
|
1933
|
+
io: progress_io,
|
|
1934
|
+
label: "release preflight",
|
|
1935
|
+
total: phases.length,
|
|
1936
|
+
jobs: 1,
|
|
1937
|
+
members: [release_preflight_progress_member],
|
|
1938
|
+
heading: "release preflight #{phases.length} #{phase_label}:"
|
|
1939
|
+
)
|
|
1940
|
+
end
|
|
1941
|
+
|
|
1942
|
+
def release_preflight_progress_member
|
|
1943
|
+
@release_preflight_progress_member ||= PreflightProgressMember.new("preflight")
|
|
1944
|
+
end
|
|
1945
|
+
|
|
1906
1946
|
def template_phase_total(member = nil)
|
|
1907
1947
|
total = 1
|
|
1908
1948
|
total += 2 if config.normalize_lockfiles?
|
|
@@ -1927,6 +1967,20 @@ module Kettle
|
|
|
1927
1967
|
end
|
|
1928
1968
|
end
|
|
1929
1969
|
|
|
1970
|
+
def release_command_log_path(member, phase)
|
|
1971
|
+
return nil unless execute
|
|
1972
|
+
|
|
1973
|
+
File.join(release_log_dir, "#{safe_log_name(member.name)}-#{safe_log_name(phase)}.log")
|
|
1974
|
+
end
|
|
1975
|
+
|
|
1976
|
+
def release_log_dir
|
|
1977
|
+
@release_log_dir ||= File.join(config.root, "tmp", "kettle-family", "release-#{Time.now.strftime("%Y%m%d-%H%M%S")}-#{$$}")
|
|
1978
|
+
end
|
|
1979
|
+
|
|
1980
|
+
def safe_log_name(value)
|
|
1981
|
+
value.to_s.gsub(/[^A-Za-z0-9_.-]+/, "_")
|
|
1982
|
+
end
|
|
1983
|
+
|
|
1930
1984
|
def template_initial_status(member = nil)
|
|
1931
1985
|
return "prepare_lockfiles" if config.normalize_lockfiles?
|
|
1932
1986
|
return "prepare_template_dependencies" if member.nil? || template_prepares_dependencies?(member)
|
|
@@ -1977,36 +2031,6 @@ module Kettle
|
|
|
1977
2031
|
progress.summary("release summary: #{release_results.count(&:ok?)}/#{release_results.length} members ok")
|
|
1978
2032
|
end
|
|
1979
2033
|
|
|
1980
|
-
def emit_release_preflight_start(phases)
|
|
1981
|
-
return unless progress_io
|
|
1982
|
-
|
|
1983
|
-
phase_label = (phases.length == 1) ? "phase" : "phases"
|
|
1984
|
-
progress_io.puts("release preflight #{phases.length} #{phase_label}:")
|
|
1985
|
-
progress_io.flush
|
|
1986
|
-
end
|
|
1987
|
-
|
|
1988
|
-
def emit_release_preflight_phase(label, index:, total:)
|
|
1989
|
-
return unless progress_io
|
|
1990
|
-
|
|
1991
|
-
progress_io.puts("[release preflight] (#{index + 1}/#{total}) > #{label}")
|
|
1992
|
-
progress_io.flush
|
|
1993
|
-
end
|
|
1994
|
-
|
|
1995
|
-
def emit_release_preflight_phase_finish(label, results)
|
|
1996
|
-
return unless progress_io
|
|
1997
|
-
|
|
1998
|
-
mark = results.empty? ? "." : "F"
|
|
1999
|
-
progress_io.puts("[release preflight] #{mark} #{label}")
|
|
2000
|
-
progress_io.flush
|
|
2001
|
-
end
|
|
2002
|
-
|
|
2003
|
-
def emit_release_preflight_summary(phases)
|
|
2004
|
-
return unless progress_io
|
|
2005
|
-
|
|
2006
|
-
progress_io.puts("release preflight summary: #{phases.length}/#{phases.length} phases ok")
|
|
2007
|
-
progress_io.flush
|
|
2008
|
-
end
|
|
2009
|
-
|
|
2010
2034
|
def template_event_line_handler(member, progress: nil)
|
|
2011
2035
|
lambda do |line|
|
|
2012
2036
|
event = parse_template_event(line)
|
|
@@ -2087,10 +2111,21 @@ module Kettle
|
|
|
2087
2111
|
when "run_start"
|
|
2088
2112
|
emit_template_event_line(member, ">", "release")
|
|
2089
2113
|
when "command_step"
|
|
2090
|
-
|
|
2091
|
-
emit_template_event_line(member, template_event_mark(event), label)
|
|
2114
|
+
emit_template_event_line(member, template_event_mark(event), command_step_event_label(event))
|
|
2092
2115
|
when "secret_provider"
|
|
2093
2116
|
emit_template_event_line(member, release_event_status_mark(event), secret_provider_event_label(event))
|
|
2117
|
+
when "remote_parity"
|
|
2118
|
+
emit_template_event_line(member, release_event_status_mark(event), remote_parity_event_label(event))
|
|
2119
|
+
when "ci_monitor"
|
|
2120
|
+
emit_template_event_line(member, release_event_status_mark(event), ci_monitor_event_label(event))
|
|
2121
|
+
when "pre_release"
|
|
2122
|
+
emit_template_event_line(member, release_event_status_mark(event), pre_release_event_label(event))
|
|
2123
|
+
when "changelog"
|
|
2124
|
+
emit_template_event_line(member, release_event_status_mark(event), changelog_event_label(event))
|
|
2125
|
+
when "release_lockfile"
|
|
2126
|
+
emit_template_event_line(member, release_event_status_mark(event), release_lockfile_event_label(event))
|
|
2127
|
+
when "release_probe"
|
|
2128
|
+
emit_template_event_line(member, release_event_status_mark(event), release_probe_event_label(event))
|
|
2094
2129
|
when "diagnostic"
|
|
2095
2130
|
emit_template_event_line(member, "!", diagnostic_event_label(event))
|
|
2096
2131
|
when "summary"
|
|
@@ -2103,9 +2138,21 @@ module Kettle
|
|
|
2103
2138
|
when "run_start"
|
|
2104
2139
|
"release"
|
|
2105
2140
|
when "command_step"
|
|
2106
|
-
|
|
2141
|
+
command_step_event_label(event)
|
|
2107
2142
|
when "secret_provider"
|
|
2108
2143
|
secret_provider_event_label(event)
|
|
2144
|
+
when "remote_parity"
|
|
2145
|
+
remote_parity_event_label(event)
|
|
2146
|
+
when "ci_monitor"
|
|
2147
|
+
ci_monitor_event_label(event)
|
|
2148
|
+
when "pre_release"
|
|
2149
|
+
pre_release_event_label(event)
|
|
2150
|
+
when "changelog"
|
|
2151
|
+
changelog_event_label(event)
|
|
2152
|
+
when "release_lockfile"
|
|
2153
|
+
release_lockfile_event_label(event)
|
|
2154
|
+
when "release_probe"
|
|
2155
|
+
release_probe_event_label(event)
|
|
2109
2156
|
when "diagnostic"
|
|
2110
2157
|
diagnostic_event_label(event)
|
|
2111
2158
|
when "summary"
|
|
@@ -2123,6 +2170,18 @@ module Kettle
|
|
|
2123
2170
|
template_event_mark(event)
|
|
2124
2171
|
when "secret_provider"
|
|
2125
2172
|
template_event_mark(event)
|
|
2173
|
+
when "remote_parity"
|
|
2174
|
+
template_event_mark(event)
|
|
2175
|
+
when "ci_monitor"
|
|
2176
|
+
template_event_mark(event)
|
|
2177
|
+
when "pre_release"
|
|
2178
|
+
template_event_mark(event)
|
|
2179
|
+
when "changelog"
|
|
2180
|
+
template_event_mark(event)
|
|
2181
|
+
when "release_lockfile"
|
|
2182
|
+
template_event_mark(event)
|
|
2183
|
+
when "release_probe"
|
|
2184
|
+
template_event_mark(event)
|
|
2126
2185
|
when "diagnostic"
|
|
2127
2186
|
"!"
|
|
2128
2187
|
when "summary"
|
|
@@ -2158,6 +2217,81 @@ module Kettle
|
|
|
2158
2217
|
parts.join(":")
|
|
2159
2218
|
end
|
|
2160
2219
|
|
|
2220
|
+
def command_step_event_label(event)
|
|
2221
|
+
parts = [event["phase"], event["name"]].map(&:to_s).reject(&:empty?)
|
|
2222
|
+
summary = event["summary"].to_s
|
|
2223
|
+
parts << summary unless summary.empty?
|
|
2224
|
+
parts.join(":")
|
|
2225
|
+
end
|
|
2226
|
+
|
|
2227
|
+
def remote_parity_event_label(event)
|
|
2228
|
+
action = event["action"].to_s
|
|
2229
|
+
remote = event["remote"].to_s
|
|
2230
|
+
trunk = event["trunk"].to_s
|
|
2231
|
+
parts = ["remote"]
|
|
2232
|
+
parts << action unless action.empty?
|
|
2233
|
+
parts << remote unless remote.empty?
|
|
2234
|
+
parts << trunk if remote.empty? && !trunk.empty?
|
|
2235
|
+
parts.join(":")
|
|
2236
|
+
end
|
|
2237
|
+
|
|
2238
|
+
def ci_monitor_event_label(event)
|
|
2239
|
+
action = event["action"].to_s
|
|
2240
|
+
provider = event["provider"].to_s
|
|
2241
|
+
target = event["workflow"].to_s
|
|
2242
|
+
target = "pipeline" if target.empty? && provider == "gitlab"
|
|
2243
|
+
parts = ["ci"]
|
|
2244
|
+
parts << action unless action.empty?
|
|
2245
|
+
parts << provider unless provider.empty?
|
|
2246
|
+
parts << target unless target.empty?
|
|
2247
|
+
if %w[github_wait github_started github_tick].include?(action) && event["completed"] && event["total"]
|
|
2248
|
+
parts << "#{event["completed"]}/#{event["total"]}"
|
|
2249
|
+
end
|
|
2250
|
+
completed_workflow = event["completed_workflow"].to_s
|
|
2251
|
+
parts << completed_workflow unless completed_workflow.empty? || completed_workflow == target
|
|
2252
|
+
parts.join(":")
|
|
2253
|
+
end
|
|
2254
|
+
|
|
2255
|
+
def pre_release_event_label(event)
|
|
2256
|
+
action = event["action"].to_s
|
|
2257
|
+
check = event["check"].to_s
|
|
2258
|
+
parts = ["pre"]
|
|
2259
|
+
parts << action unless action.empty?
|
|
2260
|
+
parts << check unless check.empty?
|
|
2261
|
+
parts.join(":")
|
|
2262
|
+
end
|
|
2263
|
+
|
|
2264
|
+
def changelog_event_label(event)
|
|
2265
|
+
action = event["action"].to_s
|
|
2266
|
+
plan = event["plan"].to_s
|
|
2267
|
+
parts = ["changelog"]
|
|
2268
|
+
parts << action unless action.empty?
|
|
2269
|
+
parts << plan unless plan.empty? || action == "coverage"
|
|
2270
|
+
parts.join(":")
|
|
2271
|
+
end
|
|
2272
|
+
|
|
2273
|
+
def release_lockfile_event_label(event)
|
|
2274
|
+
action = event["action"].to_s
|
|
2275
|
+
stage = event["stage"].to_s
|
|
2276
|
+
stage = stage.tr(" ", "_")
|
|
2277
|
+
parts = ["lockfile"]
|
|
2278
|
+
parts << action unless action.empty?
|
|
2279
|
+
parts << stage unless stage.empty?
|
|
2280
|
+
parts << "#{event["attempt"]}/#{event["attempts"]}" if event["attempt"] && event["attempts"]
|
|
2281
|
+
parts.join(":")
|
|
2282
|
+
end
|
|
2283
|
+
|
|
2284
|
+
def release_probe_event_label(event)
|
|
2285
|
+
action = event["action"].to_s
|
|
2286
|
+
gem_name = event["gem"].to_s
|
|
2287
|
+
version = event["version"].to_s
|
|
2288
|
+
parts = ["probe"]
|
|
2289
|
+
parts << action unless action.empty?
|
|
2290
|
+
parts << [gem_name, version].reject(&:empty?).join("-")
|
|
2291
|
+
parts << "#{event["attempt"]}/#{event["attempts"]}" if event["attempt"] && event["attempts"]
|
|
2292
|
+
parts.reject(&:empty?).join(":")
|
|
2293
|
+
end
|
|
2294
|
+
|
|
2161
2295
|
def diagnostic_event_label(event)
|
|
2162
2296
|
message = event["message"]
|
|
2163
2297
|
return message.to_s unless message.to_s.empty? || message.is_a?(Hash)
|
|
@@ -15,11 +15,12 @@ module Kettle
|
|
|
15
15
|
DEFAULT_TERMINAL_WIDTH = 80
|
|
16
16
|
ELLIPSIS = "..."
|
|
17
17
|
|
|
18
|
-
def initialize(io:, label:, total:, jobs:, members: [], enabled: true, clock: nil)
|
|
18
|
+
def initialize(io:, label:, total:, jobs:, members: [], enabled: true, clock: nil, heading: nil)
|
|
19
19
|
@io = io
|
|
20
20
|
@label = label
|
|
21
21
|
@total = total.to_i
|
|
22
22
|
@jobs = jobs.to_i
|
|
23
|
+
@heading = heading
|
|
23
24
|
@clock = clock || lambda { Process.clock_gettime(Process::CLOCK_MONOTONIC) }
|
|
24
25
|
@enabled = enabled && !!io
|
|
25
26
|
@bars = {}
|
|
@@ -43,7 +44,7 @@ module Kettle
|
|
|
43
44
|
synchronize do
|
|
44
45
|
next if @started
|
|
45
46
|
|
|
46
|
-
write_line("#{@label} #{@total} member#{plural(@total)} with #{@jobs} job#{plural(@jobs)}:")
|
|
47
|
+
write_line(@heading || "#{@label} #{@total} member#{plural(@total)} with #{@jobs} job#{plural(@jobs)}:")
|
|
47
48
|
@started = true
|
|
48
49
|
@line_order.each { |member_name| render_name(member_name, status: "") } if @tty
|
|
49
50
|
end
|
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.2.
|
|
4
|
+
version: 1.2.14
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Peter H. Boling
|
|
@@ -74,7 +74,7 @@ dependencies:
|
|
|
74
74
|
version: '2.3'
|
|
75
75
|
- - ">="
|
|
76
76
|
- !ruby/object:Gem::Version
|
|
77
|
-
version: 2.5.
|
|
77
|
+
version: 2.5.13
|
|
78
78
|
type: :runtime
|
|
79
79
|
prerelease: false
|
|
80
80
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -84,7 +84,7 @@ dependencies:
|
|
|
84
84
|
version: '2.3'
|
|
85
85
|
- - ">="
|
|
86
86
|
- !ruby/object:Gem::Version
|
|
87
|
-
version: 2.5.
|
|
87
|
+
version: 2.5.13
|
|
88
88
|
- !ruby/object:Gem::Dependency
|
|
89
89
|
name: kettle-test
|
|
90
90
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -342,10 +342,10 @@ licenses:
|
|
|
342
342
|
- AGPL-3.0-only
|
|
343
343
|
metadata:
|
|
344
344
|
homepage_uri: https://kettle-family.galtzo.com
|
|
345
|
-
source_code_uri: https://github.com/kettle-dev/kettle-family/tree/v1.2.
|
|
346
|
-
changelog_uri: https://github.com/kettle-dev/kettle-family/blob/v1.2.
|
|
345
|
+
source_code_uri: https://github.com/kettle-dev/kettle-family/tree/v1.2.14
|
|
346
|
+
changelog_uri: https://github.com/kettle-dev/kettle-family/blob/v1.2.14/CHANGELOG.md
|
|
347
347
|
bug_tracker_uri: https://github.com/kettle-dev/kettle-family/issues
|
|
348
|
-
documentation_uri: https://www.rubydoc.info/gems/kettle-family/1.2.
|
|
348
|
+
documentation_uri: https://www.rubydoc.info/gems/kettle-family/1.2.14
|
|
349
349
|
funding_uri: https://github.com/sponsors/pboling
|
|
350
350
|
wiki_uri: https://github.com/kettle-dev/kettle-family/wiki
|
|
351
351
|
news_uri: https://www.railsbling.com/tags/kettle-family
|
metadata.gz.sig
CHANGED
|
Binary file
|