Skip to content

Commit 6cae90d

Browse files
authored
Add more helpful error messages (#158)
1 parent 579e97f commit 6cae90d

File tree

3 files changed

+84
-4
lines changed

3 files changed

+84
-4
lines changed

github_activity/github_activity.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ def get_activity(
139139
"""
140140

141141
org, repo = _parse_target(target)
142+
142143
if repo:
143144
# We have org/repo
144145
search_query = f"repo:{org}/{repo}"
@@ -192,6 +193,10 @@ def get_activity(
192193
"via the GitHub CLI (`gh auth login`)."
193194
)
194195

196+
# Validate repository exists early if a specific repo was provided
197+
if repo:
198+
_validate_repository_exists(org, repo, auth)
199+
195200
# Figure out dates for our query
196201
since_dt, since_is_git_ref = _get_datetime_and_type(org, repo, since, auth)
197202
until_dt, until_is_git_ref = _get_datetime_and_type(org, repo, until, auth)
@@ -867,6 +872,32 @@ def _parse_target(target):
867872
return org, repo
868873

869874

875+
def _validate_repository_exists(org, repo, token):
876+
"""Validate that a repository exists on GitHub.
877+
878+
Parameters
879+
----------
880+
org : str
881+
The organization or user name
882+
repo : str
883+
The repository name
884+
token : str
885+
GitHub authentication token
886+
887+
Raises
888+
------
889+
ValueError
890+
If the repository does not exist or is not accessible
891+
"""
892+
auth = TokenAuth(token)
893+
repo_url = f"https://api.github.com/repos/{org}/{repo}"
894+
response = requests.head(repo_url, auth=auth)
895+
if response.status_code == 404:
896+
raise ValueError(
897+
f"Repository '{org}/{repo}' not found. Please check the repository name."
898+
)
899+
900+
870901
def _get_datetime_and_type(org, repo, datetime_or_git_ref, auth):
871902
"""Return a datetime object and bool indicating if it is a git reference or
872903
not."""

github_activity/graphql.py

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -195,16 +195,42 @@ def request(self, n_pages=100, n_per_page=50):
195195
auth=self.auth,
196196
)
197197
if ii_request.status_code != 200:
198+
# Check for common error cases and provide helpful messages
199+
if ii_request.status_code == 403:
200+
try:
201+
error_data = ii_request.json()
202+
error_message = error_data.get("message", "")
203+
if "rate limit" in error_message.lower():
204+
raise Exception(
205+
f"GitHub API rate limit exceeded. {error_message}\n"
206+
"Please wait before making more requests, or use an authentication token with higher rate limits."
207+
)
208+
else:
209+
# Generic 403 - likely a permissions issue
210+
raise Exception(
211+
f"GitHub API access forbidden. {error_message}\n"
212+
"This usually means your authentication token doesn't have the required permissions.\n"
213+
"Please check that your token has the necessary scopes for this repository."
214+
)
215+
except (ValueError, KeyError):
216+
pass
198217
raise Exception(
199218
"Query failed to run by returning code of {}. {}".format(
200219
ii_request.status_code, ii_gql_query
201220
)
202221
)
203-
if "errors" in ii_request.json().keys():
222+
errors = ii_request.json().get("errors")
223+
if errors:
224+
# Check for rate limit errors in GraphQL response
225+
for error in errors:
226+
if error.get("type") == "RATE_LIMITED":
227+
error_message = error.get("message", "Rate limit exceeded")
228+
raise Exception(
229+
f"GitHub API rate limit exceeded. {error_message}\n"
230+
"Please wait before making more requests, or use an authentication token with higher rate limits."
231+
)
204232
raise Exception(
205-
"Query failed to run with error {}. {}".format(
206-
ii_request.json()["errors"], ii_gql_query
207-
)
233+
"Query failed to run with error {}. {}".format(errors, ii_gql_query)
208234
)
209235
self.last_request = ii_request
210236

tests/test_cli.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,3 +132,26 @@ def test_changelog_features(file_regression):
132132
assert "@dependabot" not in md_full.lower(), (
133133
"Bot user dependabot should not appear in output"
134134
)
135+
136+
137+
def test_invalid_repository_error():
138+
"""Test that invalid repository names produce clear error messages."""
139+
from github_activity.github_activity import get_activity
140+
import pytest
141+
142+
# Test with an invalid repository name
143+
with pytest.raises(ValueError) as exc_info:
144+
get_activity(
145+
target="invalid-org/nonexistent-repo-12345",
146+
since="2021-01-01",
147+
until="2021-01-15",
148+
)
149+
150+
# Verify the error message mentions the repository
151+
error_message = str(exc_info.value)
152+
assert "repository" in error_message.lower(), (
153+
f"Error should mention repository, got: {error_message}"
154+
)
155+
assert "invalid-org/nonexistent-repo-12345" in error_message, (
156+
f"Error should include the repo name, got: {error_message}"
157+
)

0 commit comments

Comments
 (0)