diff --git a/src/sentry/integrations/github/client.py b/src/sentry/integrations/github/client.py index fc9c916258aec8..11257d75fca32b 100644 --- a/src/sentry/integrations/github/client.py +++ b/src/sentry/integrations/github/client.py @@ -330,12 +330,15 @@ def get_last_commits(self, repo: str, end_sha: str) -> Sequence[Any]: """ return self.get_cached(f"/repos/{repo}/commits", params={"sha": end_sha}) - def compare_commits(self, repo: str, start_sha: str, end_sha: str) -> Any: + def compare_commits(self, repo: str, start_sha: str, end_sha: str) -> list[Any]: """ See https://docs.github.com/en/rest/commits/commits#compare-two-commits where start sha is oldest and end is most recent. """ - return self.get_cached(f"/repos/{repo}/compare/{start_sha}...{end_sha}") + return self._get_with_pagination( + f"/repos/{repo}/compare/{start_sha}...{end_sha}", + response_key="commits", + ) def repo_hooks(self, repo: str) -> Sequence[Any]: """ diff --git a/src/sentry/integrations/github/repository.py b/src/sentry/integrations/github/repository.py index c490512d7f3dc4..b901fc89a839fd 100644 --- a/src/sentry/integrations/github/repository.py +++ b/src/sentry/integrations/github/repository.py @@ -72,8 +72,8 @@ def eval_commits(client: Any) -> Sequence[Mapping[str, Any]]: res = client.get_last_commits(name, end_sha) return self._format_commits(client, name, res[:20]) else: - res = client.compare_commits(name, start_sha, end_sha) - return self._format_commits(client, name, res["commits"]) + commits = client.compare_commits(name, start_sha, end_sha) + return self._format_commits(client, name, commits) integration_id = repo.integration_id if integration_id is None: diff --git a/tests/sentry/integrations/github/test_repository.py b/tests/sentry/integrations/github/test_repository.py index 85cde7c1136add..608a87cfd1ac8b 100644 --- a/tests/sentry/integrations/github/test_repository.py +++ b/tests/sentry/integrations/github/test_repository.py @@ -127,6 +127,45 @@ def test_compare_commits(self, get_jwt: mock.MagicMock) -> None: for commit in result: assert_commit_shape(commit) + @mock.patch("sentry.integrations.github.client.get_jwt", return_value="jwt_token_1") + @responses.activate + def test_compare_commits_pagination(self, get_jwt: mock.MagicMock) -> None: + """Test that compare_commits paginates to fetch all commits.""" + page1_data = orjson.loads(COMPARE_COMMITS_EXAMPLE) + page2_commit = { + **page1_data["commits"][0], + "sha": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + } + + responses.add( + responses.GET, + "https://api.github.com/repos/getsentry/example-repo/compare/xyz123...abcdef", + json=page1_data, + headers={ + "Link": '; rel="next"' + }, + ) + responses.add( + responses.GET, + "https://api.github.com/repos/getsentry/example-repo/compare/xyz123...abcdef?page=2", + json={**page1_data, "commits": [page2_commit]}, + ) + responses.add( + responses.GET, + "https://api.github.com/repos/getsentry/example-repo/commits/6dcb09b5b57875f334f61aebed695e2e4193db5e", + json=orjson.loads(GET_COMMIT_EXAMPLE), + ) + responses.add( + responses.GET, + "https://api.github.com/repos/getsentry/example-repo/commits/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + json=orjson.loads(GET_COMMIT_EXAMPLE), + ) + + result = self.provider.compare_commits(self.repository, "xyz123", "abcdef") + assert len(result) == 2 + assert result[0]["id"] == "6dcb09b5b57875f334f61aebed695e2e4193db5e" + assert result[1]["id"] == "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + @mock.patch("sentry.integrations.github.client.get_jwt", return_value="jwt_token_1") @responses.activate def test_compare_commits_patchset_handling(self, get_jwt: mock.MagicMock) -> None: