Golang实现gitlab下主干开发模式的CR流程
背景
GitLab下不具备gerrit那样的commit级别的CR的机制,多人在开发同一个功能的时候,往往是都大家拉出各自的分支,然后往开发分支上进行合并,如果开发过程中依赖对方实现的逻辑,那么这个合并过程就非常繁琐。要么就是开发过程中不做CR,大家都在一个分支上开发,最后在集中进行CR,那么这个时候功能开发得差不多了,CR的粒度就非常大,可能就会涉及到大量的代码逻辑调整。基于这种现状,这里尝试探索一种新的CR方式:边开发边CR,简化CR协同流程
实现思路
这里以master分支为例,来说下具体的流程:
- master分支设置为保护模式:不允许任何人提交,需要通过MR的方式合入代码.
- 大家都在本地都在master分支上写代码,不需要拉出feature分支.
- 写完代码后,直接git push推送是不成功的,这个时候需要使用git cr命令来替代git push.
- git cr命令执行后会先同步远端master代码带本地,若有冲突在本地解决,无冲突则将本地代码推送到远端临时分支,同时发起一个MR合并请求.
- 在MR里做CR,CR通过后即可合入master.
借助GitLab下的Push Options思路,来实现这种机制,Push Options详细介绍:https://wdocs.gitlab.com/ee/user/project/push_options.html
实现代码
<pre class="prism-highlight prism-language-go">package main
import (
"fmt"
"os/exec"
"strings"
"github.com/pkg/errors"
)
func gitBranch() (branch string, err error) {
cmd := exec.Command("/bin/bash", "-c", "git rev-parse --abbrev-ref HEAD")
out, err := cmd.CombinedOutput()
if err != nil {
err = errors.Wrap(err, "请在git仓库目录下运行!!!")
return
}
branch = strings.TrimSpace(string(out))
return
}
func gitUser() (username string, err error) {
cmd := exec.Command("/bin/bash", "-c", "git config user.name")
out, err := cmd.CombinedOutput()
if err != nil {
err = errors.Wrap(err, "请在git仓库目录下运行!!!")
return
}
username = strings.TrimSpace(string(out))
return
}
func gitPull(branch string) error {
fmt.Printf("开始同步分支 %s 远端代码到本地...\n", branch)
shell := `
#!/bin/bash
set -e
export TARGET_BRANCH="%s"
RES=$(git ls-remote --heads origin refs/heads/${TARGET_BRANCH})
if [[ "RES" == "" ]]; then
echo "远端仓库里不存在分支:${TARGET_BRANCH},请先创建好该分支"
exit 1
fi
git pull origin ${TARGET_BRANCH}
`
args := []string{"-c", fmt.Sprintf(shell, branch)}
cmd := exec.Command("/bin/sh", args...)
out, err := cmd.CombinedOutput()
if err != nil {
err = errors.Wrapf(err, "执行失败,错误信息如下:\n%s", string(out))
return err
}
fmt.Println("同步远端代码到本地成功.")
return nil
}
func gitPush(username, branch string) error {
fmt.Println("推送代码到远端仓库并发起评审任务...")
shell := `
#!/bin/bash
set -e
export USER_NAME="%s"
export TARGET_BRANCH="%s"
export SOURCE_BRANCH="cr/${USER_NAME}/${TARGET_BRANCH}"
git push origin HEAD:${SOURCE_BRANCH} \
-o merge_request.create \
-o merge_request.title="%s" \
-o merge_request.target=${TARGET_BRANCH} \
-o merge_request.source=${SOURCE_BRANCH} \
-o merge_request.remove_source_branch=true
`
args := []string{"-c", fmt.Sprintf(shell, username, branch, fmt.Sprintf("%s merge code into %s", username, branch))}
cmd := exec.Command("/bin/sh", args...)
out, err := cmd.CombinedOutput()
if err != nil {
err = errors.Wrapf(err, "执行失败,错误信息如下:\n%s", string(out))
return err
}
fmt.Println("推送代码并创建评审任务成功,详情如下:")
fmt.Println(string(out))
return nil
}
func main() {
branch, err := gitBranch()
if err != nil {
fmt.Println(err)
return
}
username, err := gitUser()
if err != nil {
fmt.Println(err)
return
}
if err = gitPull(branch); err != nil {
fmt.Println(err)
return
}
if err = gitPush(username, branch); err != nil {
fmt.Println(err)
return
}
}
代码已提交到github,链接地址为:https://github.com/5bug/git-cr