Skip to content

支持多仓管理的客户端工具 + 服务端功能

问题与背景

在开发包含多个代码仓库的项目,例如安卓 AOSP 项目,包含了800个左右仓库,极狐GitLab 没有提供足够的能力支持。参考Gerrit产品在多仓管理上的解决方案,需要一个客户端工具 repo 来协助研发人员批量管理多个仓库的代码提交,并会统一推送至Gerrit进行代码评审和管理。

通过改造 repo 工具来适配极狐GitLab 的MR评审功能,也能够在极狐GitLab 上实现多仓管理的能力,业内已有相关参考:https://blog.csdn.net/weixin_39986171/article/details/111223103

https://freewechat.com/a/MzA5NDY4NjUwOQ==/2458053565/1

还有一个重要需求:主从MR管理,即root仓库 MR 管理 sub仓库 MR

解决方案(新)

场景举例,开发AOSP项目的某一个需求时,开发人员Bill需要在本地3个仓库中进行代码变更,分别是仓库A,对应代码变更C-A;仓库B,对应代码变更C-B;仓库C,对应代码变更C-C;

同时,这3个仓库的层级关系如下:

  • 顶层群组 top
    • 仓库 A
    • 子群组 sub
      • 仓库 B
      • 仓库 C
  1. 开发人员Bill通过客户端工具mono,先在本地进行开发工作,需要创建功能分支
## 在本地的当前仓库创建分支
mono start FEATURE_BRANCH_NAME .
## 指定某一个仓库创建分支
mono start FEATURE_BRANCH_NAME PROJECT_NAME
  1. 开发人员Bill在本地完成开发,提交代码commit后,需要统一将相关仓库的变更同步到远端仓库
## 拉取远端代码,检测是否有代码冲突
mono sync
## 推送代码
mono upload
  1. 服务端系统会在各项目中创建对应 MR-A,MR-B,MR-C,并会统一加上标签 monorepo ,同时会通过分支名称进行关联,同时,MR详情页的原始合并按钮将隐藏,新增一个组件
草稿 设计稿
image image
  1. 开发人员Bill点击进入 MR-A,可以看到所有相关的MR列表
    • 全部合并按钮,只要在所有MR的mergeable状态(基于流水线、评审规则最终确定)都通过的情况下,才可被激活
    • 全部合并按钮,如果遇到有其他功能分支正在合并,则不可激活
    • 问题:隐藏原来的合并按钮,也就是说,不允许单个MR通过合并按钮进行合并。即使只有一个仓库的按钮有改动,也需要通过全部合并按钮进行合并,防止冲突
场景 设计稿
概览 image
如果有未通过的MR,全部合并按钮不可点击 image
所有MR已通过,全部合并按钮可点击 image
点击全部合并,开始合并 image
如果有正在合并的其他功能(多个MR),全部合并按钮不可点击 image
合并完成 image
如果某个MR关闭,将不影响其他MR的全部合并 image
  1. 如果在全部合并的过程中,某个MR发生问题而中断,系统发现后将自动revert所有MR image

  2. 如果用户没有所有MR的合并权限,那么他也没有全部合并按钮的权限 image

多仓MR 与 流水线

作为同时使用极狐GitLab代码管理和流水线的开发用户,我希望在提交多仓MR的时候只出发一次主流水线,以避免浪费时间和资源做重复工作。

  1. 用户选择一个项目仓库,例如仓库A,作为主流水线所在的项目,并配置好流水线文件
  2. 用户在 mono 工具的配置文件 manifest.yml 中指定主流水线所在的仓库 url
    • <ci-project remote="aosp" path="aosp/a"/>
  3. 当用户执行多仓代码推送的指令 mono upload,客户端通过 API 来直接触发 仓库A 的流水线(即主流水线)
    • 问题:在 FEATURE_BRANCH 时需要跑主流水线,那么在MR都合并以后,是否要跑一次目标分支的流水线?
    • 答:只需要跑一次预合并流水线即可 image

mono 工具用例(User story)

  1. 用户下载 mono 工具

  2. 用户查看 mono 功能的帮助指令,学习使用 mono 工具

    • 基于mono help,需要去掉mono download 命令
    mono help
  3. 用户初始化 mono 工具,以 AOSP 项目作为初始化的第一个项目

    • mono init -u https://android.googlesource.com/platform/manifest
    • 如果要check out到主分支,mono init -u https://android.googlesource.com/platform/manifest -b master
    • 使用 Jihu 的测试项目可以节约时间 mono init -u git@jihulab.com:test-mono/root-group.git -b main
  4. 用户开始下载 AOSP 项目

    mono sync
  5. 用户创建 topic branch

    ## 在本地的当前仓库创建分支
    mono start FEATURE_BRANCH_NAME .
    ## 给所有仓库创建分支
    mono start FEATURE_BRANCH_NAME --all
    ## 指定某一个仓库创建分支
    mono start FEATURE_BRANCH_NAME PROJECT_NAME
  6. 用户切换至topic branch

    git checkout FEATURE_BRANCH_NAME
  7. 用户暂存代码变更

    git add
  8. 用户查看文件状态和diff

    mono status
    mono diff
  9. 用户提交代码变更

    git commit
  10. 用户修改manifest文件中的 remote(远端仓库),并统一将相关仓库的变更同步到远端仓库。在使用 upload 推送代码后,GitLab 服务端自动创建对应 MR。

    ## 拉取远端代码,检测是否有代码冲突
    mono sync
    ## 推送代码
    mono upload

解决方案(旧)

展开 场景举例,开发AOSP项目的某一个需求时,开发人员Bill需要在本地3个仓库中进行代码变更,分别是仓库A,对应代码变更C-A;仓库B,对应代码变更C-B;仓库C,对应代码变更C-C;其中C-A是主要变更,后续代码合并和部署中,C-B和C-C都需要依赖C-A合并成功后才允许进行合并(C-A为主MR,C-B和C-C为从MR)

每个仓库中的代码变更,提交到远端仓库后,都会创建一个独立的 MR,在上述场景中,分别对应 MR-A,MR-B,MR-C,关系如下

graph TD;
    MR-A-->MR-B;
    MR-A-->MR-C;
  1. 开发人员Bill通过客户端工具mono,先在本地进行开发工作
可参考repo工具的使用方法,没有特殊变化
  1. 创建 topic branche
## 在本地的当前仓库创建分支
mono start FEATURE_BRANCH_NAME .
## 指定某一个仓库创建分支
mono start FEATURE_BRANCH_NAME PROJECT_NAME
  1. 切换至topic branch
git checkout FEATURE_BRANCH_NAME
  1. 暂存代码变更
git add
  1. 查看文件状态和diff
mono status
mono diff
  1. 提交代码变更
git commit
  1. 开发人员Bill在本地完成开发,提交代码commit后,需要统一将相关仓库的变更同步到远端仓库
## 拉取远端代码,检测是否有代码冲突
mono sync
## 推送代码,不指定主MR
mono upload
## 推送代码,同时指定仓库A的代码变更C-A为主MR
mono upload -m PROJECT_A

其中,如果不指定主MR,系统可配置必须有主MR并默认第一个项目的MR为主MR

  1. 服务端会在各项目中创建对应 MR-A,MR-B,MR-C image

  2. 在sub MR(MR-B)的详情页面,可以看到它依赖于MR-A;并且禁止合并,只能由MR-A来统一合并 image

  3. 在main MR(MR-A)的详情页面,可以看到所有依赖于它的MR,即MR-B和MR-C image

  4. 相关代码评审人员,对3个MR进行评审,当所有评审通过(Approval达标,流水线通过),main MR(MR-A)的合并按钮才能正式激活

  5. 代码管理人员点击main MR(MR-A)的合并按钮,所有代码最终合并完成

其他说明

  1. 我们研究了其他产品的方案 https://blog.csdn.net/weixin_39986171/article/details/111223103 ,与我们的方案机制略有不同,是基于GitLab的MR dependency功能来实现主从MR的概念和逻辑
  2. 问题:无论哪种方案,都有一个问题:主 MR 和多个从 MR 之前的代码冲突是可能发生的,如何在合并前检测到他们之间有冲突
彭亮 编辑于