Add optional screenshots to bug reports

This commit is contained in:
2026-09-15 21:16:06 +02:00
parent 39af9ecdb4
commit 5d3ae10036
10 changed files with 263 additions and 12 deletions
+35 -5
View File
@@ -62,12 +62,13 @@ class GiteaService:
self.config = config or GiteaConfig.from_env()
self.transport = transport
def create_issue(self, title, body, category):
def create_issue(self, title, body, category, screenshot=None):
self.config.validate()
repository = '/repos/' + quote(self.config.owner, safe='') + '/' + quote(self.config.repo, safe='')
wanted = {'reported-from-metalcircle', 'bug'}
wanted.update({'android': {'android'}, 'web': {'web', 'frontend'}, 'push': {'push'}}.get(category, set()))
attempted = False
issue_created = False
try:
with httpx.Client(base_url=self.config.url.rstrip('/') + '/api/v1/',
headers={'Authorization': 'token ' + self.config.token, 'Accept': 'application/json'},
@@ -105,17 +106,46 @@ class GiteaService:
issue['number'] <= 0 or not isinstance(issue.get('user'), dict) or
issue['user'].get('login') != 'metalcircle-bot'):
raise GiteaError('invalid_response', uncertain=True)
return issue['number']
issue_number = issue['number']
issue_created = True
if screenshot:
filename, image_bytes, media_type = screenshot
uploaded = client.post(
repository.lstrip('/') + f'/issues/{issue_number}/assets',
params={'name': filename},
files={'attachment': (filename, image_bytes, media_type)},
)
uploaded.raise_for_status()
attachment = uploaded.json()
download_url = attachment.get('browser_download_url') if isinstance(attachment, dict) else None
configured_origin = urlsplit(self.config.url)
attachment_origin = urlsplit(download_url) if isinstance(download_url, str) else None
if (not attachment_origin or attachment_origin.scheme not in ('http', 'https') or
attachment_origin.hostname != configured_origin.hostname or
attachment_origin.port != configured_origin.port or
attachment_origin.username or attachment_origin.password):
raise GiteaError('invalid_attachment_response', uncertain=True)
linked_body = redact(
body + '\n\n## Screenshot\n\n![Bug report screenshot](<' + quote(download_url, safe=':/?&=%') + '>)',
(self.config.token,),
)
updated = client.patch(repository.lstrip('/') + f'/issues/{issue_number}',
json={'body': linked_body})
updated.raise_for_status()
return issue_number
except GiteaError as error:
if issue_created and screenshot:
error.uncertain = True
logger.warning('Gitea issue submission failed: %s', error.kind)
raise
except httpx.HTTPStatusError as error:
code = error.response.status_code
logger.warning('Gitea issue submission failed: HTTP %d', code)
raise GiteaError('http_' + str(code), uncertain=attempted and code >= 500) from None
raise GiteaError('http_' + str(code), uncertain=(issue_created and bool(screenshot)) or (attempted and code >= 500)) from None
except (httpx.TimeoutException, httpx.NetworkError, httpx.RemoteProtocolError):
logger.warning('Gitea issue submission failed: network_or_timeout')
raise GiteaError('network_or_timeout', uncertain=attempted) from None
raise GiteaError('network_or_timeout', uncertain=issue_created or attempted) from None
except (ValueError, TypeError, KeyError, AttributeError, httpx.HTTPError):
logger.warning('Gitea issue submission failed: invalid_response')
raise GiteaError('invalid_response', uncertain=attempted) from None
raise GiteaError('invalid_response', uncertain=issue_created or attempted) from None