GitLab 代码托管平台(含自建)使用 .gitlab-ci.yml 实现代码同步
之前关注的有些 GitHub 仓库,总是有突然消失的情况,所以就写了个代码同步的CI。
因为,有些平台(比如 framagit)不提供 镜像拉取
的功能。或者那些平台(比如 gitcode)的「同步」功能很鸡肋,时不时会同步不成功。
配置
- 假设执行同步功能的仓库地址为
sync
。
sync
仓库 设置
->CI/CD
->变量
,设置 CI 环境变量 USER_TOKEN
,值为当前用户的 访问令牌
。
- (可选)设置定时任务。在
作业
-> 流水线计划
中创建定时任务。
方式一:从文件中读取同步信息
同步到本账号名下的仓库、本账号或读写的仓库
示例:
| 源 | 源仓库 | 目标仓库 | 状态 |
| -------- | --------------------------------------------------- | ---------------- | ---- |
| `github` | `linuxdeepin/linglong` | `myorg/linuxdeepin/linglong` | true |
| 源 | 源仓库 | 目标仓库 | 状态 |
源:github
, gitlab
, gitee
源仓库:源仓库地址(不含网址),如 org/repo
目标仓库:目标仓库地址(不含网址),如 org/repo
状态:是否同步,true
表示同步,其它则表示不同步
default:
image: alpine:latest
stages:
- build
build-sync-job:
stage: build
before_script: |
apk update
apk add curl git jq
script: |
USER_TOKEN="${USER_TOKEN}"
USER_NAME="${GITLAB_USER_LOGIN}"
TARGET_HUB="${CI_SERVER_HOST}"
awk -F'|' '{print $2, $3, $4, $5}' "REPOS.md" |
while IFS=" " read -r ORIGIN_HUB ORIGIN_REPO TARGET_REPO STATUS; do
CODE_HUB=$(echo "$ORIGIN_HUB" | cut -d '`' -f 2)
CODE_REPO=$(echo "$ORIGIN_REPO" | cut -d '`' -f 2)
TARGET_REPO=$(echo "$TARGET_REPO" | cut -d '`' -f 2)
STATUS=$(echo "$STATUS" | cut -d '`' -f 2)
CODE_HUB="${CODE_HUB-github}"
CODE_REPO="${CODE_REPO-}"
TARGET_REPO="${TARGET_REPO-}"
STATUS="${STATUS-}"
if [ -z "$CODE_HUB" ] || [ -z "$CODE_REPO" ] || [ -z "$TARGET_REPO" ]; then
continue
fi
if [ "$STATUS" != "true" ]; then
continue
fi
case $CODE_HUB in
github | gitlab | gitee)
CODE_URL="https://$CODE_HUB.com/$CODE_REPO.git"
;;
*)
echo "unknown code hub: $CODE_HUB"
continue
;;
esac
HTTPS_REPO_URL="https://$USER_NAME:$USER_TOKEN@$TARGET_HUB/$TARGET_REPO.git"
echo "CODE_URL: $CODE_URL"
echo "HTTPS_REPO_URL: $HTTPS_REPO_URL"
[ -d procode ] && rm -rf procode
git clone "$CODE_URL" procode
cd procode || {
echo "not found procode"
exit 1
}
git remote add target "$HTTPS_REPO_URL"
git fetch
git push target --all --force
git push target --tags --force
cd ..
done
当前只写了 github, gitlab, gitee
,可自行修改以支持同步其它平台。或者将代码提取出来,以支持非 GitLab 平台。
方式二:从描述中读取同步信息
更新本组织的仓库镜像。适合创建一个专门同步的组织
原理是,从 GitLab 提供的 API 获取当前组织下的所有仓库,并提取描述信息,再进行同步。
先创建一个仓库,可为空仓库。或者直接从源站导入。然后修改仓库描述:
# 格式:::PALTFORM@ORG/REPO 空格后面可以添加描述。
# 若不添加平台,则默认为 github。即 ::aaa/bbb 实际为 ::github@aaa/bbb
# 注意,最后是有个空格的。
::gedoor/legado
# 或者
::gitee@gedoor/legado
default:
image: alpine:latest
stages:
- build
build-sync-job:
stage: build
before_script: |
apk update
apk add bash curl git jq
script: |
ORG_NAME="$CI_PROJECT_NAMESPACE"
curl -o projects.json -H "PRIVATE-TOKEN:$USER_TOKEN" "https://$CI_SERVER_HOST/api/v4/groups/$ORG_NAME/projects"
JSON_DATA=$(cat projects.json)
for entry in $(echo "$JSON_DATA" | jq -r '.[] | @base64'); do
decoded_entry=$(echo "$entry" | base64 -d)
path=$(echo "$decoded_entry" | jq -r '.path')
description=$(echo "$decoded_entry" | jq -r '.description')
http_url_to_repo=$(echo "$decoded_entry" | jq -r '.http_url_to_repo')
path_with_namespace=$(echo "$decoded_entry" | jq -r '.path_with_namespace')
case $description in
"::"*)
echo "-> [$path] sync ..."
# origin repo -> ::gitlab@org/repo THIS IS SYNC PROJECT
SYNC_VARS="$(echo "$description" | head -n 1 | awk -F ' ' '{print $1}' | sed 's#::##')"
ORIGIN_HUB=$(echo "$SYNC_VARS" | awk -F@ '{print $1}')
ORIGIN_REPO=$(echo "$SYNC_VARS" | awk -F@ '{print $2}')
# default github
if [[ -z "$ORIGIN_REPO" ]]; then
ORIGIN_REPO="$ORIGIN_HUB"
ORIGIN_HUB="github"
fi
case $ORIGIN_HUB in
github | gitlab | gitee)
CODE_URL="https://$ORIGIN_HUB.com/$ORIGIN_REPO.git"
;;
*)
echo "unknown code hub: $ORIGIN_HUB"
return
;;
esac
HTTPS_REPO_URL="https://$GITLAB_USER_LOGIN:$USER_TOKEN@$CI_SERVER_HOST/$path_with_namespace.git"
echo "HTTPS_REPO_URL: $HTTPS_REPO_URL"
[[ -d procode ]] && rm -rf procode
git clone "$CODE_URL" procode
cd procode
git remote add target "$HTTPS_REPO_URL"
git fetch
git push target --all --force
git push target --tags --force
cd ..
;;
# *) echo "path: $path skip sync." ;;
esac
done
![](//flarum-images.w.idev.top/2023-12-23/1703346116-369420-image.png)
![](//flarum-images.w.idev.top/2023-12-23/1703346125-554286-image.png)
![](//flarum-images.w.idev.top/2023-12-23/1703346131-550822-image.png)
可将代码部分提取出来,自行实现支持更多平台的同步(同步到本平台、同步到其它平台、同步到多个平台。拉取更多的平台)。
两种方式各有侧重点:
第一种,每次有新的仓库需要同步时,都需要重新修改 REPOS.md
文件,但是支持个人账号名下的账号,以及其它个别组织的的个别仓库。
第二种,只支持当前组织下的仓库。但是,当有新的项目需要同步时,可以直接修改新仓库,并修改描述即可。适合创建一个专门做镜像用的组织。