公司团队是使用gitlab来管理源代码的,一直以来当提交了一个PR后,需要手动在内部IM群里贴出PR链接和摘要,然后@目标同事来帮忙review代码,之后就不时地手动刷新页面查看是否有足够的人review完了。这种方式比较原始费时,仔细想想其实大部分流程是可以自动化的。
一些做的好的IM可以实现自定义机器人,例如飞书(lark),如果机器人可以知道有人发了PR,同时又知道具体有哪些人需要review PR,那么就可以自动在IM群里把这个PR的信息发出来,同时@对方。然后当机器人知道PR通过了后就可以给PR作者私聊发通知,就可以开开心心合并代码了。整理下具体流程:
1 | 提交PR -> 群里发通知+@对方 -> PR通过 -> 私聊发送通知 -> 合并PR |
全程只有第一步和最后一个需要PR作者操作,中间的步骤都可以由机器人完成。
如何知道有人发了PR
这里的标题有一点误导,我们真正想知道的不是有没有人提交PR,而是那些需要被人review的PR。我们可以约定只有在PR的评论里@了同事,才认为这个PR需要review. 恰好gitlab提供了一种webhook机制,可以在发生了特定的事件时请求指定的api。 webhook的设置路径是项目仓库 -> Settings -> Integrations,如图:

其中的URL是自定义的,我们可以将它指向我们的一个后端api,gitlab会往这个api发送一个POST请求,携带事件的详细信息。Trigger我们设置为Comments,表示每次有人在PR里发表了评论都会触发api。
在设置了webhook后,点击它的Edit按钮,可以看到在什么时候触发了webhook:


还可以看到每次触发时传递的参数:

里面的信息非常丰富,每次评论的内容也在其中,还可以根据已有的信息再次调用gitlab openapi来获取更多信息。
以上,每次有人在PR里发表评论了,我们的后端api都会收到一个请求,接下来的问题是如何判断评论里是否含有有效的@.
提取@对象
首先评论的具体内容是放在了请求参数的object_attributes.note属性中,它是一个字符串例如@xiaoming @zhangsan 来看看我的PR啊~。什么是有效的@目标呢? 就是@的对象确实是同事的名字,而不是随便写的,例如@123就不是有效的@。 我们把这件事拆分一下,首先无脑提取所有的@对象,可以用以下代码:
1 | const atReg = /@[^\s]+/g |
它会返回形如['xiaoming', 'zhangsan']的数组,接下来就是判断每个元素是否有效的目标。这里可能不同公司的业务不一样,我的思路是判断目标是否为gitlab里的注册用户,可以用gitlab的users api,可以查询用户名匹配指定字符串的所有用户。我们利用这个api看返回的数组是否为空,不为空取第一个。则整个过滤逻辑如下:
1 | // 过滤@列表,只留下真实存在的gitlab用户, privateToken为gitlab openapi需要的鉴权token |
调用gitlab openapi需要鉴权的private_token,获取步骤: 进入gitlab -> 右上角个人头像 -> Settings -> Access Tokens,然后就可以增加一个token了,注意token的scopes全选.

以上,这样我们就拿到了所有有效的@目标,接下来就是如何在IM群里利用机器人@他们。
机器人自动@目标
这个基本就是调用各IM工具的open api了,举一个飞书的例子:
1 | const atText = atList.map( at => `<at user_id="${ at.userId }">@${ at.name }</at>` ); |
只需提供@目标的userId和name即可,可以同时@多人。同时需要额外再提供群的id,这样机器人才知道该把消息往哪里发送。
置于怎么申请IM机器人,这个也是不同IM不一样,这里不赘述。
以上,我们就能做到当在PR里@了一些目标同事后,机器人自动在群里@同事了。
通知merge PR
接下来要解决的问题是当有足够多的人觉得PR是ok的,实时通知PR作者来merge PR。这里涉及到2个问题:
- 怎么判断一个PR是ok的
- 怎么判断有足够多的人觉得PR是ok的
第一个问题可以约定一个暗号:当在PR中评论了LGTM(Look Good To Me)即认为PR是ok的,当然也可以用其他暗号。
第二个问题的核心是: 判断一个PR的所有评论中是否有足够的指定字符串。首先需要获取所有评论,这个依然可以通过gitlab openapi来获取,然后就依次对每条评论的内容做字符串匹配即可。核心代码示范:
1 | // 此PR所有的评论 |
1 | // 筛选出非PR作者写的note, discussion 与 note是一对多的关系 |
以上我们就可以及时给PR作者发送merge通知了。
merge PR
最后一件锦上添花的事情,当收到merge通知后,当然可以手动打开PR连接然后点击merge按钮,不过这样显得不够极致,能不能让作者直接在IM工具内点击某个按钮或链接,然后由机器人自动帮助其合并呢?这样就更方便好用了!
当然这么做的前提是IM工具支持富文本类型消息,或者可交互的消息,只要最终可以往指定链接发送GET或POST请求即可。
gitlab提供了直接merge PR的openapi,不过其只支持PUT类型请求,同时需要携带PR的关键信息。如果IM工具不支持在消息内再发送PUT类型请求,那么只能做一次中转:先发送一个普通的get/post请求到我们自己的某个后端api,然后在这个api内再发送最后的PUT请求。核心代码示范如下:
1 | // 发送支持交互的消息 |
然后在后端api发送PUT请求:
1 | // 合并PR |
以上我们就做到了PR的全程自动化! 整个机器人的代码其实就是一个node服务,找个服务器部署起来即可。
完整的源码可以参照github.