Class: Kettle::Dev::PreReleaseCLI
- Inherits:
-
Object
- Object
- Kettle::Dev::PreReleaseCLI
- Defined in:
- lib/kettle/dev/pre_release_cli.rb,
sig/kettle/dev.rbs
Overview
PreReleaseCLI: run pre-release checks before invoking full release workflow. Checks:
1) Ensure GitHub Actions workflow actions are pinned to current SHAs.
2) Normalize Markdown image URLs using Addressable normalization.
3) Validate Markdown references and local heading targets.
4) Validate Markdown image links resolve via cached HTTP(S) HEAD/GET.
Usage: Kettle::Dev::PreReleaseCLI.new(check_num: 1).run
Defined Under Namespace
Modules: HTTP, Markdown Classes: ImageUrlCache
Constant Summary collapse
- IMAGE_URL_CACHE_TTL_SECONDS =
7 * 24 * 60 * 60
- DEFAULT_IMAGE_URL_SKIP_PATTERNS =
[ "https://api.star-history.com/svg*", "https://star-history.dera.page/svg*" ].freeze
- FAMILY_CONFIG_PATHS =
[".kettle-family.yml", ".structuredmerge/kettle-family.yml"].freeze
Instance Method Summary collapse
-
#check_github_actions_sha_pins! ⇒ void
Check 1: Ensure GitHub Actions workflow action refs are current SHA pins.
-
#check_markdown_images_http! ⇒ void
Check 4: Validate Markdown image links by cached HTTP HEAD/GET.
-
#check_markdown_references! ⇒ void
Check 3: Validate Markdown references and local heading targets.
-
#check_markdown_uri_normalization! ⇒ void
Check 2: Normalize Markdown image URLs Compares URLs to Addressable-normalized form and rewrites Markdown when needed.
-
#initialize(check_num: 1, event_recorder: nil) ⇒ PreReleaseCLI
constructor
A new instance of PreReleaseCLI.
- #normalized_markdown_image_url(url_str) ⇒ Object
-
#run ⇒ void
Execute configured checks starting from @check_num.
Constructor Details
#initialize(check_num: 1, event_recorder: nil) ⇒ PreReleaseCLI
Returns a new instance of PreReleaseCLI.
280 281 282 283 284 285 286 287 |
# File 'lib/kettle/dev/pre_release_cli.rb', line 280 def initialize(check_num: 1, event_recorder: nil) @check_num = (check_num || 1).to_i @check_num = 1 if @check_num < 1 @event_recorder = event_recorder @image_url_cache_path = configured_image_url_cache_path @refresh_image_url_cache = env_truthy?(ENV["KETTLE_IMAGE_URL_CACHE_REFRESH"]) @image_url_skip_patterns = configured_image_url_skip_patterns end |
Instance Method Details
#check_github_actions_sha_pins! ⇒ void
This method returns an undefined value.
Check 1: Ensure GitHub Actions workflow action refs are current SHA pins.
319 320 321 322 323 324 325 326 327 328 329 |
# File 'lib/kettle/dev/pre_release_cli.rb', line 319 def check_github_actions_sha_pins! offline = env_truthy?(ENV["KETTLE_PRE_RELEASE_GHA_SHA_PINS_OFFLINE"]) mode = offline ? "offline cache" : "live cache validation" puts "[kettle-pre-release] Check 1: Validate GitHub Actions SHA pins (#{mode})" args = ["--root", Dir.pwd, "--check", "--upgrade", "major"] args << "--offline" if offline status = Kettle::Dev::GhaShaPinsCLI.new(args).run! return nil if status.zero? Kettle::Dev::ExitAdapter.abort("GitHub Actions SHA pin validation failed") end |
#check_markdown_images_http! ⇒ void
This method returns an undefined value.
Check 4: Validate Markdown image links by cached HTTP HEAD/GET.
414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 |
# File 'lib/kettle/dev/pre_release_cli.rb', line 414 def check_markdown_images_http! puts "[kettle-pre-release] Check 4: Validate Markdown image links (cached HTTP HEAD, with GET fallback)" urls = Markdown.extract_image_urls_from_files puts "[kettle-pre-release] Found #{urls.size} unique image URL(s)." skipped = [] cache = image_url_cache progress = CacheProgress.new( total: urls.size, cached_title: "Images cached", live_title: "Images live", skipped_title: "Images skipped", output: $stdout ) failures = [] begin urls.each do |url| if image_url_skipped?(url) skipped << url progress.skipped next end if cache && !@refresh_image_url_cache && cache.fresh_success?(url) progress.cached next end ok = HTTP.head_ok?(url) progress.live if ok cache&.write_success(url) else failures << url end end ensure progress.stop end puts "[kettle-pre-release] Image URL checks: #{progress.cached_count} cached, #{progress.live_count} live." puts "[kettle-pre-release] Skipped #{progress.skipped_count} image URL check(s)." if skipped.any? if failures.any? emit_pre_release_event(action: "image_links", status: "failed", urls: urls.size, cached: progress.cached_count, live: progress.live_count, skipped: progress.skipped_count, failures: failures.size) warn("[kettle-pre-release] #{failures.size} image URL(s) failed validation:") failures.each { |u| warn(" - #{u}") } Kettle::Dev::ExitAdapter.abort("Image link validation failed") else emit_pre_release_event(action: "image_links", status: "ok", urls: urls.size, cached: progress.cached_count, live: progress.live_count, skipped: progress.skipped_count, failures: 0) puts "[kettle-pre-release] All image links validated." end nil end |
#check_markdown_references! ⇒ void
This method returns an undefined value.
Check 3: Validate Markdown references and local heading targets.
394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 |
# File 'lib/kettle/dev/pre_release_cli.rb', line 394 def check_markdown_references! puts "[kettle-pre-release] Check 3: Validate Markdown references and local heading targets" report = MarkdownReferenceValidator.new( root: Dir.pwd, files: Markdown.project_markdown_files ).validate! puts "[kettle-pre-release] Markdown references: #{report.reference_count} references, #{report.local_target_count} local targets, #{report.file_count} files." emit_pre_release_event( action: "markdown_references", status: "ok", files: report.file_count, references: report.reference_count, local_targets: report.local_target_count, failures: 0 ) nil end |
#check_markdown_uri_normalization! ⇒ void
This method returns an undefined value.
Check 2: Normalize Markdown image URLs Compares URLs to Addressable-normalized form and rewrites Markdown when needed.
334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 |
# File 'lib/kettle/dev/pre_release_cli.rb', line 334 def check_markdown_uri_normalization! puts "[kettle-pre-release] Check 2: Normalize Markdown image URLs" files = Markdown.project_markdown_files changed = [] total_candidates = 0 files.each do |file| begin original = File.read(file) rescue => e warn("[kettle-pre-release] Could not read #{Kettle::Dev.display_path(file)}: #{e.class}: #{e.}") next end text = original.dup urls = Markdown.extract_image_urls_from_text(text) next if urls.empty? total_candidates += urls.size updated = text.dup modified = false urls.each do |url_str| normalized = normalized_markdown_image_url(url_str) next if normalized == url_str # Replace exact occurrences of the URL in the markdown content updated.gsub!(url_str, normalized) modified = true puts " -> #{Kettle::Dev.display_path(file)}: normalized #{url_str} -> #{normalized}" end if modified && updated != original begin File.write(file, updated) changed << file rescue => e warn("[kettle-pre-release] Could not write #{Kettle::Dev.display_path(file)}: #{e.class}: #{e.}") end end end puts "[kettle-pre-release] Normalization candidates: #{total_candidates}. Files changed: #{changed.uniq.size}." emit_pre_release_event(action: "markdown_urls", status: "ok", candidates: total_candidates, changed_files: changed.uniq.size) nil end |
#normalized_markdown_image_url(url_str) ⇒ Object
381 382 383 384 385 386 387 388 389 390 |
# File 'lib/kettle/dev/pre_release_cli.rb', line 381 def normalized_markdown_image_url(url_str) # Kettle-Jem template tokens are intentionally not URI components yet; # encoding them here prevents the templater from recognizing them. return url_str if url_str.include?("{KJ|") addr = Addressable::URI.parse(url_str) normalized = addr.normalize normalized.query = addr.query if addr.query && normalized.query != addr.query normalized.to_s end |
#run ⇒ void
This method returns an undefined value.
Execute configured checks starting from @check_num.
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 |
# File 'lib/kettle/dev/pre_release_cli.rb', line 291 def run checks = [] checks << method(:check_github_actions_sha_pins!) checks << method(:check_markdown_uri_normalization!) checks << method(:check_markdown_references!) checks << method(:check_markdown_images_http!) start = @check_num raise ArgumentError, "check_num must be >= 1" if start < 1 begin_idx = start - 1 checks[begin_idx..-1].each_with_index do |check, i| idx = begin_idx + i + 1 puts "[kettle-pre-release] Running check ##{idx} of #{checks.size}" emit_pre_release_event(action: "check", status: "started", check: check_name(check), index: idx, total: checks.size) begin check.call emit_pre_release_event(action: "check", status: "ok", check: check_name(check), index: idx, total: checks.size) rescue => error emit_pre_release_event(action: "check", status: "failed", check: check_name(check), index: idx, total: checks.size, reason: "#{error.class}: #{error.}") raise end end nil end |