Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: add discord webhook helpers #1045

Merged
merged 1 commit into from
Mar 10, 2025
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
11 changes: 11 additions & 0 deletions backend/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,17 @@ For debugging we have two env variables
## Open API generate
You can update the OpenAPI schema by running the `generate-schema.sh` script


## Discord Webhook Integration

The webdashboard backend can send notifications to discord via a webhook. In order to enable that, export an environment variable with the URL to the discord webhook called `DISCORD_WEBHOOK_URL`, which should be in the structure of:

`export DISCORD_WEBHOOK_URL https://discord.com/api/webhooks/<webhook_id>/<webhook_token>`

For an introduction on discord webhooks, visit https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks.

For more detailed developer resources, visit https://discord.com/developers/docs/resources/webhook.

## IDE Specific:
You are free to use whichever tool you would like, but here are tips for specific IDEs

Expand Down
65 changes: 65 additions & 0 deletions backend/kernelCI_app/helpers/discordWebhook.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
from typing import Any, Optional, TypedDict

import requests
import os

from kernelCI_app.helpers.logger import log_message

# For more information on discord webhook structure, visit
# https://discord.com/developers/docs/resources/webhook#execute-webhook

AVATAR_URL = "https://avatars.githubusercontent.com/u/11725450?s=200&v=4"
WEBHOOK_NAME = "KernelCI Dashboard Notifications"


class DiscordImage(TypedDict):
url: str
width: Optional[int]
height: Optional[int]


class DiscordEmbed(TypedDict):
title: str
description: Optional[str]
url: Optional[str]
image: Optional[DiscordImage]


def send_discord_notification(
*,
content: Optional[str] = None,
embeds: Optional[list[DiscordEmbed]] = None,
avatar_url: Optional[str] = AVATAR_URL,
webhook_name: Optional[str] = WEBHOOK_NAME,
) -> None:
url = os.getenv("DISCORD_WEBHOOK_URL")
if not url:
log_message("DISCORD_WEBHOOK_URL environment variable is not set.")
return

if not content and not embeds:
log_message(
"Either content or embeds must be set in order to send notifications."
)
return

if embeds is not None and len(embeds) > 10:
log_message("The embed list can contain at most 10 elements.")
return

data: dict[str, Any] = {
"avatar_url": avatar_url,
"username": webhook_name,
}
if content is not None:
data["content"] = content
if embeds is not None:
data["embeds"] = embeds

try:
result = requests.post(url=url, json=data)
result.raise_for_status()
except requests.HTTPError as e:
log_message(e)

return
19 changes: 19 additions & 0 deletions backend/kernelCI_app/helpers/logger.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,23 @@
from django.http import HttpRequest
from datetime import datetime


# For logging that we care about, we create a function so we can easily use
# a more sophisticated logging library later.
def log_message(message: str) -> None:
print(message)


def create_endpoint_notification(*, message: str, request: HttpRequest) -> str:
return (
message
+ "\n\nEndpoint:\n"
+ request.build_absolute_uri()
+ (
("\nBody:\n```json\n" + request.body.decode("utf-8") + "```")
if request.body
else ""
)
+ "\nAccessed in: "
+ datetime.now().strftime("%Y-%m-%d %H:%M:%S")
)
10 changes: 10 additions & 0 deletions backend/kernelCI_app/views/buildTestsView.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
from http import HTTPStatus
from kernelCI_app.helpers.discordWebhook import send_discord_notification
from kernelCI_app.helpers.logger import create_endpoint_notification
from kernelCI_app.typeModels.buildDetails import BuildTestsResponse
from kernelCI_app.models import Tests
from drf_spectacular.utils import extend_schema
Expand All @@ -18,6 +20,7 @@ def get(self, request, build_id: str) -> Response:
"start_time",
"environment_compatible",
"environment_misc",
"build__valid",
)

if not result:
Expand All @@ -26,6 +29,13 @@ def get(self, request, build_id: str) -> Response:
status=HTTPStatus.OK,
)

if result[0].get("build__valid") is False:
notification = create_endpoint_notification(
message="Found tests for a failed build.",
request=request,
)
send_discord_notification(content=notification)

try:
valid_response = BuildTestsResponse(result)
except ValidationError as e:
Expand Down
1 change: 1 addition & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ services:
- DB_DEFAULT_USER=${DB_DEFAULT_USER:-kernelci}
- DJANGO_SECRET_KEY=${DJANGO_SECRET_KEY}
- DEBUG=False
- DISCORD_WEBHOOK_URL=${DISCORD_WEBHOOK_URL}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add the env description to the backend README file


dashboard:
build: ./dashboard
Expand Down