kettle-gha-pins 0.3.8 → 0.3.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: 0a1c43269ba88dfec876d3107fb7883511cbcec7456353a8e239d74071d0d94e
4
- data.tar.gz: 7499e3b722b86736e91a8a1dfde9ea53ab4f261428e5ec6816a83db73f428ece
3
+ metadata.gz: e39d2df910b12d4b40d0978f63481a73d87a5efcdf6ea58c4966b397d3319470
4
+ data.tar.gz: 584ac1b59952635a279806c03aba51460a757e9edd2dbcafc5b7f158b8a302dd
5
5
  SHA512:
6
- metadata.gz: d05a9abcb27812e5db10f60e44e3eb9b2e40cd9747476078a22008dab208a578ed816a93255093255ee86f24ccb5856f2ae1fda212659cd97f005d12a5b6bbfb
7
- data.tar.gz: 06bf550cb1113a1acb1363307d6dc4faa902c8d283aae15ecdfffaba658b9391d09606cb8005bb6071a30031bcd72b3046aae3674f2b359789793b78c2e82f59
6
+ metadata.gz: 43c208e30cd0c6501479f4cf52a48a3e4df4b9192ada22b05017681a4761ffe01ca4abdb0398cf8c523828a32814ef9fcd51cf57f2be46f7ff55b81c89e05237
7
+ data.tar.gz: a47e19be556a73215a786b4e9fe23b50ac1890e5087ed0b5eea1a14e8e7f9dd1ce8da62d8e95a329949a6e339aacda9c1b8e12cabd0debe167e301ed12ca96f9
checksums.yaml.gz.sig CHANGED
Binary file
data/CHANGELOG.md CHANGED
@@ -30,6 +30,32 @@ Please file a bug if you notice a violation of semantic versioning.
30
30
 
31
31
  ### Security
32
32
 
33
+ ## [0.3.10] - 2026-08-09
34
+
35
+ - TAG: [v0.3.10][0.3.10t]
36
+ - COVERAGE: 98.08% -- 1022/1042 lines in 8 files
37
+ - BRANCH COVERAGE: 88.03% -- 412/468 branches in 8 files
38
+ - 26.17% documented
39
+
40
+ ### Added
41
+
42
+ - Add JSON action inventory and cache review modes, strict offline pin resolution, and configurable action metadata TTL handling.
43
+
44
+ ### Fixed
45
+
46
+ - Keep JSON action inventory and review parsing compatible with Ruby 2.5.
47
+
48
+ ## [0.3.9] - 2026-08-05
49
+
50
+ - TAG: [v0.3.9][0.3.9t]
51
+ - COVERAGE: 98.36% -- 961/977 lines in 8 files
52
+ - BRANCH COVERAGE: 89.95% -- 394/438 branches in 8 files
53
+ - 25.71% documented
54
+
55
+ ### Fixed
56
+
57
+ - Emit NDJSON progress events for family orchestration without replaying the full human report.
58
+
33
59
  ## [0.3.8] - 2026-08-05
34
60
 
35
61
  - TAG: [v0.3.8][0.3.8t]
@@ -271,7 +297,11 @@ Please file a bug if you notice a violation of semantic versioning.
271
297
  - kettle-jem-template-20260720-005 - Generated README Support & Community rows
272
298
  now include a RubyForum help badge.
273
299
 
274
- [Unreleased]: https://github.com/kettle-dev/kettle-gha-pins/compare/v0.3.8...HEAD
300
+ [Unreleased]: https://github.com/kettle-dev/kettle-gha-pins/compare/v0.3.10...HEAD
301
+ [0.3.10]: https://github.com/kettle-dev/kettle-gha-pins/compare/v0.3.9...v0.3.10
302
+ [0.3.10t]: https://github.com/kettle-dev/kettle-gha-pins/releases/tag/v0.3.10
303
+ [0.3.9]: https://github.com/kettle-dev/kettle-gha-pins/compare/v0.3.8...v0.3.9
304
+ [0.3.9t]: https://github.com/kettle-dev/kettle-gha-pins/releases/tag/v0.3.9
275
305
  [0.3.8]: https://github.com/kettle-dev/kettle-gha-pins/compare/v0.3.7...v0.3.8
276
306
  [0.3.8t]: https://github.com/kettle-dev/kettle-gha-pins/releases/tag/v0.3.8
277
307
  [0.3.7]: https://github.com/kettle-dev/kettle-gha-pins/compare/v0.3.6...v0.3.7
