Skip to content

Commit 5b617cd

Browse files
authored
Merge pull request #6 from lyleshaw/main
[docs] add docs
2 parents 6facf2a + 6d21e2c commit 5b617cd

File tree

17 files changed

+186
-21
lines changed

17 files changed

+186
-21
lines changed

README.md

Lines changed: 147 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,152 @@
11
# ospp-cr-bot
22
开源之夏 - 一种通用的 Code Review 机器人
33

4+
## 背景
5+
6+
Code Review 是软件研发协作中的重要⼀环,⼤家在代码提交后都需要等待 Reviewer 的 Review;同时当Reviewer 提交了“修改建议”后,PR/MR 的提交者还需要根据“修改建议”相 应更新⾃⼰的代码。在这个过程中可能代码提交者等了半天也没有⼈来 Review,或者 Reviewer 提交了“修改建议”后等了半天也没有看到提交者修改。所以各⽅及时收到“动作通知”,⾼效完成⾃⼰的“Review/Fix”⼯作是⾮常重要的。
7+
8+
## 目标
9+
10+
1. 通过 webhook 实现通过对 GitHub 的 PR/MR/Review/Comment 等事件的监听
11+
2. 创建⻜书机器⼈应⽤,并调⽤ fastwego 的⻜书 SDK 实现对⻜书机器⼈发送消息函数 的封装
12+
3. 设计配置⽂件格式,使项⽬可以优雅的读⼊⻜书号/群 与 Github/Gitlab Repo 之间 的映射关系
13+
4. 实现对推送⼈的持续通知等需求
14+
5. 通过 helm 完成部署
15+
16+
> Ref: https://summer-ospp.ac.cn/#/org/prodetail/22abc0185
17+
18+
## 方案
19+
20+
### 整体架构
21+
22+
![img.png](docs/img/img.png)
23+
24+
### 业务流程时序图
25+
26+
![img_1.png](docs/img/img_1.png)
27+
28+
## ShowCase
29+
30+
![img_2.png](docs/img/img_2.png)
31+
32+
## 私有化指南
33+
34+
### 部署指南
35+
36+
1. 创建飞书应用
37+
38+
在飞书开放平台的开发中后台(https://open.feishu.cn/app)创建应用。
39+
40+
![img_3.png](docs/img/img_3.png)
41+
42+
2. 项目启动配置
43+
44+
![img_4.png](docs/img/img_4.png)
45+
46+
![img_5.png](docs/img/img_5.png)
47+
48+
在应用根目录下创建 .env文件, 填入如上四个凭证:
49+
50+
```yaml
51+
LarkAppId=cli_xxx
52+
LarkAppSecret=xxx
53+
VerificationToken=xxx
54+
EncryptKey=xxx
55+
```
56+
57+
在权限管理中为应用开通必要权限
58+
59+
![img_6.png](docs/img/img_6.png)
60+
61+
在 事件订阅/应用功能-机器人 中分别填入接口 URL 做鉴权,URL 分别为:
62+
63+
```bash
64+
http://domain:port/api/lark/cardCallback
65+
http://domain:port/api/lark/callback
66+
```
67+
68+
![img_7.png](docs/img/img_7.png)
69+
70+
![img_8.png](docs/img/img_8.png)
71+
72+
3. 获取群聊 ID 及用户 ID 并配置 yaml 文件
73+
74+
启动应用后,在需要订阅消息的群聊中@cr-bot,会收到以 @oc_ 开头的一串字符,此为该群聊群号,向 bot 发送私聊消息 ID 会收到以 @ou_ 开头的一串字符,此为该用户 ID
75+
76+
![img_9.png](docs/img/img_9.png)
77+
78+
![img_10.png](docs/img/img_10.png)
79+
80+
此时可参照 common.yaml.example 文件填写 bot 配置并创建 common.yaml 文件:
81+
82+
```yaml
83+
tasks:
84+
- name: "Task 1"
85+
repo: lyleshaw/repoTest // GitHub URL
86+
repoType: github // 仓库类型,可选 github 和 gitlab
87+
receiver: oc_xxxxxxxx // 该仓库指定的群聊
88+
pushChannel: lark // 推送渠道,可选 lark 和 slack
89+
maps:
90+
- name: "1"
91+
github: lyleshaw // github ID
92+
lark: ou_xxxxxx // 飞书用户 ID
93+
role: member // 角色
94+
boss: 0 // 上级的 GitHub 账号,若无则填 0
95+
- name: "2"
96+
github: abc
97+
lark: ou_xxxxxx
98+
role: contributor
99+
boss: lyleshaw
100+
scheduler:
101+
- timeUnread1: 30 // PR/Issue 消息第一次发送消息后若未读,经过 TimeUnread1 分钟后重发
102+
- timeUnread2: 30 // PR/Issue 消息第二次发送消息后若未读,经过 TimeUnread2 分钟后发送给上级
103+
- timeUnread3: 660 // PR/Issue 消息第三次发送消息后若未读,经过 TimeUnread3 分钟后抄送群聊
104+
- commentUnread: 60 // Comment 消息第一次发送后若未读,经过 CommentUnread 分钟后抄送群聊
105+
```
106+
107+
修改完配置后,重启项目即可开始使用
108+
109+
### 修改指南
110+
111+
1. 修改升级逻辑
112+
113+
见 internal/pkg/eventListener/eventListener.go 文件及其注释
114+
115+
2. 修改推送内容
116+
117+
参考 https://open.feishu.cn/tool/cardbuilder?from=howtoguide 搭建消息卡片,并修改 internal/pkg/pushChannel/lark/messageTemplate 下的文件
118+
119+
## Check List
120+
- [x] 主体功能
121+
- [x] 读取配置
122+
- [x] GitHub 消息接收
123+
- [x] PR
124+
- [x] Issue
125+
- [x] Comment
126+
- [x] Review
127+
- [x] 飞书消息卡片
128+
- [x] PR
129+
- [x] Issue
130+
- [x] Comment
131+
- [x] Review
132+
- [x] 消息升级
133+
- [x] PR/Issue 30 分钟后未读重复提醒
134+
- [x] PR/Issue 60 分钟后未读提醒上级
135+
- [x] PR/Issue 12 小时后未读抄送群聊
136+
- [x] Comment/Review 无@成员抄送群聊
137+
- [x] Comment/Review 有@成员提醒
138+
- [x] Comment/Review 有@成员 30 分钟后未读抄送群聊
139+
- [ ] Helm 部署
140+
- [x] 测试
141+
- [x] PR/Issue 部分
142+
- [x] Comment/Review 部分
143+
- [x] 代码优化
144+
- [x] Log 打点
145+
- [x] 细节
146+
- [ ] 后续支持
147+
- [ ] Slack 支持
148+
- [ ] GitLab 支持
149+
=======
4150
## How to Build
5151
6152
```bash
@@ -50,4 +196,4 @@ tasks:
50196
请在启动服务后,拉入群聊并 @cr-bot-test,bot 会获取你的 Lark ID 并回复。
51197
52198
![img.png](docs/imgs/img.png)
53-
![img.png](img.png)
199+
![img.png](img.png)

common.yaml.example

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,9 @@ maps:
1616
lark: ou_xxxxxx
1717
role: contributor
1818
boss: lyleshaw
19+
20+
scheduler:
21+
- timeUnread1: 30
22+
- timeUnread2: 30
23+
- timeUnread3: 660
24+
- commentUnread: 60

docs/img/img.png

24.1 KB
Loading

docs/img/img_1.png

84.5 KB
Loading

docs/img/img_10.png

33.8 KB
Loading

docs/img/img_2.png

83.7 KB
Loading

docs/img/img_3.png

76.9 KB
Loading

docs/img/img_4.png

45.9 KB
Loading

docs/img/img_5.png

104 KB
Loading

docs/img/img_6.png

181 KB
Loading

docs/img/img_7.png

191 KB
Loading

docs/img/img_8.png

717 KB
Loading

docs/img/img_9.png

44.7 KB
Loading

internal/pkg/config/config.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@ var (
1414
)
1515

1616
type Config struct {
17-
Tasks []Tasks `yaml:"tasks"`
18-
Maps []Maps `yaml:"maps"`
17+
Tasks []Tasks `yaml:"tasks"`
18+
Maps []Maps `yaml:"maps"`
19+
Scheduler Scheduler `yaml:"scheduler"`
1920
}
2021
type Tasks struct {
2122
Name string `yaml:"name"`
@@ -32,6 +33,13 @@ type Maps struct {
3233
Boss string `yaml:"boss"`
3334
}
3435

36+
type Scheduler struct {
37+
TimeUnread1 int `yaml:"timeUnread1"`
38+
TimeUnread2 int `yaml:"timeUnread2"`
39+
TimeUnread3 int `yaml:"timeUnread3"`
40+
CommentUnread int `yaml:"commentUnread"`
41+
}
42+
3543
func InitConfig() {
3644
config, err := ioutil.ReadFile("./common.yaml")
3745
if err != nil {

internal/pkg/constants/constants.go

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package constants
22

3-
import "time"
3+
import (
4+
"github.com/lyleshaw/ospp-cr-bot/internal/pkg/config"
5+
"time"
6+
)
47

58
type MsgType int
69

@@ -11,9 +14,9 @@ const (
1114
Unread3 MsgType = 3
1215
)
1316

14-
const (
15-
TimeUnread1 = 30 * time.Minute // PR/Issue 消息第一次发送消息后若未读,经过 TimeUnread1 后重发
16-
TimeUnread2 = 30 * time.Minute // PR/Issue 消息第二次发送消息后若未读,经过 TimeUnread2 后发送给上级
17-
TimeUnread3 = 11 * time.Hour // PR/Issue 消息第三次发送消息后若未读,经过 TimeUnread3 后抄送群聊
18-
CommentUnread = 1 * time.Hour // Comment 消息第一次发送后若未读,经过 CommentUnread 后抄送群聊
17+
var (
18+
TimeUnread1 = time.Duration(config.Cfg.Scheduler.TimeUnread1) * time.Minute // PR/Issue 消息第一次发送消息后若未读,经过 TimeUnread1 后重发
19+
TimeUnread2 = time.Duration(config.Cfg.Scheduler.TimeUnread2) * time.Minute // PR/Issue 消息第二次发送消息后若未读,经过 TimeUnread2 后发送给上级
20+
TimeUnread3 = time.Duration(config.Cfg.Scheduler.TimeUnread3) * time.Minute // PR/Issue 消息第三次发送消息后若未读,经过 TimeUnread3 后抄送群聊
21+
CommentUnread = time.Duration(config.Cfg.Scheduler.CommentUnread) * time.Minute // Comment 消息第一次发送后若未读,经过 CommentUnread 后抄送群聊
1922
)

internal/pkg/eventListener/eventListener.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ func GitHubWebHook(c *gin.Context) {
130130

131131
// 定时未读则转发群聊
132132
time.AfterFunc(constants.CommentUnread, func() {
133-
issueCommentMsg = lark.MsgTemplateUpgrade(issueCommentMsg, "有人")
133+
issueCommentMsg = lark.MsgTemplateUpgrade(issueCommentMsg)
134134
for _, receiver := range atPeople {
135135
if _, ok := config.MsgQueue[receiver+number+string(gitHubEvent)]; ok {
136136
if config.MsgQueue[receiver+number+string(gitHubEvent)] == constants.Unread1 {
@@ -326,7 +326,7 @@ func GitHubWebHook(c *gin.Context) {
326326

327327
// 定时未读则转发群聊
328328
time.AfterFunc(constants.CommentUnread, func() {
329-
prReviewMsg = lark.MsgTemplateUpgrade(prReviewMsg, "有人")
329+
prReviewMsg = lark.MsgTemplateUpgrade(prReviewMsg)
330330
for _, receiver := range atPeople {
331331
if _, ok := config.MsgQueue[receiver+number+string(gitHubEvent)]; ok {
332332
if config.MsgQueue[receiver+number+string(gitHubEvent)] == constants.Unread1 {
@@ -413,7 +413,7 @@ func GitHubWebHook(c *gin.Context) {
413413

414414
// 定时未读则转发群聊
415415
time.AfterFunc(constants.CommentUnread, func() {
416-
prCommentMsg = lark.MsgTemplateUpgrade(prCommentMsg, "有人")
416+
prCommentMsg = lark.MsgTemplateUpgrade(prCommentMsg)
417417
for _, receiver := range atPeople {
418418
if _, ok := config.MsgQueue[receiver+number+string(gitHubEvent)]; ok {
419419
if config.MsgQueue[receiver+number+string(gitHubEvent)] == constants.Unread1 {

internal/pkg/pushChannel/lark/message.go

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ var (
1919
createMessageURL = "https://open.feishu.cn/open-apis/im/v1/messages"
2020
)
2121

22-
func MsgTemplateUpgrade(msgTemplate string, receiver string) string {
23-
msgTemplate = strings.Replace(msgTemplate, messageTemplate.PrTitle1, fmt.Sprintf(messageTemplate.PrTitle2, receiver), -1)
24-
msgTemplate = strings.Replace(msgTemplate, messageTemplate.IssueTitle1, fmt.Sprintf(messageTemplate.IssueTitle2, receiver), -1)
22+
func MsgTemplateUpgrade(msgTemplate string) string {
23+
msgTemplate = strings.Replace(msgTemplate, messageTemplate.PrTitle1, messageTemplate.PrTitle2, -1)
24+
msgTemplate = strings.Replace(msgTemplate, messageTemplate.IssueTitle1, messageTemplate.IssueTitle2, -1)
2525
msgTemplate = strings.Replace(msgTemplate, messageTemplate.PrCommentTitle1, messageTemplate.PrCommentTitle2, -1)
2626
msgTemplate = strings.Replace(msgTemplate, messageTemplate.IssueCommentTitle1, messageTemplate.IssueCommentTitle2, -1)
2727
msgTemplate = strings.Replace(msgTemplate, messageTemplate.PrReviewTitle1, messageTemplate.PrReviewTitle2, -1)
@@ -200,17 +200,18 @@ func TimeCheck2(receiveID string, receivers []string, msgTemplate string, number
200200
if config.MsgQueue[receiver+number+gitHubEvent] == constants.Unread2 {
201201
// 如果第二次未读,则调整状态为第三次未读,并发送消息给上级
202202
config.MsgQueue[receiver+number+gitHubEvent] = constants.Unread3
203-
msgTemplate = MsgTemplateUpgrade(msgTemplate, receiver)
203+
msgTemplate = MsgTemplateUpgrade(msgTemplate)
204+
msgTemplate_ := fmt.Sprintf(msgTemplate, receiver)
204205
if config.LarkMaps[receiver].Boss == "0" {
205-
_, err := SendGroupMessage(receiveID, msgTemplate)
206+
_, err := SendGroupMessage(receiveID, msgTemplate_)
206207
if err != nil {
207208
log.Errorf("send message error: %+v", err)
208209
}
209210
continue
210211
}
211-
_, err := SendMessage(config.LarkMaps[config.LarkMaps[receiver].Boss].Lark, msgTemplate)
212+
_, err := SendMessage(config.LarkMaps[config.LarkMaps[receiver].Boss].Lark, msgTemplate_)
212213
if err != nil {
213-
log.Errorf("send message failed, msgTemplate=%s, receivers=%+v, gitHubEvent=%s", msgTemplate, receivers, gitHubEvent)
214+
log.Errorf("send message failed, msgTemplate=%s, receivers=%+v, gitHubEvent=%s", msgTemplate_, receivers, gitHubEvent)
214215
log.Errorf("send message failed, err=%v", err)
215216
}
216217
log.Infof("msgQ=%v", config.MsgQueue)
@@ -231,9 +232,10 @@ func TimeCheck3(receiveID string, receivers []string, msgTemplate string, number
231232
for _, receiver := range receivers {
232233
if _, ok := config.MsgQueue[receiver+number+gitHubEvent]; ok {
233234
if config.MsgQueue[receiver+number+gitHubEvent] == constants.Unread3 {
234-
msgTemplate = MsgTemplateUpgrade(msgTemplate, receiver)
235+
msgTemplate = MsgTemplateUpgrade(msgTemplate)
236+
msgTemplate_ := fmt.Sprintf(msgTemplate, receiver)
235237
// 如果第三次未读,则从队列清除,并发送群消息
236-
_, err := SendGroupMessage(receiveID, msgTemplate)
238+
_, err := SendGroupMessage(receiveID, msgTemplate_)
237239
if err != nil {
238240
log.Errorf("send message error: %+v", err)
239241
}

0 commit comments

Comments
 (0)