Skip to content

Commit 97d0096

Browse files
committed
[add] GitHub actions of Lark notification
Signed-off-by: TechQuery <shiy2008@gmail.com>
1 parent c617c09 commit 97d0096

File tree

4 files changed

+232
-1
lines changed

4 files changed

+232
-1
lines changed

.github/scripts/deno.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"nodeModulesDir": "none"
3+
}
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
import { components } from 'npm:@octokit/openapi-types';
2+
import { stdin } from 'npm:zx';
3+
4+
type GitHubSchema = components['schemas'];
5+
6+
type GitHubUser = GitHubSchema['simple-user'];
7+
8+
interface GitHubAction
9+
extends Record<'event_name' | 'actor' | 'server_url' | 'repository', string> {
10+
action?: string;
11+
ref?: string;
12+
ref_name?: string;
13+
event: {
14+
head_commit?: GitHubSchema['git-commit'];
15+
issue?: GitHubSchema['webhook-issues-opened']['issue'];
16+
pull_request?: GitHubSchema['pull-request'];
17+
discussion?: GitHubSchema['discussion'];
18+
comment?: GitHubSchema['issue-comment'];
19+
release?: GitHubSchema['release'];
20+
};
21+
}
22+
23+
// Helper functions
24+
const getActionText = (action?: string) =>
25+
action === 'closed' ? '关闭' : action?.includes('open') ? '打开' : '编辑';
26+
27+
const createLink = (href: string, text = href) => ({ tag: 'a', href, text });
28+
29+
const createText = (text: string) => ({ tag: 'text', text });
30+
31+
// create user link
32+
const createUserLink = (user: GitHubUser) =>
33+
user ? createLink(user.html_url, user.login) : createText('无');
34+
35+
const createContentItem = (label: string, value?: string | { tag: string; text: string }) =>
36+
[
37+
createText(label),
38+
typeof value === 'string' ? createText(value || '无') : value || createText('无'),
39+
] as [object, object];
40+
41+
type EventHandler = (
42+
event: GitHubAction,
43+
actionText: string,
44+
) => {
45+
title: string;
46+
content: [object, object][];
47+
};
48+
49+
// Event handlers
50+
const eventHandlers: Record<string, EventHandler> = {
51+
push: ({ event: { head_commit }, ref, ref_name, server_url, repository, actor }) => ({
52+
title: 'GitHub 代码提交',
53+
content: [
54+
[createText('提交链接:'), createLink(head_commit!.url)],
55+
[createText('代码分支:'), createLink(`${server_url}/${repository}/tree/${ref_name}`, ref)],
56+
[createText('提交作者:'), createLink(`${server_url}/${actor}`, actor)],
57+
[createText('提交信息:'), createText(head_commit!.message)],
58+
],
59+
}),
60+
61+
issues: ({ event: { issue } }, actionText) => ({
62+
title: `GitHub issue ${actionText}${issue?.title}`,
63+
content: [
64+
[createText('链接:'), createLink(issue!.html_url)],
65+
[createText('作者:'), createLink(issue!.user!.html_url!, issue!.user!.login)],
66+
[
67+
createText('指派:'),
68+
issue?.assignee
69+
? createLink(issue.assignee.html_url!, issue.assignee.login)
70+
: createText('无'),
71+
],
72+
[createText('标签:'), createText(issue?.labels?.map(({ name }) => name).join(', ') || '无')],
73+
[createText('里程碑:'), createText(issue?.milestone?.title || '无')],
74+
[createText('描述:'), createText(issue?.body || '无')],
75+
],
76+
}),
77+
78+
pull_request: ({ event: { pull_request } }, actionText) => ({
79+
title: `GitHub PR ${actionText}${pull_request?.title}`,
80+
content: [
81+
[createText('链接:'), createLink(pull_request!.html_url)],
82+
[createText('作者:'), createLink(pull_request!.user.html_url, pull_request!.user.login)],
83+
[
84+
createText('指派:'),
85+
pull_request?.assignee
86+
? createLink(pull_request.assignee.html_url, pull_request.assignee.login)
87+
: createText('无'),
88+
],
89+
[
90+
createText('标签:'),
91+
createText(pull_request?.labels?.map(({ name }) => name).join(', ') || '无'),
92+
],
93+
[createText('里程碑:'), createText(pull_request?.milestone?.title || '无')],
94+
[createText('描述:'), createText(pull_request?.body || '无')],
95+
],
96+
}),
97+
98+
discussion: ({ event: { discussion } }, actionText) => ({
99+
title: `GitHub 讨论 ${actionText}${discussion?.title || '无'}`,
100+
content: [
101+
createContentItem('链接:', discussion?.html_url),
102+
createContentItem('作者:', createUserLink(discussion!.user as GitHubUser)),
103+
createContentItem('描述:', discussion?.body || '无'),
104+
],
105+
}),
106+
107+
issue_comment: ({ event: { comment, issue } }) => ({
108+
title: `GitHub issue 评论:${issue?.title || '未知 issue'}`,
109+
content: [
110+
createContentItem('链接:', comment?.html_url),
111+
createContentItem('作者:', createUserLink(comment!.user!)),
112+
createContentItem('描述:', comment?.body || '无'),
113+
],
114+
}),
115+
116+
discussion_comment: ({ event: { comment, discussion } }) => ({
117+
title: `GitHub 讨论评论:${discussion?.title || '无'}`,
118+
content: [
119+
createContentItem('链接:', comment?.html_url),
120+
createContentItem('作者:', createUserLink(comment!.user!)),
121+
createContentItem('描述:', comment?.body || '无'),
122+
],
123+
}),
124+
125+
release: ({ event: { release } }) => ({
126+
title: `GitHub Release 发布:${release!.name || release!.tag_name}`,
127+
content: [
128+
createContentItem('链接:', release!.html_url),
129+
createContentItem('作者:', createUserLink(release!.author)),
130+
createContentItem('描述:', release!.body!),
131+
],
132+
}),
133+
};
134+
135+
// Main processor
136+
const processEvent = (event: GitHubAction) => {
137+
const { event_name, action } = event;
138+
const actionText = getActionText(action);
139+
const handler = eventHandlers[event_name];
140+
141+
if (!handler) throw new Error(`No handler found for event: ${event_name}`);
142+
143+
try {
144+
return handler(event, actionText);
145+
} catch (cause) {
146+
throw new Error(`Error processing ${event_name} event: ${(cause as Error).message}`, { cause });
147+
}
148+
};
149+
150+
// Main execution:Processing GitHub Events and Outputting Results
151+
const event = JSON.parse((await stdin()) || '{}') as GitHubAction;
152+
const zh_cn = processEvent(event);
153+
154+
if (zh_cn) console.log(JSON.stringify({ post: { zh_cn } }));
155+
else throw new Error(`Unsupported ${event.event_name} event & ${event.action} action`);
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
name: Lark notification
2+
3+
# https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows
4+
on:
5+
issues:
6+
pull_request:
7+
discussion:
8+
issue_comment:
9+
discussion_comment:
10+
release:
11+
types:
12+
- published
13+
14+
jobs:
15+
send-Lark-message:
16+
runs-on: ubuntu-latest
17+
steps:
18+
- uses: actions/checkout@v4
19+
20+
- uses: denoland/setup-deno@v2
21+
with:
22+
deno-version: v2.x
23+
24+
- name: Event Message serialization
25+
id: message
26+
run: |
27+
YAML=$(echo '${{ toJSON(github) }}' | deno --allow-all .github/scripts/transform-message.ts)
28+
{
29+
echo 'content<<EOF'
30+
echo $YAML
31+
echo 'EOF'
32+
} >> $GITHUB_OUTPUT
33+
34+
- name: Send message to Lark
35+
if: ${{ contains(steps.message.outputs.content, ':') }}
36+
uses: foxundermoon/feishu-action@v2
37+
with:
38+
url: ${{ secrets.LARK_CHATBOT_HOOK_URL }}
39+
msg_type: post
40+
content: |
41+
${{ steps.message.outputs.content }}

