Skip to content

Commit 018ade9

Browse files
committed
fix: undefined var in _github_get + improved error msgs
Fix bug in `_github_get` where the variable `response` was undefined if an exception occurred. Improved (I hope) the error messages printed during exceptions in that function, plus also some other functions in this file.
1 parent df4b522 commit 018ade9

File tree

1 file changed

+50
-21
lines changed

1 file changed

+50
-21
lines changed

iga/github.py

Lines changed: 50 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
'''
1010

1111
import commonpy.exceptions
12-
from commonpy.network_utils import network
12+
from commonpy.network_utils import net
13+
import contextlib
1314
from functools import cache
1415
import json
1516
import os
@@ -108,8 +109,13 @@ def github_release(account_name, repo_name, tag_name):
108109
log('getting GitHub data for release at ' + endpoint)
109110
result = _object_for_github(endpoint, GitHubRelease)
110111
if not result:
111-
raise GitHubError(f'Can\'t get GitHub release data for {tag_name} in'
112-
f' repository {repo_name} of account {account_name}')
112+
raise GitHubError(f'Failed to get GitHub release data for {tag_name} in'
113+
f' repository {repo_name} of account {account_name}.'
114+
' This could be due to a number of causes. Please'
115+
' check that the repository and release do exist, and'
116+
' that the GitHub access token (if one is being used)'
117+
' is configured with appropriate permissions to grant'
118+
' access to the repository.')
113119
return result
114120

115121

@@ -119,8 +125,13 @@ def github_repo(account_name, repo_name):
119125
log('getting GitHub data for repo at ' + endpoint)
120126
result = _object_for_github(endpoint, GitHubRepo)
121127
if not result:
122-
raise GitHubError('Can\'t get GitHub repository data for'
123-
f' {account_name}/{repo_name}')
128+
raise GitHubError('Failed to get GitHub repository data for'
129+
f' {account_name}/{repo_name}.'
130+
' This could be due to a number of causes. Please'
131+
' check that the repository and release do exist, and'
132+
' that the GitHub access token (if one is being used)'
133+
' is configured with appropriate permissions to grant'
134+
' access to the repository.')
124135
return result
125136

126137

@@ -130,7 +141,12 @@ def github_account(account_name):
130141
log('getting GitHub data for user at ' + endpoint)
131142
result = _object_for_github(endpoint, GitHubAccount)
132143
if not result:
133-
raise GitHubError(f'Can\'t get GitHub account data for {account_name}')
144+
raise GitHubError(f'Failed to get GitHub account data for {account_name}.'
145+
' This could be due to a number of causes. Please'
146+
' check that the account exists, and that the GitHub'
147+
' access token (if one is being used) is configured'
148+
' with appropriate permissions to grant access to'
149+
' user account data.')
134150
return result
135151

136152

@@ -355,26 +371,39 @@ def _github_get(endpoint):
355371
using_token = 'GITHUB_TOKEN' in os.environ
356372
if using_token:
357373
headers['Authorization'] = f'token {os.environ["GITHUB_TOKEN"]}'
358-
try:
359-
response = network('get', endpoint, headers=headers)
360-
return response # noqa PIE787
361-
except KeyboardInterrupt:
362-
raise
363-
except commonpy.exceptions.NoContent:
374+
(response, error) = net('get', endpoint, headers=headers)
375+
if not error:
376+
return response
377+
elif isinstance(error, commonpy.exceptions.NoContent):
364378
log(f'got no content for {endpoint}')
365-
except commonpy.exceptions.AuthenticationFailure:
379+
elif isinstance(error, commonpy.exceptions.AuthenticationFailure):
366380
# GitHub is unusual in returning 403 when you hit the rate limit.
367381
# https://docs.github.com/en/rest/overview/resources-in-the-rest-api
368-
if 'API rate limit exceeded' in response.text:
382+
# This means an authentication failure could be due to rate limits OR
383+
# a credentials problems, and we have to try to figure out which one.
384+
message = ''
385+
with contextlib.suppress(Exception):
386+
if response and not isinstance(response, str):
387+
# Preferable case: if the response value from net() is not a
388+
# str, it'll be an httpx object & should have a message
389+
# field. This will have more specific details than the
390+
# generic Exception object we stored in the error variable.
391+
message = response.json().get('message')
392+
else:
393+
# Didn't get a response object. Use the text from the Exception.
394+
message = getattr(error, 'text', '')
395+
# Now try to distinguish what caused this GitHub error.
396+
if 'rate limit' in message:
369397
if using_token:
370-
raise GitHubError('Rate limit exceeded – try again later')
398+
raise GitHubError('GitHub rate limit exceeded – try again later')
371399
else:
372-
raise GitHubError('Rate limit exceeded – try to use a personal'
400+
raise GitHubError('GitHub rate limit exceeded – try to use a personal'
373401
' access token, or wait and try again later.')
374402
else:
375-
raise GitHubError('Permissions problem accessing ' + endpoint)
376-
except commonpy.exceptions.CommonPyException as ex:
377-
raise GitHubError(ex.args[0]) from ex
378-
except Exception:
379-
raise
403+
details = f' ("{message}")' if message else ''
404+
raise GitHubError(f'GitHub permissions error{details} accessing {endpoint}')
405+
elif isinstance(error, commonpy.exceptions.CommonPyException):
406+
raise GitHubError(error.args[0]) from error
407+
else:
408+
raise error
380409
return None

0 commit comments

Comments
 (0)