data/README.md CHANGED
@@ -155,6 +155,17 @@ cooldown window. The same default can be supplied with
155
155
  `KETTLE_GHA_PINS_COOLDOWN_DAYS`. The default is `0`, so checks remain strict
156
156
  unless a project opts into a warning window.
157
157
 
158
+ The action metadata cache uses a one-day TTL by default. Set `--ttl DAYS` to
159
+ change it; `--ttl 0` forces a refresh. `--offline` trusts the cache without
160
+ checking TTL or contacting GitHub and fails if required repository metadata is
161
+ missing.
162
+
163
+ For family orchestration, `kettle-gha-pins --list --json` emits the action
164
+ repositories used by a project without network access. A separate
165
+ `kettle-gha-pins --review --input PATH` refreshes the repositories listed in
166
+ that JSON and updates the shared cache. Review refreshes metadata independently
167
+ of the selected major/minor/patch upgrade policy.
168
+
158
169
  `Kettle::Gha::Pins::PersistentActionCache.default_path` intentionally preserves
159
170
  the historical `kettle-gha-sha-pins` cache location so command-line tools can
160
171
  share action metadata without coupling to each other.
@@ -188,6 +199,14 @@ plan[:updates]
188
199
  # => {sha: "...", version: "7.0.0", reason: "upgrade_to_allowed_release"}
