(api_url, params=None)
| 27 | |
| 28 | |
| 29 | def _fetch_github_api(api_url, params=None): |
| 30 | headers = {} |
| 31 | github_token = os.environ.get("GITHUB_TOKEN") |
| 32 | if github_token: |
| 33 | headers["Authorization"] = f"token {github_token}" |
| 34 | |
| 35 | cache_filename = _create_cache_filename(api_url, params) |
| 36 | if DEVELOPMENT_MODE and os.path.exists(cache_filename): |
| 37 | print(f"Loading cached GitHub data from {cache_filename}") |
| 38 | try: |
| 39 | cached_data = json.loads(Path(cache_filename).read_text(encoding="utf-8")) |
| 40 | if not cached_data: |
| 41 | raise ValueError("Cached data is empty") |
| 42 | return 200, cached_data |
| 43 | except Exception as e: |
| 44 | print(f"⚠️ Warning: Error reading cache file {cache_filename}: {e}") |
| 45 | try: |
| 46 | os.remove(cache_filename) |
| 47 | except Exception as delete_err: |
| 48 | print( |
| 49 | f"Failed to delete invalid cache file {cache_filename}: {delete_err}" |
| 50 | ) |
| 51 | |
| 52 | response = requests.get(api_url, params, timeout=10, headers=headers) |
| 53 | status_code = response.status_code |
| 54 | |
| 55 | # Check GitHub rate limit headers |
| 56 | rate_limit_remaining = response.headers.get("X-RateLimit-Remaining") |
| 57 | rate_limit_limit = response.headers.get("X-RateLimit-Limit") |
| 58 | rate_limit_reset = response.headers.get("X-RateLimit-Reset") |
| 59 | logger.info( |
| 60 | f"{rate_limit_remaining}/{rate_limit_limit}. Reset at {rate_limit_reset}" |
| 61 | ) |
| 62 | |
| 63 | if rate_limit_remaining is not None and rate_limit_limit is not None: |
| 64 | remaining = int(rate_limit_remaining) |
| 65 | limit = int(rate_limit_limit) |
| 66 | |
| 67 | # Log rate limit information and handle proactively |
| 68 | if remaining < 10 and rate_limit_reset: |
| 69 | reset_timestamp = int(rate_limit_reset) |
| 70 | current_timestamp = int(time.time()) |
| 71 | wait_seconds = ( |
| 72 | max(0, reset_timestamp - current_timestamp) + 5 |
| 73 | ) # Add 5 second buffer |
| 74 | reset_time = datetime.datetime.fromtimestamp(reset_timestamp) |
| 75 | |
| 76 | # Cap maximum wait time at 1 hour |
| 77 | max_wait = 3600 |
| 78 | if wait_seconds > max_wait: |
| 79 | print( |
| 80 | f"⚠️ Rate limit reset time is too far in the future ({wait_seconds}s). Capping wait to {max_wait}s" |
| 81 | ) |
| 82 | wait_seconds = max_wait |
| 83 | |
| 84 | logger.error( |
| 85 | f"⚠️ GitHub API rate limit low: {remaining}/{limit} requests remaining. Resets at {reset_time}" |
| 86 | ) |
no test coverage detected