kettle-dev 2.4.0 → 2.4.2
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 +33 -1
- data/README.md +1 -1
- data/lib/kettle/dev/release_cli.rb +328 -6
- data/lib/kettle/dev/version.rb +1 -1
- data.tar.gz.sig +0 -0
- metadata +4 -4
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a251345bb56780a5c5b9efcfb53d394ca469581b5798f10839ac8ed5b4cae682
|
|
4
|
+
data.tar.gz: 4a81578792afe11fd09299ea7d1836d66f0cd8c76af00235491b8234fcec1553
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0cfa39888af23e14856d9874d965248c8d68a83b88c42bd3cc722b1a84fe8564b3c1381aa714aaebe0df531822365b70e4f2e7e2eff913f5e781e201e5f49b13
|
|
7
|
+
data.tar.gz: aefab75e861bc0c2132385b4e7411904b01cb6562c82d3485cdbdbb27d407004450b8e0a7030f33abf869bc73df4074f2cbdd1c3ef7abcfb21e9222b5c1c7f9e
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
data/CHANGELOG.md
CHANGED
|
@@ -30,6 +30,34 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
|
30
30
|
|
|
31
31
|
### Security
|
|
32
32
|
|
|
33
|
+
## [2.4.2] - 2026-07-24
|
|
34
|
+
|
|
35
|
+
- TAG: [v2.4.2][2.4.2t]
|
|
36
|
+
- COVERAGE: 92.36% -- 3991/4321 lines in 38 files
|
|
37
|
+
- BRANCH COVERAGE: 76.06% -- 1563/2055 branches in 38 files
|
|
38
|
+
- 59.00% documented
|
|
39
|
+
|
|
40
|
+
### Fixed
|
|
41
|
+
|
|
42
|
+
- `kettle-release` now validates published gem availability with an isolated
|
|
43
|
+
Bundler probe against gem.coop before continuing past the publish step, and
|
|
44
|
+
uninstalls newly introduced local candidate gems when the release did not
|
|
45
|
+
happen or cannot be validated.
|
|
46
|
+
|
|
47
|
+
## [2.4.1] - 2026-07-24
|
|
48
|
+
|
|
49
|
+
- TAG: [v2.4.1][2.4.1t]
|
|
50
|
+
- COVERAGE: 92.29% -- 3928/4256 lines in 38 files
|
|
51
|
+
- BRANCH COVERAGE: 76.09% -- 1550/2037 branches in 38 files
|
|
52
|
+
- 58.66% documented
|
|
53
|
+
|
|
54
|
+
### Fixed
|
|
55
|
+
|
|
56
|
+
- `kettle-release` now normalizes and revalidates release lockfiles after
|
|
57
|
+
mutating setup/appraisal/doc steps, before committing or pushing, so local
|
|
58
|
+
path remotes and locally installed registry gems with empty lockfile
|
|
59
|
+
checksums cannot leak into CI.
|
|
60
|
+
|
|
33
61
|
## [2.4.0] - 2026-07-23
|
|
34
62
|
|
|
35
63
|
- TAG: [v2.4.0][2.4.0t]
|
|
@@ -2646,7 +2674,11 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
|
2646
2674
|
- Selecting will run the selected workflow via `act`
|
|
2647
2675
|
- This may move to its own gem in the future.
|
|
2648
2676
|
|
|
2649
|
-
[Unreleased]: https://github.com/kettle-dev/kettle-dev/compare/v2.4.
|
|
2677
|
+
[Unreleased]: https://github.com/kettle-dev/kettle-dev/compare/v2.4.2...HEAD
|
|
2678
|
+
[2.4.2]: https://github.com/kettle-dev/kettle-dev/compare/v2.4.1...v2.4.2
|
|
2679
|
+
[2.4.2t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v2.4.2
|
|
2680
|
+
[2.4.1]: https://github.com/kettle-dev/kettle-dev/compare/v2.4.0...v2.4.1
|
|
2681
|
+
[2.4.1t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v2.4.1
|
|
2650
2682
|
[2.4.0]: https://github.com/kettle-dev/kettle-dev/compare/v2.3.11...v2.4.0
|
|
2651
2683
|
[2.4.0t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v2.4.0
|
|
2652
2684
|
[2.3.11]: https://github.com/kettle-dev/kettle-dev/compare/v2.3.10...v2.3.11
|
data/README.md
CHANGED
|
@@ -891,7 +891,7 @@ Thanks for RTFM. ☺️
|
|
|
891
891
|
[📌gitmoji]: https://gitmoji.dev
|
|
892
892
|
[📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
|
|
893
893
|
[🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
|
|
894
|
-
[🧮kloc-img]: https://img.shields.io/badge/KLOC-4.
|
|
894
|
+
[🧮kloc-img]: https://img.shields.io/badge/KLOC-4.321-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
|
|
895
895
|
[🔐security]: https://github.com/kettle-dev/kettle-dev/blob/main/SECURITY.md
|
|
896
896
|
[🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
|
|
897
897
|
[📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
|
|
@@ -10,6 +10,7 @@ require "net/http"
|
|
|
10
10
|
require "json"
|
|
11
11
|
require "uri"
|
|
12
12
|
require "yaml"
|
|
13
|
+
require "set"
|
|
13
14
|
|
|
14
15
|
# External gems
|
|
15
16
|
require "kettle/rb/compat_matrix"
|
|
@@ -39,6 +40,8 @@ module Kettle
|
|
|
39
40
|
"BUNDLE_SUPPRESS_INSTALL_USING_MESSAGES" => "true"
|
|
40
41
|
}.freeze
|
|
41
42
|
DEBUG_TRUE_VALUES = %w[1 true yes on].freeze
|
|
43
|
+
RELEASE_VALIDATION_SOURCE = "https://gem.coop"
|
|
44
|
+
|
|
42
45
|
class << self
|
|
43
46
|
def run_cmd!(cmd)
|
|
44
47
|
# For Bundler-invoked build/release, explicitly prefix SKIP_GEM_SIGNING so
|
|
@@ -120,6 +123,7 @@ module Kettle
|
|
|
120
123
|
@skip_bundle_audit = truthy_value?(skip_bundle_audit) || truthy_value?(ENV["KETTLE_DEV_SKIP_BUNDLE_AUDIT"])
|
|
121
124
|
@version_override = Kettle::Dev::Versioning.normalize_explicit_version(version)
|
|
122
125
|
@appraisal_task = normalize_appraisal_task(appraisal_task || ENV["KETTLE_RELEASE_APPRAISAL_TASK"])
|
|
126
|
+
@release_candidate = nil
|
|
123
127
|
end
|
|
124
128
|
|
|
125
129
|
def run
|
|
@@ -256,6 +260,7 @@ module Kettle
|
|
|
256
260
|
|
|
257
261
|
# 6. git user + commit release prep
|
|
258
262
|
if run_step?(6)
|
|
263
|
+
prepare_release_lockfiles_for_commit!
|
|
259
264
|
ensure_git_user!
|
|
260
265
|
version ||= detect_version
|
|
261
266
|
committed = commit_release_prep!(version)
|
|
@@ -279,10 +284,16 @@ module Kettle
|
|
|
279
284
|
end
|
|
280
285
|
|
|
281
286
|
# 9. push branches
|
|
282
|
-
|
|
287
|
+
if run_step?(9) && !local_ci?
|
|
288
|
+
validate_release_lockfiles!(stage: "before push")
|
|
289
|
+
push!
|
|
290
|
+
end
|
|
283
291
|
|
|
284
292
|
# 10. monitor CI after push
|
|
285
|
-
|
|
293
|
+
if run_step?(10) && !local_ci?
|
|
294
|
+
validate_release_lockfiles!(stage: "before CI monitoring")
|
|
295
|
+
monitor_workflows_after_push!
|
|
296
|
+
end
|
|
286
297
|
|
|
287
298
|
# 11. merge feature into trunk and push
|
|
288
299
|
if run_step?(11) && !local_ci?
|
|
@@ -338,13 +349,18 @@ module Kettle
|
|
|
338
349
|
|
|
339
350
|
# 15. release and tag
|
|
340
351
|
if run_step?(15)
|
|
352
|
+
version ||= detect_version
|
|
353
|
+
gem_name = detect_gem_name
|
|
354
|
+
@release_candidate = build_release_candidate(gem_name, version)
|
|
341
355
|
if local_ci?
|
|
342
|
-
version
|
|
343
|
-
release_gem_and_tag_locally!(version)
|
|
356
|
+
with_unpublished_candidate_cleanup { release_gem_and_tag_locally!(version) }
|
|
344
357
|
else
|
|
345
358
|
puts "Running release (you may be prompted for signing key password and RubyGems MFA OTP)..."
|
|
346
|
-
|
|
347
|
-
|
|
359
|
+
with_unpublished_candidate_cleanup do
|
|
360
|
+
run_cmd!("bundle exec rake release")
|
|
361
|
+
confirm_release_candidate_available!(@release_candidate)
|
|
362
|
+
end
|
|
363
|
+
mark_gem_coop_release_cache_bust(version)
|
|
348
364
|
end
|
|
349
365
|
end
|
|
350
366
|
|
|
@@ -505,6 +521,187 @@ module Kettle
|
|
|
505
521
|
run_changelog!
|
|
506
522
|
end
|
|
507
523
|
|
|
524
|
+
def prepare_release_lockfiles_for_commit!
|
|
525
|
+
dirty_lockfiles = release_lockfile_paths.select { |path| release_lockfile_normalization_needed?(path) }
|
|
526
|
+
unless dirty_lockfiles.empty?
|
|
527
|
+
puts "Normalizing release lockfiles with local path dependencies disabled..."
|
|
528
|
+
dirty_lockfiles.each { |path| normalize_release_lockfile!(path) }
|
|
529
|
+
end
|
|
530
|
+
|
|
531
|
+
validate_release_lockfiles!(stage: "before release prep commit")
|
|
532
|
+
end
|
|
533
|
+
|
|
534
|
+
def validate_release_lockfiles!(stage:)
|
|
535
|
+
diagnostics = release_lockfile_paths.flat_map { |path| release_lockfile_diagnostics(path) }
|
|
536
|
+
return if diagnostics.empty?
|
|
537
|
+
|
|
538
|
+
abort(<<~MSG)
|
|
539
|
+
Release lockfile validation failed #{stage}:
|
|
540
|
+
#{diagnostics.map { |diagnostic| " - #{diagnostic}" }.join("\n")}
|
|
541
|
+
Re-run bundle lock/update with local path development env disabled before releasing.
|
|
542
|
+
MSG
|
|
543
|
+
end
|
|
544
|
+
|
|
545
|
+
def release_lockfile_paths
|
|
546
|
+
candidates = [
|
|
547
|
+
File.join(@root, "Gemfile.lock"),
|
|
548
|
+
File.join(@root, "Appraisal.root.gemfile.lock")
|
|
549
|
+
]
|
|
550
|
+
candidates.select { |path| File.file?(path) }.sort
|
|
551
|
+
end
|
|
552
|
+
|
|
553
|
+
def release_lockfile_normalization_needed?(path)
|
|
554
|
+
release_lockfile_has_local_path_remote?(path) || !release_lockfile_empty_registry_checksums(path).empty?
|
|
555
|
+
end
|
|
556
|
+
|
|
557
|
+
def normalize_release_lockfile!(path)
|
|
558
|
+
gemfile = release_gemfile_for_lockfile(path)
|
|
559
|
+
unless gemfile && File.file?(gemfile)
|
|
560
|
+
warn("Cannot normalize #{Kettle::Dev.display_path(path)} because its Gemfile was not found.")
|
|
561
|
+
return
|
|
562
|
+
end
|
|
563
|
+
|
|
564
|
+
update_gems = release_lockfile_empty_registry_checksums(path).map(&:first).uniq.sort
|
|
565
|
+
env = release_lockfile_normalization_env.merge("BUNDLE_GEMFILE" => gemfile)
|
|
566
|
+
command = +"env"
|
|
567
|
+
env.each do |key, value|
|
|
568
|
+
command << " #{key}=#{Shellwords.escape(value)}"
|
|
569
|
+
end
|
|
570
|
+
command << " bundle lock"
|
|
571
|
+
command << " --update #{update_gems.map { |gem_name| Shellwords.escape(gem_name) }.join(" ")}" unless update_gems.empty?
|
|
572
|
+
run_cmd!(command)
|
|
573
|
+
end
|
|
574
|
+
|
|
575
|
+
def release_gemfile_for_lockfile(path)
|
|
576
|
+
basename = File.basename(path)
|
|
577
|
+
return File.join(@root, "Gemfile") if basename == "Gemfile.lock"
|
|
578
|
+
|
|
579
|
+
path.delete_suffix(".lock")
|
|
580
|
+
end
|
|
581
|
+
|
|
582
|
+
def release_lockfile_normalization_env
|
|
583
|
+
{
|
|
584
|
+
"KETTLE_DEV_DEV" => "false",
|
|
585
|
+
"K_JEM_TEMPLATING" => "false",
|
|
586
|
+
"STRUCTUREDMERGE_DEV" => "false",
|
|
587
|
+
"TREE_SITTER_LANGUAGE_PACK_DEV" => "false",
|
|
588
|
+
"RUBOCOP_LTS_LOCAL" => "false",
|
|
589
|
+
"GALTZO_FLOSS_DEV" => "false",
|
|
590
|
+
"UR_BRAIN_DEV" => "false"
|
|
591
|
+
}
|
|
592
|
+
end
|
|
593
|
+
|
|
594
|
+
def release_lockfile_diagnostics(path)
|
|
595
|
+
diagnostics = []
|
|
596
|
+
release_lockfile_local_path_remote_lines(path).each do |line_number|
|
|
597
|
+
diagnostics << "#{release_lockfile_label(path)} has local path remote at line #{line_number}"
|
|
598
|
+
end
|
|
599
|
+
release_lockfile_empty_registry_checksums(path).each do |name, version, line_number|
|
|
600
|
+
diagnostics << "#{release_lockfile_label(path)} CHECKSUMS has no sha256 for #{name} #{version} at line #{line_number}"
|
|
601
|
+
end
|
|
602
|
+
diagnostics
|
|
603
|
+
end
|
|
604
|
+
|
|
605
|
+
def release_lockfile_has_local_path_remote?(path)
|
|
606
|
+
!release_lockfile_local_path_remote_lines(path).empty?
|
|
607
|
+
end
|
|
608
|
+
|
|
609
|
+
def release_lockfile_local_path_remote_lines(path)
|
|
610
|
+
File.readlines(path).filter_map.with_index(1) do |line, index|
|
|
611
|
+
next unless line.start_with?(" remote: /", " remote: ./", " remote: ../")
|
|
612
|
+
|
|
613
|
+
index
|
|
614
|
+
end
|
|
615
|
+
end
|
|
616
|
+
|
|
617
|
+
def release_lockfile_empty_registry_checksums(path)
|
|
618
|
+
path_gems = release_lockfile_path_source_gems(path) | release_lockfile_path_dependency_gems(path)
|
|
619
|
+
in_checksums = false
|
|
620
|
+
entries = File.readlines(path).filter_map.with_index(1) do |line, index|
|
|
621
|
+
stripped = line.strip
|
|
622
|
+
if stripped == "CHECKSUMS"
|
|
623
|
+
in_checksums = true
|
|
624
|
+
next
|
|
625
|
+
end
|
|
626
|
+
next unless in_checksums
|
|
627
|
+
next if stripped.empty?
|
|
628
|
+
next if stripped == "BUNDLED WITH"
|
|
629
|
+
|
|
630
|
+
match = stripped.match(/\A([A-Za-z0-9_.-]+) \(([^)]+)\)(?:\s+(sha256=.*))?\z/)
|
|
631
|
+
next unless match
|
|
632
|
+
|
|
633
|
+
name = match[1]
|
|
634
|
+
checksum = match[3].to_s
|
|
635
|
+
next if !checksum.empty?
|
|
636
|
+
next if path_gems.include?(name)
|
|
637
|
+
|
|
638
|
+
[name, match[2], index]
|
|
639
|
+
end
|
|
640
|
+
return [] unless release_lockfile_has_any_sha_checksum?(path)
|
|
641
|
+
|
|
642
|
+
entries
|
|
643
|
+
end
|
|
644
|
+
|
|
645
|
+
def release_lockfile_has_any_sha_checksum?(path)
|
|
646
|
+
in_checksums = false
|
|
647
|
+
File.readlines(path).any? do |line|
|
|
648
|
+
stripped = line.strip
|
|
649
|
+
if stripped == "CHECKSUMS"
|
|
650
|
+
in_checksums = true
|
|
651
|
+
next false
|
|
652
|
+
end
|
|
653
|
+
next false unless in_checksums
|
|
654
|
+
|
|
655
|
+
stripped.include?("sha256=")
|
|
656
|
+
end
|
|
657
|
+
end
|
|
658
|
+
|
|
659
|
+
def release_lockfile_path_source_gems(path)
|
|
660
|
+
gems = Set.new
|
|
661
|
+
in_path = false
|
|
662
|
+
in_specs = false
|
|
663
|
+
File.readlines(path).each do |line|
|
|
664
|
+
header = line.strip
|
|
665
|
+
if header.match?(/\A[A-Z][A-Z ]*\z/)
|
|
666
|
+
in_path = header == "PATH"
|
|
667
|
+
in_specs = false
|
|
668
|
+
next
|
|
669
|
+
end
|
|
670
|
+
next unless in_path
|
|
671
|
+
|
|
672
|
+
if header == "specs:"
|
|
673
|
+
in_specs = true
|
|
674
|
+
next
|
|
675
|
+
end
|
|
676
|
+
next unless in_specs
|
|
677
|
+
|
|
678
|
+
match = line.match(/\A ([A-Za-z0-9_.-]+) \([^)]+\)/)
|
|
679
|
+
gems << match[1] if match
|
|
680
|
+
end
|
|
681
|
+
gems
|
|
682
|
+
end
|
|
683
|
+
|
|
684
|
+
def release_lockfile_path_dependency_gems(path)
|
|
685
|
+
gems = Set.new
|
|
686
|
+
in_dependencies = false
|
|
687
|
+
File.readlines(path).each do |line|
|
|
688
|
+
header = line.strip
|
|
689
|
+
if header.match?(/\A[A-Z][A-Z ]*\z/)
|
|
690
|
+
in_dependencies = header == "DEPENDENCIES"
|
|
691
|
+
next
|
|
692
|
+
end
|
|
693
|
+
next unless in_dependencies
|
|
694
|
+
|
|
695
|
+
match = line.match(/\A ([A-Za-z0-9_.-]+)!\z/)
|
|
696
|
+
gems << match[1] if match
|
|
697
|
+
end
|
|
698
|
+
gems
|
|
699
|
+
end
|
|
700
|
+
|
|
701
|
+
def release_lockfile_label(path)
|
|
702
|
+
Kettle::Dev.display_path(path)
|
|
703
|
+
end
|
|
704
|
+
|
|
508
705
|
def run_changelog!
|
|
509
706
|
cmd = "bundle exec kettle-changelog"
|
|
510
707
|
cmd = "#{cmd} --version #{Shellwords.escape(@version_override)}" if @version_override
|
|
@@ -955,9 +1152,123 @@ module Kettle
|
|
|
955
1152
|
|
|
956
1153
|
puts "Publishing #{File.basename(gem_path)} to RubyGems without pushing git refs..."
|
|
957
1154
|
run_cmd!("gem push #{Shellwords.escape(gem_path)}")
|
|
1155
|
+
confirm_release_candidate_available!(@release_candidate || build_release_candidate(gem_name_from_gem_path(gem_path, version), version))
|
|
958
1156
|
mark_gem_coop_release_cache_bust(version, gem_name: gem_name_from_gem_path(gem_path, version))
|
|
959
1157
|
end
|
|
960
1158
|
|
|
1159
|
+
def build_release_candidate(gem_name, version)
|
|
1160
|
+
ReleaseCandidate.new(
|
|
1161
|
+
gem_name: gem_name.to_s,
|
|
1162
|
+
version: version.to_s,
|
|
1163
|
+
installed_before: gem_version_installed?(gem_name, version),
|
|
1164
|
+
published: false
|
|
1165
|
+
)
|
|
1166
|
+
end
|
|
1167
|
+
|
|
1168
|
+
def with_unpublished_candidate_cleanup
|
|
1169
|
+
yield
|
|
1170
|
+
rescue SystemExit, StandardError
|
|
1171
|
+
cleanup_unpublished_release_candidate(@release_candidate)
|
|
1172
|
+
raise
|
|
1173
|
+
end
|
|
1174
|
+
|
|
1175
|
+
def cleanup_unpublished_release_candidate(candidate)
|
|
1176
|
+
return unless candidate
|
|
1177
|
+
return if candidate.published
|
|
1178
|
+
return if candidate.installed_before
|
|
1179
|
+
return unless gem_version_installed?(candidate.gem_name, candidate.version)
|
|
1180
|
+
|
|
1181
|
+
warn(
|
|
1182
|
+
"Release of #{candidate.gem_name} #{candidate.version} was not validated; " \
|
|
1183
|
+
"uninstalling the local candidate gem so future bundle updates cannot resolve an unreleased version."
|
|
1184
|
+
)
|
|
1185
|
+
uninstall_release_candidate(candidate)
|
|
1186
|
+
end
|
|
1187
|
+
|
|
1188
|
+
def uninstall_release_candidate(candidate)
|
|
1189
|
+
run_cmd!(
|
|
1190
|
+
"gem uninstall #{Shellwords.escape(candidate.gem_name)} " \
|
|
1191
|
+
"-v #{Shellwords.escape(candidate.version)} -x -I --ignore-dependencies"
|
|
1192
|
+
)
|
|
1193
|
+
rescue SystemExit, StandardError => error
|
|
1194
|
+
warn("Could not uninstall local candidate #{candidate.gem_name} #{candidate.version}: #{error.message}")
|
|
1195
|
+
warn("Manual cleanup: gem uninstall #{candidate.gem_name} -v #{candidate.version} -x -I --ignore-dependencies")
|
|
1196
|
+
end
|
|
1197
|
+
|
|
1198
|
+
def gem_version_installed?(gem_name, version)
|
|
1199
|
+
Gem::Specification.reset
|
|
1200
|
+
Gem::Specification.find_all_by_name(gem_name.to_s, "= #{version}").any?
|
|
1201
|
+
rescue Gem::LoadError
|
|
1202
|
+
false
|
|
1203
|
+
end
|
|
1204
|
+
|
|
1205
|
+
def confirm_release_candidate_available!(candidate)
|
|
1206
|
+
run_release_availability_probe(candidate)
|
|
1207
|
+
candidate.published = true
|
|
1208
|
+
true
|
|
1209
|
+
rescue SystemExit
|
|
1210
|
+
raise
|
|
1211
|
+
rescue => error
|
|
1212
|
+
abort(<<~MSG)
|
|
1213
|
+
Published gem availability could not be validated for #{candidate.gem_name} #{candidate.version}: #{error.class}: #{error.message}
|
|
1214
|
+
kettle-release will clean up any local candidate install that was introduced by this failed release attempt.
|
|
1215
|
+
If the push actually succeeded, resolve the registry/checksum state manually before resuming.
|
|
1216
|
+
MSG
|
|
1217
|
+
end
|
|
1218
|
+
|
|
1219
|
+
def run_release_availability_probe(candidate)
|
|
1220
|
+
script_path = write_release_availability_probe(candidate)
|
|
1221
|
+
stdout_str = nil
|
|
1222
|
+
stderr_str = nil
|
|
1223
|
+
status = nil
|
|
1224
|
+
with_unbundled_release_probe_env do
|
|
1225
|
+
stdout_str, stderr_str, status = Open3.capture3(self.class.send(:command_env), Gem.ruby, script_path)
|
|
1226
|
+
end
|
|
1227
|
+
$stdout.print(stdout_str) unless stdout_str.to_s.empty?
|
|
1228
|
+
return true if status.success?
|
|
1229
|
+
|
|
1230
|
+
diag = stderr_str.to_s.empty? ? "" : "\n--- STDERR ---\n#{stderr_str}".rstrip
|
|
1231
|
+
abort("Published gem availability probe failed for #{candidate.gem_name} #{candidate.version} (exit #{status.exitstatus})#{diag}")
|
|
1232
|
+
ensure
|
|
1233
|
+
FileUtils.rm_f(script_path) if script_path
|
|
1234
|
+
end
|
|
1235
|
+
|
|
1236
|
+
def with_unbundled_release_probe_env(&block)
|
|
1237
|
+
if defined?(Bundler)
|
|
1238
|
+
Bundler.with_unbundled_env(&block)
|
|
1239
|
+
else
|
|
1240
|
+
yield
|
|
1241
|
+
end
|
|
1242
|
+
end
|
|
1243
|
+
|
|
1244
|
+
def write_release_availability_probe(candidate)
|
|
1245
|
+
dir = File.join(@root, "tmp", "kettle-release")
|
|
1246
|
+
FileUtils.mkdir_p(dir)
|
|
1247
|
+
path = File.join(dir, "validate-#{candidate.gem_name}-#{candidate.version}-#{$$}.rb")
|
|
1248
|
+
File.write(path, release_availability_probe_script(candidate))
|
|
1249
|
+
path
|
|
1250
|
+
end
|
|
1251
|
+
|
|
1252
|
+
def release_availability_probe_script(candidate)
|
|
1253
|
+
<<~RUBY
|
|
1254
|
+
# frozen_string_literal: true
|
|
1255
|
+
|
|
1256
|
+
gem_name = #{candidate.gem_name.dump}
|
|
1257
|
+
version = #{candidate.version.dump}
|
|
1258
|
+
|
|
1259
|
+
require "bundler/inline"
|
|
1260
|
+
|
|
1261
|
+
gemfile(true) do
|
|
1262
|
+
source #{RELEASE_VALIDATION_SOURCE.dump}
|
|
1263
|
+
gem gem_name, "= \#{version}"
|
|
1264
|
+
end
|
|
1265
|
+
|
|
1266
|
+
spec = Gem.loaded_specs.fetch(gem_name)
|
|
1267
|
+
abort("loaded \#{gem_name} \#{spec.version}, expected \#{version}") unless spec.version.to_s == version
|
|
1268
|
+
puts "Validated \#{gem_name} \#{version} from #{RELEASE_VALIDATION_SOURCE}"
|
|
1269
|
+
RUBY
|
|
1270
|
+
end
|
|
1271
|
+
|
|
961
1272
|
def detect_version
|
|
962
1273
|
Kettle::Dev::Versioning.detect_version(@root, override: @version_override)
|
|
963
1274
|
end
|
|
@@ -1520,3 +1831,14 @@ module Kettle
|
|
|
1520
1831
|
end
|
|
1521
1832
|
end
|
|
1522
1833
|
end
|
|
1834
|
+
|
|
1835
|
+
class Kettle::Dev::ReleaseCLI::ReleaseCandidate
|
|
1836
|
+
attr_accessor :gem_name, :version, :installed_before, :published
|
|
1837
|
+
|
|
1838
|
+
def initialize(gem_name:, version:, installed_before:, published:)
|
|
1839
|
+
@gem_name = gem_name
|
|
1840
|
+
@version = version
|
|
1841
|
+
@installed_before = installed_before
|
|
1842
|
+
@published = published
|
|
1843
|
+
end
|
|
1844
|
+
end
|
data/lib/kettle/dev/version.rb
CHANGED
data.tar.gz.sig
CHANGED
|
Binary file
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: kettle-dev
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.4.
|
|
4
|
+
version: 2.4.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Peter H. Boling
|
|
@@ -349,10 +349,10 @@ licenses:
|
|
|
349
349
|
- AGPL-3.0-only
|
|
350
350
|
metadata:
|
|
351
351
|
homepage_uri: https://kettle-dev.galtzo.com
|
|
352
|
-
source_code_uri: https://github.com/kettle-dev/kettle-dev/tree/v2.4.
|
|
353
|
-
changelog_uri: https://github.com/kettle-dev/kettle-dev/blob/v2.4.
|
|
352
|
+
source_code_uri: https://github.com/kettle-dev/kettle-dev/tree/v2.4.2
|
|
353
|
+
changelog_uri: https://github.com/kettle-dev/kettle-dev/blob/v2.4.2/CHANGELOG.md
|
|
354
354
|
bug_tracker_uri: https://github.com/kettle-dev/kettle-dev/issues
|
|
355
|
-
documentation_uri: https://www.rubydoc.info/gems/kettle-dev/2.4.
|
|
355
|
+
documentation_uri: https://www.rubydoc.info/gems/kettle-dev/2.4.2
|
|
356
356
|
funding_uri: https://github.com/sponsors/pboling
|
|
357
357
|
wiki_uri: https://github.com/kettle-dev/kettle-dev/wiki
|
|
358
358
|
news_uri: https://www.railsbling.com/tags/kettle-dev
|
metadata.gz.sig
CHANGED
|
Binary file
|