Skip to content

Commit a97571f

Browse files
authored
Merge pull request #5042 from github/cache-api-results-across-runs
Cache API verification results across CI runs
2 parents 016102b + cd2fa52 commit a97571f

File tree

3 files changed

+98
-0
lines changed

3 files changed

+98
-0
lines changed

.github/workflows/test.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,17 @@ jobs:
5858
with:
5959
bundler-cache: true
6060

61+
- name: Restore API cache
62+
if: |
63+
(matrix.test_type == 'collections' && steps.collections.outputs.changed) ||
64+
(matrix.test_type == 'all' && steps.all.outputs.changed)
65+
uses: actions/cache@v4
66+
with:
67+
path: .api-cache.json
68+
key: api-cache-${{ matrix.test_type }}-${{ github.run_id }}
69+
restore-keys: |
70+
api-cache-${{ matrix.test_type }}-
71+
6172
- name: Build and test with Rake
6273
if: |
6374
(matrix.test_type == 'topics' && steps.topics.outputs.changed) ||

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ vendor
88
.bundle
99
.idea
1010
.tool-versions
11+
.api-cache.json

test/test_helper.rb

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,89 @@ def add_message(type, file, line_number, message)
270270
client.messages << "::#{type} file=#{file},line=#{line_number}::#{message}"
271271
end
272272

273+
CACHE_FILE = File.expand_path("../.api-cache.json", __dir__)
274+
CACHE_TTL_SECONDS = 24 * 60 * 60 # 24 hours
275+
276+
def load_api_cache!
277+
return unless File.exist?(CACHE_FILE)
278+
279+
data = JSON.parse(File.read(CACHE_FILE))
280+
now = Time.now.to_i
281+
ttl = CACHE_TTL_SECONDS
282+
283+
if data["repos"]
284+
data["repos"].each do |key, entry|
285+
cached_at = entry["cached_at"]
286+
next unless cached_at
287+
next if now - cached_at.to_i > ttl
288+
289+
result = entry["value"]
290+
# Reconstruct a minimal object that responds to .full_name
291+
cached = if result.nil?
292+
nil
293+
else
294+
next unless result["full_name"]
295+
296+
Struct.new(:full_name).new(result["full_name"])
297+
end
298+
NewOctokit.class_variable_get(:@@repos)[key] = cached
299+
end
300+
end
301+
302+
if data["users"]
303+
data["users"].each do |key, entry|
304+
cached_at = entry["cached_at"]
305+
next unless cached_at
306+
next if now - cached_at.to_i > ttl
307+
308+
result = entry["value"]
309+
cached = if result.nil?
310+
nil
311+
else
312+
next unless result["login"]
313+
314+
Struct.new(:login).new(result["login"])
315+
end
316+
NewOctokit.class_variable_get(:@@users)[key] = cached
317+
end
318+
end
319+
rescue JSON::ParserError, StandardError => e
320+
warn "Failed to load API cache: #{e.message}"
321+
end
322+
323+
def save_api_cache!
324+
now = Time.now.to_i
325+
repos_data = {}
326+
users_data = {}
327+
328+
NewOctokit.class_variable_get(:@@repos).each do |key, value|
329+
next if key == :skip_requests
330+
next if value == true
331+
332+
repos_data[key.to_s] = {
333+
"cached_at" => now,
334+
"value" => value.nil? ? nil : { "full_name" => value.respond_to?(:full_name) ? value.full_name : value.to_s },
335+
}
336+
end
337+
338+
NewOctokit.class_variable_get(:@@users).each do |key, value|
339+
next if key == :skip_requests
340+
next if value == true
341+
342+
users_data[key.to_s] = {
343+
"cached_at" => now,
344+
"value" => value.nil? ? nil : { "login" => value.respond_to?(:login) ? value.login : value.to_s },
345+
}
346+
end
347+
348+
File.write(CACHE_FILE, JSON.pretty_generate({ "repos" => repos_data, "users" => users_data }))
349+
rescue StandardError => e
350+
warn "Failed to save API cache: #{e.message}"
351+
end
352+
353+
# Load cached API results at startup
354+
load_api_cache!
355+
273356
Minitest.after_run do
274357
warn "Repo checks were rate limited during this CI run" if NewOctokit.repos_skipped?
275358
warn "User checks were rate limited during this CI run" if NewOctokit.users_skipped?
@@ -279,4 +362,7 @@ def add_message(type, file, line_number, message)
279362
NewOctokit.messages.each do |message|
280363
puts message
281364
end
365+
366+
# Persist cache for next CI run
367+
save_api_cache!
282368
end

0 commit comments

Comments
 (0)