前言

为了优化开发体验, 设想的是小伙伴每次提交 PR 的时候, 能够推送消息到钉钉群, 提醒大家帮忙 Review, Github 提供
丰富的 web hooks 可以做这件事

为什么不用 Web Hooks

点击钉钉 -> 群设置 -> 智能群助手 添加自定义机器人

点击 Setting -> Webhooks 配置 event 为 pull_request 即可




配置好机器人后, 一切正常, 但是会有两个小问题

  1. 不能 @所有人
  2. pull request 的钩子 不能精确到 pr 打开的时候才提醒,所以在 pr 打开, 更新, 有评论, 关闭 等的时候都会收到提醒, 太频繁了,体验不是很好, 但是我发现 Github Action 可以做到这一点!

Github Action 和 普通 npm 包的区别

1. 文件构成

npm

  • 源码
  • package.json


action

  • 源码
  • action.yml


npm 包是通过 package.json 描述包的信息, 而 action 通过 action.yml 描述,区别不大, 只是形式不一样

2. 发布方式

npm

1
npm publish

action

3. 使用方式

npm

1
npm install xx@0.0.1

action

1
2
3
4
5
6
jobs:
preview:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: my-actions@0.0.1

action 除了可以使用 release 后的具体版本号 action@x.x.x 之外,还可以直接使用源码的分支 action@main 新版本的 repo 主分支是 main, 老 repo 是 我们熟悉的 master, 所以这样使用也是可以的

1
2
3
4
5
6
7
jobs:
preview:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- - uses: my-actions@0.0.1
+ - uses: my-actions@main

发送钉钉消息

现在开始编写代码, 发送让万千中小学生梦中惊醒的 午夜凶 Ding,这个很简单,调用 钉钉官方的 SDK 即可, 这里找到个简化了的官方 SDK 的模块 ding-robot, 我们这里使用 @all 功能即可

1
2
3
4
const DingRobot = require('ding-robot');
const robot = new DingRobot(钉钉TOKEN);

robot.atAll(atAll).text(content);

集成到 Github Action 中

1. 钉钉消息构成

一条消息, 预期要有当前 PR 的标题和链接, 然后是谁的 PR, 使用官方的 @actions/github

1
2
3
4
5
6
7
const github = require('@actions/github');
const context = github.context;
const pr = context.payload.pull_request;

pr.user.login; // 当前用户
pr.title; // 标题
pr.html_url; // 链接

2. 接受用户参数

在 Action 里, 参数通过 with 声明, 在脚本中, 可以通过官方的 @actions/core 拿到, 我们这里要拿到 钉钉TOKEN

1
2
const core = require('@actions/core');
const dingTalkToken = core.getInput('ding_talk_token');

3. 完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
const core = require('@actions/core');
const github = require('@actions/github');
const DingRobot = require('ding-robot');

async function run() {
try {
const context = github.context;
const pr = context.payload.pull_request;
const dingTalkToken = core.getInput('ding_talk_token');
const extraContent = core.getInput('extra_content') || '';
const atAll = core.getInput('at_all') || false;

if (!dingTalkToken) {
core.setFailed('Please set DingTalk access token!');
}

const robot = new DingRobot(dingTalkToken, (error) => {
if (error) {
core.setFailed(error.message);
}
});
const prLink = pr.html_url;
const content = `📢 ${pr.user.login} 发起PR: (${pr.title}), 请大家帮忙review 👀 \n🔗 链接: ${prLink} \n${extraContent}`;
robot.atAll(atAll).text(content);
} catch (error) {
core.setFailed(error.message);
}
}

run();

4. 打包源代码

使用 ncc 打包,将源码打包成单文件, 提供给 Action 运行

1
2
3
npm install @vercel/ncc

ncc build

5. 编写 action.yml

参考 官方文档 即可,复述一遍文档没啥意义,最后指定 main 为打包后的 dist/index.js 当别人使用你的 Action 时,其实就是运行的 index.js 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions
name: 'Ding Talk PR Notify'
description: 'A ding talk pr notify of GitHub actions.'
author: 'lijinke666'

branding:
# https://actions-cool.github.io/github-action-branding/
icon: 'file'
color: 'blue'

inputs:
GITHUB_TOKEN:
description: Secret GitHub API token to use for making API requests.
default: ${{ github.token }}
required: true

ding_talk_token:
description: 'dingtalk web hook token'
required: true

content:
description: 'message content'

at_all:
description: 'at all users'

runs:
using: 'node12'
main: 'dist/index.js'

6. 发布

发布比较简单, 手动点几下就可以了, 自动化的方式也有, 自行搜索




最后就可以在 Github 的 Marketplace 搜索到你发布的 Action 了


使用

写完之后, 我们随便找个仓库测试一下, 实现编写 Action,让 PR 在打开的时候发送钉钉通知

1
2
3
4
5
6
7
8
9
10
11
12
13
name: 🔊 PR Ding Talk Notify
on:
pull_request:
types: [opened]

jobs:
preview:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: lijinke666/ding-talk-pr-notify@main
with:
ding_talk_token: ${{ secrets.DING_TALK_ACCESS_TOKEN}}



大功告成, 仓库地址 https://github.com/lijinke666/ding-talk-pr-notify

参考链接

https://github.com/actions-cool
https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions