|
11 | 11 | PRInfo, |
12 | 12 | fetch_pr_info, |
13 | 13 | find_pr_by_branch, |
| 14 | + get_latest_release, |
14 | 15 | handle_github_rate_limit, |
15 | 16 | handle_pr_checkout, |
16 | 17 | parse_pr_reference, |
@@ -445,6 +446,57 @@ def test_checkout_pr_remote_already_exists(self, mock_getcwd, mock_chdir, mock_s |
445 | 446 | assert mock_subprocess.call_count == 3 |
446 | 447 |
|
447 | 448 |
|
| 449 | +class TestGetLatestRelease: |
| 450 | + """Test get_latest_release GitHub API calls""" |
| 451 | + |
| 452 | + @patch("requests.get") |
| 453 | + def test_sends_auth_header_when_token_set(self, mock_get): |
| 454 | + """Ensure GITHUB_TOKEN is sent as Bearer auth to avoid rate limits (issue #425)""" |
| 455 | + mock_response = Mock() |
| 456 | + mock_response.status_code = 200 |
| 457 | + mock_response.json.return_value = { |
| 458 | + "tag_name": "v0.18.2", |
| 459 | + "zipball_url": "https://github.com/comfyanonymous/ComfyUI/archive/v0.18.2.zip", |
| 460 | + } |
| 461 | + mock_get.return_value = mock_response |
| 462 | + |
| 463 | + with patch.dict("os.environ", {"GITHUB_TOKEN": "ghp_test123"}): |
| 464 | + result = get_latest_release("comfyanonymous", "ComfyUI") |
| 465 | + |
| 466 | + headers = mock_get.call_args.kwargs.get("headers", {}) |
| 467 | + assert headers["Authorization"] == "Bearer ghp_test123" |
| 468 | + assert result is not None |
| 469 | + assert result["tag"] == "v0.18.2" |
| 470 | + |
| 471 | + @patch("requests.get") |
| 472 | + def test_no_auth_header_without_token(self, mock_get): |
| 473 | + """Without GITHUB_TOKEN the request has no Authorization header""" |
| 474 | + mock_response = Mock() |
| 475 | + mock_response.status_code = 200 |
| 476 | + mock_response.json.return_value = { |
| 477 | + "tag_name": "v0.18.2", |
| 478 | + "zipball_url": "https://github.com/comfyanonymous/ComfyUI/archive/v0.18.2.zip", |
| 479 | + } |
| 480 | + mock_get.return_value = mock_response |
| 481 | + |
| 482 | + with patch.dict("os.environ", {}, clear=True): |
| 483 | + get_latest_release("comfyanonymous", "ComfyUI") |
| 484 | + |
| 485 | + headers = mock_get.call_args.kwargs.get("headers", {}) |
| 486 | + assert "Authorization" not in headers |
| 487 | + |
| 488 | + @patch("requests.get") |
| 489 | + def test_rate_limit_raises_error(self, mock_get): |
| 490 | + """A 403 with exhausted rate limit raises GitHubRateLimitError""" |
| 491 | + mock_response = Mock() |
| 492 | + mock_response.status_code = 403 |
| 493 | + mock_response.headers = {"x-ratelimit-remaining": "0", "x-ratelimit-reset": "1700000000"} |
| 494 | + mock_get.return_value = mock_response |
| 495 | + |
| 496 | + with pytest.raises(GitHubRateLimitError): |
| 497 | + get_latest_release("comfyanonymous", "ComfyUI") |
| 498 | + |
| 499 | + |
448 | 500 | class TestHandleGithubRateLimit: |
449 | 501 | def test_primary_rate_limit_message_format(self): |
450 | 502 | """Verify the error message does not contain stray characters.""" |
|
0 commit comments