mirror of
https://github.com/ReCloudStudio/WebHooker.git
synced 2026-09-22 16:11:29 +00:00
feat: add per-group emoji toggle and standardized embed titles
This commit is contained in:
parent
49baf63a17
commit
809f89400b
11 changed files with 437 additions and 133 deletions
18
AGENTS.md
18
AGENTS.md
|
|
@ -29,7 +29,7 @@ src/
|
||||||
├── discord.ts # Dispatch via REST (or DO RPC when gateway enabled), initGateway (scheduled)
|
├── discord.ts # Dispatch via REST (or DO RPC when gateway enabled), initGateway (scheduled)
|
||||||
├── discord-rest.ts # Discord REST sendMessage with retry + rate-limit handling
|
├── discord-rest.ts # Discord REST sendMessage with retry + rate-limit handling
|
||||||
├── discord-gateway.ts # Optional Durable Object: Discord Gateway WS, heartbeat, channel cache, send
|
├── discord-gateway.ts # Optional Durable Object: Discord Gateway WS, heartbeat, channel cache, send
|
||||||
├── formatter.ts # 23 event formatters + generic fallback (~1380 lines)
|
├── formatter.ts # 24 event formatters + generic fallback (~1570 lines)
|
||||||
├── github-oauth.ts # OAuth URL, callback token exchange, getUserOctokit
|
├── github-oauth.ts # OAuth URL, callback token exchange, getUserOctokit
|
||||||
├── oauth-routes.ts # GET /auth/github, callback (sets admin session if redirect=/admin), DELETE /token/:userId
|
├── oauth-routes.ts # GET /auth/github, callback (sets admin session if redirect=/admin), DELETE /token/:userId
|
||||||
├── action-routes.ts # POST /api/comment|merge|react (Bearer token auth via KV lookup)
|
├── action-routes.ts # POST /api/comment|merge|react (Bearer token auth via KV lookup)
|
||||||
|
|
@ -48,6 +48,20 @@ src/
|
||||||
- Route messages to Discord channels/threads via Durable Object RPC
|
- Route messages to Discord channels/threads via Durable Object RPC
|
||||||
- Maintain Discord Gateway connection with heartbeat and alarm-based keepalive
|
- Maintain Discord Gateway connection with heartbeat and alarm-based keepalive
|
||||||
|
|
||||||
|
## Message Format Spec
|
||||||
|
|
||||||
|
- Every embed title must start with the repo, then optional `#number`, then `: subject`:
|
||||||
|
`{repo}{#number}: {subject}` (e.g. `acme/widget#7: Add feature`). Repo comes from
|
||||||
|
`payload.repository.full_name`; fall back to `t("common.repository")` when missing.
|
||||||
|
- Do NOT use `"Comment on org/repo"` / `"Review on org/repo"` prefixes. Comments, reviews
|
||||||
|
and inline comments use the same `{repo}{#number}: {title}` title as their parent object.
|
||||||
|
- All event-specific emoji live in `src/formatter.ts` (via the `em()` helper), never in the
|
||||||
|
locale files. Emoji is controlled per group through the `Group.emoji` toggle (default true);
|
||||||
|
`showEmoji=false` must strip every emoji from titles, descriptions, fields and links.
|
||||||
|
- Milestone progress bars (🟢🟡🟠⬜) are data visualization and are exempt from the emoji toggle.
|
||||||
|
- Locale templates use a `{emoji}` placeholder immediately followed by the text (no space);
|
||||||
|
the formatter injects `em(...)` which carries the trailing space.
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|
@ -60,7 +74,7 @@ npm run lint # ESLint
|
||||||
|
|
||||||
- **Local dev**: `.dev.vars` (wrangler reads this for env bindings)
|
- **Local dev**: `.dev.vars` (wrangler reads this for env bindings)
|
||||||
- **Production**: `wrangler secret put <NAME>` for each secret
|
- **Production**: `wrangler secret put <NAME>` for each secret
|
||||||
- **Routes**: KV key `config:routes` (JSON array); 7 defaults on first boot
|
- **Routes**: KV key `config:routes` (JSON array, empty until configured)
|
||||||
- **KV namespace**: Required binding for token/state/config storage
|
- **KV namespace**: Required binding for token/state/config storage
|
||||||
|
|
||||||
## Deployment
|
## Deployment
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,10 @@
|
||||||
/>
|
/>
|
||||||
<div class="hint">{{ t("groupEditor.ownersHint") }}</div>
|
<div class="hint">{{ t("groupEditor.ownersHint") }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
<label class="inline">
|
||||||
|
<input v-model="form.emoji" type="checkbox" />
|
||||||
|
<span>{{ t("groupEditor.emoji") }}</span>
|
||||||
|
</label>
|
||||||
<div class="err">{{ formError }}</div>
|
<div class="err">{{ formError }}</div>
|
||||||
</form>
|
</form>
|
||||||
<div class="editor-foot">
|
<div class="editor-foot">
|
||||||
|
|
@ -91,6 +95,7 @@ const form = reactive({
|
||||||
name: "",
|
name: "",
|
||||||
adminIds: "",
|
adminIds: "",
|
||||||
owners: "",
|
owners: "",
|
||||||
|
emoji: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
function splitList(text: string): string[] {
|
function splitList(text: string): string[] {
|
||||||
|
|
@ -109,6 +114,7 @@ watch(
|
||||||
form.name = g?.name ?? "";
|
form.name = g?.name ?? "";
|
||||||
form.adminIds = (g?.adminIds ?? []).join(", ");
|
form.adminIds = (g?.adminIds ?? []).join(", ");
|
||||||
form.owners = (g?.owners ?? []).join(", ");
|
form.owners = (g?.owners ?? []).join(", ");
|
||||||
|
form.emoji = g?.emoji ?? true;
|
||||||
formError.value = "";
|
formError.value = "";
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -135,6 +141,7 @@ function save(): void {
|
||||||
name,
|
name,
|
||||||
adminIds: splitList(form.adminIds),
|
adminIds: splitList(form.adminIds),
|
||||||
owners: owners.length ? owners : undefined,
|
owners: owners.length ? owners : undefined,
|
||||||
|
emoji: form.emoji,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -88,6 +88,7 @@ const en: Dict = {
|
||||||
"groupEditor.ownersPlaceholder": "my-org, some-user",
|
"groupEditor.ownersPlaceholder": "my-org, some-user",
|
||||||
"groupEditor.ownersHint":
|
"groupEditor.ownersHint":
|
||||||
"Only webhook events from these orgs/users enter this group's routes. Leave empty for no restriction.",
|
"Only webhook events from these orgs/users enter this group's routes. Leave empty for no restriction.",
|
||||||
|
"groupEditor.emoji": "Show emojis in messages",
|
||||||
"groupEditor.cancel": "Cancel",
|
"groupEditor.cancel": "Cancel",
|
||||||
"groupEditor.save": "Save group",
|
"groupEditor.save": "Save group",
|
||||||
"groupEditor.errIdFormat": "ID must be a-z / 0-9 / dashes",
|
"groupEditor.errIdFormat": "ID must be a-z / 0-9 / dashes",
|
||||||
|
|
@ -194,6 +195,7 @@ const zh: Dict = {
|
||||||
"groupEditor.ownersPlaceholder": "my-org, some-user",
|
"groupEditor.ownersPlaceholder": "my-org, some-user",
|
||||||
"groupEditor.ownersHint":
|
"groupEditor.ownersHint":
|
||||||
"只有来自这些组织/用户的 webhook 事件才会进入本分组的路由。留空表示不限制。",
|
"只有来自这些组织/用户的 webhook 事件才会进入本分组的路由。留空表示不限制。",
|
||||||
|
"groupEditor.emoji": "消息中显示表情符号",
|
||||||
"groupEditor.cancel": "取消",
|
"groupEditor.cancel": "取消",
|
||||||
"groupEditor.save": "保存分组",
|
"groupEditor.save": "保存分组",
|
||||||
"groupEditor.errIdFormat": "ID 只能是 a-z / 0-9 / 短横线",
|
"groupEditor.errIdFormat": "ID 只能是 a-z / 0-9 / 短横线",
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ export interface Group {
|
||||||
name: string;
|
name: string;
|
||||||
adminIds: string[];
|
adminIds: string[];
|
||||||
owners?: string[];
|
owners?: string[];
|
||||||
|
emoji?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Me {
|
export interface Me {
|
||||||
|
|
|
||||||
185
src/__tests__/formatter.test.ts
Normal file
185
src/__tests__/formatter.test.ts
Normal file
|
|
@ -0,0 +1,185 @@
|
||||||
|
import { describe, it, expect } from "bun:test";
|
||||||
|
import { formatEvent } from "../formatter";
|
||||||
|
import type { Route, WebhookEvent } from "../types";
|
||||||
|
|
||||||
|
const route: Route = {
|
||||||
|
id: "test",
|
||||||
|
name: "Test",
|
||||||
|
enabled: true,
|
||||||
|
filters: [],
|
||||||
|
target: { channelId: "111" },
|
||||||
|
};
|
||||||
|
|
||||||
|
function event(ev: string, payload: Record<string, unknown>): WebhookEvent {
|
||||||
|
return { event: ev, payload };
|
||||||
|
}
|
||||||
|
|
||||||
|
const repo = { full_name: "acme/widget", html_url: "https://github.com/acme/widget" };
|
||||||
|
const sender = { login: "octocat" };
|
||||||
|
|
||||||
|
describe("message title spec", () => {
|
||||||
|
it("push title starts with the repo", () => {
|
||||||
|
const msg = formatEvent(
|
||||||
|
route,
|
||||||
|
event("push", {
|
||||||
|
ref: "refs/heads/main",
|
||||||
|
compare: "https://github.com/acme/widget/compare/abc...def",
|
||||||
|
created: false,
|
||||||
|
forced: false,
|
||||||
|
commits: [{ id: "abcd1234ef", message: "fix stuff", added: [], removed: [], modified: [] }],
|
||||||
|
repository: repo,
|
||||||
|
sender,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
expect(msg.embeds![0].title).toBe("acme/widget: Pushed 1 commit");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("pull_request title is repo#number: title", () => {
|
||||||
|
const msg = formatEvent(
|
||||||
|
route,
|
||||||
|
event("pull_request", {
|
||||||
|
action: "opened",
|
||||||
|
number: 7,
|
||||||
|
pull_request: {
|
||||||
|
title: "Add feature",
|
||||||
|
number: 7,
|
||||||
|
state: "open",
|
||||||
|
merged: false,
|
||||||
|
draft: false,
|
||||||
|
html_url: "https://github.com/acme/widget/pull/7",
|
||||||
|
body: null,
|
||||||
|
user: sender,
|
||||||
|
head: { ref: "feat", repo: { full_name: "acme/widget" } },
|
||||||
|
base: { ref: "main" },
|
||||||
|
},
|
||||||
|
repository: repo,
|
||||||
|
sender,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
expect(msg.embeds![0].title).toBe("acme/widget#7: Add feature");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("issue_comment title has no 'Comment on' prefix", () => {
|
||||||
|
const msg = formatEvent(
|
||||||
|
route,
|
||||||
|
event("issue_comment", {
|
||||||
|
action: "created",
|
||||||
|
issue: {
|
||||||
|
number: 3,
|
||||||
|
title: "Bug report",
|
||||||
|
html_url: "https://github.com/acme/widget/issues/3",
|
||||||
|
},
|
||||||
|
comment: {
|
||||||
|
body: "thanks",
|
||||||
|
html_url: "https://github.com/acme/widget/issues/3#issuecomment-1",
|
||||||
|
},
|
||||||
|
repository: repo,
|
||||||
|
sender,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
expect(msg.embeds![0].title).toBe("acme/widget#3: Bug report");
|
||||||
|
expect(msg.embeds![0].title).not.toContain("Comment on");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("workflow_run title is repo: name — conclusion", () => {
|
||||||
|
const msg = formatEvent(
|
||||||
|
route,
|
||||||
|
event("workflow_run", {
|
||||||
|
action: "completed",
|
||||||
|
workflow_run: {
|
||||||
|
name: "CI",
|
||||||
|
conclusion: "success",
|
||||||
|
html_url: "https://github.com/acme/widget/actions/runs/42",
|
||||||
|
head_branch: "main",
|
||||||
|
run_number: 42,
|
||||||
|
jobs: [{ name: "build", conclusion: "success" }],
|
||||||
|
},
|
||||||
|
repository: repo,
|
||||||
|
sender,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
expect(msg.embeds![0].title).toBe("acme/widget: CI — success");
|
||||||
|
expect(msg.embeds![0].fields![1].value).toBe("✅ build");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("unknown events fall back to repo: event: action", () => {
|
||||||
|
const msg = formatEvent(
|
||||||
|
route,
|
||||||
|
event("custom_event", { action: "ran", repository: repo, sender }),
|
||||||
|
);
|
||||||
|
expect(msg.embeds![0].title).toBe("acme/widget: custom_event: ran");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("group emoji toggle", () => {
|
||||||
|
it("includes emoji by default", () => {
|
||||||
|
const msg = formatEvent(
|
||||||
|
route,
|
||||||
|
event("repository", {
|
||||||
|
action: "created",
|
||||||
|
repository: { ...repo, visibility: "public", description: "a widget", fork: false },
|
||||||
|
sender,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
expect(msg.embeds![0].title).toBe("acme/widget: 📦 Repository Created");
|
||||||
|
expect(msg.embeds![0].description).toContain("🔗");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("strips emoji when showEmoji is false", () => {
|
||||||
|
const msg = formatEvent(
|
||||||
|
route,
|
||||||
|
event("repository", {
|
||||||
|
action: "created",
|
||||||
|
repository: { ...repo, visibility: "public", description: "a widget", fork: false },
|
||||||
|
sender,
|
||||||
|
}),
|
||||||
|
undefined,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
expect(msg.embeds![0].title).toBe("acme/widget: Repository Created");
|
||||||
|
expect(msg.embeds![0].title).not.toContain("📦");
|
||||||
|
expect(msg.embeds![0].description).not.toContain("🔗");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("strips emoji from push description when disabled", () => {
|
||||||
|
const msg = formatEvent(
|
||||||
|
route,
|
||||||
|
event("push", {
|
||||||
|
ref: "refs/heads/main",
|
||||||
|
compare: "https://github.com/acme/widget/compare/abc...def",
|
||||||
|
created: true,
|
||||||
|
forced: true,
|
||||||
|
commits: [{ id: "abcd1234ef", message: "fix stuff", added: [], removed: [], modified: [] }],
|
||||||
|
repository: repo,
|
||||||
|
sender,
|
||||||
|
}),
|
||||||
|
undefined,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
expect(msg.embeds![0].description).not.toContain("⚠️");
|
||||||
|
expect(msg.embeds![0].description).not.toContain("🆕");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("strips emoji from workflow_run status when disabled", () => {
|
||||||
|
const msg = formatEvent(
|
||||||
|
route,
|
||||||
|
event("workflow_run", {
|
||||||
|
action: "completed",
|
||||||
|
workflow_run: {
|
||||||
|
name: "CI",
|
||||||
|
conclusion: "failure",
|
||||||
|
html_url: "https://github.com/acme/widget/actions/runs/42",
|
||||||
|
head_branch: "main",
|
||||||
|
run_number: 42,
|
||||||
|
jobs: [{ name: "build", conclusion: "failure" }],
|
||||||
|
},
|
||||||
|
repository: repo,
|
||||||
|
sender,
|
||||||
|
}),
|
||||||
|
undefined,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
expect(msg.embeds![0].fields![0].value).toBe("failure");
|
||||||
|
expect(msg.embeds![0].fields![1].value).toBe("build");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -141,6 +141,9 @@ function validateGroups(
|
||||||
) {
|
) {
|
||||||
return { ok: false, error: `group "${g.id}".owners must be a list of strings` };
|
return { ok: false, error: `group "${g.id}".owners must be a list of strings` };
|
||||||
}
|
}
|
||||||
|
if (g.emoji !== undefined && typeof g.emoji !== "boolean") {
|
||||||
|
return { ok: false, error: `group "${g.id}".emoji must be a boolean` };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return { ok: true, groups: groups as Group[] };
|
return { ok: true, groups: groups as Group[] };
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,9 @@ export async function dispatchEvent(config: Config, event: WebhookEvent, env: En
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const tr = trMap.get(route.lang ?? "en")!;
|
const tr = trMap.get(route.lang ?? "en")!;
|
||||||
const message = formatEvent(route, event, tr);
|
const group = route.groupId ? groupById.get(route.groupId) : undefined;
|
||||||
|
const showEmoji = group?.emoji !== false;
|
||||||
|
const message = formatEvent(route, event, tr, showEmoji);
|
||||||
await sendToChannel(route.target.channelId, message, env, route.target.threadId);
|
await sendToChannel(route.target.channelId, message, env, route.target.threadId);
|
||||||
await recordSend(env.KV, {
|
await recordSend(env.KV, {
|
||||||
ts: Date.now(),
|
ts: Date.now(),
|
||||||
|
|
|
||||||
203
src/formatter.ts
203
src/formatter.ts
|
|
@ -65,12 +65,17 @@ const WORKFLOW_CONCLUSION_EMOJI: Record<string, string> = {
|
||||||
stale: "♻️",
|
stale: "♻️",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function emojiPrefix(emoji: string, show: boolean): string {
|
||||||
|
return show ? `${emoji} ` : "";
|
||||||
|
}
|
||||||
|
|
||||||
type T = (key: string, params?: Record<string, string | number>) => string;
|
type T = (key: string, params?: Record<string, string | number>) => string;
|
||||||
|
|
||||||
export function formatEvent(
|
export function formatEvent(
|
||||||
route: Route,
|
route: Route,
|
||||||
event: WebhookEvent,
|
event: WebhookEvent,
|
||||||
tr?: Translations,
|
tr?: Translations,
|
||||||
|
showEmoji = true,
|
||||||
): FormattedMessage {
|
): FormattedMessage {
|
||||||
const { event: eventType, payload } = event;
|
const { event: eventType, payload } = event;
|
||||||
const repo = (payload.repository as { full_name?: string })?.full_name;
|
const repo = (payload.repository as { full_name?: string })?.full_name;
|
||||||
|
|
@ -88,53 +93,53 @@ export function formatEvent(
|
||||||
|
|
||||||
switch (eventType) {
|
switch (eventType) {
|
||||||
case "push":
|
case "push":
|
||||||
return formatPush(payload, repo, author, t);
|
return formatPush(payload, repo, author, t, showEmoji);
|
||||||
case "pull_request":
|
case "pull_request":
|
||||||
return formatPullRequest(payload, repo, author, t);
|
return formatPullRequest(payload, repo, author, t, showEmoji);
|
||||||
case "pull_request_review":
|
case "pull_request_review":
|
||||||
return formatPullRequestReview(payload, repo, author, t);
|
return formatPullRequestReview(payload, repo, author, t, showEmoji);
|
||||||
case "pull_request_review_comment":
|
case "pull_request_review_comment":
|
||||||
return formatPullRequestReviewComment(payload, repo, author, t);
|
return formatPullRequestReviewComment(payload, repo, author, t, showEmoji);
|
||||||
case "issues":
|
case "issues":
|
||||||
return formatIssues(payload, repo, author, t);
|
return formatIssues(payload, repo, author, t, showEmoji);
|
||||||
case "issue_comment":
|
case "issue_comment":
|
||||||
return formatIssueComment(payload, repo, author, t);
|
return formatIssueComment(payload, repo, author, t, showEmoji);
|
||||||
case "workflow_run":
|
case "workflow_run":
|
||||||
return formatWorkflowRun(payload, repo, author, t);
|
return formatWorkflowRun(payload, repo, author, t, showEmoji);
|
||||||
case "release":
|
case "release":
|
||||||
return formatRelease(payload, repo, author, t);
|
return formatRelease(payload, repo, author, t, showEmoji);
|
||||||
case "create":
|
case "create":
|
||||||
return formatCreate(payload, repo, author, t);
|
return formatCreate(payload, repo, author, t, showEmoji);
|
||||||
case "delete":
|
case "delete":
|
||||||
return formatDelete(payload, repo, author, t);
|
return formatDelete(payload, repo, author, t, showEmoji);
|
||||||
case "star":
|
case "star":
|
||||||
return formatStar(payload, repo, repoUrl, author, t);
|
return formatStar(payload, repo, repoUrl, author, t, showEmoji);
|
||||||
case "fork":
|
case "fork":
|
||||||
return formatFork(payload, repo, repoUrl, author, t);
|
return formatFork(payload, repo, repoUrl, author, t, showEmoji);
|
||||||
case "check_run":
|
case "check_run":
|
||||||
return formatCheckRun(payload, repo, author, t);
|
return formatCheckRun(payload, repo, author, t, showEmoji);
|
||||||
case "commit_comment":
|
case "commit_comment":
|
||||||
return formatCommitComment(payload, repo, author, t);
|
return formatCommitComment(payload, repo, author, t, showEmoji);
|
||||||
case "deployment_status":
|
case "deployment_status":
|
||||||
return formatDeploymentStatus(payload, repo, author, t);
|
return formatDeploymentStatus(payload, repo, author, t, showEmoji);
|
||||||
case "member":
|
case "member":
|
||||||
return formatMember(payload, repo, author, t);
|
return formatMember(payload, repo, author, t, showEmoji);
|
||||||
case "label":
|
case "label":
|
||||||
return formatLabel(payload, repo, author, t);
|
return formatLabel(payload, repo, author, t, showEmoji);
|
||||||
case "milestone":
|
case "milestone":
|
||||||
return formatMilestone(payload, repo, author, t);
|
return formatMilestone(payload, repo, author, t, showEmoji);
|
||||||
case "discussion":
|
case "discussion":
|
||||||
return formatDiscussion(payload, repo, author, t);
|
return formatDiscussion(payload, repo, author, t, showEmoji);
|
||||||
case "discussion_comment":
|
case "discussion_comment":
|
||||||
return formatDiscussionComment(payload, repo, author, t);
|
return formatDiscussionComment(payload, repo, author, t, showEmoji);
|
||||||
case "repository":
|
case "repository":
|
||||||
return formatRepository(payload, repo, repoUrl, author, t);
|
return formatRepository(payload, repo, repoUrl, author, t, showEmoji);
|
||||||
case "code_scanning_alert":
|
case "code_scanning_alert":
|
||||||
return formatCodeScanningAlert(payload, repo, author, t);
|
return formatCodeScanningAlert(payload, repo, author, t, showEmoji);
|
||||||
case "dependabot_alert":
|
case "dependabot_alert":
|
||||||
return formatDependabotAlert(payload, repo, author, t);
|
return formatDependabotAlert(payload, repo, author, t, showEmoji);
|
||||||
default:
|
default:
|
||||||
return formatGeneric(eventType, payload, repo, author, t);
|
return formatGeneric(eventType, payload, repo, author, t, showEmoji);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -143,6 +148,7 @@ function formatPush(
|
||||||
repo: string | undefined,
|
repo: string | undefined,
|
||||||
author: { name: string; icon_url?: string; url?: string },
|
author: { name: string; icon_url?: string; url?: string },
|
||||||
t: T,
|
t: T,
|
||||||
|
showEmoji: boolean,
|
||||||
): FormattedMessage {
|
): FormattedMessage {
|
||||||
const ref = (payload.ref as string)?.replace("refs/heads/", "").replace("refs/tags/", "tag: ");
|
const ref = (payload.ref as string)?.replace("refs/heads/", "").replace("refs/tags/", "tag: ");
|
||||||
const commits = (payload.commits ?? []) as Array<{
|
const commits = (payload.commits ?? []) as Array<{
|
||||||
|
|
@ -157,14 +163,15 @@ function formatPush(
|
||||||
const compareUrl = payload.compare as string | undefined;
|
const compareUrl = payload.compare as string | undefined;
|
||||||
const forced = payload.forced as boolean | undefined;
|
const forced = payload.forced as boolean | undefined;
|
||||||
const created = payload.created as boolean | undefined;
|
const created = payload.created as boolean | undefined;
|
||||||
|
const em = (e: string): string => emojiPrefix(e, showEmoji);
|
||||||
|
|
||||||
const descriptionParts: string[] = [];
|
const descriptionParts: string[] = [];
|
||||||
|
|
||||||
if (forced) {
|
if (forced) {
|
||||||
descriptionParts.push(t("events.push.force_push"));
|
descriptionParts.push(em("⚠️") + t("events.push.force_push"));
|
||||||
}
|
}
|
||||||
if (created) {
|
if (created) {
|
||||||
descriptionParts.push(t("events.push.branch_created"));
|
descriptionParts.push(em("🆕") + t("events.push.branch_created"));
|
||||||
}
|
}
|
||||||
|
|
||||||
descriptionParts.push(
|
descriptionParts.push(
|
||||||
|
|
@ -246,6 +253,7 @@ function formatPullRequest(
|
||||||
repo: string | undefined,
|
repo: string | undefined,
|
||||||
author: { name: string; icon_url?: string; url?: string },
|
author: { name: string; icon_url?: string; url?: string },
|
||||||
t: T,
|
t: T,
|
||||||
|
showEmoji: boolean,
|
||||||
): FormattedMessage {
|
): FormattedMessage {
|
||||||
const action = (payload.action as string) ?? "opened";
|
const action = (payload.action as string) ?? "opened";
|
||||||
const pr = payload.pull_request as {
|
const pr = payload.pull_request as {
|
||||||
|
|
@ -282,9 +290,10 @@ function formatPullRequest(
|
||||||
: action === "opened"
|
: action === "opened"
|
||||||
? "🟢"
|
? "🟢"
|
||||||
: "🔵";
|
: "🔵";
|
||||||
|
const em = (e: string): string => emojiPrefix(e, showEmoji);
|
||||||
|
|
||||||
const descriptionParts: string[] = [];
|
const descriptionParts: string[] = [];
|
||||||
descriptionParts.push(t("events.pr.action_pr", { emoji: stateEmoji, action: al }));
|
descriptionParts.push(t("events.pr.action_pr", { emoji: em(stateEmoji), action: al }));
|
||||||
|
|
||||||
if (pr.body) {
|
if (pr.body) {
|
||||||
const truncated = pr.body.slice(0, 300);
|
const truncated = pr.body.slice(0, 300);
|
||||||
|
|
@ -363,6 +372,7 @@ function formatIssues(
|
||||||
repo: string | undefined,
|
repo: string | undefined,
|
||||||
author: { name: string; icon_url?: string; url?: string },
|
author: { name: string; icon_url?: string; url?: string },
|
||||||
t: T,
|
t: T,
|
||||||
|
showEmoji: boolean,
|
||||||
): FormattedMessage {
|
): FormattedMessage {
|
||||||
const action = (payload.action as string) ?? "opened";
|
const action = (payload.action as string) ?? "opened";
|
||||||
const issue = payload.issue as {
|
const issue = payload.issue as {
|
||||||
|
|
@ -387,9 +397,10 @@ function formatIssues(
|
||||||
|
|
||||||
const al = t("actions." + action) ?? action;
|
const al = t("actions." + action) ?? action;
|
||||||
const stateEmoji = action === "closed" ? "🔴" : action === "opened" ? "🟢" : "🟣";
|
const stateEmoji = action === "closed" ? "🔴" : action === "opened" ? "🟢" : "🟣";
|
||||||
|
const em = (e: string): string => emojiPrefix(e, showEmoji);
|
||||||
|
|
||||||
const descriptionParts: string[] = [];
|
const descriptionParts: string[] = [];
|
||||||
descriptionParts.push(t("events.issues.action_issue", { emoji: stateEmoji, action: al }));
|
descriptionParts.push(t("events.issues.action_issue", { emoji: em(stateEmoji), action: al }));
|
||||||
|
|
||||||
if (issue.body) {
|
if (issue.body) {
|
||||||
const truncated = issue.body.slice(0, 300);
|
const truncated = issue.body.slice(0, 300);
|
||||||
|
|
@ -447,6 +458,7 @@ function formatIssueComment(
|
||||||
repo: string | undefined,
|
repo: string | undefined,
|
||||||
author: { name: string; icon_url?: string; url?: string },
|
author: { name: string; icon_url?: string; url?: string },
|
||||||
t: T,
|
t: T,
|
||||||
|
showEmoji: boolean,
|
||||||
): FormattedMessage {
|
): FormattedMessage {
|
||||||
const action = (payload.action as string) ?? "created";
|
const action = (payload.action as string) ?? "created";
|
||||||
const issue = payload.issue as {
|
const issue = payload.issue as {
|
||||||
|
|
@ -460,6 +472,7 @@ function formatIssueComment(
|
||||||
};
|
};
|
||||||
|
|
||||||
const al = t("actions." + action) ?? action;
|
const al = t("actions." + action) ?? action;
|
||||||
|
const em = (e: string): string => emojiPrefix(e, showEmoji);
|
||||||
const commentBody = comment.body?.slice(0, 500) ?? "";
|
const commentBody = comment.body?.slice(0, 500) ?? "";
|
||||||
const truncated = comment.body && comment.body.length > 500;
|
const truncated = comment.body && comment.body.length > 500;
|
||||||
|
|
||||||
|
|
@ -467,14 +480,14 @@ function formatIssueComment(
|
||||||
embeds: [
|
embeds: [
|
||||||
{
|
{
|
||||||
author,
|
author,
|
||||||
title: t("events.issue_comment.comment_on", {
|
title: t("events.issue_comment.title", {
|
||||||
repo: repo ?? t("common.repository"),
|
repo: repo ?? t("common.repository"),
|
||||||
number: issue.number ?? "?",
|
number: issue.number ?? "?",
|
||||||
title: issue.title ?? t("common.untitled"),
|
title: issue.title ?? t("common.untitled"),
|
||||||
}),
|
}),
|
||||||
url: comment.html_url ?? issue.html_url,
|
url: comment.html_url ?? issue.html_url,
|
||||||
color: GITHUB_COLORS.issue_comment,
|
color: GITHUB_COLORS.issue_comment,
|
||||||
description: `${t("events.issue_comment.action_comment", { action: al })}\n\n> ${commentBody}${truncated ? "..." : ""}`,
|
description: `${t("events.issue_comment.action_comment", { emoji: em("💬"), action: al })}\n\n> ${commentBody}${truncated ? "..." : ""}`,
|
||||||
footer: { text: t("common.footer", { repo: repo ?? t("common.github") }) },
|
footer: { text: t("common.footer", { repo: repo ?? t("common.github") }) },
|
||||||
timestamp: new Date().toISOString(),
|
timestamp: new Date().toISOString(),
|
||||||
},
|
},
|
||||||
|
|
@ -487,6 +500,7 @@ function formatWorkflowRun(
|
||||||
repo: string | undefined,
|
repo: string | undefined,
|
||||||
author: { name: string; icon_url?: string; url?: string },
|
author: { name: string; icon_url?: string; url?: string },
|
||||||
t: T,
|
t: T,
|
||||||
|
showEmoji: boolean,
|
||||||
): FormattedMessage {
|
): FormattedMessage {
|
||||||
const workflow = payload.workflow_run as {
|
const workflow = payload.workflow_run as {
|
||||||
name?: string;
|
name?: string;
|
||||||
|
|
@ -502,6 +516,7 @@ function formatWorkflowRun(
|
||||||
|
|
||||||
const conclusion = workflow.conclusion ?? "pending";
|
const conclusion = workflow.conclusion ?? "pending";
|
||||||
const emoji = WORKFLOW_CONCLUSION_EMOJI[conclusion] ?? "⏳";
|
const emoji = WORKFLOW_CONCLUSION_EMOJI[conclusion] ?? "⏳";
|
||||||
|
const em = (e: string): string => emojiPrefix(e, showEmoji);
|
||||||
const colorKey =
|
const colorKey =
|
||||||
conclusion === "success"
|
conclusion === "success"
|
||||||
? "workflow_run_success"
|
? "workflow_run_success"
|
||||||
|
|
@ -513,13 +528,13 @@ function formatWorkflowRun(
|
||||||
|
|
||||||
fields.push({
|
fields.push({
|
||||||
name: t("fields.status"),
|
name: t("fields.status"),
|
||||||
value: `${emoji} ${conclusion}`,
|
value: `${em(emoji)}${conclusion}`,
|
||||||
inline: true,
|
inline: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (workflow.jobs?.length) {
|
if (workflow.jobs?.length) {
|
||||||
const jobLines = workflow.jobs.map(
|
const jobLines = workflow.jobs.map(
|
||||||
(j) => `${WORKFLOW_CONCLUSION_EMOJI[j.conclusion ?? ""] ?? "⏳"} ${j.name ?? ""}`,
|
(j) => `${em(WORKFLOW_CONCLUSION_EMOJI[j.conclusion ?? ""] ?? "⏳")}${j.name ?? ""}`,
|
||||||
);
|
);
|
||||||
fields.push({
|
fields.push({
|
||||||
name: t("fields.job"),
|
name: t("fields.job"),
|
||||||
|
|
@ -558,7 +573,11 @@ function formatWorkflowRun(
|
||||||
embeds: [
|
embeds: [
|
||||||
{
|
{
|
||||||
author,
|
author,
|
||||||
title: t("events.workflow_run.title", { name: workflow.name ?? "Workflow", conclusion }),
|
title: t("events.workflow_run.title", {
|
||||||
|
repo: repo ?? t("common.repository"),
|
||||||
|
name: workflow.name ?? "Workflow",
|
||||||
|
conclusion,
|
||||||
|
}),
|
||||||
url: workflow.html_url,
|
url: workflow.html_url,
|
||||||
color: GITHUB_COLORS[colorKey],
|
color: GITHUB_COLORS[colorKey],
|
||||||
fields,
|
fields,
|
||||||
|
|
@ -574,6 +593,7 @@ function formatRelease(
|
||||||
repo: string | undefined,
|
repo: string | undefined,
|
||||||
author: { name: string; icon_url?: string; url?: string },
|
author: { name: string; icon_url?: string; url?: string },
|
||||||
t: T,
|
t: T,
|
||||||
|
showEmoji: boolean,
|
||||||
): FormattedMessage {
|
): FormattedMessage {
|
||||||
const action = (payload.action as string) ?? "published";
|
const action = (payload.action as string) ?? "published";
|
||||||
const release = payload.release as {
|
const release = payload.release as {
|
||||||
|
|
@ -595,11 +615,12 @@ function formatRelease(
|
||||||
: "release_published";
|
: "release_published";
|
||||||
const al = t("actions." + action) ?? action;
|
const al = t("actions." + action) ?? action;
|
||||||
const emoji = action === "deleted" ? "🗑️" : isPrerelease ? "⚠️" : "🚀";
|
const emoji = action === "deleted" ? "🗑️" : isPrerelease ? "⚠️" : "🚀";
|
||||||
|
const em = (e: string): string => emojiPrefix(e, showEmoji);
|
||||||
|
|
||||||
const descriptionParts: string[] = [];
|
const descriptionParts: string[] = [];
|
||||||
descriptionParts.push(
|
descriptionParts.push(
|
||||||
t("events.release.action_release", {
|
t("events.release.action_release", {
|
||||||
emoji,
|
emoji: em(emoji),
|
||||||
action: al,
|
action: al,
|
||||||
tag: release.tag_name ?? t("common.unknown"),
|
tag: release.tag_name ?? t("common.unknown"),
|
||||||
}),
|
}),
|
||||||
|
|
@ -615,8 +636,8 @@ function formatRelease(
|
||||||
{
|
{
|
||||||
author,
|
author,
|
||||||
title: t("events.release.title", {
|
title: t("events.release.title", {
|
||||||
name: release.name ?? release.tag_name ?? "Release",
|
|
||||||
repo: repo ?? t("common.repository"),
|
repo: repo ?? t("common.repository"),
|
||||||
|
name: release.name ?? release.tag_name ?? "Release",
|
||||||
}),
|
}),
|
||||||
url: release.html_url,
|
url: release.html_url,
|
||||||
color: GITHUB_COLORS[colorKey],
|
color: GITHUB_COLORS[colorKey],
|
||||||
|
|
@ -633,11 +654,13 @@ function formatCreate(
|
||||||
repo: string | undefined,
|
repo: string | undefined,
|
||||||
author: { name: string; icon_url?: string; url?: string },
|
author: { name: string; icon_url?: string; url?: string },
|
||||||
t: T,
|
t: T,
|
||||||
|
showEmoji: boolean,
|
||||||
): FormattedMessage {
|
): FormattedMessage {
|
||||||
const refType = (payload.ref_type as string) ?? "branch";
|
const refType = (payload.ref_type as string) ?? "branch";
|
||||||
const ref = (payload.ref as string) ?? t("common.unknown");
|
const ref = (payload.ref as string) ?? t("common.unknown");
|
||||||
|
|
||||||
const emoji = refType === "tag" ? "🏷️" : "🌿";
|
const emoji = refType === "tag" ? "🏷️" : "🌿";
|
||||||
|
const em = (e: string): string => emojiPrefix(e, showEmoji);
|
||||||
|
|
||||||
const fields: Array<{ name: string; value: string; inline?: boolean }> = [];
|
const fields: Array<{ name: string; value: string; inline?: boolean }> = [];
|
||||||
|
|
||||||
|
|
@ -666,10 +689,10 @@ function formatCreate(
|
||||||
{
|
{
|
||||||
author,
|
author,
|
||||||
title: t("events.create.title", {
|
title: t("events.create.title", {
|
||||||
emoji,
|
repo: repo ?? t("common.repository"),
|
||||||
|
emoji: em(emoji),
|
||||||
type: refType,
|
type: refType,
|
||||||
ref,
|
ref,
|
||||||
repo: repo ?? t("common.repository"),
|
|
||||||
}),
|
}),
|
||||||
color: GITHUB_COLORS.create,
|
color: GITHUB_COLORS.create,
|
||||||
fields,
|
fields,
|
||||||
|
|
@ -685,21 +708,23 @@ function formatDelete(
|
||||||
repo: string | undefined,
|
repo: string | undefined,
|
||||||
author: { name: string; icon_url?: string; url?: string },
|
author: { name: string; icon_url?: string; url?: string },
|
||||||
t: T,
|
t: T,
|
||||||
|
showEmoji: boolean,
|
||||||
): FormattedMessage {
|
): FormattedMessage {
|
||||||
const refType = (payload.ref_type as string) ?? "branch";
|
const refType = (payload.ref_type as string) ?? "branch";
|
||||||
const ref = (payload.ref as string) ?? t("common.unknown");
|
const ref = (payload.ref as string) ?? t("common.unknown");
|
||||||
|
|
||||||
const emoji = refType === "tag" ? "🏷️" : "🌿";
|
const emoji = refType === "tag" ? "🏷️" : "🌿";
|
||||||
|
const em = (e: string): string => emojiPrefix(e, showEmoji);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
embeds: [
|
embeds: [
|
||||||
{
|
{
|
||||||
author,
|
author,
|
||||||
title: t("events.delete.title", {
|
title: t("events.delete.title", {
|
||||||
emoji,
|
repo: repo ?? t("common.repository"),
|
||||||
|
emoji: em(emoji),
|
||||||
type: refType,
|
type: refType,
|
||||||
ref,
|
ref,
|
||||||
repo: repo ?? t("common.repository"),
|
|
||||||
}),
|
}),
|
||||||
color: GITHUB_COLORS.delete,
|
color: GITHUB_COLORS.delete,
|
||||||
footer: { text: t("common.footer", { repo: repo ?? t("common.github") }) },
|
footer: { text: t("common.footer", { repo: repo ?? t("common.github") }) },
|
||||||
|
|
@ -715,15 +740,21 @@ function formatStar(
|
||||||
repoUrl: string | undefined,
|
repoUrl: string | undefined,
|
||||||
author: { name: string; icon_url?: string; url?: string },
|
author: { name: string; icon_url?: string; url?: string },
|
||||||
t: T,
|
t: T,
|
||||||
|
showEmoji: boolean,
|
||||||
): FormattedMessage {
|
): FormattedMessage {
|
||||||
const action = (payload.action as string) ?? "created";
|
const action = (payload.action as string) ?? "created";
|
||||||
const actionLabel = action === "created" ? t("events.star.starred") : t("events.star.unstarred");
|
const actionLabel = action === "created" ? t("events.star.starred") : t("events.star.unstarred");
|
||||||
|
const em = (e: string): string => emojiPrefix(e, showEmoji);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
embeds: [
|
embeds: [
|
||||||
{
|
{
|
||||||
author,
|
author,
|
||||||
title: `${actionLabel} ${repo ?? t("common.repository")}`,
|
title: t("events.star.title", {
|
||||||
|
repo: repo ?? t("common.repository"),
|
||||||
|
emoji: em(action === "created" ? "⭐" : "💫"),
|
||||||
|
label: actionLabel,
|
||||||
|
}),
|
||||||
url: repoUrl,
|
url: repoUrl,
|
||||||
color: GITHUB_COLORS.star,
|
color: GITHUB_COLORS.star,
|
||||||
footer: { text: t("common.footer", { repo: repo ?? t("common.github") }) },
|
footer: { text: t("common.footer", { repo: repo ?? t("common.github") }) },
|
||||||
|
|
@ -739,8 +770,10 @@ function formatFork(
|
||||||
repoUrl: string | undefined,
|
repoUrl: string | undefined,
|
||||||
author: { name: string; icon_url?: string; url?: string },
|
author: { name: string; icon_url?: string; url?: string },
|
||||||
t: T,
|
t: T,
|
||||||
|
showEmoji: boolean,
|
||||||
): FormattedMessage {
|
): FormattedMessage {
|
||||||
const forkee = payload.forkee as { full_name?: string; html_url?: string } | undefined;
|
const forkee = payload.forkee as { full_name?: string; html_url?: string } | undefined;
|
||||||
|
const em = (e: string): string => emojiPrefix(e, showEmoji);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
embeds: [
|
embeds: [
|
||||||
|
|
@ -748,6 +781,7 @@ function formatFork(
|
||||||
author,
|
author,
|
||||||
title: t("events.fork.title", {
|
title: t("events.fork.title", {
|
||||||
repo: repo ?? t("common.repository"),
|
repo: repo ?? t("common.repository"),
|
||||||
|
emoji: em("🍴"),
|
||||||
forkee: forkee?.full_name ?? t("common.unknown"),
|
forkee: forkee?.full_name ?? t("common.unknown"),
|
||||||
}),
|
}),
|
||||||
url: forkee?.html_url ?? repoUrl,
|
url: forkee?.html_url ?? repoUrl,
|
||||||
|
|
@ -764,6 +798,7 @@ function formatCheckRun(
|
||||||
repo: string | undefined,
|
repo: string | undefined,
|
||||||
author: { name: string; icon_url?: string; url?: string },
|
author: { name: string; icon_url?: string; url?: string },
|
||||||
t: T,
|
t: T,
|
||||||
|
showEmoji: boolean,
|
||||||
): FormattedMessage {
|
): FormattedMessage {
|
||||||
const checkRun = payload.check_run as {
|
const checkRun = payload.check_run as {
|
||||||
name?: string;
|
name?: string;
|
||||||
|
|
@ -775,6 +810,7 @@ function formatCheckRun(
|
||||||
|
|
||||||
const conclusion = checkRun.conclusion ?? "pending";
|
const conclusion = checkRun.conclusion ?? "pending";
|
||||||
const emoji = WORKFLOW_CONCLUSION_EMOJI[conclusion] ?? "⏳";
|
const emoji = WORKFLOW_CONCLUSION_EMOJI[conclusion] ?? "⏳";
|
||||||
|
const em = (e: string): string => emojiPrefix(e, showEmoji);
|
||||||
const colorKey =
|
const colorKey =
|
||||||
conclusion === "success"
|
conclusion === "success"
|
||||||
? "check_run_success"
|
? "check_run_success"
|
||||||
|
|
@ -786,7 +822,7 @@ function formatCheckRun(
|
||||||
|
|
||||||
fields.push({
|
fields.push({
|
||||||
name: t("fields.status"),
|
name: t("fields.status"),
|
||||||
value: `${emoji} ${conclusion}`,
|
value: `${em(emoji)}${conclusion}`,
|
||||||
inline: true,
|
inline: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -802,7 +838,11 @@ function formatCheckRun(
|
||||||
embeds: [
|
embeds: [
|
||||||
{
|
{
|
||||||
author,
|
author,
|
||||||
title: t("events.check_run.title", { name: checkRun.name ?? "Check Run", conclusion }),
|
title: t("events.check_run.title", {
|
||||||
|
repo: repo ?? t("common.repository"),
|
||||||
|
name: checkRun.name ?? "Check Run",
|
||||||
|
conclusion,
|
||||||
|
}),
|
||||||
url: checkRun.html_url,
|
url: checkRun.html_url,
|
||||||
color: GITHUB_COLORS[colorKey],
|
color: GITHUB_COLORS[colorKey],
|
||||||
fields,
|
fields,
|
||||||
|
|
@ -818,6 +858,7 @@ function formatPullRequestReview(
|
||||||
repo: string | undefined,
|
repo: string | undefined,
|
||||||
author: { name: string; icon_url?: string; url?: string },
|
author: { name: string; icon_url?: string; url?: string },
|
||||||
t: T,
|
t: T,
|
||||||
|
showEmoji: boolean,
|
||||||
): FormattedMessage {
|
): FormattedMessage {
|
||||||
const action = (payload.action as string) ?? "submitted";
|
const action = (payload.action as string) ?? "submitted";
|
||||||
const review = payload.review as {
|
const review = payload.review as {
|
||||||
|
|
@ -841,8 +882,9 @@ function formatPullRequestReview(
|
||||||
|
|
||||||
const stateEmoji = state === "approved" ? "✅" : state === "changes_requested" ? "🔴" : "💬";
|
const stateEmoji = state === "approved" ? "✅" : state === "changes_requested" ? "🔴" : "💬";
|
||||||
const al = t("actions." + action) ?? state;
|
const al = t("actions." + action) ?? state;
|
||||||
|
const em = (e: string): string => emojiPrefix(e, showEmoji);
|
||||||
const descriptionParts: string[] = [];
|
const descriptionParts: string[] = [];
|
||||||
descriptionParts.push(t("events.pr_review.action_review", { emoji: stateEmoji, action: al }));
|
descriptionParts.push(t("events.pr_review.action_review", { emoji: em(stateEmoji), action: al }));
|
||||||
|
|
||||||
if (review.body) {
|
if (review.body) {
|
||||||
const truncated = review.body.slice(0, 500);
|
const truncated = review.body.slice(0, 500);
|
||||||
|
|
@ -873,6 +915,7 @@ function formatPullRequestReviewComment(
|
||||||
repo: string | undefined,
|
repo: string | undefined,
|
||||||
author: { name: string; icon_url?: string; url?: string },
|
author: { name: string; icon_url?: string; url?: string },
|
||||||
t: T,
|
t: T,
|
||||||
|
showEmoji: boolean,
|
||||||
): FormattedMessage {
|
): FormattedMessage {
|
||||||
const action = (payload.action as string) ?? "created";
|
const action = (payload.action as string) ?? "created";
|
||||||
const comment = payload.comment as {
|
const comment = payload.comment as {
|
||||||
|
|
@ -887,6 +930,7 @@ function formatPullRequestReviewComment(
|
||||||
};
|
};
|
||||||
|
|
||||||
const al = t("actions." + action) ?? action;
|
const al = t("actions." + action) ?? action;
|
||||||
|
const em = (e: string): string => emojiPrefix(e, showEmoji);
|
||||||
const commentBody = comment.body?.slice(0, 400) ?? "";
|
const commentBody = comment.body?.slice(0, 400) ?? "";
|
||||||
const truncated = comment.body && comment.body.length > 400;
|
const truncated = comment.body && comment.body.length > 400;
|
||||||
|
|
||||||
|
|
@ -911,10 +955,11 @@ function formatPullRequestReviewComment(
|
||||||
title: t("events.pr_review_comment.title", {
|
title: t("events.pr_review_comment.title", {
|
||||||
repo: repo ?? t("common.repository"),
|
repo: repo ?? t("common.repository"),
|
||||||
number: pr.number ?? "?",
|
number: pr.number ?? "?",
|
||||||
|
title: pr.title ?? t("common.untitled"),
|
||||||
}),
|
}),
|
||||||
url: comment.html_url,
|
url: comment.html_url,
|
||||||
color: GITHUB_COLORS.pull_request_review_commented,
|
color: GITHUB_COLORS.pull_request_review_commented,
|
||||||
description: `${t("events.pr_review_comment.action_inline", { action: al })}\n\n> ${commentBody}${truncated ? "..." : ""}`,
|
description: `${t("events.pr_review_comment.action_inline", { emoji: em("💬"), action: al })}\n\n> ${commentBody}${truncated ? "..." : ""}`,
|
||||||
fields: fields.length > 0 ? fields : undefined,
|
fields: fields.length > 0 ? fields : undefined,
|
||||||
footer: { text: t("common.footer", { repo: repo ?? t("common.github") }) },
|
footer: { text: t("common.footer", { repo: repo ?? t("common.github") }) },
|
||||||
timestamp: new Date().toISOString(),
|
timestamp: new Date().toISOString(),
|
||||||
|
|
@ -928,6 +973,7 @@ function formatCommitComment(
|
||||||
repo: string | undefined,
|
repo: string | undefined,
|
||||||
author: { name: string; icon_url?: string; url?: string },
|
author: { name: string; icon_url?: string; url?: string },
|
||||||
t: T,
|
t: T,
|
||||||
|
showEmoji: boolean,
|
||||||
): FormattedMessage {
|
): FormattedMessage {
|
||||||
const action = (payload.action as string) ?? "created";
|
const action = (payload.action as string) ?? "created";
|
||||||
const comment = payload.comment as {
|
const comment = payload.comment as {
|
||||||
|
|
@ -937,6 +983,7 @@ function formatCommitComment(
|
||||||
};
|
};
|
||||||
|
|
||||||
const al = t("actions." + action) ?? action;
|
const al = t("actions." + action) ?? action;
|
||||||
|
const em = (e: string): string => emojiPrefix(e, showEmoji);
|
||||||
const commentBody = comment.body?.slice(0, 500) ?? "";
|
const commentBody = comment.body?.slice(0, 500) ?? "";
|
||||||
const truncated = comment.body && comment.body.length > 500;
|
const truncated = comment.body && comment.body.length > 500;
|
||||||
const shortSha = comment.commit_id?.slice(0, 7) ?? "???????";
|
const shortSha = comment.commit_id?.slice(0, 7) ?? "???????";
|
||||||
|
|
@ -956,12 +1003,12 @@ function formatCommitComment(
|
||||||
{
|
{
|
||||||
author,
|
author,
|
||||||
title: t("events.commit_comment.title", {
|
title: t("events.commit_comment.title", {
|
||||||
sha: shortSha,
|
|
||||||
repo: repo ?? t("common.repository"),
|
repo: repo ?? t("common.repository"),
|
||||||
|
sha: shortSha,
|
||||||
}),
|
}),
|
||||||
url: comment.html_url,
|
url: comment.html_url,
|
||||||
color: GITHUB_COLORS.commit_comment,
|
color: GITHUB_COLORS.commit_comment,
|
||||||
description: `${t("events.commit_comment.action_comment", { action: al })}\n\n> ${commentBody}${truncated ? "..." : ""}`,
|
description: `${t("events.commit_comment.action_comment", { emoji: em("💬"), action: al })}\n\n> ${commentBody}${truncated ? "..." : ""}`,
|
||||||
fields: fields.length > 0 ? fields : undefined,
|
fields: fields.length > 0 ? fields : undefined,
|
||||||
footer: { text: t("common.footer", { repo: repo ?? t("common.github") }) },
|
footer: { text: t("common.footer", { repo: repo ?? t("common.github") }) },
|
||||||
timestamp: new Date().toISOString(),
|
timestamp: new Date().toISOString(),
|
||||||
|
|
@ -975,6 +1022,7 @@ function formatDeploymentStatus(
|
||||||
repo: string | undefined,
|
repo: string | undefined,
|
||||||
author: { name: string; icon_url?: string; url?: string },
|
author: { name: string; icon_url?: string; url?: string },
|
||||||
t: T,
|
t: T,
|
||||||
|
showEmoji: boolean,
|
||||||
): FormattedMessage {
|
): FormattedMessage {
|
||||||
const status = payload.deployment_status as {
|
const status = payload.deployment_status as {
|
||||||
state?: string;
|
state?: string;
|
||||||
|
|
@ -996,6 +1044,7 @@ function formatDeploymentStatus(
|
||||||
? "deployment_failure"
|
? "deployment_failure"
|
||||||
: "deployment_pending";
|
: "deployment_pending";
|
||||||
const emoji = state === "success" ? "✅" : state === "failure" ? "❌" : "⏳";
|
const emoji = state === "success" ? "✅" : state === "failure" ? "❌" : "⏳";
|
||||||
|
const em = (e: string): string => emojiPrefix(e, showEmoji);
|
||||||
const env = status.environment ?? deployment.environment ?? t("common.unknown");
|
const env = status.environment ?? deployment.environment ?? t("common.unknown");
|
||||||
const shortSha = deployment.sha?.slice(0, 7) ?? "???????";
|
const shortSha = deployment.sha?.slice(0, 7) ?? "???????";
|
||||||
|
|
||||||
|
|
@ -1003,7 +1052,7 @@ function formatDeploymentStatus(
|
||||||
|
|
||||||
fields.push({
|
fields.push({
|
||||||
name: t("fields.status"),
|
name: t("fields.status"),
|
||||||
value: `${emoji} ${state}`,
|
value: `${em(emoji)}${state}`,
|
||||||
inline: true,
|
inline: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -1049,7 +1098,7 @@ function formatDeploymentStatus(
|
||||||
embeds: [
|
embeds: [
|
||||||
{
|
{
|
||||||
author,
|
author,
|
||||||
title: t("events.deployment.title", { env, state }),
|
title: t("events.deployment.title", { repo: repo ?? t("common.repository"), env, state }),
|
||||||
color: GITHUB_COLORS[colorKey],
|
color: GITHUB_COLORS[colorKey],
|
||||||
fields,
|
fields,
|
||||||
footer: { text: t("common.footer", { repo: repo ?? t("common.github") }) },
|
footer: { text: t("common.footer", { repo: repo ?? t("common.github") }) },
|
||||||
|
|
@ -1064,19 +1113,26 @@ function formatMember(
|
||||||
repo: string | undefined,
|
repo: string | undefined,
|
||||||
author: { name: string; icon_url?: string; url?: string },
|
author: { name: string; icon_url?: string; url?: string },
|
||||||
t: T,
|
t: T,
|
||||||
|
showEmoji: boolean,
|
||||||
): FormattedMessage {
|
): FormattedMessage {
|
||||||
const action = (payload.action as string) ?? "added";
|
const action = (payload.action as string) ?? "added";
|
||||||
const member = payload.member as { login?: string } | undefined;
|
const member = payload.member as { login?: string } | undefined;
|
||||||
|
|
||||||
const al = t("actions." + action) ?? action;
|
const al = t("actions." + action) ?? action;
|
||||||
const emoji = action === "added" ? "➕" : action === "removed" ? "➖" : "👤";
|
const emoji = action === "added" ? "➕" : action === "removed" ? "➖" : "👤";
|
||||||
|
const em = (e: string): string => emojiPrefix(e, showEmoji);
|
||||||
const memberName = member?.login ?? t("common.unknown");
|
const memberName = member?.login ?? t("common.unknown");
|
||||||
|
|
||||||
return {
|
return {
|
||||||
embeds: [
|
embeds: [
|
||||||
{
|
{
|
||||||
author,
|
author,
|
||||||
title: t("events.member.title", { emoji, action: al, name: memberName }),
|
title: t("events.member.title", {
|
||||||
|
repo: repo ?? t("common.repository"),
|
||||||
|
emoji: em(emoji),
|
||||||
|
action: al,
|
||||||
|
name: memberName,
|
||||||
|
}),
|
||||||
color: action === "added" ? GITHUB_COLORS.member_added : GITHUB_COLORS.member_removed,
|
color: action === "added" ? GITHUB_COLORS.member_added : GITHUB_COLORS.member_removed,
|
||||||
footer: { text: t("common.footer", { repo: repo ?? t("common.github") }) },
|
footer: { text: t("common.footer", { repo: repo ?? t("common.github") }) },
|
||||||
timestamp: new Date().toISOString(),
|
timestamp: new Date().toISOString(),
|
||||||
|
|
@ -1090,6 +1146,7 @@ function formatLabel(
|
||||||
repo: string | undefined,
|
repo: string | undefined,
|
||||||
author: { name: string; icon_url?: string; url?: string },
|
author: { name: string; icon_url?: string; url?: string },
|
||||||
t: T,
|
t: T,
|
||||||
|
showEmoji: boolean,
|
||||||
): FormattedMessage {
|
): FormattedMessage {
|
||||||
const action = (payload.action as string) ?? "created";
|
const action = (payload.action as string) ?? "created";
|
||||||
const label = payload.label as {
|
const label = payload.label as {
|
||||||
|
|
@ -1100,6 +1157,7 @@ function formatLabel(
|
||||||
|
|
||||||
const al = t("actions." + action) ?? action;
|
const al = t("actions." + action) ?? action;
|
||||||
const emoji = action === "deleted" ? "🗑️" : action === "edited" ? "✏️" : "🏷️";
|
const emoji = action === "deleted" ? "🗑️" : action === "edited" ? "✏️" : "🏷️";
|
||||||
|
const em = (e: string): string => emojiPrefix(e, showEmoji);
|
||||||
|
|
||||||
const fields: Array<{ name: string; value: string; inline?: boolean }> = [];
|
const fields: Array<{ name: string; value: string; inline?: boolean }> = [];
|
||||||
|
|
||||||
|
|
@ -1132,7 +1190,8 @@ function formatLabel(
|
||||||
{
|
{
|
||||||
author,
|
author,
|
||||||
title: t("events.label.title", {
|
title: t("events.label.title", {
|
||||||
emoji,
|
repo: repo ?? t("common.repository"),
|
||||||
|
emoji: em(emoji),
|
||||||
action: al,
|
action: al,
|
||||||
name: label.name ?? t("common.unknown"),
|
name: label.name ?? t("common.unknown"),
|
||||||
}),
|
}),
|
||||||
|
|
@ -1150,6 +1209,7 @@ function formatMilestone(
|
||||||
repo: string | undefined,
|
repo: string | undefined,
|
||||||
author: { name: string; icon_url?: string; url?: string },
|
author: { name: string; icon_url?: string; url?: string },
|
||||||
t: T,
|
t: T,
|
||||||
|
showEmoji: boolean,
|
||||||
): FormattedMessage {
|
): FormattedMessage {
|
||||||
const action = (payload.action as string) ?? "created";
|
const action = (payload.action as string) ?? "created";
|
||||||
const milestone = payload.milestone as {
|
const milestone = payload.milestone as {
|
||||||
|
|
@ -1164,6 +1224,7 @@ function formatMilestone(
|
||||||
|
|
||||||
const al = t("actions." + action) ?? action;
|
const al = t("actions." + action) ?? action;
|
||||||
const stateEmoji = milestone.state === "closed" ? "✅" : "🔵";
|
const stateEmoji = milestone.state === "closed" ? "✅" : "🔵";
|
||||||
|
const em = (e: string): string => emojiPrefix(e, showEmoji);
|
||||||
|
|
||||||
const fields: Array<{ name: string; value: string; inline?: boolean }> = [];
|
const fields: Array<{ name: string; value: string; inline?: boolean }> = [];
|
||||||
|
|
||||||
|
|
@ -1207,7 +1268,8 @@ function formatMilestone(
|
||||||
{
|
{
|
||||||
author,
|
author,
|
||||||
title: t("events.milestone.title", {
|
title: t("events.milestone.title", {
|
||||||
emoji: stateEmoji,
|
repo: repo ?? t("common.repository"),
|
||||||
|
emoji: em(stateEmoji),
|
||||||
action: al,
|
action: al,
|
||||||
title: milestone.title ?? t("common.unknown"),
|
title: milestone.title ?? t("common.unknown"),
|
||||||
}),
|
}),
|
||||||
|
|
@ -1229,6 +1291,7 @@ function formatDiscussion(
|
||||||
repo: string | undefined,
|
repo: string | undefined,
|
||||||
author: { name: string; icon_url?: string; url?: string },
|
author: { name: string; icon_url?: string; url?: string },
|
||||||
t: T,
|
t: T,
|
||||||
|
showEmoji: boolean,
|
||||||
): FormattedMessage {
|
): FormattedMessage {
|
||||||
const action = (payload.action as string) ?? "created";
|
const action = (payload.action as string) ?? "created";
|
||||||
const discussion = payload.discussion as {
|
const discussion = payload.discussion as {
|
||||||
|
|
@ -1239,6 +1302,7 @@ function formatDiscussion(
|
||||||
};
|
};
|
||||||
|
|
||||||
const al = t("actions." + action) ?? action;
|
const al = t("actions." + action) ?? action;
|
||||||
|
const em = (e: string): string => emojiPrefix(e, showEmoji);
|
||||||
const stateEmoji =
|
const stateEmoji =
|
||||||
action === "answered"
|
action === "answered"
|
||||||
? "✅"
|
? "✅"
|
||||||
|
|
@ -1257,7 +1321,7 @@ function formatDiscussion(
|
||||||
{
|
{
|
||||||
author,
|
author,
|
||||||
title: t("events.discussion.title", {
|
title: t("events.discussion.title", {
|
||||||
emoji: stateEmoji,
|
repo: repo ?? t("common.repository"),
|
||||||
number: discussion.number ?? "?",
|
number: discussion.number ?? "?",
|
||||||
title: discussion.title ?? t("common.untitled"),
|
title: discussion.title ?? t("common.untitled"),
|
||||||
}),
|
}),
|
||||||
|
|
@ -1267,6 +1331,7 @@ function formatDiscussion(
|
||||||
? GITHUB_COLORS.discussion_answered
|
? GITHUB_COLORS.discussion_answered
|
||||||
: GITHUB_COLORS.discussion_created,
|
: GITHUB_COLORS.discussion_created,
|
||||||
description: t("events.discussion.action_discussion", {
|
description: t("events.discussion.action_discussion", {
|
||||||
|
emoji: em(stateEmoji),
|
||||||
action: al,
|
action: al,
|
||||||
category: category ? ` in **${category}**` : "",
|
category: category ? ` in **${category}**` : "",
|
||||||
}),
|
}),
|
||||||
|
|
@ -1282,6 +1347,7 @@ function formatDiscussionComment(
|
||||||
repo: string | undefined,
|
repo: string | undefined,
|
||||||
author: { name: string; icon_url?: string; url?: string },
|
author: { name: string; icon_url?: string; url?: string },
|
||||||
t: T,
|
t: T,
|
||||||
|
showEmoji: boolean,
|
||||||
): FormattedMessage {
|
): FormattedMessage {
|
||||||
const action = (payload.action as string) ?? "created";
|
const action = (payload.action as string) ?? "created";
|
||||||
const comment = payload.comment as {
|
const comment = payload.comment as {
|
||||||
|
|
@ -1294,6 +1360,7 @@ function formatDiscussionComment(
|
||||||
};
|
};
|
||||||
|
|
||||||
const al = t("actions." + action) ?? action;
|
const al = t("actions." + action) ?? action;
|
||||||
|
const em = (e: string): string => emojiPrefix(e, showEmoji);
|
||||||
const commentBody = comment.body?.slice(0, 500) ?? "";
|
const commentBody = comment.body?.slice(0, 500) ?? "";
|
||||||
const truncated = comment.body && comment.body.length > 500;
|
const truncated = comment.body && comment.body.length > 500;
|
||||||
|
|
||||||
|
|
@ -1301,13 +1368,14 @@ function formatDiscussionComment(
|
||||||
embeds: [
|
embeds: [
|
||||||
{
|
{
|
||||||
author,
|
author,
|
||||||
title: t("events.discussion_comment.comment_on", {
|
title: t("events.discussion_comment.title", {
|
||||||
|
repo: repo ?? t("common.repository"),
|
||||||
number: discussion.number ?? "?",
|
number: discussion.number ?? "?",
|
||||||
title: discussion.title ?? t("common.untitled"),
|
title: discussion.title ?? t("common.untitled"),
|
||||||
}),
|
}),
|
||||||
url: comment.html_url,
|
url: comment.html_url,
|
||||||
color: GITHUB_COLORS.discussion_comment,
|
color: GITHUB_COLORS.discussion_comment,
|
||||||
description: `${t("events.discussion_comment.action_comment", { action: al })}\n\n> ${commentBody}${truncated ? "..." : ""}`,
|
description: `${t("events.discussion_comment.action_comment", { emoji: em("💬"), action: al })}\n\n> ${commentBody}${truncated ? "..." : ""}`,
|
||||||
footer: { text: t("common.footer", { repo: repo ?? t("common.github") }) },
|
footer: { text: t("common.footer", { repo: repo ?? t("common.github") }) },
|
||||||
timestamp: new Date().toISOString(),
|
timestamp: new Date().toISOString(),
|
||||||
},
|
},
|
||||||
|
|
@ -1321,10 +1389,12 @@ function formatRepository(
|
||||||
repoUrl: string | undefined,
|
repoUrl: string | undefined,
|
||||||
author: { name: string; icon_url?: string; url?: string },
|
author: { name: string; icon_url?: string; url?: string },
|
||||||
t: T,
|
t: T,
|
||||||
|
showEmoji: boolean,
|
||||||
): FormattedMessage {
|
): FormattedMessage {
|
||||||
const action = (payload.action as string) ?? "created";
|
const action = (payload.action as string) ?? "created";
|
||||||
|
|
||||||
const al = t("actions." + action) ?? action;
|
const al = t("actions." + action) ?? action;
|
||||||
|
const em = (e: string): string => emojiPrefix(e, showEmoji);
|
||||||
|
|
||||||
const fields: Array<{ name: string; value: string; inline?: boolean }> = [];
|
const fields: Array<{ name: string; value: string; inline?: boolean }> = [];
|
||||||
|
|
||||||
|
|
@ -1380,7 +1450,7 @@ function formatRepository(
|
||||||
|
|
||||||
const descriptionParts: string[] = [];
|
const descriptionParts: string[] = [];
|
||||||
if (isCreateOrVisibility && repoUrl) {
|
if (isCreateOrVisibility && repoUrl) {
|
||||||
descriptionParts.push(`[${t("events.repository.open")}](${repoUrl})`);
|
descriptionParts.push(`[${em("🔗")}${t("events.repository.open")}](${repoUrl})`);
|
||||||
}
|
}
|
||||||
if (isCreateOrVisibility && repoData.description) {
|
if (isCreateOrVisibility && repoData.description) {
|
||||||
descriptionParts.push(`> ${repoData.description}`);
|
descriptionParts.push(`> ${repoData.description}`);
|
||||||
|
|
@ -1390,7 +1460,11 @@ function formatRepository(
|
||||||
embeds: [
|
embeds: [
|
||||||
{
|
{
|
||||||
author,
|
author,
|
||||||
title: t("events.repository.title", { action: al, repo: repo ?? t("common.repository") }),
|
title: t("events.repository.title", {
|
||||||
|
repo: repo ?? t("common.repository"),
|
||||||
|
emoji: em("📦"),
|
||||||
|
action: al,
|
||||||
|
}),
|
||||||
url: repoUrl,
|
url: repoUrl,
|
||||||
color: GITHUB_COLORS.repository,
|
color: GITHUB_COLORS.repository,
|
||||||
description: descriptionParts.length > 0 ? descriptionParts.join("\n") : undefined,
|
description: descriptionParts.length > 0 ? descriptionParts.join("\n") : undefined,
|
||||||
|
|
@ -1407,6 +1481,7 @@ function formatCodeScanningAlert(
|
||||||
repo: string | undefined,
|
repo: string | undefined,
|
||||||
author: { name: string; icon_url?: string; url?: string },
|
author: { name: string; icon_url?: string; url?: string },
|
||||||
t: T,
|
t: T,
|
||||||
|
showEmoji: boolean,
|
||||||
): FormattedMessage {
|
): FormattedMessage {
|
||||||
const action = (payload.action as string) ?? "created";
|
const action = (payload.action as string) ?? "created";
|
||||||
const alert = payload.alert as {
|
const alert = payload.alert as {
|
||||||
|
|
@ -1434,12 +1509,13 @@ function formatCodeScanningAlert(
|
||||||
? "🟡"
|
? "🟡"
|
||||||
: "⚪";
|
: "⚪";
|
||||||
const al = t("actions." + action) ?? action;
|
const al = t("actions." + action) ?? action;
|
||||||
|
const em = (e: string): string => emojiPrefix(e, showEmoji);
|
||||||
|
|
||||||
const fields: Array<{ name: string; value: string; inline?: boolean }> = [];
|
const fields: Array<{ name: string; value: string; inline?: boolean }> = [];
|
||||||
|
|
||||||
fields.push({
|
fields.push({
|
||||||
name: t("fields.severity"),
|
name: t("fields.severity"),
|
||||||
value: `${severityEmoji} ${severity}`,
|
value: `${em(severityEmoji)}${severity}`,
|
||||||
inline: true,
|
inline: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -1471,7 +1547,10 @@ function formatCodeScanningAlert(
|
||||||
embeds: [
|
embeds: [
|
||||||
{
|
{
|
||||||
author,
|
author,
|
||||||
title: t("events.code_scanning.title", { action: al }),
|
title: t("events.code_scanning.title", {
|
||||||
|
repo: repo ?? t("common.repository"),
|
||||||
|
action: al,
|
||||||
|
}),
|
||||||
color: GITHUB_COLORS[colorKey],
|
color: GITHUB_COLORS[colorKey],
|
||||||
fields,
|
fields,
|
||||||
footer: { text: t("common.footer", { repo: repo ?? t("common.github") }) },
|
footer: { text: t("common.footer", { repo: repo ?? t("common.github") }) },
|
||||||
|
|
@ -1486,6 +1565,7 @@ function formatDependabotAlert(
|
||||||
repo: string | undefined,
|
repo: string | undefined,
|
||||||
author: { name: string; icon_url?: string; url?: string },
|
author: { name: string; icon_url?: string; url?: string },
|
||||||
t: T,
|
t: T,
|
||||||
|
showEmoji: boolean,
|
||||||
): FormattedMessage {
|
): FormattedMessage {
|
||||||
const action = (payload.action as string) ?? "created";
|
const action = (payload.action as string) ?? "created";
|
||||||
const alert = payload.alert as {
|
const alert = payload.alert as {
|
||||||
|
|
@ -1519,12 +1599,13 @@ function formatDependabotAlert(
|
||||||
? "🟡"
|
? "🟡"
|
||||||
: "⚪";
|
: "⚪";
|
||||||
const al = t("actions." + action) ?? action;
|
const al = t("actions." + action) ?? action;
|
||||||
|
const em = (e: string): string => emojiPrefix(e, showEmoji);
|
||||||
|
|
||||||
const fields: Array<{ name: string; value: string; inline?: boolean }> = [];
|
const fields: Array<{ name: string; value: string; inline?: boolean }> = [];
|
||||||
|
|
||||||
fields.push({
|
fields.push({
|
||||||
name: t("fields.severity"),
|
name: t("fields.severity"),
|
||||||
value: `${severityEmoji} ${severity}`,
|
value: `${em(severityEmoji)}${severity}`,
|
||||||
inline: true,
|
inline: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -1558,7 +1639,7 @@ function formatDependabotAlert(
|
||||||
embeds: [
|
embeds: [
|
||||||
{
|
{
|
||||||
author,
|
author,
|
||||||
title: t("events.dependabot.title", { action: al }),
|
title: t("events.dependabot.title", { repo: repo ?? t("common.repository"), action: al }),
|
||||||
url: alert.html_url,
|
url: alert.html_url,
|
||||||
color: GITHUB_COLORS[colorKey],
|
color: GITHUB_COLORS[colorKey],
|
||||||
fields,
|
fields,
|
||||||
|
|
@ -1575,12 +1656,14 @@ function formatGeneric(
|
||||||
repo: string | undefined,
|
repo: string | undefined,
|
||||||
author: { name: string; icon_url?: string; url?: string },
|
author: { name: string; icon_url?: string; url?: string },
|
||||||
t: T,
|
t: T,
|
||||||
|
_showEmoji: boolean,
|
||||||
): FormattedMessage {
|
): FormattedMessage {
|
||||||
return {
|
return {
|
||||||
embeds: [
|
embeds: [
|
||||||
{
|
{
|
||||||
author,
|
author,
|
||||||
title: t("events.generic.title", {
|
title: t("events.generic.title", {
|
||||||
|
repo: repo ?? t("common.repository"),
|
||||||
event: eventType,
|
event: eventType,
|
||||||
action: payload.action ? `: ${payload.action}` : "",
|
action: payload.action ? `: ${payload.action}` : "",
|
||||||
}),
|
}),
|
||||||
|
|
|
||||||
|
|
@ -83,86 +83,87 @@ export const en = {
|
||||||
},
|
},
|
||||||
events: {
|
events: {
|
||||||
push: {
|
push: {
|
||||||
force_push: "⚠️ **Force push**",
|
force_push: "**Force push**",
|
||||||
branch_created: "🆕 Branch created",
|
branch_created: "Branch created",
|
||||||
commits_pushed: "**{count}** commit{s} pushed to `{ref}`",
|
commits_pushed: "**{count}** commit{s} pushed to `{ref}`",
|
||||||
view_comparison: "[View comparison]({url})",
|
view_comparison: "[View comparison]({url})",
|
||||||
added: "+{count} added",
|
added: "+{count} added",
|
||||||
removed: "-{count} removed",
|
removed: "-{count} removed",
|
||||||
modified: "~{count} modified",
|
modified: "~{count} modified",
|
||||||
title: "Pushed {count} commit{s} to {repo}",
|
title: "{repo}: Pushed {count} commit{s}",
|
||||||
},
|
},
|
||||||
pr: {
|
pr: {
|
||||||
action_pr: "{emoji} **{action}** pull request",
|
action_pr: "{emoji}**{action}** pull request",
|
||||||
title: "{repo}#{number}: {title}",
|
title: "{repo}#{number}: {title}",
|
||||||
},
|
},
|
||||||
issues: {
|
issues: {
|
||||||
action_issue: "{emoji} **{action}** issue",
|
action_issue: "{emoji}**{action}** issue",
|
||||||
title: "{repo}#{number}: {title}",
|
title: "{repo}#{number}: {title}",
|
||||||
},
|
},
|
||||||
issue_comment: {
|
issue_comment: {
|
||||||
comment_on: "Comment on {repo}#{number}: {title}",
|
title: "{repo}#{number}: {title}",
|
||||||
action_comment: "💬 **{action}** comment",
|
action_comment: "{emoji}**{action}** comment",
|
||||||
},
|
},
|
||||||
workflow_run: {
|
workflow_run: {
|
||||||
title: "{name} — {conclusion}",
|
title: "{repo}: {name} — {conclusion}",
|
||||||
},
|
},
|
||||||
release: {
|
release: {
|
||||||
action_release: "{emoji} **{action}** release `{tag}`",
|
action_release: "{emoji}**{action}** release `{tag}`",
|
||||||
title: "{name} — {repo}",
|
title: "{repo}: {name}",
|
||||||
},
|
},
|
||||||
create: {
|
create: {
|
||||||
title: "{emoji} Created {type} `{ref}` in {repo}",
|
title: "{repo}: {emoji}Created {type} `{ref}`",
|
||||||
},
|
},
|
||||||
delete: {
|
delete: {
|
||||||
title: "{emoji} Deleted {type} `{ref}` in {repo}",
|
title: "{repo}: {emoji}Deleted {type} `{ref}`",
|
||||||
},
|
},
|
||||||
star: {
|
star: {
|
||||||
starred: "⭐ starred",
|
starred: "Starred",
|
||||||
unstarred: "💫 unstarred",
|
unstarred: "Unstarred",
|
||||||
|
title: "{repo}: {emoji}{label}",
|
||||||
},
|
},
|
||||||
fork: {
|
fork: {
|
||||||
title: "🍴 Forked {repo} to {forkee}",
|
title: "{repo}: {emoji}Forked to {forkee}",
|
||||||
},
|
},
|
||||||
check_run: {
|
check_run: {
|
||||||
title: "{name} — {conclusion}",
|
title: "{repo}: {name} — {conclusion}",
|
||||||
},
|
},
|
||||||
pr_review: {
|
pr_review: {
|
||||||
action_review: "{emoji} **{action}** review",
|
action_review: "{emoji}**{action}** review",
|
||||||
title: "Review on {repo}#{number}: {title}",
|
title: "{repo}#{number}: {title}",
|
||||||
},
|
},
|
||||||
pr_review_comment: {
|
pr_review_comment: {
|
||||||
action_inline: "💬 **{action}** inline comment",
|
action_inline: "{emoji}**{action}** inline comment",
|
||||||
title: "Review comment on {repo}#{number}",
|
title: "{repo}#{number}: {title}",
|
||||||
line: " (line {position})",
|
line: " (line {position})",
|
||||||
},
|
},
|
||||||
commit_comment: {
|
commit_comment: {
|
||||||
action_comment: "💬 **{action}**",
|
action_comment: "{emoji}**{action}**",
|
||||||
title: "Comment on commit `{sha}` in {repo}",
|
title: "{repo}: Comment on commit `{sha}`",
|
||||||
},
|
},
|
||||||
deployment: {
|
deployment: {
|
||||||
title: "Deployment to `{env}` — {state}",
|
title: "{repo}: Deployment to `{env}` — {state}",
|
||||||
},
|
},
|
||||||
member: {
|
member: {
|
||||||
title: "{emoji} {action} collaborator: {name}",
|
title: "{repo}: {emoji}{action} collaborator: {name}",
|
||||||
},
|
},
|
||||||
label: {
|
label: {
|
||||||
title: "{emoji} Label {action}: {name}",
|
title: "{repo}: {emoji}Label {action}: {name}",
|
||||||
},
|
},
|
||||||
milestone: {
|
milestone: {
|
||||||
title: "{emoji} Milestone {action}: {title}",
|
title: "{repo}: {emoji}Milestone {action}: {title}",
|
||||||
},
|
},
|
||||||
discussion: {
|
discussion: {
|
||||||
title: "{emoji} Discussion #{number}: {title}",
|
title: "{repo}#{number}: {title}",
|
||||||
action_discussion: "{action} discussion{category}",
|
action_discussion: "{emoji}{action} discussion{category}",
|
||||||
},
|
},
|
||||||
discussion_comment: {
|
discussion_comment: {
|
||||||
comment_on: "Comment on Discussion #{number}: {title}",
|
title: "{repo}#{number}: {title}",
|
||||||
action_comment: "💬 **{action}** comment",
|
action_comment: "{emoji}**{action}** comment",
|
||||||
},
|
},
|
||||||
repository: {
|
repository: {
|
||||||
title: "📦 Repository {action}: {repo}",
|
title: "{repo}: {emoji}Repository {action}",
|
||||||
open: "🔗 Open repository",
|
open: "Open repository",
|
||||||
public: "public",
|
public: "public",
|
||||||
private: "private",
|
private: "private",
|
||||||
internal: "internal",
|
internal: "internal",
|
||||||
|
|
@ -170,13 +171,13 @@ export const en = {
|
||||||
visibility: "Visibility",
|
visibility: "Visibility",
|
||||||
},
|
},
|
||||||
code_scanning: {
|
code_scanning: {
|
||||||
title: "🔍 Code Scanning: {action}",
|
title: "{repo}: Code Scanning {action}",
|
||||||
},
|
},
|
||||||
dependabot: {
|
dependabot: {
|
||||||
title: "🛡️ Dependabot: {action}",
|
title: "{repo}: Dependabot {action}",
|
||||||
},
|
},
|
||||||
generic: {
|
generic: {
|
||||||
title: "{event}{action}",
|
title: "{repo}: {event}{action}",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -83,86 +83,87 @@ export const zh = {
|
||||||
},
|
},
|
||||||
events: {
|
events: {
|
||||||
push: {
|
push: {
|
||||||
force_push: "⚠️ **强制推送**",
|
force_push: "**强制推送**",
|
||||||
branch_created: "🆕 分支已创建",
|
branch_created: "分支已创建",
|
||||||
commits_pushed: "**{count}** 个提交已推送到 `{ref}`",
|
commits_pushed: "**{count}** 个提交已推送到 `{ref}`",
|
||||||
view_comparison: "[查看比较]({url})",
|
view_comparison: "[查看比较]({url})",
|
||||||
added: "+{count} 新增",
|
added: "+{count} 新增",
|
||||||
removed: "-{count} 删除",
|
removed: "-{count} 删除",
|
||||||
modified: "~{count} 修改",
|
modified: "~{count} 修改",
|
||||||
title: "推送了 {count} 个提交到 {repo}",
|
title: "{repo}: 推送了 {count} 个提交",
|
||||||
},
|
},
|
||||||
pr: {
|
pr: {
|
||||||
action_pr: "{emoji} **{action}** 拉取请求",
|
action_pr: "{emoji}**{action}** 拉取请求",
|
||||||
title: "{repo}#{number}: {title}",
|
title: "{repo}#{number}: {title}",
|
||||||
},
|
},
|
||||||
issues: {
|
issues: {
|
||||||
action_issue: "{emoji} **{action}** 议题",
|
action_issue: "{emoji}**{action}** 议题",
|
||||||
title: "{repo}#{number}: {title}",
|
title: "{repo}#{number}: {title}",
|
||||||
},
|
},
|
||||||
issue_comment: {
|
issue_comment: {
|
||||||
comment_on: "{repo}#{number} 的评论: {title}",
|
title: "{repo}#{number}: {title}",
|
||||||
action_comment: "💬 **{action}** 评论",
|
action_comment: "{emoji}**{action}** 评论",
|
||||||
},
|
},
|
||||||
workflow_run: {
|
workflow_run: {
|
||||||
title: "{name} — {conclusion}",
|
title: "{repo}: {name} — {conclusion}",
|
||||||
},
|
},
|
||||||
release: {
|
release: {
|
||||||
action_release: "{emoji} **{action}** 发布 `{tag}`",
|
action_release: "{emoji}**{action}** 发布 `{tag}`",
|
||||||
title: "{name} — {repo}",
|
title: "{repo}: {name}",
|
||||||
},
|
},
|
||||||
create: {
|
create: {
|
||||||
title: "{emoji} 已创建{type} `{ref}` 于 {repo}",
|
title: "{repo}: {emoji}已创建{type} `{ref}`",
|
||||||
},
|
},
|
||||||
delete: {
|
delete: {
|
||||||
title: "{emoji} 已删除{type} `{ref}` 于 {repo}",
|
title: "{repo}: {emoji}已删除{type} `{ref}`",
|
||||||
},
|
},
|
||||||
star: {
|
star: {
|
||||||
starred: "⭐ 已加星标",
|
starred: "已加星标",
|
||||||
unstarred: "💫 已取消星标",
|
unstarred: "已取消星标",
|
||||||
|
title: "{repo}: {emoji}{label}",
|
||||||
},
|
},
|
||||||
fork: {
|
fork: {
|
||||||
title: "🍴 已将 {repo} 复刻到 {forkee}",
|
title: "{repo}: {emoji}复刻到 {forkee}",
|
||||||
},
|
},
|
||||||
check_run: {
|
check_run: {
|
||||||
title: "{name} — {conclusion}",
|
title: "{repo}: {name} — {conclusion}",
|
||||||
},
|
},
|
||||||
pr_review: {
|
pr_review: {
|
||||||
action_review: "{emoji} **{action}** 审查",
|
action_review: "{emoji}**{action}** 审查",
|
||||||
title: "{repo}#{number} 的审查: {title}",
|
title: "{repo}#{number}: {title}",
|
||||||
},
|
},
|
||||||
pr_review_comment: {
|
pr_review_comment: {
|
||||||
action_inline: "💬 **{action}** 行内评论",
|
action_inline: "{emoji}**{action}** 行内评论",
|
||||||
title: "{repo}#{number} 的审查评论",
|
title: "{repo}#{number}: {title}",
|
||||||
line: " (第 {position} 行)",
|
line: " (第 {position} 行)",
|
||||||
},
|
},
|
||||||
commit_comment: {
|
commit_comment: {
|
||||||
action_comment: "💬 **{action}**",
|
action_comment: "{emoji}**{action}**",
|
||||||
title: "{repo} 中提交 `{sha}` 的评论",
|
title: "{repo}: 提交 `{sha}` 的评论",
|
||||||
},
|
},
|
||||||
deployment: {
|
deployment: {
|
||||||
title: "部署到 `{env}` — {state}",
|
title: "{repo}: 部署到 `{env}` — {state}",
|
||||||
},
|
},
|
||||||
member: {
|
member: {
|
||||||
title: "{emoji} {action} 协作者: {name}",
|
title: "{repo}: {emoji}{action} 协作者: {name}",
|
||||||
},
|
},
|
||||||
label: {
|
label: {
|
||||||
title: "{emoji} 标签 {action}: {name}",
|
title: "{repo}: {emoji}标签 {action}: {name}",
|
||||||
},
|
},
|
||||||
milestone: {
|
milestone: {
|
||||||
title: "{emoji} 里程碑 {action}: {title}",
|
title: "{repo}: {emoji}里程碑 {action}: {title}",
|
||||||
},
|
},
|
||||||
discussion: {
|
discussion: {
|
||||||
title: "{emoji} 讨论 #{number}: {title}",
|
title: "{repo}#{number}: {title}",
|
||||||
action_discussion: "{action} 讨论{category}",
|
action_discussion: "{emoji}{action} 讨论{category}",
|
||||||
},
|
},
|
||||||
discussion_comment: {
|
discussion_comment: {
|
||||||
comment_on: "讨论 #{number} 的评论: {title}",
|
title: "{repo}#{number}: {title}",
|
||||||
action_comment: "💬 **{action}** 评论",
|
action_comment: "{emoji}**{action}** 评论",
|
||||||
},
|
},
|
||||||
repository: {
|
repository: {
|
||||||
title: "📦 仓库 {action}: {repo}",
|
title: "{repo}: {emoji}仓库 {action}",
|
||||||
open: "🔗 打开仓库",
|
open: "打开仓库",
|
||||||
public: "公开",
|
public: "公开",
|
||||||
private: "私有",
|
private: "私有",
|
||||||
internal: "内部",
|
internal: "内部",
|
||||||
|
|
@ -170,13 +171,13 @@ export const zh = {
|
||||||
visibility: "可见性",
|
visibility: "可见性",
|
||||||
},
|
},
|
||||||
code_scanning: {
|
code_scanning: {
|
||||||
title: "🔍 代码扫描: {action}",
|
title: "{repo}: 代码扫描 {action}",
|
||||||
},
|
},
|
||||||
dependabot: {
|
dependabot: {
|
||||||
title: "🛡️ Dependabot: {action}",
|
title: "{repo}: Dependabot {action}",
|
||||||
},
|
},
|
||||||
generic: {
|
generic: {
|
||||||
title: "{event}{action}",
|
title: "{repo}: {event}{action}",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,11 @@ export interface Group {
|
||||||
* Only super admins may edit this field.
|
* Only super admins may edit this field.
|
||||||
*/
|
*/
|
||||||
owners?: string[];
|
owners?: string[];
|
||||||
|
/**
|
||||||
|
* Whether to include emoji in messages sent through this group's routes.
|
||||||
|
* Defaults to true when omitted.
|
||||||
|
*/
|
||||||
|
emoji?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Filter {
|
export interface Filter {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue