Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/good_egg/github_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,8 @@ async def fetch_user_merged_prs(
if len(prs) >= max_prs:
break
repo = node["repository"] # type: ignore[index]
if repo is None:
continue
prs.append(
MergedPR(
repo_name_with_owner=repo["nameWithOwner"],
Expand Down Expand Up @@ -434,6 +436,8 @@ async def get_user_contribution_data(
if len(prs) >= max_prs:
break
repo = node["repository"] # type: ignore[index]
if repo is None:
continue
repo_name = repo["nameWithOwner"]
prs.append(
MergedPR(
Expand Down Expand Up @@ -471,6 +475,8 @@ async def get_user_contribution_data(
if len(prs) >= max_prs:
break
repo = node["repository"] # type: ignore[index]
if repo is None:
continue
repo_name = repo["nameWithOwner"]
prs.append(
MergedPR(
Expand Down
107 changes: 107 additions & 0 deletions tests/test_github_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,59 @@ async def test_fetch_user_merged_prs(self) -> None:
assert prs[1].title == "Add WebSocket compression support"
assert prs[1].additions == 200

@respx.mock
async def test_fetch_user_merged_prs_skips_null_repository(self) -> None:
"""PRs whose repository is null (deleted/inaccessible) should be skipped."""
fixture = {
"data": {
"user": {
"login": "testuser",
"createdAt": "2020-01-01T00:00:00Z",
"__typename": "User",
"followers": {"totalCount": 50},
"repositories": {"totalCount": 20},
"pullRequests": {
"totalCount": 3,
"pageInfo": {"hasNextPage": False, "endCursor": None},
"nodes": [
{
"title": "PR to deleted repo",
"mergedAt": "2024-06-15T00:00:00Z",
"additions": 10,
"deletions": 5,
"changedFiles": 1,
"repository": None,
},
{
"title": "PR to accessible repo",
"mergedAt": "2024-03-10T00:00:00Z",
"additions": 20,
"deletions": 3,
"changedFiles": 2,
"repository": {
"nameWithOwner": "elixir-lang/elixir",
"stargazerCount": 23000,
"forkCount": 3200,
"primaryLanguage": {"name": "Elixir"},
"isArchived": False,
"isFork": False,
},
},
],
},
}
}
}
respx.post(GRAPHQL_URL).mock(
return_value=httpx.Response(200, json=fixture)
)

async with _make_client() as client:
prs = await client.fetch_user_merged_prs("testuser")

assert len(prs) == 1
assert prs[0].title == "PR to accessible repo"

@respx.mock
async def test_fetch_user_merged_prs_pagination(self) -> None:
"""Two pages of results should be fetched and concatenated."""
Expand Down Expand Up @@ -299,6 +352,60 @@ async def test_get_user_contribution_data(self) -> None:
assert "phoenixframework/phoenix" in data.contributed_repos
assert data.contributed_repos["elixir-lang/elixir"].stargazer_count == 23000

@respx.mock
async def test_null_repository_skipped(self) -> None:
"""PRs with null repository (deleted/inaccessible) should be skipped."""
fixture = {
"data": {
"user": {
"login": "testuser",
"createdAt": "2020-01-01T00:00:00Z",
"__typename": "User",
"followers": {"totalCount": 50},
"repositories": {"totalCount": 20},
"pullRequests": {
"totalCount": 3,
"pageInfo": {"hasNextPage": False, "endCursor": None},
"nodes": [
{
"title": "PR to deleted repo",
"mergedAt": "2024-06-15T00:00:00Z",
"additions": 10,
"deletions": 5,
"changedFiles": 1,
"repository": None,
},
{
"title": "PR to accessible repo",
"mergedAt": "2024-03-10T00:00:00Z",
"additions": 20,
"deletions": 3,
"changedFiles": 2,
"repository": {
"nameWithOwner": "elixir-lang/elixir",
"stargazerCount": 23000,
"forkCount": 3200,
"primaryLanguage": {"name": "Elixir"},
"isArchived": False,
"isFork": False,
},
},
],
},
}
}
}
respx.post(GRAPHQL_URL).mock(
return_value=httpx.Response(200, json=fixture)
)

async with _make_client() as client:
data = await client.get_user_contribution_data("testuser")

assert len(data.merged_prs) == 1
assert data.merged_prs[0].title == "PR to accessible repo"
assert "elixir-lang/elixir" in data.contributed_repos


# ---------------------------------------------------------------------------
# REST: PR comments
Expand Down