在GitLab CI/CD中push回原仓库的一些细节

2023-03-02

< view all posts

最近写了一个小工具,让它在每次commit之后,自动统计仓库里面的一些内容,并且在仓库内生成一份新的统计文件。查询资料之后,了解到在GitLab的CI/CD Runner中,是可以使用git命令的,能够实现这样的功能。下面记录一些容易遇到问题的细节。

首先,需要为项目生成一个 Project Access Token ,在项目左侧的Settings-Access Tokens里面操作。注意这个token是必须设定一个过期日期的。

在拿到这个token之后,在项目的 .gitlab-ci.yml 文件中,push时使用这样的配置:

git push http://[任意一个用户名]:[生成的token]@[gitlab地址]/具体仓库路径.git HEAD:master

注意点有几个。一是看一下本地的GitLab有没有启用 https ,如果用的是 http 的话,使用 https 连接就会遇到443报错: git failed to connect to port 443。另一个点是用户名可以是任意的,不一定是自己的账户名称/仓库名称。例如:

git push http://anything:tokenxxxxxxxxx@127.0.0.1/user/repo.git HEAD:master

在提交的时候还有一个注意点。因为我们不希望这次CI当中的自动commit再次触发CI(那样就会无限循环),因此需要指定跳过CI的配置。虽然GitLab提供了 git push -o ci.skip 的选项,但这个选项有两个缺点。其一是 -o ci.skip 在进行Merge Request是时候是不触发的,其二是旧版本的GitLab并不支持这个选项。更方便的方法是在commit message中标明 [skip ci] 。方法非常简单,直接写在message里面就行:

git commit -m "xxxxxx [skip ci]"

在实践中还遇到了一个问题,CI/CD流水线前几次都能正常运行,但一定次数之后就开始报错:

fatal: git fetch-pack: expected shallow list
fatal: The remote end hung up unexpectedly

查阅资料之后发现这是因为GitLab的CI/CD runner中的git版本太旧,不支持 fetch-pack 命令。最简单的修复方法是在yml文件中增加如下配置:

variables:
  GIT_STRATEGY: clone

最后,我们希望这个CI只在某个文件被改动时触发,其它文件改动时不触发,可以使用如下的配置:

rules:
  - changes:
    - filename

总结上面这些点之后,以下是一份运行成功的 .gitlab-ci.yml 模板:

image: python:latest

variables:
  GIT_STRATEGY: clone

before_script:
  - python --version
  - git --version

run:
  script:
    - python do_something.py
    - git config user.email "xxx@mail.com"
    - git config user.name "bot"
    - git add .
    - git commit -m "auto push back [skip ci]"
    - git push http://anything:tokenxxxxxxxxx@127.0.0.1/user/repo.git HEAD:master

rules:
  - changes:
    - filename