业务背景
由于要求每次代码提交都必须通过gerrit合并到对应开发分支上,因此需要开发一个脚本定时review别人提给自己的代码变更,然后提交之后合并到相应分支上。
主要思路
1、登录gerrit账号获取所有状态为Open的代码变更
2、遍历每一条变更的项目,是否为自定义设置的项目列表中的一个,并且reviewers包含自己的话,就Code Review + 2并且提交。
3、重复上述步骤
代码实现
主要使用golang语言进行开发,gerrit rest api sdk是在github上找的。
package main
import (
"bytes"
"context"
"encoding/json"
"fmt"
"github.com/andygrunwald/go-gerrit"
"github.com/go-ini/ini"
"io/ioutil"
"log"
"net/http"
"strings"
"time"
"unsafe"
)
var (
Cig *ini.File
UserName string
Password string
DesiredProjects string
Internal int64
)
func init() {
var err error
Cig, err = ini.Load("config/app.ini")
if err != nil {
log.Fatalf("加载初始化文件 'conf/app.ini' 文件失败: %v", err)
}
sec, err := Cig.GetSection("app")
if err != nil {
log.Fatalf("Fail to get section 'app': %v", err)
}
UserName = sec.Key("username").String()
Password = sec.Key("password").String()
DesiredProjects = sec.Key("desired_projects").String()
Internal = sec.Key("internal").MustInt64(10)
// 目标项目不能为空
if DesiredProjects == "" {
log.Fatalf("配置文件中目标项目不能为空!")
}
fmt.Println("登录配置读取成功!")
}
func main() {
fmt.Printf("程序开始启动,持续监听待review的提交(间隔%ds)....\n", Internal)
var count int64 = 1
for {
fmt.Printf("=========第%d次执行开始==============\n", count)
doJob()
fmt.Printf("=========第%d次执行结束==============\n\n", count)
count = count + 1
time.Sleep(time.Duration(Internal * 1000 * 1000 * 1000))
}
}
func doJob() {
instance := "http://xxxx"
ctx := context.Background()
client, err := gerrit.NewClient(ctx, instance, nil)
client.Authentication.SetBasicAuth(UserName, Password)
if err != nil {
fmt.Println("登录出错,请核对用户名和密码:", err.Error())
return
}
// 请求目前状态为Open的changes
opt := &gerrit.QueryChangeOptions{}
opt.Query = []string{"status:open"}
changes, _, err := client.Changes.QueryChanges(ctx, opt)
if err != nil {
fmt.Println("请求Changes Open出错:", err.Error())
return
}
for _, change := range *changes {
// 不是目标项目 直接跳过
if change.Project == "" {
continue
}
// 找到最后一个斜杠的索引
i := strings.LastIndex(change.Project, "/")
if i == -1 {
fmt.Println("项目名称有误:", change.Project)
continue
} else {
// 分割字符串
projectName := change.Project[i+1:]
if !strings.Contains(DesiredProjects, projectName) {
fmt.Println("该项目不是目标项目:", change.Project)
continue
}
}
getChange, _, _ := client.Changes.GetChangeDetail(ctx, change.ChangeID, nil)
// 判断Reviewers里面是否有自己
reviewers, ok := getChange.Reviewers["REVIEWER"]
if !ok {
continue
}
for _, reviewer := range reviewers {
if reviewer.Username == UserName {
// code review
labels := make(map[string]string)
labels["Code-Review"] = "+2"
client.Changes.SetReview(ctx, getChange.ChangeID, "current", &gerrit.ReviewInput{
Message: "同意!",
Labels: labels})
// 间隔1秒再提交
time.Sleep(time.Second * 1)
// submit
client.Changes.SubmitChange(ctx, getChange.ChangeID, &gerrit.SubmitInput{})
fmt.Printf("处理完成 》》》 Project: %s -> %s -> %s%d\n", change.Project, change.Subject, instance, change.Number)
break
}
}
}
}
在根目录config/app.ini文件根据注释填写内容:
;密码需要在gerrit用户配置里面生成,不是登录密码
[app]
username=abc
password=xxxx
;需要review哪些项目 必填
desired_projects=AProject,BProject
;执行间隔(单位秒)
internal=10
运行
go build main.go生成可执行文件,点击exe文件运行即可。
如有疑问,欢迎一起讨论!