大家好,我是馋嘴的猫。最近的工作中,遇到了 gitlab 中,两个仓库需要代码同步的场景。经过一番摸索,成功使用 gitlab-ci 实现了此需求,下面请跟着我,一起来看看如何实现吧~
背景
假设我们现在有一个场景,有两个 Gitlab 仓库,分别叫 A 和 B。
我们需要在 A 仓库每次 main 分支的 src 目录有变化,则执行 build 操作来生成产物,并将产物同步到 B 仓库的 src 目录下。
B 仓库 src 目录检测到更新后,也需要执行它的 build 操作,生成产物并发布到 npm 包。
问题
在上面的流程中,我们需要注意到的是,有几个难点:
- 如何保证全流程自动,不需要手动执行
- 如何保证准确监听到合适的目录、分支
- 如何可以跨仓库提交增量修改的代码
仓库地址
解决方案
-
在 B 仓库的 gitlab 页面,申请一个 token,用于后续的提交代码操作。
新增 token 路径:
- 确定当前登录用户拥有 B 仓库的 maintainer 权限
- 打开 B 仓库的 gitlab 页面,点击左侧菜单栏的
Settings
->Access Tokens
- 填入 token name,请注意,这个 token name 与后面提交 MR 的用户名一致,此处为了方便辨别,我们选择命名为
ci-bot
。 - 根据自己需求,选择
expiration date
,role
和scope
。 - 点击
Create personal access token
,生成 token。 - 页面此时会刷新,并在页面的 Your new project access token 下显示新生成的 token。请复制下来。
- 回到仓库 A 的 gitlab 页面,点击左侧菜单栏的
Settings
->CI/CD
->Variables
,添加一个名为REPO_B_GITLAB_TOKEN
的变量,值为刚刚复制的 token。
-
查看A仓库的 .gitlab-ci.yml, 有两个 stage,分别为 build(构建产物)和 update(同步产物)操作。
-
在 build 操作中,我们通过
rules
规则,来加上 build 的条件,只有在 main 分支 的 src 目录下有变更时,才自动触发 build 操作。
yaml
rules:
- if: '$CI_COMMIT_REF_NAME == "main"'
changes:
- 'src/**/*'
when: on_success
然后,通过 artifacts 规则,将产物保存下来,供 update 环节使用。
yaml
artifacts:
paths:
- dist/**/*
- 在 update 操作中,我们通过 needs 规则,确定前置条件要先执行
build
操作。
yaml
needs: [ "build" ]
通过 before_script 规则,添加淘宝源并安装jq,用于后续的 json 解析。
yaml
before_script:
# 省略添加淘宝源的操作
- apt-get update -y && apt-get install -y jq
- 在 update 操作中的 script 部分,就是我们的重头戏了。大概有以下重点,可对照 .gitlab-ci.yml 查看
- 克隆仓库 B,使用刚刚配置的 REPO_B_GITLAB_TOKEN,并将 build 步骤生成的产物拷贝到仓库 B 的 src 目录下。注意:需要将下面的
<your gitlab host>
替换为你的 gitlab 域名。
yaml
- git clone -b main https://oauth2:$REPO_B_GITLAB_TOKEN@<your gitlab host>/rickiezheng/gitlab-sync-demo-b.git b
- cp -r dist/* b/src/dist-a
- 执行常规的 git add、commit、push 操作,并且定义好提交的分支名,用户名,邮箱等信息
注意,这里由于是先 clone 的 B 仓库代码再覆盖的代码,所以不会全量提交,只会提交有更新的代码。
- 生成 MR 并提交到 B 仓库。 在这里,我们调用了gitlab提供的 API, 并传入刚刚设置的 REPO_B_GITLAB_TOKEN,即可完成 MR 新建操作。
- 注意:需要将下面的
<your gitlab host>
替换为你的 gitlab 域名。
yaml
- "merge_request_response=$(curl --silent --header 'PRIVATE-TOKEN: '$REPO_B_GITLAB_TOKEN -X POST 'https://<your gitlab host>/api/v4/projects/'$repo_id'/merge_requests' -F 'source_branch='$branch_name -F 'target_branch=main' -F 'title=Update dist files from demo-a' -F 'description=Automated MR for updating dist files' -F 'remove_source_branch=true' -F 'squash=true'); if [ $? -eq 0 ]; then echo $merge_request_response | jq -r '.web_url'; else echo $merge_request_response | jq -r '.message'; fi"
注: repo_id 可以在仓库 B 的 gitlab 主页上的仓库名下找到,格式类似:
ProjectID: 12345
在 MR 提交成功后,jq会解析出 MR 的地址,并显示在 gitlab job 的控制台,方便用户查看。
- 至此,我们已经完成仓库 A 的 gitlab-ci 设置了。让我们来尝试在 src 目录做些修改,并提交到 main 分支吧。
- 可以看到,仓库 A 的 main 分支在 src 目录代码有更新后,自动执行了 pipeline,且成功运行了其下的 build 和 update 操作。
此时查看 update stage 的控制台日志,ci成功将仓库 A 的改动,提交到了仓库 B, 并输出了仓库 B 的 MR 地址。
- 点击 MR 地址,进入仓库 B 的
Merge request
页面,可以看到 PR 已经顺利提过来了,查看 Changes 面板,可以看到仓库 A 修改好的文件,已经增量提交过来了,而并不是全量提交。
- 在合入这笔提交前,先让我们来看下仓库 B 的 .gitlab-ci.yml。
在这个文件里,我们定义了 build 和 update 两个 stage。
yaml
stages:
- build
- publish
- 在 build 操作中,与仓库 A 类似,我们通过
rules
规则,来加上 build 的条件,只有在 main 分支 的 src 目录下有变更时,才自动触发 build 操作。
yaml
rules:
- if: '$CI_COMMIT_REF_NAME == "main"'
changes:
- 'src/**/*'
when: on_success
然后,通过 artifacts 规则,将产物保存下来,供 publish 环节使用。
yaml
artifacts:
paths:
- dist/**/*
- 在 publish 操作中,我们通过 needs 规则,确定前置条件要先执行
build
操作。
yaml
needs: [ "build" ]
在正常情况下,这里将执行 npm 发布的完整操作,但是因为这是个示例项目,我们暂且不实现具体逻辑,只用 ls 查看发包的目录是否正常~
yaml
- echo "Publishing to npm now..."
# - pnpm publish
- ls dist
- 现在,让我们来尝试合入此笔 MR。在合入 MR 后,pipeline 也会自动执行,且成功运行了其下的 build 和 publish 操作。
- 至此,gitlab 跨仓库同步的全流程演示完成。
总结
我们今天通过两个 gitlab 仓库的联合演示,讲述了如何通过 gitlab 提供的 ci 与 pipeline 功能,实现跨仓库的同步。其中,涉及到了如 token 的设置,对指定目录的监听,MR 的自动生成等等知识点,最终,我们实现了本文一开始定下的目标:
- 保证全流程自动,不需要手动执行
- 保证准确监听到合适的目录、分支
- 实现跨仓库提交增量修改的代码
好的,以上就是对如何实现 gitlab 的跨仓库同步的全部介绍啦!
欢迎多多点赞,有问题也欢迎在评论区交流~