snapshot of https://github.com/zulip/zulip.git @ 48c69911c7dd4e03b20552eb3bd77ad8151c1357 (2026-09-15)
Some checks failed
Code scanning / CodeQL (push) Failing after 15s
Zulip production suite / Ubuntu 22.04 production build (push) Failing after 26s
Zulip production suite / Debian 12 production install with custom db name and user (push) Has been skipped
Zulip production suite / Ubuntu 22.04 production install and PostgreSQL upgrade with pgroonga (push) Has been skipped
Zulip production suite / Ubuntu 24.04 production install (push) Has been skipped
Zulip production suite / Ubuntu 26.04 production install (push) Has been skipped
Zulip production suite / Debian 13 production install (push) Has been skipped
Zulip production suite / 7.0 Version Upgrade (push) Has been skipped
Zulip production suite / 8.0 Version Upgrade (push) Has been skipped
Zulip production suite / 6.0 Version Upgrade (push) Has been skipped
Zulip production suite / 10.0 Version Upgrade (push) Has been skipped
Zulip production suite / 9.0 Version Upgrade (push) Has been skipped
Zulip production suite / 12.0 Version Upgrade (push) Has been skipped
Zulip production suite / 11.0 Version Upgrade (push) Has been skipped
GitHub Actions Security Analysis with zizmor / zizmor (push) Failing after 3s
Zulip CI / Debian 12 (Python 3.11, backend + documentation) (push) Failing after 26s
Zulip CI / Ubuntu 22.04 (Python 3.10, backend + frontend) (push) Failing after 3s
Zulip CI / Ubuntu 24.04 (Python 3.12, backend) (push) Failing after 25s
Zulip CI / Ubuntu 26.04 (Python 3.14, backend) (push) Failing after 25s
Zulip CI / Debian 13 (Python 3.13, backend) (push) Failing after 28s
Zulip production suite / Required jobs (push) Has been cancelled
Zulip CI / Required jobs (push) Has been cancelled
API Documentation Update Check / check-feature-level-updated (push) Has been cancelled
API Documentation Update Check / notify-if-api-docs-changed (push) Has been cancelled
Some checks failed
Code scanning / CodeQL (push) Failing after 15s
Zulip production suite / Ubuntu 22.04 production build (push) Failing after 26s
Zulip production suite / Debian 12 production install with custom db name and user (push) Has been skipped
Zulip production suite / Ubuntu 22.04 production install and PostgreSQL upgrade with pgroonga (push) Has been skipped
Zulip production suite / Ubuntu 24.04 production install (push) Has been skipped
Zulip production suite / Ubuntu 26.04 production install (push) Has been skipped
Zulip production suite / Debian 13 production install (push) Has been skipped
Zulip production suite / 7.0 Version Upgrade (push) Has been skipped
Zulip production suite / 8.0 Version Upgrade (push) Has been skipped
Zulip production suite / 6.0 Version Upgrade (push) Has been skipped
Zulip production suite / 10.0 Version Upgrade (push) Has been skipped
Zulip production suite / 9.0 Version Upgrade (push) Has been skipped
Zulip production suite / 12.0 Version Upgrade (push) Has been skipped
Zulip production suite / 11.0 Version Upgrade (push) Has been skipped
GitHub Actions Security Analysis with zizmor / zizmor (push) Failing after 3s
Zulip CI / Debian 12 (Python 3.11, backend + documentation) (push) Failing after 26s
Zulip CI / Ubuntu 22.04 (Python 3.10, backend + frontend) (push) Failing after 3s
Zulip CI / Ubuntu 24.04 (Python 3.12, backend) (push) Failing after 25s
Zulip CI / Ubuntu 26.04 (Python 3.14, backend) (push) Failing after 25s
Zulip CI / Debian 13 (Python 3.13, backend) (push) Failing after 28s
Zulip production suite / Required jobs (push) Has been cancelled
Zulip CI / Required jobs (push) Has been cancelled
API Documentation Update Check / check-feature-level-updated (push) Has been cancelled
API Documentation Update Check / notify-if-api-docs-changed (push) Has been cancelled
This commit is contained in:
106
zerver/webhooks/heroku/view.py
Normal file
106
zerver/webhooks/heroku/view.py
Normal file
@@ -0,0 +1,106 @@
|
||||
from django.http import HttpRequest, HttpResponse
|
||||
|
||||
from zerver.decorator import webhook_view
|
||||
from zerver.lib.exceptions import UnsupportedWebhookEventTypeError
|
||||
from zerver.lib.response import json_success
|
||||
from zerver.lib.typed_endpoint import JsonBodyPayload, typed_endpoint
|
||||
from zerver.lib.validator import WildValue, check_bool, check_int, check_none_or, check_string
|
||||
from zerver.lib.webhooks.common import check_send_webhook_message
|
||||
from zerver.models import UserProfile
|
||||
|
||||
ENTITY_CREATED_MESSAGE = "{status_emoji}{actor} triggered a {entity}."
|
||||
ENTITY_UPDATED_MESSAGE = "{status_emoji}The {entity} triggered by {actor} **{status}**."
|
||||
|
||||
# The events here are ignored not because they are noisy.
|
||||
# But we do not have accurate fixtures for them.
|
||||
# The fixtures documented in https://devcenter.heroku.com/articles/webhook-events
|
||||
# have been reported to drift from actual payloads.
|
||||
# Heroku does not provide a free trial account.
|
||||
IGNORED_ENTITIES = [
|
||||
"addon-attachment",
|
||||
"addon",
|
||||
"app",
|
||||
"collaborator",
|
||||
"domain",
|
||||
"dyno",
|
||||
"formation",
|
||||
"sni-endpoint",
|
||||
]
|
||||
|
||||
STATUS_MAP = {
|
||||
"succeeded": ":check:",
|
||||
"failed": ":warning:",
|
||||
"pending": ":time_ticking:",
|
||||
"expired": ":times_up:",
|
||||
}
|
||||
|
||||
|
||||
def get_body(payload: WildValue, entity: str) -> str:
|
||||
data = payload["data"]
|
||||
actor = payload["actor"]["email"].tame(check_string)
|
||||
|
||||
entity_url = data["output_stream_url"].tame(check_none_or(check_string))
|
||||
display_entity = f"[{entity}]({entity_url})" if entity_url else entity
|
||||
|
||||
if entity == "release":
|
||||
version = data["version"].tame(check_int)
|
||||
description = data["description"].tame(check_string)
|
||||
display_entity = f"{display_entity}(v{version}): {description}"
|
||||
|
||||
action = payload["action"].tame(check_string)
|
||||
status = data["status"].tame(check_string)
|
||||
status_emoji = f"{STATUS_MAP[status]} " if status in STATUS_MAP else ""
|
||||
|
||||
template = ENTITY_UPDATED_MESSAGE if action == "update" else ENTITY_CREATED_MESSAGE
|
||||
body = template.format(
|
||||
entity=display_entity, actor=actor, status=status, status_emoji=status_emoji
|
||||
)
|
||||
|
||||
return body
|
||||
|
||||
|
||||
def should_ignore_event(entity: str, event_type: str, payload: WildValue) -> bool:
|
||||
if entity in IGNORED_ENTITIES:
|
||||
return True
|
||||
|
||||
# Ignore release phase update events, for now, to avoid duplicate notifications.
|
||||
# https://devcenter.heroku.com/articles/release-phase
|
||||
# 1. Release started: action="create" data.status="pending" data.current=false
|
||||
# 2. Release phase(s) finished: action="update" data.status="succeeded" data.current=false
|
||||
# 3. Release live: action="update" data.status="succeeded" data.current=true
|
||||
status = payload["data"]["status"].tame(check_string)
|
||||
if (
|
||||
event_type == "release.update"
|
||||
and status in {"succeeded", "failed"}
|
||||
and not payload["data"]["current"].tame(check_bool)
|
||||
):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
ALL_EVENT_TYPES = ["build.create", "build.update", "release.create", "release.update"]
|
||||
|
||||
|
||||
@webhook_view("Heroku", all_event_types=ALL_EVENT_TYPES)
|
||||
@typed_endpoint
|
||||
def api_heroku_webhook(
|
||||
request: HttpRequest,
|
||||
user_profile: UserProfile,
|
||||
*,
|
||||
payload: JsonBodyPayload[WildValue],
|
||||
) -> HttpResponse:
|
||||
entity = payload["resource"].tame(check_string)
|
||||
event = payload["action"].tame(check_string)
|
||||
event_type = f"{entity}.{event}"
|
||||
|
||||
if should_ignore_event(entity, event_type, payload):
|
||||
return json_success(request)
|
||||
|
||||
if event_type not in ALL_EVENT_TYPES:
|
||||
raise UnsupportedWebhookEventTypeError(event_type)
|
||||
topic_name = payload["data"]["app"]["name"].tame(check_string)
|
||||
body = get_body(payload, entity)
|
||||
|
||||
check_send_webhook_message(request, user_profile, topic_name, body, event_type)
|
||||
return json_success(request)
|
||||
Reference in New Issue
Block a user