.github/workflows/main.yml

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ jobs:
1616
- uses: actions/checkout@v4
1717

1818
- name: Deploy to Vercel
19+
id: vercel-deployment
1920
uses: amondnet/vercel-action@v25
2021
if: ${{ env.VERCEL_TOKEN && env.VERCEL_ORG_ID && env.VERCEL_PROJECT_ID }}
2122
with:
@@ -24,4 +25,35 @@ jobs:
2425
vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
2526
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
2627
working-directory: ./
27-
vercel-args: ${{ github.ref == 'refs/heads/main' && ' --prod' || '' }}
28+
vercel-args: ${{ github.ref == 'refs/heads/main' && ' --prod' || ''}}
29+
30+
- name: Lark notification
31+
uses: foxundermoon/feishu-action@v2
32+
with:
33+
url: ${{ secrets.LARK_CHATBOT_HOOK_URL }}
34+
msg_type: post
35+
content: |
36+
post:
37+
zh_cn:
38+
title: Vercel 预览环境
39+
content:
40+
- - tag: text
41+
text: Git 仓库:
42+
- tag: a
43+
text: ${{ github.server_url }}/${{ github.repository }}
44+
href: ${{ github.server_url }}/${{ github.repository }}
45+
- - tag: text
46+
text: 代码分支:
47+
- tag: a
48+
text: ${{ github.ref }}
49+
href: ${{ github.server_url }}/${{ github.repository }}/tree/${{ github.ref_name }}
50+
- - tag: text
51+
text: 提交作者:
52+
- tag: a
53+
text: ${{ github.actor }}
54+
href: ${{ github.server_url }}/${{ github.actor }}
55+
- - tag: text
56+
text: 预览链接:
57+
- tag: a
58+
text: ${{ steps.vercel-deployment.outputs.preview-url }}
59+
href: ${{ steps.vercel-deployment.outputs.preview-url }}

0 commit comments

Comments
 (0)