1
0
Fork 0

jenkins: Add Jenkins webhook

Using the [Generic Event Plugin][0], we can receive a notification from
Jenkins when builds start and finish.  We'll relay these to *ntfy* on a
unique topic that I will subscribe to on my desktop.  That way, I can
get desktop notifications about jobs while I am working, which will be
particularly useful while developing and troubleshooting pipelines.

[0]: https://plugins.jenkins.io/generic-event/
master
Dustin 2024-01-15 21:16:38 -06:00
parent 55df6f61a7
commit 9cf2345aa9
1 changed files with 94 additions and 0 deletions

View File

@ -1,3 +1,4 @@
import base64
import datetime
import importlib.metadata
import logging
@ -44,6 +45,7 @@ MAX_DOCUMENT_SIZE = int(
50 * 2**20,
)
)
NTFY_URL = os.environ.get('NTFY_URL', 'http://ntfy.ntfy:2586')
PAPERLESS_URL = os.environ.get(
'PAPERLESS_URL',
'http://paperless-ngx',
@ -308,6 +310,55 @@ def response_filename(response: httpx.Response) -> str:
return response.url.path.rstrip('/').rsplit('/', 1)[-1]
async def ntfy(
message: Optional[str],
topic: str,
title: Optional[str] = None,
tags: Optional[str] = None,
attach: Optional[bytes] = None,
filename: Optional[str] = None,
) -> None:
assert message or attach
headers = {
}
if title:
headers['Title'] = title
if tags:
headers['Tags'] = tags
url = f'{NTFY_URL}/{topic}'
client = httpx.AsyncClient()
if attach:
if filename:
headers['Filename'] = filename
if message:
try:
message.encode("ascii")
except UnicodeEncodeError:
message = rfc2047_base64encode(message)
else:
message = message.replace('\n', '\\n')
headers['Message'] = message
r = await client.put(
url,
headers=headers,
content=attach,
)
else:
r = await client.post(
url,
headers=headers,
content=message,
)
r.raise_for_status()
def rfc2047_base64encode(
message: str,
) -> str:
encoded = base64.b64encode(message.encode("utf-8")).decode("ascii")
return f"=?UTF-8?B?{encoded}?="
app = fastapi.FastAPI(
name=DIST['Name'],
version=DIST['Version'],
@ -331,3 +382,46 @@ def status() -> str:
@app.post('/hooks/firefly-iii/create')
async def firefly_iii_create(hook: FireflyIIIWebhook) -> None:
await handle_firefly_transaction(hook.content)
@app.post('/hooks/jenkins')
async def jenkins_notify(request: fastapi.Request) -> None:
body = await request.json()
data = body.get('data', {})
if body['type'] == 'run.started':
title = 'Build started'
tag = 'building_construction'
build_cause = None
for action in data.get('actions', []):
for cause in action.get('causes', []):
if build_cause := cause.get('shortDescription'):
break
else:
continue
break
message = f'Build started: {data["fullDisplayName"]}'
if build_cause:
message = f'{message} ({build_cause})'
elif body['type'] == 'run.finalized':
message = f'{data["fullDisplayName"]} {data["result"]}'
title = 'Build finished'
match data['result']:
case 'FAILURE':
tag = 'red_circle'
case 'SUCCESS':
tag = 'green_circle'
case 'UNSTABLE':
tag = 'yellow_circle'
case 'NOT_BUILT':
tag = 'large_blue_circle'
case 'ABORTED':
tag = 'black_circle'
case _:
tag = 'white_circle'
else:
return
try:
await ntfy(message, 'jenkins', title, tag)
except httpx.HTTPError:
log.exception('Failed to send notification:')