kettle-dev 2.2.8 → 2.2.10
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 +35 -1
- data/README.md +1 -1
- data/lib/kettle/dev/gha_sha_pins_cli.rb +7 -5
- data/lib/kettle/dev/pre_release_cli.rb +114 -1
- data/lib/kettle/dev/version.rb +1 -1
- data/sig/kettle/dev/pre_release_cli.rbs +10 -0
- 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: 9216115bc5448b3e08cfcd393c22029d70e7b6d31bcb80617b44b7d97644b649
|
|
4
|
+
data.tar.gz: e86c38ac97fbac63e1258bf15d6454f408e62ffe927af628bc5f7090472f98fd
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 52d369f7c70a48bf3c2fde5898cc7f99ac9eda0b6e09319d7166976e20057d95360a56f29bf00dbd226976a853dd212e915fd31026b7c647df1f68bee6331cd4
|
|
7
|
+
data.tar.gz: 7ab61300d6f489ddc25636e10dcea667998a20c5ef3755a9b7773e2ccb0fde69871c8ba5607303a618501a55c2c05289dc3585905c6243e1ca524a7de1cb7c8a
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
data/CHANGELOG.md
CHANGED
|
@@ -30,6 +30,36 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
|
30
30
|
|
|
31
31
|
### Security
|
|
32
32
|
|
|
33
|
+
## [2.2.10] - 2026-06-16
|
|
34
|
+
|
|
35
|
+
- TAG: [v2.2.10][2.2.10t]
|
|
36
|
+
- COVERAGE: 92.24% -- 3911/4240 lines in 28 files
|
|
37
|
+
- BRANCH COVERAGE: 73.87% -- 1552/2101 branches in 28 files
|
|
38
|
+
- 64.35% documented
|
|
39
|
+
|
|
40
|
+
### Changed
|
|
41
|
+
|
|
42
|
+
- `kettle-pre-release` now caches successful Markdown image URL validations in
|
|
43
|
+
the global kettle-dev state cache for seven days to avoid repeated network
|
|
44
|
+
HEAD requests during release readiness checks.
|
|
45
|
+
|
|
46
|
+
## [2.2.9] - 2026-06-14
|
|
47
|
+
|
|
48
|
+
- TAG: [v2.2.9][2.2.9t]
|
|
49
|
+
- COVERAGE: 92.57% -- 3863/4173 lines in 28 files
|
|
50
|
+
- BRANCH COVERAGE: 74.00% -- 1534/2073 branches in 28 files
|
|
51
|
+
- 65.38% documented
|
|
52
|
+
|
|
53
|
+
### Fixed
|
|
54
|
+
|
|
55
|
+
- `kettle-gha-sha-pins --check` no longer fails solely because releases outside
|
|
56
|
+
the selected `--upgrade` policy exist, and `kettle-pre-release` now validates
|
|
57
|
+
workflow pins with the inclusive `major` policy used for release readiness.
|
|
58
|
+
|
|
59
|
+
- `kettle-gha-sha-pins --write` now handles major-line adjacent version comments
|
|
60
|
+
such as `# v7` idempotently instead of repeatedly planning the same
|
|
61
|
+
`update_version_comment` change.
|
|
62
|
+
|
|
33
63
|
## [2.2.8] - 2026-06-13
|
|
34
64
|
|
|
35
65
|
- TAG: [v2.2.8][2.2.8t]
|
|
@@ -2109,7 +2139,11 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
|
2109
2139
|
- Selecting will run the selected workflow via `act`
|
|
2110
2140
|
- This may move to its own gem in the future.
|
|
2111
2141
|
|
|
2112
|
-
[Unreleased]: https://github.com/kettle-dev/kettle-dev/compare/v2.2.
|
|
2142
|
+
[Unreleased]: https://github.com/kettle-dev/kettle-dev/compare/v2.2.10...HEAD
|
|
2143
|
+
[2.2.10]: https://github.com/kettle-dev/kettle-dev/compare/v2.2.9...v2.2.10
|
|
2144
|
+
[2.2.10t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v2.2.10
|
|
2145
|
+
[2.2.9]: https://github.com/kettle-dev/kettle-dev/compare/v2.2.8...v2.2.9
|
|
2146
|
+
[2.2.9t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v2.2.9
|
|
2113
2147
|
[2.2.8]: https://github.com/kettle-dev/kettle-dev/compare/v2.2.7...v2.2.8
|
|
2114
2148
|
[2.2.8t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v2.2.8
|
|
2115
2149
|
[2.2.7]: https://github.com/kettle-dev/kettle-dev/compare/v2.2.6...v2.2.7
|
data/README.md
CHANGED
|
@@ -854,7 +854,7 @@ Thanks for RTFM. ☺️
|
|
|
854
854
|
[📌gitmoji]: https://gitmoji.dev
|
|
855
855
|
[📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
|
|
856
856
|
[🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
|
|
857
|
-
[🧮kloc-img]: https://img.shields.io/badge/KLOC-4.
|
|
857
|
+
[🧮kloc-img]: https://img.shields.io/badge/KLOC-4.240-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
|
|
858
858
|
[🔐security]: https://github.com/kettle-dev/kettle-dev/blob/main/SECURITY.md
|
|
859
859
|
[🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
|
|
860
860
|
[📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
|
|
@@ -33,6 +33,8 @@ module Kettle
|
|
|
33
33
|
DEFAULT_UPGRADE_LEVEL = "patch"
|
|
34
34
|
DEFAULT_CACHE_TTL_SECONDS = 24 * 60 * 60
|
|
35
35
|
VALID_UPGRADE_LEVELS = %w[major minor patch].freeze
|
|
36
|
+
VERSION_COMMENT_SUFFIX_RE = /\A\s+#\s*v?(?<version>\d+(?:\.\d+\.\d+(?:[-.]?[0-9A-Za-z.-]+)?)?)/
|
|
37
|
+
VERSION_COMMENT_REPLACEMENT_RE = /\A(?<prefix>\s+#\s*)v?\d+(?:\.\d+\.\d+(?:[-.]?[0-9A-Za-z.-]+)?)?/
|
|
36
38
|
|
|
37
39
|
def initialize(argv, err: $stderr)
|
|
38
40
|
@argv = argv
|
|
@@ -215,7 +217,7 @@ module Kettle
|
|
|
215
217
|
|
|
216
218
|
print_report(state)
|
|
217
219
|
return 2 unless state[:failures].zero?
|
|
218
|
-
return 3 if @options[:check] &&
|
|
220
|
+
return 3 if @options[:check] && state[:updates].positive?
|
|
219
221
|
|
|
220
222
|
0
|
|
221
223
|
end
|
|
@@ -745,8 +747,8 @@ module Kettle
|
|
|
745
747
|
return nil unless token_info[:token] == old_token
|
|
746
748
|
|
|
747
749
|
suffix = raw[token_info[:span]..-1].to_s
|
|
748
|
-
match = suffix.match(
|
|
749
|
-
match && match[
|
|
750
|
+
match = suffix.match(VERSION_COMMENT_SUFFIX_RE)
|
|
751
|
+
match && match[:version]
|
|
750
752
|
end
|
|
751
753
|
|
|
752
754
|
def build_replacement_from_line(text, line, col, old_token, new_ref, new_version = nil)
|
|
@@ -767,7 +769,7 @@ module Kettle
|
|
|
767
769
|
new_scalar = rendered[:quoted]
|
|
768
770
|
if new_version && token_info[:quote] == :plain
|
|
769
771
|
suffix = raw[span..-1].to_s
|
|
770
|
-
comment = suffix.match(
|
|
772
|
+
comment = suffix.match(VERSION_COMMENT_REPLACEMENT_RE)
|
|
771
773
|
if comment
|
|
772
774
|
span += comment[0].length
|
|
773
775
|
new_scalar += "#{comment[:prefix]}v#{new_version}"
|
|
@@ -902,7 +904,7 @@ module Kettle
|
|
|
902
904
|
lines << "- #{change[:path]}:#{change[:line]} #{from} -> #{to} #{change[:reason]}"
|
|
903
905
|
end
|
|
904
906
|
end
|
|
905
|
-
if @options[:check] &&
|
|
907
|
+
if @options[:check] && state[:planned_changes].any?
|
|
906
908
|
lines << ""
|
|
907
909
|
lines << "Recommended fix: kettle-gha-sha-pins --write --upgrade #{@options[:upgrade]}"
|
|
908
910
|
end
|
|
@@ -2,9 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
require "optparse"
|
|
4
4
|
require "English"
|
|
5
|
+
require "json"
|
|
6
|
+
require "fileutils"
|
|
5
7
|
require "uri"
|
|
6
8
|
require "net/http"
|
|
7
9
|
require "openssl"
|
|
10
|
+
require "time"
|
|
8
11
|
begin
|
|
9
12
|
require "addressable/uri"
|
|
10
13
|
rescue LoadError
|
|
@@ -21,6 +24,8 @@ module Kettle
|
|
|
21
24
|
#
|
|
22
25
|
# Usage: Kettle::Dev::PreReleaseCLI.new(check_num: 1).run
|
|
23
26
|
class PreReleaseCLI
|
|
27
|
+
IMAGE_URL_CACHE_TTL_SECONDS = 7 * 24 * 60 * 60
|
|
28
|
+
|
|
24
29
|
# Simple HTTP helpers for link validation
|
|
25
30
|
module HTTP
|
|
26
31
|
module_function
|
|
@@ -93,6 +98,85 @@ module Kettle
|
|
|
93
98
|
end
|
|
94
99
|
end
|
|
95
100
|
|
|
101
|
+
# Persistent cache of successfully validated Markdown image URLs.
|
|
102
|
+
class ImageUrlCache
|
|
103
|
+
VERSION = 1
|
|
104
|
+
|
|
105
|
+
def self.default_path
|
|
106
|
+
state_home = ENV["XDG_STATE_HOME"]
|
|
107
|
+
state_home = File.join(Dir.home, ".local", "state") if state_home.to_s.empty?
|
|
108
|
+
File.join(state_home, "kettle-dev", "image-url-cache.json")
|
|
109
|
+
rescue ArgumentError
|
|
110
|
+
nil
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def initialize(path:, ttl_seconds: IMAGE_URL_CACHE_TTL_SECONDS, clock: -> { Time.now })
|
|
114
|
+
@path = path
|
|
115
|
+
@ttl_seconds = ttl_seconds
|
|
116
|
+
@clock = clock
|
|
117
|
+
@data = nil
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def fresh_success?(url)
|
|
121
|
+
entry = data.fetch("images")[url.to_s]
|
|
122
|
+
return false unless entry.is_a?(Hash)
|
|
123
|
+
return false unless entry["ok"] == true
|
|
124
|
+
|
|
125
|
+
fresh_entry?(entry)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def write_success(url)
|
|
129
|
+
return if @path.to_s.empty?
|
|
130
|
+
return if url.to_s.empty?
|
|
131
|
+
|
|
132
|
+
data.fetch("images")[url.to_s] = {
|
|
133
|
+
"ok" => true,
|
|
134
|
+
"cached_at" => @clock.call.utc.iso8601
|
|
135
|
+
}
|
|
136
|
+
save!
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def to_h
|
|
140
|
+
data
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
private
|
|
144
|
+
|
|
145
|
+
def data
|
|
146
|
+
@data ||= load_data
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def load_data
|
|
150
|
+
parsed = if @path && File.file?(@path)
|
|
151
|
+
JSON.parse(File.read(@path))
|
|
152
|
+
end
|
|
153
|
+
return empty_data unless parsed.is_a?(Hash)
|
|
154
|
+
return empty_data unless parsed["version"].to_i == VERSION
|
|
155
|
+
|
|
156
|
+
parsed["version"] ||= VERSION
|
|
157
|
+
parsed["images"] = {} unless parsed["images"].is_a?(Hash)
|
|
158
|
+
parsed
|
|
159
|
+
rescue JSON::ParserError, Errno::EACCES
|
|
160
|
+
empty_data
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def empty_data
|
|
164
|
+
{"version" => VERSION, "images" => {}}
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def save!
|
|
168
|
+
FileUtils.mkdir_p(File.dirname(@path))
|
|
169
|
+
File.write(@path, JSON.pretty_generate(data) + "\n")
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def fresh_entry?(entry)
|
|
173
|
+
cached_at = Time.iso8601(entry["cached_at"].to_s)
|
|
174
|
+
cached_at >= @clock.call - @ttl_seconds
|
|
175
|
+
rescue ArgumentError
|
|
176
|
+
false
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
|
|
96
180
|
# Markdown parsing helpers
|
|
97
181
|
module Markdown
|
|
98
182
|
module_function
|
|
@@ -184,6 +268,8 @@ module Kettle
|
|
|
184
268
|
def initialize(check_num: 1)
|
|
185
269
|
@check_num = (check_num || 1).to_i
|
|
186
270
|
@check_num = 1 if @check_num < 1
|
|
271
|
+
@image_url_cache_path = configured_image_url_cache_path
|
|
272
|
+
@refresh_image_url_cache = env_truthy?(ENV["KETTLE_IMAGE_URL_CACHE_REFRESH"])
|
|
187
273
|
end
|
|
188
274
|
|
|
189
275
|
# Execute configured checks starting from @check_num.
|
|
@@ -210,7 +296,7 @@ module Kettle
|
|
|
210
296
|
# @return [void]
|
|
211
297
|
def check_github_actions_sha_pins!
|
|
212
298
|
puts "[kettle-pre-release] Check 1: Validate GitHub Actions SHA pins"
|
|
213
|
-
status = Kettle::Dev::GhaShaPinsCLI.new(["--root", Dir.pwd, "--check"]).run!
|
|
299
|
+
status = Kettle::Dev::GhaShaPinsCLI.new(["--root", Dir.pwd, "--check", "--upgrade", "major"]).run!
|
|
214
300
|
return nil if status.zero?
|
|
215
301
|
|
|
216
302
|
Kettle::Dev::ExitAdapter.abort("GitHub Actions SHA pin validation failed")
|
|
@@ -272,12 +358,19 @@ module Kettle
|
|
|
272
358
|
puts "[kettle-pre-release] Check 3: Validate Markdown image links (HTTP HEAD)"
|
|
273
359
|
urls = Markdown.extract_image_urls_from_files
|
|
274
360
|
puts "[kettle-pre-release] Found #{urls.size} unique image URL(s)."
|
|
361
|
+
cache = image_url_cache
|
|
275
362
|
failures = []
|
|
276
363
|
urls.each do |url|
|
|
277
364
|
print(" -> #{url} … ")
|
|
365
|
+
if cache && !@refresh_image_url_cache && cache.fresh_success?(url)
|
|
366
|
+
puts "OK (cached)"
|
|
367
|
+
next
|
|
368
|
+
end
|
|
369
|
+
|
|
278
370
|
ok = HTTP.head_ok?(url)
|
|
279
371
|
if ok
|
|
280
372
|
puts "OK"
|
|
373
|
+
cache&.write_success(url)
|
|
281
374
|
else
|
|
282
375
|
puts "FAIL"
|
|
283
376
|
failures << url
|
|
@@ -292,6 +385,26 @@ module Kettle
|
|
|
292
385
|
end
|
|
293
386
|
nil
|
|
294
387
|
end
|
|
388
|
+
|
|
389
|
+
private
|
|
390
|
+
|
|
391
|
+
def image_url_cache
|
|
392
|
+
return nil if @image_url_cache_path.to_s.empty?
|
|
393
|
+
|
|
394
|
+
@image_url_cache ||= ImageUrlCache.new(path: @image_url_cache_path)
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
def configured_image_url_cache_path
|
|
398
|
+
value = ENV.fetch("KETTLE_IMAGE_URL_CACHE", nil)
|
|
399
|
+
return ImageUrlCache.default_path if value.nil? || value.to_s.strip.empty?
|
|
400
|
+
return nil if value.to_s.strip.match?(Kettle::Dev::ENV_FALSE_RE)
|
|
401
|
+
|
|
402
|
+
value
|
|
403
|
+
end
|
|
404
|
+
|
|
405
|
+
def env_truthy?(value)
|
|
406
|
+
!!value.to_s.strip.match?(/\A(true|y|yes|1|on)\z/i)
|
|
407
|
+
end
|
|
295
408
|
end
|
|
296
409
|
end
|
|
297
410
|
end
|
data/lib/kettle/dev/version.rb
CHANGED
|
@@ -11,6 +11,16 @@ module Kettle
|
|
|
11
11
|
def self.extract_image_urls_from_files: (?String glob_pattern) -> Array[String]
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
+
class ImageUrlCache
|
|
15
|
+
VERSION: Integer
|
|
16
|
+
|
|
17
|
+
def self.default_path: () -> String?
|
|
18
|
+
def initialize: (path: String?, ?ttl_seconds: Integer, ?clock: ^() -> Time) -> void
|
|
19
|
+
def fresh_success?: (String url) -> bool
|
|
20
|
+
def write_success: (String url) -> void
|
|
21
|
+
def to_h: () -> Hash[String, untyped]
|
|
22
|
+
end
|
|
23
|
+
|
|
14
24
|
def initialize: (?check_num: Integer) -> void
|
|
15
25
|
def run: () -> void
|
|
16
26
|
def check_markdown_uri_normalization!: () -> void
|
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.2.
|
|
4
|
+
version: 2.2.10
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Peter H. Boling
|
|
@@ -338,10 +338,10 @@ licenses:
|
|
|
338
338
|
- AGPL-3.0-only
|
|
339
339
|
metadata:
|
|
340
340
|
homepage_uri: https://kettle-dev.galtzo.com
|
|
341
|
-
source_code_uri: https://github.com/kettle-dev/kettle-dev/tree/v2.2.
|
|
342
|
-
changelog_uri: https://github.com/kettle-dev/kettle-dev/blob/v2.2.
|
|
341
|
+
source_code_uri: https://github.com/kettle-dev/kettle-dev/tree/v2.2.10
|
|
342
|
+
changelog_uri: https://github.com/kettle-dev/kettle-dev/blob/v2.2.10/CHANGELOG.md
|
|
343
343
|
bug_tracker_uri: https://github.com/kettle-dev/kettle-dev/issues
|
|
344
|
-
documentation_uri: https://www.rubydoc.info/gems/kettle-dev/2.2.
|
|
344
|
+
documentation_uri: https://www.rubydoc.info/gems/kettle-dev/2.2.10
|
|
345
345
|
funding_uri: https://github.com/sponsors/pboling
|
|
346
346
|
wiki_uri: https://github.com/kettle-dev/kettle-dev/wiki
|
|
347
347
|
news_uri: https://www.railsbling.com/tags/kettle-dev
|
metadata.gz.sig
CHANGED
|
Binary file
|