kettle-dev 2.2.9 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3bee699f7f3622c9ae1e63f19cec10ec46a54fe67bd97869169b309bbbcb4bb2
4
- data.tar.gz: '099d1ddeab902593baa43b8a1fe6de1b899f1ab3bdff9bd6ddba3363d5627b02'
3
+ metadata.gz: 9216115bc5448b3e08cfcd393c22029d70e7b6d31bcb80617b44b7d97644b649
4
+ data.tar.gz: e86c38ac97fbac63e1258bf15d6454f408e62ffe927af628bc5f7090472f98fd
5
5
  SHA512:
6
- metadata.gz: 7af3f2c8a7a278416c97a9a006d4a45946c371fcf75d11f9e6dc29b2a29fbc629fa53fb647cc3fbab0b7a18436dd4ecfa1139fcb993f51c89c798c7f3e95a6c0
7
- data.tar.gz: 78c1377327823ab8ae01bb76f4e318fc501fc0ba8e3c60ffc95dc661a68853a338bc501c9ea631992ea6cc7bf5b31b74865ed3a503770c6c9223e253ece33403
6
+ metadata.gz: 52d369f7c70a48bf3c2fde5898cc7f99ac9eda0b6e09319d7166976e20057d95360a56f29bf00dbd226976a853dd212e915fd31026b7c647df1f68bee6331cd4
7
+ data.tar.gz: 7ab61300d6f489ddc25636e10dcea667998a20c5ef3755a9b7773e2ccb0fde69871c8ba5607303a618501a55c2c05289dc3585905c6243e1ca524a7de1cb7c8a
checksums.yaml.gz.sig CHANGED
Binary file
data/CHANGELOG.md CHANGED
@@ -30,6 +30,19 @@ 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
+
33
46
  ## [2.2.9] - 2026-06-14
34
47
 
35
48
  - TAG: [v2.2.9][2.2.9t]
@@ -2126,7 +2139,9 @@ Please file a bug if you notice a violation of semantic versioning.
2126
2139
  - Selecting will run the selected workflow via `act`
2127
2140
  - This may move to its own gem in the future.
2128
2141
 
2129
- [Unreleased]: https://github.com/kettle-dev/kettle-dev/compare/v2.2.9...HEAD
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
2130
2145
  [2.2.9]: https://github.com/kettle-dev/kettle-dev/compare/v2.2.8...v2.2.9
2131
2146
  [2.2.9t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v2.2.9
2132
2147
  [2.2.8]: https://github.com/kettle-dev/kettle-dev/compare/v2.2.7...v2.2.8
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.173-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
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
@@ -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.
@@ -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
@@ -3,7 +3,7 @@
3
3
  module Kettle
4
4
  module Dev
5
5
  module Version
6
- VERSION = "2.2.9"
6
+ VERSION = "2.2.10"
7
7
  end
8
8
  VERSION = Version::VERSION # Traditional Constant Location
9
9
  end
@@ -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.9
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.9
342
- changelog_uri: https://github.com/kettle-dev/kettle-dev/blob/v2.2.9/CHANGELOG.md
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.9
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