Files
zulip/zerver/webhooks/gocd/view.py
swayam0322 6c583c9bfe integrations: Update GoCD integration.
Previously, the GoCD integration relied on GoCD's integration with bug
tracking and monitoring tools through the users' Config XML file [1].
However, this feature no longer works as expected, as it cannot send
HTTPS payloads to an external endpoint.

This commit updates our GoCD integration to use Sentry's WebHook
notifier GoCD plugin [2] to send webhook payloads from users GoCD server
to Zulip. We are using an older version of the plugin—v0.0.6—because the
newer version—v0.0.9—doesn't work at this time.

Additionally, this change reformats the notifications to include more
details on the GoCD event, such as lists of passed and failed jobs.

Fixes #21224.

Co-authored-by: Pieter CK <pieterceka123@gmail.com>

[1]:
https://docs.gocd.org/current/integration/#integration-with-bug-tracking-and-story-management-tools
[2]:
https://github.com/getsentry/gocd-webhook-notification-plugin/releases/tag/v0.0.6
2024-11-07 10:25:29 -08:00

112 lines
3.7 KiB
Python

# Webhooks for external integrations.
from collections import defaultdict
from django.http import HttpRequest, HttpResponse
from zerver.decorator import webhook_view
from zerver.lib.response import json_success
from zerver.lib.typed_endpoint import JsonBodyPayload, typed_endpoint
from zerver.lib.validator import WildValue, check_string
from zerver.lib.webhooks.common import check_send_webhook_message
from zerver.lib.webhooks.git import get_short_sha
from zerver.models import UserProfile
COMMIT_INFO_TEMPLATE = """[`{commit_details}`]({commit_link}) on branch `{branch_name}`"""
TOPIC_TEMPLATE = "{pipeline} / {stage}"
SCHEDULED_BODY_TEMPLATE = """
**Pipeline {status}**: {pipeline} / {stage}
- **Commit**: {commit_details}
- **Started**: {start_time}
"""
COMPLETED_BODY_TEMPLATE = """
{emoji} **Build {status}**: {pipeline} / {stage}
- **Commit**: {commit_details}
- **Started**: {start_time}
- **Finished**: {end_time}
"""
@webhook_view("Gocd")
@typed_endpoint
def api_gocd_webhook(
request: HttpRequest,
user_profile: UserProfile,
*,
payload: JsonBodyPayload[WildValue],
) -> HttpResponse:
type = payload["type"].tame(check_string)
if type == "stage":
body = get_body(payload)
topic_name = get_topic(payload)
check_send_webhook_message(request, user_profile, topic_name, body)
return json_success(request)
def get_topic(payload: WildValue) -> str:
return TOPIC_TEMPLATE.format(
pipeline=payload["data"]["pipeline"]["name"].tame(check_string),
stage=payload["data"]["pipeline"]["stage"]["name"].tame(check_string),
)
def get_commit_details(payload: WildValue) -> str:
build = payload["data"]["pipeline"]["build-cause"][0]
material = build["material"]
url_base = material["git-configuration"]["url"].tame(check_string)
revision = build["modifications"][0]["revision"].tame(check_string)
commit_sha = get_short_sha(revision)
url = f"{url_base}/commit/{commit_sha}"
branch = material["git-configuration"]["branch"].tame(check_string)
return COMMIT_INFO_TEMPLATE.format(
commit_details=commit_sha,
commit_link=url,
branch_name=branch,
)
def get_jobs_details(pipeline_data: WildValue) -> str:
job_dict_list = pipeline_data["stage"]["jobs"]
formatted_job_dict = defaultdict(list)
job_details_template = ""
for job in job_dict_list:
job_name = job["name"].tame(check_string)
job_result = job["result"].tame(check_string)
formatted_job_dict[job_result].append(f"`{job_name}`")
for key in formatted_job_dict:
formatted_job_list = ", ".join(formatted_job_dict[key])
job_details_template += f"- **{key}**: {formatted_job_list}\n"
return job_details_template
def get_body(payload: WildValue) -> str:
pipeline_data = payload["data"]["pipeline"]
body_details = {
"commit_details": get_commit_details(payload),
"status": pipeline_data["stage"]["state"].tame(check_string).lower(),
"pipeline": pipeline_data["name"].tame(check_string),
"stage": pipeline_data["stage"]["name"].tame(check_string),
"start_time": pipeline_data["stage"]["create-time"].tame(check_string),
}
if body_details["status"] == "building":
return SCHEDULED_BODY_TEMPLATE.format(**body_details)
result = pipeline_data["stage"]["result"].tame(check_string)
body_details.update(
{
"result": result,
"emoji": ":green_circle:" if result == "Passed" else ":red_circle:",
"end_time": pipeline_data["stage"]["last-transition-time"].tame(check_string),
}
)
body = COMPLETED_BODY_TEMPLATE.format(**body_details)
body += get_jobs_details(pipeline_data)
return body