-
Notifications
You must be signed in to change notification settings - Fork 14.2k
Cache API verification results across CI runs #5042
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
fa0901c
ba1b294
083835c
cd2fa52
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,3 +8,4 @@ vendor | |
| .bundle | ||
| .idea | ||
| .tool-versions | ||
| .api-cache.json | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -270,6 +270,79 @@ def add_message(type, file, line_number, message) | |
| client.messages << "::#{type} file=#{file},line=#{line_number}::#{message}" | ||
| end | ||
|
|
||
| CACHE_FILE = File.expand_path("../.api-cache.json", File.dirname(__FILE__)) | ||
| CACHE_TTL_SECONDS = 24 * 60 * 60 # 24 hours | ||
|
|
||
| def self.load_api_cache! | ||
| return unless File.exist?(CACHE_FILE) | ||
|
|
||
| data = JSON.parse(File.read(CACHE_FILE)) | ||
| now = Time.now.to_i | ||
| ttl = CACHE_TTL_SECONDS | ||
|
|
||
| if data["repos"] | ||
| data["repos"].each do |key, entry| | ||
| next if now - entry["cached_at"].to_i > ttl | ||
|
||
|
|
||
| result = entry["value"] | ||
| # Reconstruct a minimal object that responds to .full_name | ||
| cached = if result.nil? | ||
| nil | ||
| else | ||
| Struct.new(:full_name).new(result["full_name"]) | ||
|
Comment on lines
+290
to
+296
|
||
| end | ||
| NewOctokit.class_variable_get(:@@repos)[key] = cached | ||
| end | ||
| end | ||
|
|
||
| if data["users"] | ||
| data["users"].each do |key, entry| | ||
| next if now - entry["cached_at"].to_i > ttl | ||
|
|
||
| result = entry["value"] | ||
| cached = if result.nil? | ||
| nil | ||
| else | ||
| Struct.new(:login).new(result["login"]) | ||
| end | ||
| NewOctokit.class_variable_get(:@@users)[key] = cached | ||
| end | ||
| end | ||
| rescue JSON::ParserError, StandardError => e | ||
| warn "Failed to load API cache: #{e.message}" | ||
| end | ||
|
|
||
| def self.save_api_cache! | ||
|
||
| now = Time.now.to_i | ||
| repos_data = {} | ||
| users_data = {} | ||
|
|
||
| NewOctokit.class_variable_get(:@@repos).each do |key, value| | ||
| next if key == :skip_requests | ||
|
|
||
| repos_data[key.to_s] = { | ||
| "cached_at" => now, | ||
| "value" => value.nil? ? nil : { "full_name" => value.respond_to?(:full_name) ? value.full_name : value.to_s }, | ||
|
Comment on lines
+332
to
+334
|
||
| } | ||
| end | ||
|
|
||
| NewOctokit.class_variable_get(:@@users).each do |key, value| | ||
| next if key == :skip_requests | ||
|
|
||
| users_data[key.to_s] = { | ||
| "cached_at" => now, | ||
| "value" => value.nil? ? nil : { "login" => value.respond_to?(:login) ? value.login : value.to_s }, | ||
| } | ||
| end | ||
|
|
||
| File.write(CACHE_FILE, JSON.pretty_generate({ "repos" => repos_data, "users" => users_data })) | ||
| rescue StandardError => e | ||
| warn "Failed to save API cache: #{e.message}" | ||
| end | ||
|
|
||
| # Load cached API results at startup | ||
| load_api_cache! | ||
|
|
||
| Minitest.after_run do | ||
| warn "Repo checks were rate limited during this CI run" if NewOctokit.repos_skipped? | ||
| warn "User checks were rate limited during this CI run" if NewOctokit.users_skipped? | ||
|
|
@@ -279,4 +352,7 @@ def add_message(type, file, line_number, message) | |
| NewOctokit.messages.each do |message| | ||
| puts message | ||
| end | ||
|
|
||
| # Persist cache for next CI run | ||
| save_api_cache! | ||
| end | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The CACHE_FILE path uses
File.expand_path("../.api-cache.json", File.dirname(__FILE__)). Since__FILE__istest/test_helper.rb,File.dirname(__FILE__)istest/, and../.api-cache.jsonrelative totest/is.api-cache.jsonin the repository root. This is correct and matches the .gitignore entry and workflow path. However, usingFile.expand_path("../.api-cache.json", __dir__)would be more idiomatic Ruby.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed — changed to
File.expand_path("../.api-cache.json", __dir__). More idiomatic Ruby.