189
200
  ```
190
201
 
202
+ The family-oriented cache workflow is:
203
+
204
+ ```console
205
+ kettle-gha-pins --list --json
206
+ kettle-gha-pins --review --input pins.json
207
+ kettle-gha-pins --offline --write --upgrade major
208
+ ```
209
+
191
210
  When two version-equivalent tags point at the same SHA, the rubric keeps the
192
211
  more explicit release spelling. For example, `v7` and `v7.0.0` pointing at the
193
212
  same commit canonicalize to `v7.0.0`; if they point at different SHAs, both
@@ -563,7 +582,7 @@ Thanks for RTFM. ☺️
563
582
  [📌gitmoji]: https://gitmoji.dev
564
583
  [📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
565
584
  [🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
566
- [🧮kloc-img]: https://img.shields.io/badge/KLOC-0.961-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
585
+ [🧮kloc-img]: https://img.shields.io/badge/KLOC-1.042-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
567
586
  [🔐security]: https://github.com/kettle-dev/kettle-gha-pins/blob/main/SECURITY.md
568
587
  [🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
569
588
  [📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
@@ -59,6 +59,7 @@ module Kettle
59
59
  dry_run: true,
60
60
  token: ENV["GITHUB_TOKEN"] || ENV["GH_TOKEN"],
61
61
  json: false,
62
+ events: false,
62
63
  validate: true,
63
64
  write: false,
64
65
  check: false,
@@ -66,9 +67,13 @@ module Kettle
66
67
  user_agent: "kettle-gha-pins",
67
68
  upgrade: DEFAULT_UPGRADE_LEVEL,
68
69
  cache_path: ENV["KETTLE_GHA_SHA_PINS_CACHE"] || PersistentActionCache.default_path,
70
+ ttl_days: DEFAULT_CACHE_TTL_SECONDS / 86_400.0,
69
71
  cooldown_days: cooldown_days,
70
72
  clock: clock,
71
73
  refresh_cache: false,
74
+ offline: false,
75
+ mode: :project,
76
+ input: nil,
72
77
  reject_patterns: Set.new,
73
78
  progress: nil
74
79
  }
@@ -77,20 +82,43 @@ module Kettle
77
82
  def run!
78
83
  parse!
79
84
 
80
- @options[:token] ||= gh_auth_token if @options[:api_base] == API_BASE
85
+ return list_workflows! if @options[:mode] == :list
86
+
87
+ client, persistent_cache = build_client
88
+ return review_cache!(client: client, persistent_cache: persistent_cache) if @options[:mode] == :review
89
+
90
+ run_project!(client: client)
91
+ rescue Error, GitHubClient::CacheMissError, GitHubClient::RefreshError => error
92
+ @err.puts("kettle-gha-pins: #{error.message}")
93
+ 2
94
+ end
95
+
96
+ private
97
+
98
+ def build_client
99
+ @options[:token] ||= gh_auth_token if @options[:api_base] == API_BASE && !@options[:offline]
81
100
  persistent_cache = if @options[:cache_path].to_s.empty?
82
101
  nil
83
102
  else
84
- PersistentActionCache.new(path: @options[:cache_path])
103
+ PersistentActionCache.new(
104
+ path: @options[:cache_path],
105
+ ttl_seconds: (@options[:ttl_days] * 86_400).to_i,
106
+ clock: @options[:clock]
107
+ )
85
108
  end
86
109
  client = GitHubClient.new(
87
110
  token: @options[:token],
88
111
  api_base: @options[:api_base],
89
112
  user_agent: @options[:user_agent],
90
113
  persistent_cache: persistent_cache,
91
- refresh_cache: @options[:refresh_cache]
114
+ refresh_cache: @options[:refresh_cache],
115
+ offline: @options[:offline],
116
+ fail_on_refresh_error: @options[:mode] == :review
92
117
  )
118
+ [client, persistent_cache]
119
+ end
93
120
 
121
+ def run_project!(client:)
94
122
  state = {
95
123
  files_scanned: 0,
96
124
  files_with_changes: 0,
@@ -104,8 +132,10 @@ module Kettle
104
132
  }
105
133
 
106
134
  progress_message("Discovering workflow files under #{display_path(@options[:root])}...")
135
+ emit_event("start", root: @options[:root])
107
136
  workflow_files = discover_workflow_files(@options[:root], @options[:reject_patterns])
108
137
  progress_message("Discovered #{workflow_files.length} workflow file(s).")
138
+ emit_event("workflows", total: workflow_files.length)
109
139
 
110
140
  workflows = load_workflows(workflow_files, state)
111
141
  action_count = workflows.sum { |workflow| workflow[:uses_nodes].count { |node| classify_action_ref(node[:value].to_s) } }
@@ -119,6 +149,7 @@ module Kettle
119
149
  )
120
150
  action_plan_cache = {}
121
151
 
152
+ completed_actions = 0
122
153
  workflows.each do |workflow|
123
154
  path = workflow.fetch(:path)
124
155
  text = workflow.fetch(:text)
@@ -134,6 +165,7 @@ module Kettle
134
165
  action = parsed_ref[:action]
135
166
  repo_ref = "#{action[:owner]}/#{action[:repo]}"
136
167
  old_ref = action[:ref]
168
+ cached_before = action_plan_cache.key?(repo_ref)
137
169
  upgrade_plan = resolve_action_plan(
138
170
  cache: action_plan_cache,
139
171
  client: client,
@@ -141,6 +173,16 @@ module Kettle
141
173
  repo_ref: repo_ref,
142
174
  old_ref: old_ref
143
175
  )
176
+ completed_actions += 1
177
+ emit_event(
178
+ "action",
179
+ action_ref: repo_ref,
180
+ path: path,
181
+ line: node[:line] + 1,
182
+ completed: completed_actions,
183
+ total: action_count,
184
+ cache: (cached_before || (client.respond_to?(:last_versions_cache_hit) && client.last_versions_cache_hit)) ? "hit" : "miss"
185
+ )
144
186
 
145
187
  updates = nil
146
188
  if upgrade_plan[:updates]
@@ -261,6 +303,15 @@ module Kettle
261
303
  end
262
304
  action_progress.stop
263
305
  progress_message("Action resolution checks: #{action_progress.cached_count} cached, #{action_progress.live_count} live.") if action_count.positive?
306
+ emit_event(
307
+ "summary",
308
+ files_scanned: state[:files_scanned],
309
+ changed_files: state[:changed_files].length,
310
+ updates: state[:updates],
311
+ failures: state[:failures],
312
+ cached: action_progress.cached_count,
313
+ live: action_progress.live_count
314
+ )
264
315
 
265
316
  print_report(state)
266
317
  return 2 unless state[:failures].zero?
@@ -269,7 +320,79 @@ module Kettle
269
320
  0
270
321
  end
271
322
 
272
- private
323
+ def list_workflows!
324
+ state = {files_scanned: 0, failures: 0, errors: []}
325
+ workflow_files = discover_workflow_files(@options[:root], @options[:reject_patterns])
326
+ workflows = load_workflows(workflow_files, state)
327
+ pins = workflows.flat_map do |workflow|
328
+ workflow.fetch(:uses_nodes).each_with_object([]) do |node, entries|
329
+ parsed = classify_action_ref(node[:value].to_s)
330
+ next unless parsed
331
+
332
+ action = parsed.fetch(:action)
333
+ entries << {
334
+ "repository" => "#{action[:owner]}/#{action[:repo]}",
335
+ "ref" => action[:ref],
336
+ "value" => parsed[:value],
337
+ "path" => workflow[:path],
338
+ "line" => node[:line].to_i + 1
339
+ }
340
+ end
341
+ end
342
+ repositories = pins.map { |pin| pin.fetch("repository") }.uniq.sort
343
+ puts JSON.pretty_generate(
344
+ "schema_version" => 1,
345
+ "root" => @options[:root],
346
+ "repositories" => repositories,
347
+ "pins" => pins
348
+ )
349
+ state[:failures].zero? ? 0 : 2
350
+ end
351
+
352
+ def review_cache!(client:, persistent_cache:)
353
+ raise Error, "--review requires a writable cache; do not use --cache-path \"\"" unless persistent_cache
354
+
355
+ repositories = review_repositories
356
+ refreshed = repositories.map do |repository|
357
+ versions = client.versions_for_repo(repository)
358
+ {
359
+ "repository" => repository,
360
+ "versions" => versions.length,
361
+ "cache" => client.last_versions_cache_hit ? "hit" : "refreshed"
362
+ }
363
+ end
364
+ puts JSON.pretty_generate(
365
+ "schema_version" => 1,
366
+ "mode" => "review",
367
+ "ttl_days" => @options[:ttl_days],
368
+ "repositories" => refreshed
369
+ )
370
+ 0
371
+ end
372
+
373
+ def review_repositories
374
+ source = @options[:input].to_s
375
+ source = if source.empty? || source == "-"
376
+ $stdin.read
377
+ else
378
+ File.read(source)
379
+ end
380
+ payload = JSON.parse(source)
381
+ entries = if payload.is_a?(Array)
382
+ payload
383
+ elsif payload.is_a?(Hash)
384
+ payload["repositories"] || payload["actions"] || payload["pins"] || []
385
+ else
386
+ []
387
+ end
388
+ entries.each_with_object([]) do |entry, repositories|
389
+ value = entry.is_a?(Hash) ? (entry["repository"] || entry["action"] || entry["value"]) : entry
390
+ repository = value.to_s.split("@", 2).first
391
+ repositories << repository if repository.match?(%r{\A[^/\s]+/[^/\s]+\z})
392
+ end.uniq.sort
393
+ rescue JSON::ParserError => error
394
+ raise Error, "invalid review JSON: #{error.message}"
395
+ end
273
396
 
274
397
  def parse!
275
398
  parser = OptionParser.new do |opt|
@@ -304,12 +427,36 @@ module Kettle
304
427
  opt.on("--refresh-cache", "Bypass cached action release data and refresh discovered actions") do
305
428
  @options[:refresh_cache] = true
306
429
  end
430
+ opt.on("--ttl DAYS", Float, "Cache TTL in days (default: #{@options[:ttl_days]})") do |days|
431
+ Kernel.abort("Invalid --ttl value #{days.inspect}; use a non-negative number") if days.negative?
432
+
433
+ @options[:ttl_days] = days
434
+ end
435
+ opt.on("--offline", "Use only the persistent cache; fail on a cache miss") do
436
+ @options[:offline] = true
437
+ end
438
+ opt.on("--list", "List project action pins as JSON without network access") do
439
+ raise OptionParser::InvalidOption, "--list cannot be combined with --review" if @options[:mode] == :review
440
+
441
+ @options[:mode] = :list
442
+ end
443
+ opt.on("--review", "Refresh action metadata from JSON input and update the cache") do
444
+ raise OptionParser::InvalidOption, "--review cannot be combined with --list" if @options[:mode] == :list
445
+
446
+ @options[:mode] = :review
447
+ end
448
+ opt.on("--input PATH", "Review JSON input path, or - for stdin") do |path|
449
+ @options[:input] = path
450
+ end
307
451
  opt.on("--cache-path PATH", "Action release cache path (default: #{@options[:cache_path]})") do |path|
308
452
  @options[:cache_path] = path
309
453
  end
310
454
  opt.on("--json", "Emit JSON report") do
311
455
  @options[:json] = true
312
456
  end
457
+ opt.on("--events", "Emit line-delimited JSON events") do
458
+ @options[:events] = true
459
+ end
313
460
  opt.on("--[no-]progress", "Show progress feedback on STDERR (default: on unless --json)") do |bool|
314
461
  @options[:progress] = bool
315
462
  end
@@ -329,6 +476,9 @@ module Kettle
329
476
  end
330
477
  end
331
478
  parser.parse!(@argv)
479
+ if @options[:mode] == :review && @options[:offline]
480
+ raise OptionParser::InvalidOption, "--review cannot be combined with --offline"
481
+ end
332
482
  end
333
483
 
334
484
  def display_path(path)
@@ -384,7 +534,13 @@ module Kettle
384
534
  def progress_enabled?
385
535
  return @options[:progress] unless @options[:progress].nil?
386
536
 
387
- !@options[:json]
537
+ !@options[:json] && !@options[:events]
538
+ end
539
+
540
+ def emit_event(action, payload = {})
541
+ return unless @options[:events]
542
+
543
+ puts JSON.generate({"event_version" => 1, "type" => "gha_sha_pins_#{action}", "action" => action}.merge(payload))
388
544
  end
389
545
 
390
546
  def progress_message(message)
@@ -858,8 +1014,12 @@ module Kettle
858
1014
  lines << "Recommended fix: kettle-gha-pins --write --upgrade #{@options[:upgrade]}"
859
1015
  end
860
1016
 
861
- puts lines.join("
862
- ")
1017
+ output = lines.join("\n")
1018
+ if @options[:events]
1019
+ @err.puts output
1020
+ else
1021
+ puts output
1022
+ end
863
1023
  end
864
1024
  end
865
1025
  end
@@ -10,12 +10,17 @@ module Kettle
10
10
  module Pins
11
11
  # Lightweight GitHub API client for commit and release SHA resolution.
12
12
  class GitHubClient
13
- def initialize(token:, api_base:, user_agent:, persistent_cache: nil, refresh_cache: false, open_timeout: DEFAULT_HTTP_OPEN_TIMEOUT_SECONDS, read_timeout: DEFAULT_HTTP_READ_TIMEOUT_SECONDS, refresh_timeout: DEFAULT_HTTP_REFRESH_TIMEOUT_SECONDS)
13
+ class CacheMissError < Error; end
14
+ class RefreshError < Error; end
15
+
16
+ def initialize(token:, api_base:, user_agent:, persistent_cache: nil, refresh_cache: false, offline: false, fail_on_refresh_error: false, open_timeout: DEFAULT_HTTP_OPEN_TIMEOUT_SECONDS, read_timeout: DEFAULT_HTTP_READ_TIMEOUT_SECONDS, refresh_timeout: DEFAULT_HTTP_REFRESH_TIMEOUT_SECONDS)
14
17
  @token = token
15
18
  @api_base = api_base
16
19
  @user_agent = user_agent
17
20
  @persistent_cache = persistent_cache
18
21
  @refresh_cache = refresh_cache
22
+ @offline = offline
23
+ @fail_on_refresh_error = fail_on_refresh_error
19
24
  @open_timeout = open_timeout
20
25
  @read_timeout = read_timeout
21
26
  @refresh_timeout = refresh_timeout
@@ -34,15 +39,22 @@ module Kettle
34
39
  return @release_cache[repo_ref]
35
40
  end
36
41
 
42
+ if @offline
43
+ cached = @persistent_cache&.versions_for_repo(repo_ref, fresh: false)
44
+ raise CacheMissError, "offline cache miss for #{repo_ref}" if cached.nil?
45
+
46
+ @last_versions_cache_hit = true
47
+ @release_cache[repo_ref] = cached
48
+ return cached
49
+ end
50
+
37
51
  stale = nil
38
52
  unless @refresh_cache
39
53
  cached = @persistent_cache&.versions_for_repo(repo_ref, fresh: true)
40
54
  if cached
41
- unless cache_requires_refresh?(repo_ref, cached)
42
- @last_versions_cache_hit = true
43
- @release_cache[repo_ref] = cached
44
- return cached
45
- end
55
+ @last_versions_cache_hit = true
56
+ @release_cache[repo_ref] = cached
57
+ return cached
46
58
  end
47
59
  stale = @persistent_cache&.versions_for_repo(repo_ref, fresh: false)
48
60
  end
@@ -50,10 +62,10 @@ module Kettle
50
62
  releases = nil
51
63
  Timeout.timeout(@refresh_timeout) do
52
64
  data = request_json("/repos/#{repo_ref}/releases?per_page=100")
53
- return cached_versions(repo_ref, stale) unless data.is_a?(Array)
65
+ return refresh_failed!(repo_ref, stale, "invalid releases response") unless data.is_a?(Array)
54
66
 
55
67
  tag_shas = tag_ref_shas(repo_ref)
56
- return cached_versions(repo_ref, stale) unless tag_shas
68
+ return refresh_failed!(repo_ref, stale, "invalid tag response") unless tag_shas
57
69
 
58
70
  releases = build_release_versions(data, tag_shas)
59
71
  end
@@ -61,7 +73,7 @@ module Kettle
61
73
  @release_cache[repo_ref] = releases
62
74
  releases
63
75
  rescue Timeout::Error
64
- cached_versions(repo_ref, stale)
76
+ refresh_failed!(repo_ref, stale, "GitHub refresh timed out")
65
77
  end
66
78
 
67
79
  def commit_sha(repo_ref, ref, refresh: false)
@@ -71,13 +83,15 @@ module Kettle
71
83
  return @commit_cache[cache_key] if @commit_cache.key?(cache_key) && !refresh
72
84
 
73
85
  unless @refresh_cache || refresh
74
- cached = @persistent_cache&.ref_sha(repo_ref, ref, fresh: true)
86
+ cached = @persistent_cache&.ref_sha(repo_ref, ref, fresh: !@offline)
75
87
  if cached
76
88
  @commit_cache[cache_key] = cached
77
89
  return cached
78
90
  end
79
91
  end
80
92
 
93
+ raise CacheMissError, "offline cache miss for #{repo_ref}@#{ref}" if @offline
94
+
81
95
  data = request_json("/repos/#{repo_ref}/commits/#{uri_encode(ref)}")
82
96
  sha = if data.is_a?(Hash)
83
97
  data.fetch("sha", "")[0, 40]
@@ -106,24 +120,10 @@ module Kettle
106
120
  versions
107
121
  end
108
122
 
109
- # Release tags can be added or retargeted inside the cache TTL. Probe
110
- # the latest release before trusting a cached inventory, and refresh
111
- # only when that probe identifies a tag or target the cache lacks.
112
- def cache_requires_refresh?(repo_ref, cached)
113
- latest = request_json("/repos/#{repo_ref}/releases/latest")
114
- return false unless latest.is_a?(Hash)
115
-
116
- tag = latest["tag_name"].to_s
117
- return false unless VersionRubric.parse(tag)
118
-
119
- cached_entry = cached.find { |entry| entry[:tag].to_s == tag }
120
- return true unless cached_entry
121
-
122
- latest_sha = commit_sha(repo_ref, tag, refresh: true)
123
- cached_sha = cached_entry[:sha].to_s
124
- return !latest_sha.to_s.empty? if cached_sha.empty?
123
+ def refresh_failed!(repo_ref, stale, message)
124
+ return cached_versions(repo_ref, stale) unless @fail_on_refresh_error
125
125
 
126
- !latest_sha.to_s.empty? && latest_sha != cached_sha
126
+ raise RefreshError, "#{message} for #{repo_ref}"
127
127
  end
128
128
 
129
129
  def build_release_versions(data, tag_shas)
@@ -6,7 +6,7 @@ module Kettle
6
6
  # Version namespace for this gem.
7
7
  module Version
8
8
  # Current gem version.
9
- VERSION = "0.3.8"
9
+ VERSION = "0.3.10"
10
10
  end
11
11
  # Current gem version exposed at the traditional constant location.
12
12
  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-gha-pins
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.8
4
+ version: 0.3.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter H. Boling
@@ -301,10 +301,10 @@ licenses:
301
301
  - MIT
302
302
  metadata:
303
303
  homepage_uri: https://github.com/kettle-dev/kettle-gha-pins
304
- source_code_uri: https://github.com/kettle-dev/kettle-gha-pins/tree/v0.3.8
305
- changelog_uri: https://github.com/kettle-dev/kettle-gha-pins/blob/v0.3.8/CHANGELOG.md
304
+ source_code_uri: https://github.com/kettle-dev/kettle-gha-pins/tree/v0.3.10
305
+ changelog_uri: https://github.com/kettle-dev/kettle-gha-pins/blob/v0.3.10/CHANGELOG.md
306
306
  bug_tracker_uri: https://github.com/kettle-dev/kettle-gha-pins/issues
307
- documentation_uri: https://www.rubydoc.info/gems/kettle-gha-pins/0.3.8
307
+ documentation_uri: https://www.rubydoc.info/gems/kettle-gha-pins/0.3.10
308
308
  funding_uri: https://github.com/sponsors/pboling
309
309
  wiki_uri: https://github.com/kettle-dev/kettle-gha-pins/wiki
310
310
  news_uri: https://www.railsbling.com/tags/kettle-gha-pins
metadata.gz.sig CHANGED
Binary file