[other] GitLab 代码托管平台(含自建)使用 .gitlab-ci.yml 实现代码同步
Tofloor
poster avatar
爱开发
deepin
2023-12-24 07:32
Author

之前关注的有些 GitHub 仓库,总是有突然消失的情况,所以就写了个代码同步的CI。

  • 为什么不用那些托管平台提供的「同步」功能?

因为,有些平台(比如 framagit)不提供 镜像拉取的功能。或者那些平台(比如 gitcode)的「同步」功能很鸡肋,时不时会同步不成功。

配置

  1. 假设执行同步功能的仓库地址为 sync
  2. sync 仓库 设置->CI/CD->变量,设置 CI 环境变量 USER_TOKEN,值为当前用户的 访问令牌
  3. (可选)设置定时任务。在 作业 -> 流水线计划 中创建定时任务。

方式一:从文件中读取同步信息

同步到本账号名下的仓库、本账号或读写的仓库

  • 文件:REPOS.md

示例:

| 源       | 源仓库                                              | 目标仓库         | 状态 |
| -------- | --------------------------------------------------- | ---------------- | ---- |
| `github` | `linuxdeepin/linglong` | `myorg/linuxdeepin/linglong` | true |
| 源 | 源仓库 | 目标仓库 | 状态 |

源:github, gitlab, gitee
源仓库:源仓库地址(不含网址),如 org/repo
目标仓库:目标仓库地址(不含网址),如 org/repo
状态:是否同步,true 表示同步,其它则表示不同步

  • 文件:.gitlab-ci.yml
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
  • 文件:.gitlab-ci.yml
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

image.png

image.png

image.png


可将代码部分提取出来,自行实现支持更多平台的同步(同步到本平台、同步到其它平台、同步到多个平台。拉取更多的平台)。

两种方式各有侧重点:
第一种,每次有新的仓库需要同步时,都需要重新修改 REPOS.md文件,但是支持个人账号名下的账号,以及其它个别组织的的个别仓库。
第二种,只支持当前组织下的仓库。但是,当有新的项目需要同步时,可以直接修改新仓库,并修改描述即可。适合创建一个专门做镜像用的组织。

Reply Favorite View the author
All Replies
爱开发
deepin
2023-12-24 07:37
#1

如果是要做代码推送时同步的功能。不需要这么麻烦,只需要在在“设置”->“仓库”->“镜像仓库”中设置推送的目标仓库即可。

image.png

Reply View the author