kettle-family 1.2.81 → 1.2.83
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 +27 -1
- data/README.md +1 -1
- data/lib/kettle/family/version.rb +1 -1
- data/lib/kettle/family/workflow.rb +288 -39
- 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: 4597b93884181bec791afb1965da15957f01eec43876c13835191eb9419ff0fe
|
|
4
|
+
data.tar.gz: 57e1d3dd4799d826baed78d1fb258ce8fe658eae94d163681b20d1af718b4151
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: dabdf35f9aa98339e0443282e1bd5ed26c61ec9ebdb9a71b7238c8b4282cf26b87a54888e0cf853874cb6becf165050e218d6ac11708bcea0306dbf9d97a8ff6
|
|
7
|
+
data.tar.gz: 0da1b0a6fb5f9f4391613c7431d4b4e54827e90c137f87df16b06399fbfe009236d4dbbc9bc20bef450930be11dcf78f13f76f18e121b9a658fe1c8596f4e632
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
data/CHANGELOG.md
CHANGED
|
@@ -30,6 +30,28 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
|
30
30
|
|
|
31
31
|
### Security
|
|
32
32
|
|
|
33
|
+
## [1.2.83] - 2026-09-02
|
|
34
|
+
|
|
35
|
+
- TAG: [v1.2.83][1.2.83t]
|
|
36
|
+
- COVERAGE: 93.08% -- 5782/6212 lines in 33 files
|
|
37
|
+
- BRANCH COVERAGE: 76.04% -- 2345/3084 branches in 33 files
|
|
38
|
+
- 30.69% documented
|
|
39
|
+
|
|
40
|
+
### Fixed
|
|
41
|
+
|
|
42
|
+
- Run aggregate monorepo release members in isolated worktrees and serialize shared release finalization.
|
|
43
|
+
|
|
44
|
+
## [1.2.82] - 2026-09-01
|
|
45
|
+
|
|
46
|
+
- TAG: [v1.2.82][1.2.82t]
|
|
47
|
+
- COVERAGE: 93.26% -- 5655/6064 lines in 33 files
|
|
48
|
+
- BRANCH COVERAGE: 76.34% -- 2310/3026 branches in 33 files
|
|
49
|
+
- 30.69% documented
|
|
50
|
+
|
|
51
|
+
### Fixed
|
|
52
|
+
|
|
53
|
+
- Keep the configured family local dependency graph active throughout template bootstrap and preparation; release-only lockfile cleanup remains isolated to release commands.
|
|
54
|
+
|
|
33
55
|
## [1.2.81] - 2026-09-01
|
|
34
56
|
|
|
35
57
|
- TAG: [v1.2.81][1.2.81t]
|
|
@@ -2477,7 +2499,11 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
|
2477
2499
|
- Fixed CI load failures on engines without compatible `pty` support by falling back to Open3 for interactive release commands.
|
|
2478
2500
|
- Fixed Ruby 3.2 version-bump support by loading Prism lazily and wiring the Prism gem only for MRI versions that need it.
|
|
2479
2501
|
|
|
2480
|
-
[Unreleased]: https://github.com/kettle-dev/kettle-family/compare/v1.2.
|
|
2502
|
+
[Unreleased]: https://github.com/kettle-dev/kettle-family/compare/v1.2.83...HEAD
|
|
2503
|
+
[1.2.83]: https://github.com/kettle-dev/kettle-family/compare/v1.2.82...v1.2.83
|
|
2504
|
+
[1.2.83t]: https://github.com/kettle-dev/kettle-family/releases/tag/v1.2.83
|
|
2505
|
+
[1.2.82]: https://github.com/kettle-dev/kettle-family/compare/v1.2.81...v1.2.82
|
|
2506
|
+
[1.2.82t]: https://github.com/kettle-dev/kettle-family/releases/tag/v1.2.82
|
|
2481
2507
|
[1.2.81]: https://github.com/kettle-dev/kettle-family/compare/v1.2.80...v1.2.81
|
|
2482
2508
|
[1.2.81t]: https://github.com/kettle-dev/kettle-family/releases/tag/v1.2.81
|
|
2483
2509
|
[1.2.80]: https://github.com/kettle-dev/kettle-family/compare/v1.2.79...v1.2.80
|
data/README.md
CHANGED
|
@@ -1049,7 +1049,7 @@ Thanks for RTFM. ☺️
|
|
|
1049
1049
|
[📌gitmoji]: https://gitmoji.dev
|
|
1050
1050
|
[📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
|
|
1051
1051
|
[🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
|
|
1052
|
-
[🧮kloc-img]: https://img.shields.io/badge/KLOC-6.
|
|
1052
|
+
[🧮kloc-img]: https://img.shields.io/badge/KLOC-6.212-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
|
|
1053
1053
|
[🔐security]: https://github.com/kettle-dev/kettle-family/blob/main/SECURITY.md
|
|
1054
1054
|
[🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
|
|
1055
1055
|
[📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
|
|
@@ -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.83"
|
|
9
9
|
end
|
|
10
10
|
# Current gem version exposed at the traditional constant location.
|
|
11
11
|
VERSION = Version::VERSION # Traditional Constant Location
|
|
@@ -822,34 +822,13 @@ module Kettle
|
|
|
822
822
|
versions.max
|
|
823
823
|
end
|
|
824
824
|
|
|
825
|
-
def template_bootstrap_dependency_env(
|
|
826
|
-
env =
|
|
827
|
-
env.each_key do |key|
|
|
828
|
-
env[key] = "false" if key.end_with?("_DEV") && !local_path_env_requested?(key)
|
|
829
|
-
end
|
|
825
|
+
def template_bootstrap_dependency_env(_member)
|
|
826
|
+
env = template_prepare_env
|
|
830
827
|
env["K_JEM_TEMPLATING"] = "false"
|
|
831
828
|
env["BUNDLE_DISABLE_CHECKSUM_VALIDATION"] = "true"
|
|
832
|
-
family_env_name = config.family_local_path_env_name
|
|
833
|
-
env[family_env_name] = "false" if family_env_name && !local_path_env_requested?(family_env_name)
|
|
834
|
-
env.merge!(template_bootstrap_direct_sibling_env(member))
|
|
835
829
|
env
|
|
836
830
|
end
|
|
837
831
|
|
|
838
|
-
# The bootstrap refreshes nomono before the template bundle is available,
|
|
839
|
-
# but a sibling member can itself require an unreleased family gem. Keep
|
|
840
|
-
# that direct dependency local without enabling the full template context.
|
|
841
|
-
def template_bootstrap_direct_sibling_env(member)
|
|
842
|
-
return {} unless config.family_mode == "sibling_repos"
|
|
843
|
-
|
|
844
|
-
direct_sibling_env = "#{config.family_name.gsub(/[^A-Za-z0-9]+/, "_").upcase}_DEV"
|
|
845
|
-
return {} if local_path_env_requested?(direct_sibling_env)
|
|
846
|
-
|
|
847
|
-
family_names = family_members.map(&:name)
|
|
848
|
-
return {} if (Array(member.dependencies) & family_names).empty?
|
|
849
|
-
|
|
850
|
-
{direct_sibling_env => config.family_local_path_root}
|
|
851
|
-
end
|
|
852
|
-
|
|
853
832
|
def template_results_for_member(member, progress: nil)
|
|
854
833
|
progress&.start_member(member, total: template_phase_total(member), status: template_initial_status(member))
|
|
855
834
|
runner = CommandRunner.new(execute: execute, accept: accept)
|
|
@@ -1035,15 +1014,15 @@ module Kettle
|
|
|
1035
1014
|
File.join(config.root, "tmp", "kettle-family", "template-worktrees", safe_member, "#{Process.pid}-#{safe_branch}")
|
|
1036
1015
|
end
|
|
1037
1016
|
|
|
1038
|
-
def relocate_member_to_worktree(member, worktree_root)
|
|
1017
|
+
def relocate_member_to_worktree(member, worktree_root, source_root: member.root)
|
|
1039
1018
|
relocate = lambda do |path|
|
|
1040
1019
|
next unless path
|
|
1041
1020
|
|
|
1042
|
-
relative = Pathname.new(path).relative_path_from(Pathname.new(
|
|
1021
|
+
relative = Pathname.new(path).relative_path_from(Pathname.new(source_root))
|
|
1043
1022
|
File.join(worktree_root, relative)
|
|
1044
1023
|
end
|
|
1045
1024
|
member.dup.tap do |worktree_member|
|
|
1046
|
-
worktree_member.root =
|
|
1025
|
+
worktree_member.root = relocate.call(member.root)
|
|
1047
1026
|
worktree_member.gemspec_path = relocate.call(member.gemspec_path)
|
|
1048
1027
|
worktree_member.version_file = relocate.call(member.version_file)
|
|
1049
1028
|
end
|
|
@@ -1464,6 +1443,8 @@ module Kettle
|
|
|
1464
1443
|
end
|
|
1465
1444
|
|
|
1466
1445
|
def parallel_release_member_results(release_members, initial_results)
|
|
1446
|
+
return parallel_monorepo_release_member_results(release_members, initial_results) if monorepo_release_workers?
|
|
1447
|
+
|
|
1467
1448
|
results = initial_results.dup
|
|
1468
1449
|
waves = release_waves(release_members)
|
|
1469
1450
|
completed_members = []
|
|
@@ -1523,6 +1504,248 @@ module Kettle
|
|
|
1523
1504
|
ordered_results.compact
|
|
1524
1505
|
end
|
|
1525
1506
|
|
|
1507
|
+
def parallel_monorepo_release_member_results(release_members, initial_results)
|
|
1508
|
+
results = initial_results.dup
|
|
1509
|
+
completed_members = []
|
|
1510
|
+
@release_completed_member_names = []
|
|
1511
|
+
release_progress = start_release_progress(release_members)
|
|
1512
|
+
@release_progress = release_progress
|
|
1513
|
+
begin
|
|
1514
|
+
release_waves(release_members).each_with_index do |wave, index|
|
|
1515
|
+
results << release_wave_result(wave, index: index, total: release_waves(release_members).length)
|
|
1516
|
+
aggregate_members, independent_members = wave.partition { |member| aggregate_release_member?(member) }
|
|
1517
|
+
|
|
1518
|
+
unless aggregate_members.empty?
|
|
1519
|
+
worker_results = run_monorepo_release_wave(aggregate_members)
|
|
1520
|
+
results.concat(worker_results.flatten)
|
|
1521
|
+
break unless worker_results.all? { |member_results| member_results.all?(&:ok?) }
|
|
1522
|
+
|
|
1523
|
+
finalization_results = finalize_monorepo_release_wave(aggregate_members)
|
|
1524
|
+
results.concat(finalization_results)
|
|
1525
|
+
break unless finalization_results.all?(&:ok?)
|
|
1526
|
+
end
|
|
1527
|
+
|
|
1528
|
+
independent_members.each do |member|
|
|
1529
|
+
results.concat(release_results_for_member(member, runner: release_command_runner))
|
|
1530
|
+
break unless results.last.ok?
|
|
1531
|
+
end
|
|
1532
|
+
break unless results.last&.ok?
|
|
1533
|
+
|
|
1534
|
+
completed_members.concat(wave)
|
|
1535
|
+
@release_completed_member_names.concat(wave.map(&:name))
|
|
1536
|
+
remaining_members = release_members - completed_members
|
|
1537
|
+
append_dependency_floor_results(released_members: wave, dependent_members: remaining_members, runner: release_command_runner, memo: results)
|
|
1538
|
+
break unless results.last&.ok?
|
|
1539
|
+
end
|
|
1540
|
+
ensure
|
|
1541
|
+
emit_release_progress_summary(results, progress: release_progress)
|
|
1542
|
+
@release_progress = nil
|
|
1543
|
+
end
|
|
1544
|
+
results
|
|
1545
|
+
end
|
|
1546
|
+
|
|
1547
|
+
def run_monorepo_release_wave(members)
|
|
1548
|
+
entries, setup_results = monorepo_release_worktree_entries(members)
|
|
1549
|
+
unless setup_results.all?(&:ok?)
|
|
1550
|
+
return setup_results.zip
|
|
1551
|
+
end
|
|
1552
|
+
|
|
1553
|
+
worker_results = run_monorepo_release_worktree_entries(entries)
|
|
1554
|
+
materialization_results = materialize_monorepo_release_artifacts(entries, worker_results)
|
|
1555
|
+
worker_results.each_with_index.map do |member_results, index|
|
|
1556
|
+
artifact_result = materialization_results[index]
|
|
1557
|
+
artifact_result ? [*member_results, artifact_result] : member_results
|
|
1558
|
+
end
|
|
1559
|
+
ensure
|
|
1560
|
+
cleanup_monorepo_release_worktrees(entries || [])
|
|
1561
|
+
end
|
|
1562
|
+
|
|
1563
|
+
def monorepo_release_worktree_entries(members)
|
|
1564
|
+
runner = command_runner
|
|
1565
|
+
control_member = monorepo_release_control_member
|
|
1566
|
+
entries = []
|
|
1567
|
+
results = []
|
|
1568
|
+
members.each do |member|
|
|
1569
|
+
root = monorepo_release_worktree_path(member)
|
|
1570
|
+
result = runner.call(
|
|
1571
|
+
member: control_member,
|
|
1572
|
+
phase: "release_worktree_add",
|
|
1573
|
+
command: ["git", "worktree", "add", "--detach", root, "HEAD"]
|
|
1574
|
+
)
|
|
1575
|
+
results << result
|
|
1576
|
+
break unless result.ok?
|
|
1577
|
+
|
|
1578
|
+
entries << {member: relocate_member_to_worktree(member, root, source_root: config.root), original_member: member, worktree_root: root}
|
|
1579
|
+
end
|
|
1580
|
+
[entries, results]
|
|
1581
|
+
end
|
|
1582
|
+
|
|
1583
|
+
def monorepo_release_worktree_path(member)
|
|
1584
|
+
safe_member = member.name.to_s.gsub(/[^A-Za-z0-9_.-]+/, "_")
|
|
1585
|
+
File.join(config.root, "tmp", "kettle-family", "release-worktrees", safe_member, "#{Process.pid}-#{Time.now.to_i}")
|
|
1586
|
+
end
|
|
1587
|
+
|
|
1588
|
+
def monorepo_release_control_member
|
|
1589
|
+
family_member.dup.tap { |member| member.root = config.root }
|
|
1590
|
+
end
|
|
1591
|
+
|
|
1592
|
+
def run_monorepo_release_worktree_entries(entries)
|
|
1593
|
+
queue = Queue.new
|
|
1594
|
+
entries.each_with_index { |entry, index| queue << [index, entry] }
|
|
1595
|
+
ordered_results = Array.new(entries.length)
|
|
1596
|
+
mutex = Mutex.new
|
|
1597
|
+
stop = false
|
|
1598
|
+
Array.new(release_jobs(entries)) do
|
|
1599
|
+
Thread.new do # rubocop:disable ThreadSafety/NewThread -- each member has an isolated detached monorepo worktree.
|
|
1600
|
+
loop do
|
|
1601
|
+
break if mutex.synchronize { stop }
|
|
1602
|
+
|
|
1603
|
+
index, entry = queue.pop(true)
|
|
1604
|
+
member_results = release_results_for_monorepo_worktree(entry)
|
|
1605
|
+
mutex.synchronize do
|
|
1606
|
+
ordered_results[index] = member_results
|
|
1607
|
+
stop = true unless member_results.all?(&:ok?)
|
|
1608
|
+
end
|
|
1609
|
+
rescue ThreadError
|
|
1610
|
+
break
|
|
1611
|
+
rescue => error
|
|
1612
|
+
mutex.synchronize do
|
|
1613
|
+
ordered_results[index] = [release_worker_error_result(entry.fetch(:original_member), error)]
|
|
1614
|
+
stop = true
|
|
1615
|
+
end
|
|
1616
|
+
break
|
|
1617
|
+
end
|
|
1618
|
+
end
|
|
1619
|
+
end.each(&:join)
|
|
1620
|
+
ordered_results.compact
|
|
1621
|
+
end
|
|
1622
|
+
|
|
1623
|
+
def release_results_for_monorepo_worktree(entry)
|
|
1624
|
+
member = entry.fetch(:member)
|
|
1625
|
+
original_member = entry.fetch(:original_member)
|
|
1626
|
+
progress = @release_progress
|
|
1627
|
+
progress&.start_member(original_member, total: release_phase_total(original_member), status: "check")
|
|
1628
|
+
[].tap do |memo|
|
|
1629
|
+
if skip_already_released?(original_member)
|
|
1630
|
+
memo << already_released_result(original_member)
|
|
1631
|
+
emit_member_result_progress(original_member, memo.last, progress: progress)
|
|
1632
|
+
return memo
|
|
1633
|
+
end
|
|
1634
|
+
|
|
1635
|
+
append_release_internal_checks(member: member, memo: memo)
|
|
1636
|
+
memo.last(2).each { |result| emit_member_result_progress(original_member, result, progress: progress) }
|
|
1637
|
+
return memo unless memo.last(2).all?(&:ok?)
|
|
1638
|
+
|
|
1639
|
+
release_event_state = {}
|
|
1640
|
+
result = release_command_runner.call(
|
|
1641
|
+
member: member,
|
|
1642
|
+
phase: release_phase,
|
|
1643
|
+
command: release_command_for(member),
|
|
1644
|
+
env: release_env_for_member(member, family_root: entry.fetch(:worktree_root)).merge("KETTLE_RELEASE_FAMILY_MEMBER_PUBLISH" => "true"),
|
|
1645
|
+
interactive: release_command_interactive?,
|
|
1646
|
+
stdout_line_handler: release_event_line_handler(original_member, progress: progress, state: release_event_state),
|
|
1647
|
+
log_path: release_command_log_path(original_member, release_phase),
|
|
1648
|
+
passthrough_output: release_command_passthrough_output?
|
|
1649
|
+
)
|
|
1650
|
+
result.member_name = original_member.name
|
|
1651
|
+
result.resume_step = release_event_state[:failed_step] unless result.ok?
|
|
1652
|
+
memo << result
|
|
1653
|
+
emit_member_result_progress(original_member, result, progress: progress)
|
|
1654
|
+
ensure
|
|
1655
|
+
finished_result = memo.find { |result| result.phase == release_phase } || memo.last
|
|
1656
|
+
progress&.finish_member(original_member, success: memo.all?(&:ok?), status: release_member_finish_status(finished_result)) if finished_result
|
|
1657
|
+
end
|
|
1658
|
+
end
|
|
1659
|
+
|
|
1660
|
+
def materialize_monorepo_release_artifacts(entries, worker_results)
|
|
1661
|
+
entries.each_with_index.map do |entry, index|
|
|
1662
|
+
next unless worker_results[index]&.all?(&:ok?)
|
|
1663
|
+
|
|
1664
|
+
copy_monorepo_release_artifact(entry)
|
|
1665
|
+
end
|
|
1666
|
+
end
|
|
1667
|
+
|
|
1668
|
+
def copy_monorepo_release_artifact(entry)
|
|
1669
|
+
member = entry.fetch(:member)
|
|
1670
|
+
original_member = entry.fetch(:original_member)
|
|
1671
|
+
version = original_member.version.to_s
|
|
1672
|
+
source = Dir[File.join(member.root, "pkg", "#{original_member.name}-#{version}.gem")].first
|
|
1673
|
+
destination = File.join(original_member.root, "pkg", "#{original_member.name}-#{version}.gem")
|
|
1674
|
+
unless source && File.file?(source)
|
|
1675
|
+
return release_worker_error_result(original_member, Error.new("worker did not produce #{File.basename(destination)}"))
|
|
1676
|
+
end
|
|
1677
|
+
|
|
1678
|
+
FileUtils.mkdir_p(File.dirname(destination))
|
|
1679
|
+
FileUtils.cp(source, destination)
|
|
1680
|
+
CommandResult.new(
|
|
1681
|
+
member_name: original_member.name,
|
|
1682
|
+
phase: "release_artifact_materialize",
|
|
1683
|
+
command: ["internal", "copy-release-artifact"],
|
|
1684
|
+
workdir: original_member.root,
|
|
1685
|
+
status: 0,
|
|
1686
|
+
success: true,
|
|
1687
|
+
stdout: File.basename(destination),
|
|
1688
|
+
stderr: "",
|
|
1689
|
+
elapsed_seconds: 0.0,
|
|
1690
|
+
skipped: false,
|
|
1691
|
+
reason: "copied from isolated release worktree"
|
|
1692
|
+
)
|
|
1693
|
+
rescue => error
|
|
1694
|
+
release_worker_error_result(original_member, error)
|
|
1695
|
+
end
|
|
1696
|
+
|
|
1697
|
+
def cleanup_monorepo_release_worktrees(entries)
|
|
1698
|
+
runner = command_runner
|
|
1699
|
+
control_member = monorepo_release_control_member
|
|
1700
|
+
entries.each do |entry|
|
|
1701
|
+
root = entry.fetch(:worktree_root)
|
|
1702
|
+
next unless Dir.exist?(root)
|
|
1703
|
+
|
|
1704
|
+
runner.call(member: control_member, phase: "release_worktree_remove", command: ["git", "worktree", "remove", "--force", root])
|
|
1705
|
+
end
|
|
1706
|
+
end
|
|
1707
|
+
|
|
1708
|
+
def finalize_monorepo_release_wave(members)
|
|
1709
|
+
runner = release_command_runner
|
|
1710
|
+
results = []
|
|
1711
|
+
members.each do |member|
|
|
1712
|
+
results << ensure_monorepo_release_tag(member, runner: runner)
|
|
1713
|
+
break unless results.last.ok?
|
|
1714
|
+
|
|
1715
|
+
results << runner.call(
|
|
1716
|
+
member: member,
|
|
1717
|
+
phase: "release_finalize",
|
|
1718
|
+
command: release_command_for(member),
|
|
1719
|
+
env: release_env_for_member(member).merge("KETTLE_RELEASE_FAMILY_MEMBER_FINALIZE" => "true"),
|
|
1720
|
+
interactive: release_command_interactive?,
|
|
1721
|
+
stdout_line_handler: release_event_line_handler(member, progress: @release_progress, state: {}),
|
|
1722
|
+
log_path: release_command_log_path(member, "release_finalize"),
|
|
1723
|
+
passthrough_output: release_command_passthrough_output?
|
|
1724
|
+
)
|
|
1725
|
+
break unless results.last.ok?
|
|
1726
|
+
end
|
|
1727
|
+
return results unless results.all?(&:ok?)
|
|
1728
|
+
|
|
1729
|
+
results << runner.call(
|
|
1730
|
+
member: monorepo_release_control_member,
|
|
1731
|
+
phase: "release_shared_push",
|
|
1732
|
+
command: config.release_push_command
|
|
1733
|
+
)
|
|
1734
|
+
results
|
|
1735
|
+
end
|
|
1736
|
+
|
|
1737
|
+
def ensure_monorepo_release_tag(member, runner:)
|
|
1738
|
+
version = member.version.to_s
|
|
1739
|
+
tag = release_tag_name(version)
|
|
1740
|
+
escaped_tag = Shellwords.escape(tag)
|
|
1741
|
+
runner.call(
|
|
1742
|
+
member: monorepo_release_control_member,
|
|
1743
|
+
phase: "release_shared_tag",
|
|
1744
|
+
command: ["sh", "-lc", "git rev-parse -q --verify refs/tags/#{escaped_tag} >/dev/null || git tag -a #{escaped_tag} -m #{escaped_tag}"],
|
|
1745
|
+
env: release_env
|
|
1746
|
+
)
|
|
1747
|
+
end
|
|
1748
|
+
|
|
1526
1749
|
def release_wave_result(wave, index:, total:, jobs: nil)
|
|
1527
1750
|
CommandResult.new(
|
|
1528
1751
|
member_name: "wave #{index + 1}",
|
|
@@ -1647,7 +1870,19 @@ module Kettle
|
|
|
1647
1870
|
execute &&
|
|
1648
1871
|
release_jobs(release_members) > 1 &&
|
|
1649
1872
|
release_members.length > 1 &&
|
|
1650
|
-
distinct_git_roots?(release_members)
|
|
1873
|
+
(distinct_git_roots?(release_members) || monorepo_release_workers?)
|
|
1874
|
+
end
|
|
1875
|
+
|
|
1876
|
+
# Aggregate monorepo members share one Git checkout, so their complete
|
|
1877
|
+
# kettle-release workflows cannot safely run concurrently. They are
|
|
1878
|
+
# instead published from disposable worktrees using the explicit
|
|
1879
|
+
# member-only contract, then finalized serially in the primary checkout.
|
|
1880
|
+
def monorepo_release_workers?
|
|
1881
|
+
execute &&
|
|
1882
|
+
publish &&
|
|
1883
|
+
config.configured_monorepo_release? &&
|
|
1884
|
+
aggregate_monorepo_github_release? &&
|
|
1885
|
+
kettle_release_command?(raw_release_command)
|
|
1651
1886
|
end
|
|
1652
1887
|
|
|
1653
1888
|
def release_jobs(release_members)
|
|
@@ -2701,10 +2936,10 @@ module Kettle
|
|
|
2701
2936
|
# A monorepo member runs kettle-release from its own checkout, while its
|
|
2702
2937
|
# changelog may live at the family root. Pass the shared paths to the
|
|
2703
2938
|
# member release phase as well as to the separate family phase.
|
|
2704
|
-
def release_env_for_member(member)
|
|
2939
|
+
def release_env_for_member(member, family_root: config.root)
|
|
2705
2940
|
env = release_env
|
|
2706
|
-
env.merge!(release_wave_local_path_env_for(member))
|
|
2707
|
-
env.merge!(release_local_path_policy_env)
|
|
2941
|
+
env.merge!(release_wave_local_path_env_for(member, family_root: family_root))
|
|
2942
|
+
env.merge!(release_local_path_policy_env(family_root: family_root))
|
|
2708
2943
|
# Family release performs one live pin review before member releases.
|
|
2709
2944
|
# Child kettle-release must consume that reviewed cache instead of
|
|
2710
2945
|
# repeating the GitHub API lookup for every member.
|
|
@@ -2724,7 +2959,7 @@ module Kettle
|
|
|
2724
2959
|
if config.family_mode == "monorepo"
|
|
2725
2960
|
# Monorepo members release from subdirectories, while CI workflows
|
|
2726
2961
|
# live at the shared repository root.
|
|
2727
|
-
env["K_RELEASE_CI_ROOT"] =
|
|
2962
|
+
env["K_RELEASE_CI_ROOT"] = family_root
|
|
2728
2963
|
env["K_RELEASE_CI_WORKFLOWS"] ||= "current.yml"
|
|
2729
2964
|
# Explicit multi-gem monorepos publish one aggregate GitHub Release
|
|
2730
2965
|
# after their member gems. A standalone gem uses the default
|
|
@@ -2784,13 +3019,13 @@ module Kettle
|
|
|
2784
3019
|
# release for the next member. Dependencies outside the selected set are
|
|
2785
3020
|
# already treated as registry dependencies; this is what makes resume
|
|
2786
3021
|
# runs work after an earlier wave has been published.
|
|
2787
|
-
def release_wave_local_path_env_for(member)
|
|
3022
|
+
def release_wave_local_path_env_for(member, family_root: config.root)
|
|
2788
3023
|
# Monorepo members and their sibling dependencies share the same CI
|
|
2789
3024
|
# checkout, so their canonical development lockfile may keep those
|
|
2790
3025
|
# paths throughout every release wave.
|
|
2791
3026
|
if config.configured_monorepo_release?
|
|
2792
3027
|
env_name = config.family_local_path_env_name
|
|
2793
|
-
return env_name ? {env_name =>
|
|
3028
|
+
return env_name ? {env_name => family_local_path_root_for(family_root)} : {}
|
|
2794
3029
|
end
|
|
2795
3030
|
|
|
2796
3031
|
return {} unless config.release_local_path_strategy == "waves"
|
|
@@ -4377,10 +4612,10 @@ module Kettle
|
|
|
4377
4612
|
end
|
|
4378
4613
|
|
|
4379
4614
|
def template_prepare_env
|
|
4380
|
-
|
|
4381
|
-
|
|
4382
|
-
|
|
4383
|
-
|
|
4615
|
+
# Templating is development work. It must resolve the configured
|
|
4616
|
+
# family graph exactly as template application does; release-only
|
|
4617
|
+
# lockfile cleanup owns disabling local path sources.
|
|
4618
|
+
workflow_env
|
|
4384
4619
|
end
|
|
4385
4620
|
|
|
4386
4621
|
def local_path_env_requested?(name)
|
|
@@ -4451,14 +4686,28 @@ module Kettle
|
|
|
4451
4686
|
config.release_allowed_local_path_roots
|
|
4452
4687
|
end
|
|
4453
4688
|
|
|
4689
|
+
def family_local_path_root_for(family_root)
|
|
4690
|
+
return config.family_local_path_root if File.expand_path(family_root) == File.expand_path(config.root)
|
|
4691
|
+
|
|
4692
|
+
relative = Pathname.new(config.family_local_path_root).relative_path_from(Pathname.new(config.root))
|
|
4693
|
+
File.expand_path(relative, family_root)
|
|
4694
|
+
end
|
|
4695
|
+
|
|
4454
4696
|
def release_allowed_local_path_env_names
|
|
4455
4697
|
names = config.release_allowed_local_path_env_names
|
|
4456
4698
|
names << "K_JEM_TEMPLATING" if preserve_monorepo_template_context?
|
|
4457
4699
|
names.uniq
|
|
4458
4700
|
end
|
|
4459
4701
|
|
|
4460
|
-
def release_local_path_policy_env
|
|
4461
|
-
roots = release_allowed_local_path_roots
|
|
4702
|
+
def release_local_path_policy_env(family_root: config.root)
|
|
4703
|
+
roots = release_allowed_local_path_roots.map do |root|
|
|
4704
|
+
if File.expand_path(family_root) == File.expand_path(config.root)
|
|
4705
|
+
root
|
|
4706
|
+
else
|
|
4707
|
+
relative = Pathname.new(root).relative_path_from(Pathname.new(config.root))
|
|
4708
|
+
File.expand_path(relative, family_root)
|
|
4709
|
+
end
|
|
4710
|
+
end
|
|
4462
4711
|
env_names = release_allowed_local_path_env_names
|
|
4463
4712
|
return {} if roots.empty? && env_names.empty?
|
|
4464
4713
|
|
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.83
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Peter H. Boling
|
|
@@ -91,7 +91,7 @@ dependencies:
|
|
|
91
91
|
requirements:
|
|
92
92
|
- - ">="
|
|
93
93
|
- !ruby/object:Gem::Version
|
|
94
|
-
version: 3.0.
|
|
94
|
+
version: 3.0.30
|
|
95
95
|
- - "<"
|
|
96
96
|
- !ruby/object:Gem::Version
|
|
97
97
|
version: 4.0.0
|
|
@@ -101,7 +101,7 @@ dependencies:
|
|
|
101
101
|
requirements:
|
|
102
102
|
- - ">="
|
|
103
103
|
- !ruby/object:Gem::Version
|
|
104
|
-
version: 3.0.
|
|
104
|
+
version: 3.0.30
|
|
105
105
|
- - "<"
|
|
106
106
|
- !ruby/object:Gem::Version
|
|
107
107
|
version: 4.0.0
|
|
@@ -441,10 +441,10 @@ licenses:
|
|
|
441
441
|
- AGPL-3.0-only
|
|
442
442
|
metadata:
|
|
443
443
|
homepage_uri: https://kettle-family.galtzo.com
|
|
444
|
-
source_code_uri: https://github.com/kettle-dev/kettle-family/tree/v1.2.
|
|
445
|
-
changelog_uri: https://github.com/kettle-dev/kettle-family/blob/v1.2.
|
|
444
|
+
source_code_uri: https://github.com/kettle-dev/kettle-family/tree/v1.2.83
|
|
445
|
+
changelog_uri: https://github.com/kettle-dev/kettle-family/blob/v1.2.83/CHANGELOG.md
|
|
446
446
|
bug_tracker_uri: https://github.com/kettle-dev/kettle-family/issues
|
|
447
|
-
documentation_uri: https://www.rubydoc.info/gems/kettle-family/1.2.
|
|
447
|
+
documentation_uri: https://www.rubydoc.info/gems/kettle-family/1.2.83
|
|
448
448
|
funding_uri: https://github.com/sponsors/pboling
|
|
449
449
|
wiki_uri: https://github.com/kettle-dev/kettle-family/wiki
|
|
450
450
|
news_uri: https://www.railsbling.com/tags/kettle-family
|
metadata.gz.sig
CHANGED
|
Binary file
|