kettle-dev 3.1.19 → 3.1.20
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 +14 -1
- data/README.md +1 -1
- data/lib/kettle/dev/release_cli.rb +82 -11
- 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: 9efc79f5aed2cce009a847b8054a5ce39d54bd5c11f567d5463085e1ce11fcd6
|
|
4
|
+
data.tar.gz: 28b1079640e41dbd9f7ff7c0d844f377b177c4d408b504af893cc888b5abf200
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f4982d17aabae7fc0e4d970a55fac3e8403f4daceea4d6e5399380a928c270a2a80ff879c3698eb3558276c39e3fd9a540d801a6ec226ad5e8989c96dd737ded
|
|
7
|
+
data.tar.gz: 7ada13071f91419315448d6b9d03be92c8a25f68d827fb5acbf94b97aad444d7173f6eb411bf7ac6ebdd6251deb4f8f86fdba868ab1edb308ce69eaf199d5eb9
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
data/CHANGELOG.md
CHANGED
|
@@ -30,6 +30,17 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
|
30
30
|
|
|
31
31
|
### Security
|
|
32
32
|
|
|
33
|
+
## [3.1.20] - 2026-10-21
|
|
34
|
+
|
|
35
|
+
- TAG: [v3.1.20][3.1.20t]
|
|
36
|
+
- COVERAGE: 91.52% -- 5773/6308 lines in 48 files
|
|
37
|
+
- BRANCH COVERAGE: 75.66% -- 2226/2942 branches in 48 files
|
|
38
|
+
- 53.70% documented
|
|
39
|
+
|
|
40
|
+
### Fixed
|
|
41
|
+
|
|
42
|
+
- Release availability probe no longer fails a release after a successful push when the gem.coop proxy lags rubygems.org: the probe alternates the gem.coop consumer-mirror validation with a live rubygems.org confirmation of the push target, backs off exponentially between attempts (10s base, 1.6x growth, 120s cap; tunable via KETTLE_DEV_RELEASE_PROBE_ATTEMPTS / KETTLE_DEV_RELEASE_PROBE_INITIAL_DELAY / KETTLE_DEV_RELEASE_PROBE_INTERVAL / KETTLE_DEV_RELEASE_PROBE_MAX_INTERVAL, also applied to release lockfile-reset retries), and proceeds with a warning when rubygems.org confirms the publish but gem.coop has not yet synced, instead of aborting the wave
|
|
43
|
+
|
|
33
44
|
## [3.1.19] - 2026-10-19
|
|
34
45
|
|
|
35
46
|
- TAG: [v3.1.19][3.1.19t]
|
|
@@ -4189,7 +4200,9 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
|
4189
4200
|
- Selecting will run the selected workflow via `act`
|
|
4190
4201
|
- This may move to its own gem in the future.
|
|
4191
4202
|
|
|
4192
|
-
[Unreleased]: https://github.com/kettle-dev/kettle-dev/compare/v3.1.
|
|
4203
|
+
[Unreleased]: https://github.com/kettle-dev/kettle-dev/compare/v3.1.20...HEAD
|
|
4204
|
+
[3.1.20]: https://github.com/kettle-dev/kettle-dev/compare/v3.1.19...v3.1.20
|
|
4205
|
+
[3.1.20t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v3.1.20
|
|
4193
4206
|
[3.1.19]: https://github.com/kettle-dev/kettle-dev/compare/v3.1.18...v3.1.19
|
|
4194
4207
|
[3.1.19t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v3.1.19
|
|
4195
4208
|
[3.1.18]: https://github.com/kettle-dev/kettle-dev/compare/v3.1.17...v3.1.18
|
data/README.md
CHANGED
|
@@ -1084,7 +1084,7 @@ Thanks for RTFM. ☺️
|
|
|
1084
1084
|
[📌gitmoji]: https://gitmoji.dev
|
|
1085
1085
|
[📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
|
|
1086
1086
|
[🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
|
|
1087
|
-
[🧮kloc-img]: https://img.shields.io/badge/KLOC-6.
|
|
1087
|
+
[🧮kloc-img]: https://img.shields.io/badge/KLOC-6.308-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
|
|
1088
1088
|
[🔐security]: https://github.com/kettle-dev/kettle-dev/blob/main/SECURITY.md
|
|
1089
1089
|
[🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
|
|
1090
1090
|
[📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
|
|
@@ -71,6 +71,9 @@ module Kettle
|
|
|
71
71
|
].freeze
|
|
72
72
|
DEBUG_TRUE_VALUES = %w[1 true yes on].freeze
|
|
73
73
|
RELEASE_VALIDATION_SOURCE = "https://gem.coop"
|
|
74
|
+
# The push target registry. gem.coop is a caching proxy that can lag it,
|
|
75
|
+
# so this is authoritative for whether a pushed gem landed at all.
|
|
76
|
+
RELEASE_UPSTREAM_SOURCE = "https://rubygems.org"
|
|
74
77
|
FAMILY_MEMBER_PUBLISH_MODE_ENV = "KETTLE_RELEASE_FAMILY_MEMBER_PUBLISH"
|
|
75
78
|
FAMILY_MEMBER_FINALIZE_MODE_ENV = "KETTLE_RELEASE_FAMILY_MEMBER_FINALIZE"
|
|
76
79
|
|
|
@@ -887,7 +890,7 @@ module Kettle
|
|
|
887
890
|
)
|
|
888
891
|
if retryable
|
|
889
892
|
puts "Release lockfile reset could not resolve a newly published workspace gem from #{RELEASE_VALIDATION_SOURCE}; waiting before retry #{attempt + 1}/#{attempts}."
|
|
890
|
-
sleep(release_availability_probe_interval)
|
|
893
|
+
sleep(release_availability_probe_interval(attempt))
|
|
891
894
|
next
|
|
892
895
|
end
|
|
893
896
|
|
|
@@ -908,7 +911,7 @@ module Kettle
|
|
|
908
911
|
raise unless retryable
|
|
909
912
|
|
|
910
913
|
puts "Release lockfile reset could not resolve a gem from #{RELEASE_VALIDATION_SOURCE}; waiting before retry #{attempt + 1}/#{attempts}."
|
|
911
|
-
sleep(release_availability_probe_interval)
|
|
914
|
+
sleep(release_availability_probe_interval(attempt))
|
|
912
915
|
end
|
|
913
916
|
end
|
|
914
917
|
|
|
@@ -2222,6 +2225,7 @@ module Kettle
|
|
|
2222
2225
|
attempts = release_availability_probe_attempts
|
|
2223
2226
|
last_stderr = nil
|
|
2224
2227
|
last_status = nil
|
|
2228
|
+
upstream_confirmed = false
|
|
2225
2229
|
sleep(release_availability_probe_initial_delay)
|
|
2226
2230
|
attempts.times do |index|
|
|
2227
2231
|
attempt = index + 1
|
|
@@ -2247,33 +2251,99 @@ module Kettle
|
|
|
2247
2251
|
|
|
2248
2252
|
last_stderr = stderr_str
|
|
2249
2253
|
last_status = status
|
|
2254
|
+
# Alternate the consumer-mirror check with the push target:
|
|
2255
|
+
# #{RELEASE_UPSTREAM_SOURCE} answers "did the push land at all",
|
|
2256
|
+
# while #{RELEASE_VALIDATION_SOURCE} is a caching proxy that can lag
|
|
2257
|
+
# it. A confirmed push gets the full backoff window to sync.
|
|
2258
|
+
upstream_confirmed ||= release_probe_upstream_published?(candidate)
|
|
2259
|
+
if upstream_confirmed
|
|
2260
|
+
puts("#{candidate.gem_name} #{candidate.version} is published on #{RELEASE_UPSTREAM_SOURCE}; " \
|
|
2261
|
+
"waiting for #{RELEASE_VALIDATION_SOURCE} to sync (attempt #{attempt}/#{attempts}).")
|
|
2262
|
+
end
|
|
2250
2263
|
emit_release_probe_event(
|
|
2251
2264
|
action: "availability",
|
|
2252
|
-
status: (attempt < attempts) ? "retrying" : "failed",
|
|
2265
|
+
status: (attempt < attempts || upstream_confirmed) ? "retrying" : "failed",
|
|
2253
2266
|
candidate: candidate,
|
|
2254
2267
|
attempt: attempt,
|
|
2255
2268
|
attempts: attempts,
|
|
2256
|
-
reason: "exit #{status.exitstatus}"
|
|
2269
|
+
reason: "exit #{status.exitstatus}",
|
|
2270
|
+
upstream: upstream_confirmed ? "confirmed" : "unconfirmed"
|
|
2271
|
+
)
|
|
2272
|
+
sleep(release_availability_probe_interval(attempt)) if attempt < attempts
|
|
2273
|
+
end
|
|
2274
|
+
|
|
2275
|
+
if upstream_confirmed
|
|
2276
|
+
warn(<<~MSG)
|
|
2277
|
+
WARNING: #{candidate.gem_name} #{candidate.version} is published on #{RELEASE_UPSTREAM_SOURCE}, but #{RELEASE_VALIDATION_SOURCE} has not synced it after #{attempts} attempt(s).
|
|
2278
|
+
Proceeding because the push target is authoritative for the publish; downstream release steps resolve from #{RELEASE_VALIDATION_SOURCE} and retry on their own.
|
|
2279
|
+
If a later step fails to resolve this gem, wait for #{RELEASE_VALIDATION_SOURCE} to sync and resume that member.
|
|
2280
|
+
MSG
|
|
2281
|
+
emit_release_probe_event(
|
|
2282
|
+
action: "availability",
|
|
2283
|
+
status: "ok",
|
|
2284
|
+
candidate: candidate,
|
|
2285
|
+
attempt: attempts,
|
|
2286
|
+
attempts: attempts,
|
|
2287
|
+
reason: "confirmed on #{RELEASE_UPSTREAM_SOURCE}; #{RELEASE_VALIDATION_SOURCE} sync pending",
|
|
2288
|
+
upstream: "confirmed"
|
|
2257
2289
|
)
|
|
2258
|
-
|
|
2290
|
+
return true
|
|
2259
2291
|
end
|
|
2260
2292
|
|
|
2261
2293
|
diag = last_stderr.to_s.empty? ? "" : "\n--- STDERR ---\n#{last_stderr}".rstrip
|
|
2262
|
-
abort("Published gem availability probe failed for #{candidate.gem_name} #{candidate.version} after #{attempts} attempt(s) (exit #{last_status.exitstatus})
|
|
2294
|
+
abort("Published gem availability probe failed for #{candidate.gem_name} #{candidate.version} after #{attempts} attempt(s) (exit #{last_status.exitstatus}); " \
|
|
2295
|
+
"the version is not visible on #{RELEASE_UPSTREAM_SOURCE} either, so the push itself may have failed#{diag}")
|
|
2263
2296
|
ensure
|
|
2264
2297
|
FileUtils.rm_f(script_path) if script_path
|
|
2265
2298
|
end
|
|
2266
2299
|
|
|
2267
2300
|
def release_availability_probe_attempts
|
|
2268
|
-
15
|
|
2301
|
+
env_positive_integer("KETTLE_DEV_RELEASE_PROBE_ATTEMPTS") || 15
|
|
2269
2302
|
end
|
|
2270
2303
|
|
|
2271
2304
|
def release_availability_probe_initial_delay
|
|
2272
|
-
5
|
|
2305
|
+
env_positive_integer("KETTLE_DEV_RELEASE_PROBE_INITIAL_DELAY") || 5
|
|
2306
|
+
end
|
|
2307
|
+
|
|
2308
|
+
# Exponential backoff between probe attempts: the base interval grows per
|
|
2309
|
+
# attempt, capped, because the consumer-mirror proxy (gem.coop) can lag
|
|
2310
|
+
# the push target (rubygems.org) by minutes. With defaults the worst case
|
|
2311
|
+
# is ~20 minutes across 15 attempts, and it only accrues when the
|
|
2312
|
+
# registry genuinely lags — a fast sync still passes on attempt 1.
|
|
2313
|
+
def release_availability_probe_interval(attempt = 1)
|
|
2314
|
+
base = env_positive_integer("KETTLE_DEV_RELEASE_PROBE_INTERVAL") || 10
|
|
2315
|
+
cap = env_positive_integer("KETTLE_DEV_RELEASE_PROBE_MAX_INTERVAL") || 120
|
|
2316
|
+
[(base * (1.6**(attempt - 1))).round, cap].min
|
|
2317
|
+
end
|
|
2318
|
+
|
|
2319
|
+
# Whether the push target registry already serves the candidate.
|
|
2320
|
+
# confirm: true forces a live registry read, never a stale cache entry,
|
|
2321
|
+
# because this answer decides whether a failed mirror probe is fatal.
|
|
2322
|
+
def release_probe_upstream_published?(candidate)
|
|
2323
|
+
versions = Kettle::Dev::RubyGemsVersions.published_version_numbers(
|
|
2324
|
+
candidate.gem_name,
|
|
2325
|
+
source: RELEASE_UPSTREAM_SOURCE,
|
|
2326
|
+
version: candidate.version,
|
|
2327
|
+
confirm: true
|
|
2328
|
+
)
|
|
2329
|
+
return false if versions.nil?
|
|
2330
|
+
|
|
2331
|
+
versions.include?(candidate.version.to_s)
|
|
2332
|
+
rescue => error
|
|
2333
|
+
warn("Upstream availability check against #{RELEASE_UPSTREAM_SOURCE} failed: #{error.class}: #{error.message}")
|
|
2334
|
+
false
|
|
2273
2335
|
end
|
|
2274
2336
|
|
|
2275
|
-
def
|
|
2276
|
-
|
|
2337
|
+
def env_positive_integer(name)
|
|
2338
|
+
raw = ENV.fetch(name, nil).to_s.strip
|
|
2339
|
+
return nil if raw.empty?
|
|
2340
|
+
|
|
2341
|
+
value = begin
|
|
2342
|
+
Integer(raw)
|
|
2343
|
+
rescue ArgumentError, TypeError
|
|
2344
|
+
nil
|
|
2345
|
+
end
|
|
2346
|
+
value&.positive? ? value : nil
|
|
2277
2347
|
end
|
|
2278
2348
|
|
|
2279
2349
|
def with_release_availability_probe_gem_home
|
|
@@ -2627,7 +2697,7 @@ module Kettle
|
|
|
2627
2697
|
)
|
|
2628
2698
|
end
|
|
2629
2699
|
|
|
2630
|
-
def emit_release_probe_event(action:, status:, candidate:, attempt:, attempts:, reason: nil)
|
|
2700
|
+
def emit_release_probe_event(action:, status:, candidate:, attempt:, attempts:, reason: nil, upstream: nil)
|
|
2631
2701
|
Kettle::Ndjson.emit_event(
|
|
2632
2702
|
@event_recorder,
|
|
2633
2703
|
"release_probe",
|
|
@@ -2640,6 +2710,7 @@ module Kettle
|
|
|
2640
2710
|
attempt: attempt,
|
|
2641
2711
|
attempts: attempts,
|
|
2642
2712
|
reason: reason,
|
|
2713
|
+
upstream: upstream,
|
|
2643
2714
|
mark: release_progress_mark(status)
|
|
2644
2715
|
)
|
|
2645
2716
|
end
|
data/lib/kettle/dev/version.rb
CHANGED
|
@@ -5,7 +5,7 @@ module Kettle
|
|
|
5
5
|
# Version namespace for this gem.
|
|
6
6
|
module Version
|
|
7
7
|
# Current gem version.
|
|
8
|
-
VERSION = "3.1.
|
|
8
|
+
VERSION = "3.1.20"
|
|
9
9
|
end
|
|
10
10
|
# Current gem version exposed at the traditional constant location.
|
|
11
11
|
VERSION = Version::VERSION # Traditional Constant Location
|
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: 3.1.
|
|
4
|
+
version: 3.1.20
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Peter H. Boling
|
|
@@ -423,10 +423,10 @@ licenses:
|
|
|
423
423
|
- AGPL-3.0-only
|
|
424
424
|
metadata:
|
|
425
425
|
homepage_uri: https://kettle-dev.galtzo.com
|
|
426
|
-
source_code_uri: https://github.com/kettle-dev/kettle-dev/tree/v3.1.
|
|
427
|
-
changelog_uri: https://github.com/kettle-dev/kettle-dev/blob/v3.1.
|
|
426
|
+
source_code_uri: https://github.com/kettle-dev/kettle-dev/tree/v3.1.20
|
|
427
|
+
changelog_uri: https://github.com/kettle-dev/kettle-dev/blob/v3.1.20/CHANGELOG.md
|
|
428
428
|
bug_tracker_uri: https://github.com/kettle-dev/kettle-dev/issues
|
|
429
|
-
documentation_uri: https://www.rubydoc.info/gems/kettle-dev/3.1.
|
|
429
|
+
documentation_uri: https://www.rubydoc.info/gems/kettle-dev/3.1.20
|
|
430
430
|
funding_uri: https://github.com/sponsors/pboling
|
|
431
431
|
wiki_uri: https://github.com/kettle-dev/kettle-dev/wiki
|
|
432
432
|
news_uri: https://www.railsbling.com/tags/kettle-dev
|
metadata.gz.sig
CHANGED
|
Binary file
|