From fb9550b94da865cb9270bd3f8021c078d2a9c807 Mon Sep 17 00:00:00 2001 From: RhenCloud Date: Mon, 3 Aug 2026 06:58:47 +0800 Subject: [PATCH] feat: support check_suite webhook events --- src/__tests__/formatter.test.ts | 20 +++++++++ src/events/match.ts | 4 ++ src/formatters/check.ts | 79 +++++++++++++++++++++++++++++++++ src/formatters/index.ts | 6 ++- src/lib/locales/en.ts | 4 ++ src/lib/locales/zh.ts | 4 ++ 6 files changed, 115 insertions(+), 2 deletions(-) diff --git a/src/__tests__/formatter.test.ts b/src/__tests__/formatter.test.ts index a69e3db..4a5e577 100644 --- a/src/__tests__/formatter.test.ts +++ b/src/__tests__/formatter.test.ts @@ -150,6 +150,26 @@ describe("message title spec", () => { expect(msg.fields![0].value).toBe("🔄 running"); }); + it("check_suite shows conclusion, service, branch and commit", () => { + const suite = { + html_url: "https://github.com/acme/widget/runs/2", + conclusion: "success", + status: "completed", + app: { name: "Cloudflare Pages" }, + head_branch: "main", + head_sha: "abc123def456", + }; + const msg = formatEvent( + route, + event("check_suite", { check_suite: suite, repository: repo, sender }), + ); + expect(msg.title).toBe("acme/widget: Check suite success"); + expect(msg.fields![0].value).toBe("✅ success"); + expect(msg.fields![1].value).toBe("Cloudflare Pages"); + expect(msg.fields![2].value).toBe("main"); + expect(msg.fields![3].value).toBe("abc123d"); + }); + it("unknown events fall back to repo: event: action", () => { const msg = formatEvent( route, diff --git a/src/events/match.ts b/src/events/match.ts index bd15e3b..20dcf2b 100644 --- a/src/events/match.ts +++ b/src/events/match.ts @@ -44,6 +44,10 @@ function extractBranch(event: WebhookEvent): string | undefined { const wf = event.payload.workflow_run as { head_branch?: string } | undefined; return wf?.head_branch; } + if (event.event === "check_suite") { + const suite = event.payload.check_suite as { head_branch?: string } | undefined; + return suite?.head_branch; + } if (event.event === "commit_comment") { const comment = event.payload.comment as { position?: number | null } | undefined; if (comment?.position != null) { diff --git a/src/formatters/check.ts b/src/formatters/check.ts index 3ad13ed..64ac7c6 100644 --- a/src/formatters/check.ts +++ b/src/formatters/check.ts @@ -2,6 +2,85 @@ import type { NeutralMessage, NeutralAuthor } from "../types"; import { GITHUB_COLORS, WORKFLOW_CONCLUSION_EMOJI } from "./colors"; import { emojiPrefix, type T, buildMessage } from "./helpers"; +export function formatCheckSuite( + payload: Record, + repo: string | undefined, + author: NeutralAuthor, + t: T, + showEmoji: boolean, +): NeutralMessage { + const suite = payload.check_suite as { + head_branch?: string; + head_sha?: string; + conclusion?: string; + status?: string; + app?: { name?: string }; + html_url?: string; + }; + + const status = + suite.status === "queued" + ? "queued" + : suite.status === "in_progress" + ? "running" + : (suite.conclusion ?? "pending"); + const emoji = WORKFLOW_CONCLUSION_EMOJI[status] ?? "⏳"; + const em = (e: string): string => emojiPrefix(e, showEmoji); + const colorKey = + status === "success" + ? "check_run_success" + : status === "failure" + ? "check_run_failure" + : "check_run_other"; + + const fields: Array<{ name: string; value: string; inline?: boolean }> = []; + + fields.push({ + name: t("fields.status"), + value: `${em(emoji)}${status}`, + inline: true, + }); + + if (suite.app?.name) { + fields.push({ + name: t("fields.service"), + value: suite.app.name, + inline: true, + }); + } + + if (suite.head_branch) { + fields.push({ + name: t("fields.branch"), + value: suite.head_branch, + inline: true, + }); + } + + if (suite.head_sha) { + fields.push({ + name: t("fields.commit"), + value: suite.head_sha.slice(0, 7), + inline: true, + }); + } + + return buildMessage( + { + author, + title: t("events.check_suite.title", { + repo: repo ?? t("common.repository"), + conclusion: status, + }), + url: suite.html_url, + color: GITHUB_COLORS[colorKey], + fields, + }, + t, + repo, + ); +} + export function formatCheckRun( payload: Record, repo: string | undefined, diff --git a/src/formatters/index.ts b/src/formatters/index.ts index c819523..9020997 100644 --- a/src/formatters/index.ts +++ b/src/formatters/index.ts @@ -10,7 +10,7 @@ import { formatWorkflowRun } from "./workflow"; import { formatRelease } from "./release"; import { formatCreate, formatDelete } from "./create"; import { formatStar, formatFork } from "./repo"; -import { formatCheckRun } from "./check"; +import { formatCheckRun, formatCheckSuite } from "./check"; import { formatCommitComment } from "./commit-comment"; import { formatDeploymentStatus } from "./deployment"; import { formatMember } from "./member"; @@ -31,7 +31,7 @@ export { formatWorkflowRun } from "./workflow"; export { formatRelease } from "./release"; export { formatCreate, formatDelete } from "./create"; export { formatStar, formatFork } from "./repo"; -export { formatCheckRun } from "./check"; +export { formatCheckRun, formatCheckSuite } from "./check"; export { formatCommitComment } from "./commit-comment"; export { formatDeploymentStatus } from "./deployment"; export { formatMember } from "./member"; @@ -89,6 +89,8 @@ export function formatEvent( return formatFork(payload, repo, repoUrl, author, t, showEmoji); case "check_run": return formatCheckRun(payload, repo, author, t, showEmoji); + case "check_suite": + return formatCheckSuite(payload, repo, author, t, showEmoji); case "commit_comment": return formatCommitComment(payload, repo, author, t, showEmoji); case "deployment_status": diff --git a/src/lib/locales/en.ts b/src/lib/locales/en.ts index 2a81235..7b56ec2 100644 --- a/src/lib/locales/en.ts +++ b/src/lib/locales/en.ts @@ -56,6 +56,7 @@ export const en = { commit: "Commit", environment: "Environment", url: "URL", + service: "Service", severity: "Severity", rule: "Rule", package: "Package", @@ -128,6 +129,9 @@ export const en = { check_run: { title: "{repo}: {name} — {conclusion}", }, + check_suite: { + title: "{repo}: Check suite {conclusion}", + }, pr_review: { action_review: "{emoji}**{action}** review", title: "{repo}#{number}: {title}", diff --git a/src/lib/locales/zh.ts b/src/lib/locales/zh.ts index e6a1361..955be99 100644 --- a/src/lib/locales/zh.ts +++ b/src/lib/locales/zh.ts @@ -56,6 +56,7 @@ export const zh = { commit: "提交", environment: "环境", url: "链接", + service: "服务", severity: "严重程度", rule: "规则", package: "包", @@ -128,6 +129,9 @@ export const zh = { check_run: { title: "{repo}: {name} — {conclusion}", }, + check_suite: { + title: "{repo}: 检查套件 {conclusion}", + }, pr_review: { action_review: "{emoji}**{action}** 审查", title: "{repo}#{number}: {title}",