kettle-family 1.2.95 → 1.2.96
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 +20 -1
- data/README.md +1 -1
- data/lib/kettle/family/cli.rb +28 -10
- data/lib/kettle/family/discovery.rb +10 -3
- data/lib/kettle/family/release_state_check.rb +14 -11
- data/lib/kettle/family/release_state_event_tape.rb +12 -6
- data/lib/kettle/family/version.rb +1 -1
- data/lib/kettle/family/workflow.rb +85 -30
- data/lib/kettle/family/workflow_progress.rb +39 -38
- data.tar.gz.sig +0 -0
- metadata +20 -20
- 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: d2f776638603414ab6c27f457473dea3f6088bae63f58a45fcbc0f165fe0e026
|
|
4
|
+
data.tar.gz: b44e74efb8e840e929df24573b815df7b7a749f27e67f86f76561ab654b406ea
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 77f9c29784b453d8d270398c675ed52e18d8ba5f374fc8add80465bce88f59a679ab254080e3fe349685bff16134bb97541ef087d5c32116123c95e443b64685
|
|
7
|
+
data.tar.gz: 4e750df4e8f1f7f92ee8a653bac8ed02a95ee7ddfa5daa8f8eef92003b78e2c58c93b41498b0b93f8649626dcaf3a645f36fdedabf78928e35653131f14431c3
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
data/CHANGELOG.md
CHANGED
|
@@ -30,6 +30,23 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
|
30
30
|
|
|
31
31
|
### Security
|
|
32
32
|
|
|
33
|
+
## [1.2.96] - 2026-09-08
|
|
34
|
+
|
|
35
|
+
- TAG: [v1.2.96][1.2.96t]
|
|
36
|
+
- COVERAGE: 93.49% -- 6235/6669 lines in 35 files
|
|
37
|
+
- BRANCH COVERAGE: 77.99% -- 2523/3235 branches in 35 files
|
|
38
|
+
- 32.75% documented
|
|
39
|
+
|
|
40
|
+
### Fixed
|
|
41
|
+
|
|
42
|
+
- Render branch-worktree template events in distinct live progress rows.
|
|
43
|
+
|
|
44
|
+
- Run release-state branch targets concurrently and render distinct branch progress rows.
|
|
45
|
+
|
|
46
|
+
- Preserve configured release waves for ordinary sibling members when another member has release-target branches.
|
|
47
|
+
|
|
48
|
+
- Restore the version_gem runtime dependency and preserve worktree integration documentation during template updates.
|
|
49
|
+
|
|
33
50
|
## [1.2.95] - 2026-09-07
|
|
34
51
|
|
|
35
52
|
- TAG: [v1.2.95][1.2.95t]
|
|
@@ -2651,7 +2668,9 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
|
2651
2668
|
- Fixed CI load failures on engines without compatible `pty` support by falling back to Open3 for interactive release commands.
|
|
2652
2669
|
- Fixed Ruby 3.2 version-bump support by loading Prism lazily and wiring the Prism gem only for MRI versions that need it.
|
|
2653
2670
|
|
|
2654
|
-
[Unreleased]: https://github.com/kettle-dev/kettle-family/compare/v1.2.
|
|
2671
|
+
[Unreleased]: https://github.com/kettle-dev/kettle-family/compare/v1.2.96...HEAD
|
|
2672
|
+
[1.2.96]: https://github.com/kettle-dev/kettle-family/compare/v1.2.95...v1.2.96
|
|
2673
|
+
[1.2.96t]: https://github.com/kettle-dev/kettle-family/releases/tag/v1.2.96
|
|
2655
2674
|
[1.2.95]: https://github.com/kettle-dev/kettle-family/compare/v1.2.94...v1.2.95
|
|
2656
2675
|
[1.2.95t]: https://github.com/kettle-dev/kettle-family/releases/tag/v1.2.95
|
|
2657
2676
|
[1.2.94]: https://github.com/kettle-dev/kettle-family/compare/v1.2.93...v1.2.94
|
data/README.md
CHANGED
|
@@ -1171,7 +1171,7 @@ Thanks for RTFM. ☺️
|
|
|
1171
1171
|
[📌gitmoji]: https://gitmoji.dev
|
|
1172
1172
|
[📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
|
|
1173
1173
|
[🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
|
|
1174
|
-
[🧮kloc-img]: https://img.shields.io/badge/KLOC-6.
|
|
1174
|
+
[🧮kloc-img]: https://img.shields.io/badge/KLOC-6.669-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
|
|
1175
1175
|
[🔐security]: https://github.com/kettle-dev/kettle-family/blob/main/SECURITY.md
|
|
1176
1176
|
[🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
|
|
1177
1177
|
[📄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
|
@@ -709,7 +709,7 @@ module Kettle
|
|
|
709
709
|
display_selected_members = display_members_for(command: command, config: config, members: selected, selected_members: selected)
|
|
710
710
|
print_execution_intent(command: command, config: config, members: display_selected_members, options: options, start_at: start_at)
|
|
711
711
|
started_at = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
712
|
-
state_progress = release_state_progress(command: command, members: result_members, options: options)
|
|
712
|
+
state_progress = release_state_progress(command: command, config: config, members: result_members, options: options)
|
|
713
713
|
state_progress&.start
|
|
714
714
|
state_event_handler = release_state_event_handler(
|
|
715
715
|
event_tape: state_event_tape,
|
|
@@ -901,21 +901,36 @@ module Kettle
|
|
|
901
901
|
stdout
|
|
902
902
|
end
|
|
903
903
|
|
|
904
|
-
def release_state_progress(command:, members:, options:)
|
|
904
|
+
def release_state_progress(command:, config:, members:, options:)
|
|
905
905
|
return nil unless command == "release-state"
|
|
906
906
|
return nil if options[:events] || options[:json]
|
|
907
907
|
return nil unless stdout.respond_to?(:tty?) && stdout.tty?
|
|
908
908
|
|
|
909
|
+
targets = release_state_progress_targets(config: config, members: members)
|
|
910
|
+
|
|
909
911
|
WorkflowProgress.new(
|
|
910
912
|
io: stdout,
|
|
911
913
|
label: "release state",
|
|
912
|
-
total:
|
|
913
|
-
jobs: Concurrency.wave_jobs(requested: options[:jobs], item_count:
|
|
914
|
-
members:
|
|
915
|
-
heading: "release state #{
|
|
914
|
+
total: targets.length,
|
|
915
|
+
jobs: Concurrency.wave_jobs(requested: options[:jobs], item_count: targets.length),
|
|
916
|
+
members: targets.map { |target| target.fetch(:progress_member) },
|
|
917
|
+
heading: "release state #{targets.length} target#{"s" unless targets.length == 1}:"
|
|
916
918
|
)
|
|
917
919
|
end
|
|
918
920
|
|
|
921
|
+
def release_state_progress_targets(config:, members:)
|
|
922
|
+
members.flat_map do |member|
|
|
923
|
+
member_config = member_release_config(member: member, config: config)
|
|
924
|
+
branches = member_config&.release_target_branches.to_a
|
|
925
|
+
next [{member: member, key: member.name, label: member.name, progress_member: member}] if branches.empty?
|
|
926
|
+
|
|
927
|
+
branches.map do |branch|
|
|
928
|
+
label = "#{member.name}@#{branch}"
|
|
929
|
+
{member: member, key: label, label: label, progress_member: member.dup.tap { |copy| copy.name = label }}
|
|
930
|
+
end
|
|
931
|
+
end
|
|
932
|
+
end
|
|
933
|
+
|
|
919
934
|
def release_state_event_handler(event_tape:, progress:, members:)
|
|
920
935
|
return nil unless event_tape || progress
|
|
921
936
|
|
|
@@ -927,18 +942,21 @@ module Kettle
|
|
|
927
942
|
member = members_by_name[event["member"]]
|
|
928
943
|
next unless member
|
|
929
944
|
|
|
945
|
+
branch = event["branch"].to_s
|
|
946
|
+
progress_key = branch.empty? ? member.name : "#{member.name}@#{branch}"
|
|
947
|
+
|
|
930
948
|
action = event["action"].to_s
|
|
931
949
|
status = event["status"].to_s
|
|
932
950
|
case action
|
|
933
951
|
when "member_start"
|
|
934
|
-
progress.start_member(member, total: 5, status: "release_state")
|
|
952
|
+
progress.start_member(member, total: 5, status: "release_state", key: progress_key, label: progress_key)
|
|
935
953
|
when "member_complete"
|
|
936
|
-
progress.finish_member(member, success: status == "ok", status: status)
|
|
954
|
+
progress.finish_member(member, success: status == "ok", status: status, key: progress_key, label: progress_key)
|
|
937
955
|
when "changelog_command", "computed_booleans", "git_state", "github_release", "transfer_changelog"
|
|
938
956
|
if status == "running"
|
|
939
|
-
progress.update(member, status: action)
|
|
957
|
+
progress.update(member, status: action, key: progress_key, label: progress_key)
|
|
940
958
|
elsif status == "ok" || status == "failed"
|
|
941
|
-
progress.advance(member, status: action, success: status == "ok")
|
|
959
|
+
progress.advance(member, status: action, success: status == "ok", key: progress_key, label: progress_key)
|
|
942
960
|
end
|
|
943
961
|
end
|
|
944
962
|
end
|
|
@@ -5,6 +5,11 @@ require "open3"
|
|
|
5
5
|
module Kettle
|
|
6
6
|
module Family
|
|
7
7
|
class Discovery
|
|
8
|
+
# Dir.chdir changes process-global state. Legacy gemspecs require this
|
|
9
|
+
# evaluation context, so serialize only that boundary; discovery callers
|
|
10
|
+
# may still resolve separate members and worktrees concurrently.
|
|
11
|
+
GEMSPEC_EVALUATION_MUTEX = Mutex.new
|
|
12
|
+
|
|
8
13
|
def initialize(config:, release_dependency_member_names: nil)
|
|
9
14
|
@config = config
|
|
10
15
|
@release_dependency_member_names = release_dependency_member_names&.map(&:to_s)
|
|
@@ -174,9 +179,11 @@ module Kettle
|
|
|
174
179
|
# evaluates gemspecs relative to the current process directory.
|
|
175
180
|
# Gem::Specification.load caches by path, which is wrong for branch-stack
|
|
176
181
|
# workflows that checkout different contents at the same path.
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
182
|
+
spec = GEMSPEC_EVALUATION_MUTEX.synchronize do
|
|
183
|
+
# rubocop:disable ThreadSafety/DirChdir
|
|
184
|
+
Dir.chdir(File.dirname(path)) { eval_gemspec(path) }
|
|
185
|
+
# rubocop:enable ThreadSafety/DirChdir
|
|
186
|
+
end
|
|
180
187
|
raise Error, "could not load gemspec #{path}" unless spec
|
|
181
188
|
|
|
182
189
|
spec
|
|
@@ -56,20 +56,23 @@ module Kettle
|
|
|
56
56
|
def branch_results(event_handler: nil)
|
|
57
57
|
root = git_root
|
|
58
58
|
selected_names = members.map(&:name)
|
|
59
|
-
release_target_branches
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
results = parallel_map(branch_members) { |member| check_shared_changelog_member_or_local(member, branch: branch, event_handler: event_handler) }
|
|
64
|
-
memo.concat(normalize_shared_version_bump(results))
|
|
65
|
-
next
|
|
66
|
-
end
|
|
59
|
+
parallel_map(release_target_branches) do |branch|
|
|
60
|
+
branch_results_for(branch: branch, root: root, selected_names: selected_names, event_handler: event_handler)
|
|
61
|
+
end.flatten
|
|
62
|
+
end
|
|
67
63
|
|
|
68
|
-
|
|
64
|
+
def branch_results_for(branch:, root:, selected_names:, event_handler:)
|
|
65
|
+
with_branch_worktree(root: root, branch: branch) do |worktree_root|
|
|
66
|
+
branch_members = discover_branch_members(worktree_root: worktree_root, selected_names: selected_names)
|
|
67
|
+
if shared_changelog?
|
|
68
|
+
results = parallel_map(branch_members) { |member| check_shared_changelog_member_or_local(member, branch: branch, event_handler: event_handler) }
|
|
69
|
+
next normalize_shared_version_bump(results)
|
|
69
70
|
end
|
|
70
|
-
|
|
71
|
-
|
|
71
|
+
|
|
72
|
+
parallel_map(branch_members) { |member| check_member(member, branch: branch, event_handler: event_handler) }
|
|
72
73
|
end
|
|
74
|
+
rescue Error => error
|
|
75
|
+
[error_result(branch: branch, error: error)]
|
|
73
76
|
end
|
|
74
77
|
|
|
75
78
|
def check_member(member, branch: nil, event_handler: nil)
|
|
@@ -27,12 +27,12 @@ module Kettle
|
|
|
27
27
|
"timestamp" => @wall_clock.call,
|
|
28
28
|
"elapsed_seconds" => @clock.call - @started_at
|
|
29
29
|
)
|
|
30
|
-
|
|
30
|
+
target = target_key(payload)
|
|
31
31
|
@mutex.synchronize do
|
|
32
|
-
@sequence_by_member[
|
|
33
|
-
payload["sequence"] = @sequence_by_member.fetch(
|
|
32
|
+
@sequence_by_member[target] += 1
|
|
33
|
+
payload["sequence"] = @sequence_by_member.fetch(target)
|
|
34
34
|
line = JSON.generate(payload)
|
|
35
|
-
File.open(path_for(
|
|
35
|
+
File.open(path_for(target), "a") { |file| file.puts(line) }
|
|
36
36
|
@stream&.puts(line)
|
|
37
37
|
@stream.flush if @stream&.respond_to?(:flush)
|
|
38
38
|
end
|
|
@@ -43,8 +43,14 @@ module Kettle
|
|
|
43
43
|
|
|
44
44
|
private
|
|
45
45
|
|
|
46
|
-
def
|
|
47
|
-
|
|
46
|
+
def target_key(payload)
|
|
47
|
+
member = payload.fetch("member", "family").to_s
|
|
48
|
+
branch = payload["branch"].to_s
|
|
49
|
+
branch.empty? ? member : "#{member}@#{branch}"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def path_for(target)
|
|
53
|
+
filename = target.gsub(/[^A-Za-z0-9_.-]+/, "_")
|
|
48
54
|
File.join(@directory, "#{filename}.ndjson")
|
|
49
55
|
end
|
|
50
56
|
end
|
|
@@ -5,7 +5,7 @@ module Kettle
|
|
|
5
5
|
# Version namespace for this gem.
|
|
6
6
|
module Version
|
|
7
7
|
# Current gem version.
|
|
8
|
-
VERSION = "1.2.
|
|
8
|
+
VERSION = "1.2.96"
|
|
9
9
|
end
|
|
10
10
|
# Current gem version exposed at the traditional constant location.
|
|
11
11
|
VERSION = Version::VERSION # Traditional Constant Location
|
|
@@ -1411,13 +1411,20 @@ module Kettle
|
|
|
1411
1411
|
)
|
|
1412
1412
|
end
|
|
1413
1413
|
|
|
1414
|
-
def template_results_for_member(member, progress: nil, commit_changes: true, wave_jobs: 1)
|
|
1415
|
-
|
|
1414
|
+
def template_results_for_member(member, progress: nil, progress_key: nil, progress_label: nil, commit_changes: true, wave_jobs: 1)
|
|
1415
|
+
progress_key ||= member.name
|
|
1416
|
+
progress_label ||= member.name
|
|
1417
|
+
progress&.start_member(
|
|
1418
|
+
member,
|
|
1419
|
+
total: template_phase_total(member),
|
|
1420
|
+
status: template_initial_status(member),
|
|
1421
|
+
**template_progress_identity_options(member, progress_key, progress_label)
|
|
1422
|
+
)
|
|
1416
1423
|
runner = CommandRunner.new(execute: execute, accept: accept)
|
|
1417
1424
|
[].tap do |memo|
|
|
1418
1425
|
if config.normalize_lockfiles?
|
|
1419
1426
|
normalize_lockfiles(member: member, runner: runner, memo: memo, phase: "prepare_lockfiles", commit_changes: commit_changes)
|
|
1420
|
-
emit_member_result_progress(member, memo.last, progress: progress)
|
|
1427
|
+
emit_member_result_progress(member, memo.last, progress: progress, progress_key: progress_key, progress_label: progress_label)
|
|
1421
1428
|
return memo unless memo.last.ok?
|
|
1422
1429
|
end
|
|
1423
1430
|
|
|
@@ -1428,7 +1435,7 @@ module Kettle
|
|
|
1428
1435
|
commit_changes: commit_changes,
|
|
1429
1436
|
wave_jobs: wave_jobs
|
|
1430
1437
|
)
|
|
1431
|
-
emit_member_result_progress(member, memo.last, progress: progress) if memo.last&.phase == "prepare_template_dependencies"
|
|
1438
|
+
emit_member_result_progress(member, memo.last, progress: progress, progress_key: progress_key, progress_label: progress_label) if memo.last&.phase == "prepare_template_dependencies"
|
|
1432
1439
|
return memo if prepared == false
|
|
1433
1440
|
|
|
1434
1441
|
memo << runner.call(
|
|
@@ -1436,22 +1443,23 @@ module Kettle
|
|
|
1436
1443
|
phase: command,
|
|
1437
1444
|
command: workflow_command(member),
|
|
1438
1445
|
env: template_command_env(wave_jobs: wave_jobs),
|
|
1439
|
-
stdout_line_handler: template_event_line_handler(member, progress: progress)
|
|
1446
|
+
stdout_line_handler: template_event_line_handler(member, progress: progress, progress_key: progress_key, progress_label: progress_label)
|
|
1440
1447
|
)
|
|
1441
|
-
emit_member_result_progress(member, memo.last, progress: progress)
|
|
1448
|
+
emit_member_result_progress(member, memo.last, progress: progress, progress_key: progress_key, progress_label: progress_label)
|
|
1442
1449
|
return memo unless memo.last.ok?
|
|
1443
1450
|
|
|
1444
1451
|
normalize_lockfiles(member: member, runner: runner, memo: memo, phase: "normalize_lockfiles", commit_changes: commit_changes)
|
|
1445
|
-
emit_member_result_progress(member, memo.last, progress: progress)
|
|
1452
|
+
emit_member_result_progress(member, memo.last, progress: progress, progress_key: progress_key, progress_label: progress_label)
|
|
1446
1453
|
commit_template_changes(member: member, runner: runner, memo: memo) if commit_changes
|
|
1447
|
-
emit_member_result_progress(member, memo.last, progress: progress) if memo.last&.phase == "commit_template"
|
|
1454
|
+
emit_member_result_progress(member, memo.last, progress: progress, progress_key: progress_key, progress_label: progress_label) if memo.last&.phase == "commit_template"
|
|
1448
1455
|
ensure
|
|
1449
1456
|
template_result = memo.find { |result| result.phase == "template" } || memo.last
|
|
1450
1457
|
if template_result
|
|
1451
1458
|
progress&.finish_member(
|
|
1452
1459
|
member,
|
|
1453
1460
|
success: memo.all?(&:ok?),
|
|
1454
|
-
status: template_member_finish_status(template_result)
|
|
1461
|
+
status: template_member_finish_status(template_result),
|
|
1462
|
+
**template_progress_identity_options(member, progress_key, progress_label)
|
|
1455
1463
|
)
|
|
1456
1464
|
end
|
|
1457
1465
|
end
|
|
@@ -1568,7 +1576,13 @@ module Kettle
|
|
|
1568
1576
|
|
|
1569
1577
|
if outcomes.all?(&:ok?)
|
|
1570
1578
|
emit_template_event_line(member, ">", "branch worktrees #{entries.length} branches, #{template_jobs(entries)} jobs")
|
|
1571
|
-
|
|
1579
|
+
progress = start_template_progress(
|
|
1580
|
+
entries.map { |entry| template_branch_progress_member(entry) },
|
|
1581
|
+
heading: "templating #{entries.length} branch worktree#{"s" unless entries.length == 1} with #{template_jobs(entries)} job#{"s" unless template_jobs(entries) == 1}:"
|
|
1582
|
+
)
|
|
1583
|
+
branch_results = template_branch_worktree_entries_results(entries, progress: progress)
|
|
1584
|
+
emit_template_progress_summary(branch_results, progress: progress)
|
|
1585
|
+
outcomes.concat(branch_results)
|
|
1572
1586
|
end
|
|
1573
1587
|
end
|
|
1574
1588
|
end
|
|
@@ -1658,7 +1672,7 @@ module Kettle
|
|
|
1658
1672
|
[]
|
|
1659
1673
|
end
|
|
1660
1674
|
|
|
1661
|
-
def template_branch_worktree_entries_results(entries)
|
|
1675
|
+
def template_branch_worktree_entries_results(entries, progress: nil)
|
|
1662
1676
|
results = template_branch_worktree_sync_results(entries)
|
|
1663
1677
|
return results unless results.all?(&:ok?)
|
|
1664
1678
|
|
|
@@ -1681,7 +1695,7 @@ module Kettle
|
|
|
1681
1695
|
loop do
|
|
1682
1696
|
break if mutex.synchronize { stop }
|
|
1683
1697
|
index, entry = queue.pop(true)
|
|
1684
|
-
branch_results = template_branch_worktree_entry_results(entry, wave_jobs: wave_jobs)
|
|
1698
|
+
branch_results = template_branch_worktree_entry_results(entry, progress: progress, wave_jobs: wave_jobs)
|
|
1685
1699
|
mutex.synchronize do
|
|
1686
1700
|
ordered_results[index] = branch_results
|
|
1687
1701
|
stop = true unless branch_results.all?(&:ok?)
|
|
@@ -1694,18 +1708,36 @@ module Kettle
|
|
|
1694
1708
|
results + ordered_results.compact.flatten
|
|
1695
1709
|
end
|
|
1696
1710
|
|
|
1697
|
-
def template_branch_worktree_entry_results(entry, wave_jobs: 1)
|
|
1711
|
+
def template_branch_worktree_entry_results(entry, progress: nil, wave_jobs: 1)
|
|
1698
1712
|
member = entry.fetch(:member)
|
|
1699
1713
|
branch = entry.fetch(:branch)
|
|
1700
1714
|
# Bootstrap and upstream synchronization are deliberately performed
|
|
1701
1715
|
# for the complete branch set before workers start. The member body is
|
|
1702
1716
|
# the same method normal template waves invoke.
|
|
1703
|
-
results = template_results_for_member(
|
|
1717
|
+
results = template_results_for_member(
|
|
1718
|
+
member,
|
|
1719
|
+
progress: progress,
|
|
1720
|
+
progress_key: template_branch_progress_key(entry),
|
|
1721
|
+
progress_label: template_branch_progress_label(entry),
|
|
1722
|
+
wave_jobs: wave_jobs
|
|
1723
|
+
)
|
|
1704
1724
|
tag_branch_results(results, branch)
|
|
1705
1725
|
emit_template_event_line(member, results.all?(&:ok?) ? "." : "F", "branch #{branch}")
|
|
1706
1726
|
results
|
|
1707
1727
|
end
|
|
1708
1728
|
|
|
1729
|
+
def template_branch_progress_member(entry)
|
|
1730
|
+
entry.fetch(:member).dup.tap { |member| member.name = template_branch_progress_label(entry) }
|
|
1731
|
+
end
|
|
1732
|
+
|
|
1733
|
+
def template_branch_progress_key(entry)
|
|
1734
|
+
template_branch_progress_label(entry)
|
|
1735
|
+
end
|
|
1736
|
+
|
|
1737
|
+
def template_branch_progress_label(entry)
|
|
1738
|
+
"#{entry.fetch(:member).name}@#{entry.fetch(:branch)}"
|
|
1739
|
+
end
|
|
1740
|
+
|
|
1709
1741
|
def template_branch_worktree_sync_results(entries)
|
|
1710
1742
|
runner = command_runner
|
|
1711
1743
|
entries.filter_map do |entry|
|
|
@@ -2002,18 +2034,21 @@ module Kettle
|
|
|
2002
2034
|
end
|
|
2003
2035
|
|
|
2004
2036
|
def release_member_local_branch_target_results
|
|
2005
|
-
|
|
2037
|
+
target_members, current_branch_members = members.partition do |member|
|
|
2038
|
+
member_local_release_config(member)
|
|
2039
|
+
end
|
|
2006
2040
|
results = []
|
|
2007
|
-
|
|
2041
|
+
|
|
2042
|
+
# A member with release targets must not force unrelated sibling
|
|
2043
|
+
# repositories through one-at-a-time release workflows. Run those
|
|
2044
|
+
# members through the normal release scheduler first so configured
|
|
2045
|
+
# waves and their worker budget remain effective.
|
|
2046
|
+
results.concat(current_branch_results(current_branch_members)) unless current_branch_members.empty?
|
|
2008
2047
|
return results unless results.all?(&:ok?)
|
|
2009
2048
|
|
|
2010
|
-
|
|
2049
|
+
target_members.each_with_object(results) do |member, memo|
|
|
2011
2050
|
member_config = member_local_release_config(member)
|
|
2012
|
-
|
|
2013
|
-
memo.concat(member_local_workflow(member: member, member_config: member_config).results)
|
|
2014
|
-
else
|
|
2015
|
-
memo.concat(release_member_results([member], include_family_changelog: false))
|
|
2016
|
-
end
|
|
2051
|
+
memo.concat(member_local_workflow(member: member, member_config: member_config).results)
|
|
2017
2052
|
break memo unless memo.last&.ok?
|
|
2018
2053
|
end
|
|
2019
2054
|
end
|
|
@@ -4362,13 +4397,14 @@ module Kettle
|
|
|
4362
4397
|
append_command_args(command_text, args)
|
|
4363
4398
|
end
|
|
4364
4399
|
|
|
4365
|
-
def start_template_progress(workflow_members)
|
|
4400
|
+
def start_template_progress(workflow_members, heading: nil)
|
|
4366
4401
|
progress = WorkflowProgress.new(
|
|
4367
4402
|
io: progress_io,
|
|
4368
4403
|
label: "templating",
|
|
4369
4404
|
total: workflow_members.length,
|
|
4370
4405
|
jobs: template_jobs(workflow_members),
|
|
4371
|
-
members: workflow_members
|
|
4406
|
+
members: workflow_members,
|
|
4407
|
+
heading: heading
|
|
4372
4408
|
)
|
|
4373
4409
|
progress.start
|
|
4374
4410
|
progress
|
|
@@ -4472,10 +4508,16 @@ module Kettle
|
|
|
4472
4508
|
kettle_jem_template_command?(command_text)
|
|
4473
4509
|
end
|
|
4474
4510
|
|
|
4475
|
-
def emit_member_result_progress(member, result, progress:)
|
|
4511
|
+
def emit_member_result_progress(member, result, progress:, progress_key: member.name, progress_label: member.name)
|
|
4476
4512
|
return unless result
|
|
4477
4513
|
|
|
4478
|
-
progress&.advance(
|
|
4514
|
+
progress&.advance(
|
|
4515
|
+
member,
|
|
4516
|
+
status: result.phase,
|
|
4517
|
+
success: result.ok?,
|
|
4518
|
+
mark: command_result_progress_mark(result),
|
|
4519
|
+
**template_progress_identity_options(member, progress_key, progress_label)
|
|
4520
|
+
)
|
|
4479
4521
|
end
|
|
4480
4522
|
|
|
4481
4523
|
def command_result_progress_mark(result)
|
|
@@ -4522,7 +4564,7 @@ module Kettle
|
|
|
4522
4564
|
progress.summary("release summary: #{release_results.count(&:ok?)}/#{release_results.length} members ok")
|
|
4523
4565
|
end
|
|
4524
4566
|
|
|
4525
|
-
def template_event_line_handler(member, progress: nil)
|
|
4567
|
+
def template_event_line_handler(member, progress: nil, progress_key: member.name, progress_label: member.name)
|
|
4526
4568
|
lambda do |line|
|
|
4527
4569
|
event = parse_template_event(line)
|
|
4528
4570
|
next false unless event
|
|
@@ -4531,7 +4573,7 @@ module Kettle
|
|
|
4531
4573
|
if verbose || debug
|
|
4532
4574
|
emit_template_event_progress(member, event)
|
|
4533
4575
|
elsif progress&.tty?
|
|
4534
|
-
emit_template_event_status(member, event, progress: progress)
|
|
4576
|
+
emit_template_event_status(member, event, progress: progress, progress_key: progress_key, progress_label: progress_label)
|
|
4535
4577
|
end
|
|
4536
4578
|
end
|
|
4537
4579
|
true
|
|
@@ -4649,7 +4691,7 @@ module Kettle
|
|
|
4649
4691
|
end
|
|
4650
4692
|
end
|
|
4651
4693
|
|
|
4652
|
-
def emit_template_event_status(member, event, progress:)
|
|
4694
|
+
def emit_template_event_status(member, event, progress:, progress_key: member.name, progress_label: member.name)
|
|
4653
4695
|
status = case event["type"]
|
|
4654
4696
|
when "phase_start", "phase_finish"
|
|
4655
4697
|
event["phase"].to_s
|
|
@@ -4663,7 +4705,20 @@ module Kettle
|
|
|
4663
4705
|
template_event_summary_label(event)
|
|
4664
4706
|
end
|
|
4665
4707
|
mark = template_event_status_mark(event)
|
|
4666
|
-
|
|
4708
|
+
if status && !status.empty?
|
|
4709
|
+
progress&.update(
|
|
4710
|
+
member,
|
|
4711
|
+
status: status,
|
|
4712
|
+
mark: mark,
|
|
4713
|
+
**template_progress_identity_options(member, progress_key, progress_label)
|
|
4714
|
+
)
|
|
4715
|
+
end
|
|
4716
|
+
end
|
|
4717
|
+
|
|
4718
|
+
def template_progress_identity_options(member, progress_key, progress_label)
|
|
4719
|
+
return {} if progress_key == member.name && progress_label == member.name
|
|
4720
|
+
|
|
4721
|
+
{key: progress_key, label: progress_label}
|
|
4667
4722
|
end
|
|
4668
4723
|
|
|
4669
4724
|
def emit_release_event_progress(member, event)
|
|
@@ -27,6 +27,7 @@ module Kettle
|
|
|
27
27
|
@started = false
|
|
28
28
|
@stopped = false
|
|
29
29
|
@member_totals = {}
|
|
30
|
+
@member_labels = @line_order.to_h { |member_name| [member_name, member_name] }
|
|
30
31
|
@member_counts = Hash.new(0)
|
|
31
32
|
@member_started_at = {}
|
|
32
33
|
@member_finished_elapsed = {}
|
|
@@ -55,62 +56,66 @@ module Kettle
|
|
|
55
56
|
end
|
|
56
57
|
end
|
|
57
58
|
|
|
58
|
-
def start_member(member, total:, status:)
|
|
59
|
+
def start_member(member, total:, status:, key: member.name, label: member.name)
|
|
59
60
|
return unless @enabled
|
|
60
61
|
|
|
61
62
|
synchronize do
|
|
62
|
-
@
|
|
63
|
-
@
|
|
64
|
-
@
|
|
65
|
-
@
|
|
63
|
+
@member_labels[key] = label
|
|
64
|
+
@member_totals[key] = total.to_i
|
|
65
|
+
@member_counts[key] = 0
|
|
66
|
+
@member_started_at[key] ||= monotonic_now
|
|
67
|
+
@member_finished_elapsed.delete(key)
|
|
66
68
|
if @tty
|
|
67
|
-
render(
|
|
69
|
+
render(key, status: status)
|
|
68
70
|
else
|
|
69
|
-
write_line(non_tty_line(
|
|
71
|
+
write_line(non_tty_line(key, mark: ">", status: status))
|
|
70
72
|
end
|
|
71
73
|
end
|
|
72
74
|
end
|
|
73
75
|
|
|
74
|
-
def advance(member, status:, success: true, mark: nil)
|
|
76
|
+
def advance(member, status:, success: true, mark: nil, key: member.name, label: member.name)
|
|
75
77
|
return unless @enabled
|
|
76
78
|
|
|
77
79
|
synchronize do
|
|
80
|
+
@member_labels[key] = label
|
|
78
81
|
event_mark = mark || (success ? "." : "F")
|
|
79
|
-
increment_member_count(
|
|
82
|
+
increment_member_count(key)
|
|
80
83
|
if @tty
|
|
81
|
-
append_event(
|
|
82
|
-
render(
|
|
84
|
+
append_event(key, event_mark)
|
|
85
|
+
render(key, status: status)
|
|
83
86
|
else
|
|
84
|
-
write_line(non_tty_line(
|
|
87
|
+
write_line(non_tty_line(key, mark: event_mark, status: status))
|
|
85
88
|
end
|
|
86
89
|
end
|
|
87
90
|
end
|
|
88
91
|
|
|
89
|
-
def update(member, status:, mark: nil)
|
|
92
|
+
def update(member, status:, mark: nil, key: member.name, label: member.name)
|
|
90
93
|
return unless @enabled
|
|
91
94
|
return if status.to_s.empty?
|
|
92
95
|
|
|
93
96
|
synchronize do
|
|
97
|
+
@member_labels[key] = label
|
|
94
98
|
if @tty
|
|
95
|
-
append_event(
|
|
96
|
-
render(
|
|
99
|
+
append_event(key, mark) if mark
|
|
100
|
+
render(key, status: status)
|
|
97
101
|
else
|
|
98
|
-
write_line(non_tty_line(
|
|
102
|
+
write_line(non_tty_line(key, mark: mark || ">", status: status))
|
|
99
103
|
end
|
|
100
104
|
end
|
|
101
105
|
end
|
|
102
106
|
|
|
103
|
-
def finish_member(member, success:, status:)
|
|
107
|
+
def finish_member(member, success:, status:, key: member.name, label: member.name)
|
|
104
108
|
return unless @enabled
|
|
105
109
|
|
|
106
110
|
synchronize do
|
|
107
|
-
|
|
108
|
-
@
|
|
109
|
-
@
|
|
111
|
+
@member_labels[key] = label
|
|
112
|
+
total = @member_totals[key].to_i
|
|
113
|
+
@member_counts[key] = total if total.positive?
|
|
114
|
+
@member_finished_elapsed[key] = elapsed_seconds_by_name(key)
|
|
110
115
|
if @tty
|
|
111
|
-
render(
|
|
116
|
+
render(key, status: status)
|
|
112
117
|
else
|
|
113
|
-
write_line(non_tty_line(
|
|
118
|
+
write_line(non_tty_line(key, mark: success ? "done" : "failed", status: status))
|
|
114
119
|
end
|
|
115
120
|
end
|
|
116
121
|
end
|
|
@@ -168,15 +173,15 @@ module Kettle
|
|
|
168
173
|
|
|
169
174
|
private
|
|
170
175
|
|
|
171
|
-
def render(
|
|
172
|
-
render_name(
|
|
176
|
+
def render(member_key, status:)
|
|
177
|
+
render_name(member_key, status: status)
|
|
173
178
|
render_tty_block if @tty
|
|
174
179
|
end
|
|
175
180
|
|
|
176
|
-
def append_event(
|
|
181
|
+
def append_event(member_key, mark)
|
|
177
182
|
return if mark.to_s.empty?
|
|
178
183
|
|
|
179
|
-
@member_events[
|
|
184
|
+
@member_events[member_key] = (@member_events[member_key] + mark.to_s).chars.last(EVENT_WIDTH).join
|
|
180
185
|
end
|
|
181
186
|
|
|
182
187
|
def render_name(member_name, status:)
|
|
@@ -222,7 +227,7 @@ module Kettle
|
|
|
222
227
|
def tty_line(member_name)
|
|
223
228
|
Kernel.format(
|
|
224
229
|
FORMAT,
|
|
225
|
-
member: member_name,
|
|
230
|
+
member: @member_labels.fetch(member_name, member_name),
|
|
226
231
|
progress: progress_text(member_name),
|
|
227
232
|
duration: elapsed_text(member_name),
|
|
228
233
|
events: @member_events[member_name].rjust(EVENT_WIDTH),
|
|
@@ -234,15 +239,15 @@ module Kettle
|
|
|
234
239
|
"s" unless count == 1
|
|
235
240
|
end
|
|
236
241
|
|
|
237
|
-
def non_tty_line(
|
|
238
|
-
|
|
242
|
+
def non_tty_line(member_key, mark:, status:)
|
|
243
|
+
label = @member_labels.fetch(member_key, member_key)
|
|
244
|
+
"[#{label}] #{progress_text(member_key)} #{elapsed_text(member_key)} #{mark} #{status}"
|
|
239
245
|
end
|
|
240
246
|
|
|
241
|
-
def increment_member_count(
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
@member_counts[
|
|
245
|
-
@member_counts[member_name] = total if total.positive? && @member_counts[member_name] > total
|
|
247
|
+
def increment_member_count(member_key)
|
|
248
|
+
total = @member_totals[member_key].to_i
|
|
249
|
+
@member_counts[member_key] += 1
|
|
250
|
+
@member_counts[member_key] = total if total.positive? && @member_counts[member_key] > total
|
|
246
251
|
end
|
|
247
252
|
|
|
248
253
|
def progress_text(member_name)
|
|
@@ -256,10 +261,6 @@ module Kettle
|
|
|
256
261
|
format_elapsed(elapsed_seconds_by_name(member_name)).rjust(ELAPSED_WIDTH)
|
|
257
262
|
end
|
|
258
263
|
|
|
259
|
-
def elapsed_seconds(member)
|
|
260
|
-
elapsed_seconds_by_name(member.name)
|
|
261
|
-
end
|
|
262
|
-
|
|
263
264
|
def elapsed_seconds_by_name(member_name)
|
|
264
265
|
return @member_finished_elapsed[member_name] if @member_finished_elapsed.key?(member_name)
|
|
265
266
|
|
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.96
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Peter H. Boling
|
|
@@ -89,22 +89,22 @@ dependencies:
|
|
|
89
89
|
name: kettle-dev
|
|
90
90
|
requirement: !ruby/object:Gem::Requirement
|
|
91
91
|
requirements:
|
|
92
|
-
- - "
|
|
92
|
+
- - "~>"
|
|
93
93
|
- !ruby/object:Gem::Version
|
|
94
|
-
version: 3.0
|
|
95
|
-
- - "
|
|
94
|
+
version: '3.0'
|
|
95
|
+
- - ">="
|
|
96
96
|
- !ruby/object:Gem::Version
|
|
97
|
-
version:
|
|
97
|
+
version: 3.0.33
|
|
98
98
|
type: :runtime
|
|
99
99
|
prerelease: false
|
|
100
100
|
version_requirements: !ruby/object:Gem::Requirement
|
|
101
101
|
requirements:
|
|
102
|
-
- - "
|
|
102
|
+
- - "~>"
|
|
103
103
|
- !ruby/object:Gem::Version
|
|
104
|
-
version: 3.0
|
|
105
|
-
- - "
|
|
104
|
+
version: '3.0'
|
|
105
|
+
- - ">="
|
|
106
106
|
- !ruby/object:Gem::Version
|
|
107
|
-
version:
|
|
107
|
+
version: 3.0.33
|
|
108
108
|
- !ruby/object:Gem::Dependency
|
|
109
109
|
name: kettle-gha-pins
|
|
110
110
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -131,20 +131,20 @@ dependencies:
|
|
|
131
131
|
requirements:
|
|
132
132
|
- - "~>"
|
|
133
133
|
- !ruby/object:Gem::Version
|
|
134
|
-
version: '7.
|
|
134
|
+
version: '7.1'
|
|
135
135
|
- - ">="
|
|
136
136
|
- !ruby/object:Gem::Version
|
|
137
|
-
version: 7.
|
|
137
|
+
version: 7.1.23
|
|
138
138
|
type: :runtime
|
|
139
139
|
prerelease: false
|
|
140
140
|
version_requirements: !ruby/object:Gem::Requirement
|
|
141
141
|
requirements:
|
|
142
142
|
- - "~>"
|
|
143
143
|
- !ruby/object:Gem::Version
|
|
144
|
-
version: '7.
|
|
144
|
+
version: '7.1'
|
|
145
145
|
- - ">="
|
|
146
146
|
- !ruby/object:Gem::Version
|
|
147
|
-
version: 7.
|
|
147
|
+
version: 7.1.23
|
|
148
148
|
- !ruby/object:Gem::Dependency
|
|
149
149
|
name: kettle-test
|
|
150
150
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -304,7 +304,7 @@ dependencies:
|
|
|
304
304
|
version: '3.2'
|
|
305
305
|
- - ">="
|
|
306
306
|
- !ruby/object:Gem::Version
|
|
307
|
-
version: 3.2.
|
|
307
|
+
version: 3.2.3
|
|
308
308
|
type: :development
|
|
309
309
|
prerelease: false
|
|
310
310
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -314,7 +314,7 @@ dependencies:
|
|
|
314
314
|
version: '3.2'
|
|
315
315
|
- - ">="
|
|
316
316
|
- !ruby/object:Gem::Version
|
|
317
|
-
version: 3.2.
|
|
317
|
+
version: 3.2.3
|
|
318
318
|
- !ruby/object:Gem::Dependency
|
|
319
319
|
name: turbo_tests2
|
|
320
320
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -324,7 +324,7 @@ dependencies:
|
|
|
324
324
|
version: '3.2'
|
|
325
325
|
- - ">="
|
|
326
326
|
- !ruby/object:Gem::Version
|
|
327
|
-
version: 3.2.
|
|
327
|
+
version: 3.2.7
|
|
328
328
|
type: :development
|
|
329
329
|
prerelease: false
|
|
330
330
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -334,7 +334,7 @@ dependencies:
|
|
|
334
334
|
version: '3.2'
|
|
335
335
|
- - ">="
|
|
336
336
|
- !ruby/object:Gem::Version
|
|
337
|
-
version: 3.2.
|
|
337
|
+
version: 3.2.7
|
|
338
338
|
- !ruby/object:Gem::Dependency
|
|
339
339
|
name: ruby-progressbar
|
|
340
340
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -443,10 +443,10 @@ licenses:
|
|
|
443
443
|
- AGPL-3.0-only
|
|
444
444
|
metadata:
|
|
445
445
|
homepage_uri: https://kettle-family.galtzo.com
|
|
446
|
-
source_code_uri: https://github.com/kettle-dev/kettle-family/tree/v1.2.
|
|
447
|
-
changelog_uri: https://github.com/kettle-dev/kettle-family/blob/v1.2.
|
|
446
|
+
source_code_uri: https://github.com/kettle-dev/kettle-family/tree/v1.2.96
|
|
447
|
+
changelog_uri: https://github.com/kettle-dev/kettle-family/blob/v1.2.96/CHANGELOG.md
|
|
448
448
|
bug_tracker_uri: https://github.com/kettle-dev/kettle-family/issues
|
|
449
|
-
documentation_uri: https://www.rubydoc.info/gems/kettle-family/1.2.
|
|
449
|
+
documentation_uri: https://www.rubydoc.info/gems/kettle-family/1.2.96
|
|
450
450
|
funding_uri: https://github.com/sponsors/pboling
|
|
451
451
|
wiki_uri: https://github.com/kettle-dev/kettle-family/wiki
|
|
452
452
|
news_uri: https://www.railsbling.com/tags/kettle-family
|
metadata.gz.sig
CHANGED
|
Binary file
|