CocaColf

庭前桃李满,院外小径芳

制定你的GitLab流水线任务

2021-10-13


    最近要将开发的 npm 包合入 CICD 流水线里,摸索着完成了这个搭建。

本文默认你已了解 CICD 是什么,并且 GitLab 具备必要条件:如可用的 Runner。

    一个流水线服务需要以下几个基本要素:

编写配置文件和脚本

    .gitlab-ci.yml 文件是必须的,它定义了流水线任务如何执行。而我们的任务肯定要在某个环境中执行,Runner 就是一个具备运行条件的环境,可能是某个服务器,也可能是某个 Docker 容器,这里不涉及 Runner 的搭建,因此默认已经有可用的 Runner。

下面是一个示例文件:

stages:
  - code_scan
  - eslint_check

代码扫描:
  stage: code_scan
  tags:
    - code-check
  script:
    - cd ${CI_PROJECT_DIR}
    - chmod +x ./.gitlab/ci/codeCheck.sh
    - ./.gitlab/ci/codeCheck.sh encore
  allow_failure: true
  when: always
  only:
    variables:
      - $UEDC_MERGE_REQUEST_APPROVED == "true"

eslint检查:
  stage: eslint_check
  tags:
  	- eslint-check
  script:
  	- ./.gitlab/ci/eslintCheck.sh encore
  only:
  	- pushes

stages

    它定义了整个流水线的阶段,你的流水线的任务会按照这个阶段的编写顺序一步步来执行。

    接下来就需要指定 Job,即流水线要做的事情。比如我这里就制定了 代码扫描eslint检查 两个任务。 以 代码扫描 为例来讲述 Job 的内容。

stage

    它表示 代码扫描 这个任务属于哪一个阶段,前面说了 stages 会按照定义的顺序来执行,也就是说如果多个 Job 都属于同一个 stage,那么这些 Job 是同时执行的。

tags

    它用来指定这个 Job 在哪个特定的 Runner 上执行,因为不同的任务可能需要不同的运行环境,一个公用的 Runner 无法满足。

script

    它定义了这个 Job 具体要做的事情。如果比较简单,那么就可以直接在这里写上脚本命令;如果比较复杂,则建议将其单独写在某个文件里。这里是写在了 codeCheck.sh 这个 shell 文件里。

allow_failure

    它表示这个 Job 是否允许失败,即它是否会阻塞剩余的 CI 执行

when

    它指定这个任务的执行时机。有以下字段可配置:

only

    这个字段定义 Job 在什么时候被创建,注意这个【创建】,说明从过程上来说它是在 when 之前。

    它的内容还蛮多的,详细可以见这里。简单来说你可以指定:

    顺带一提,示例文件中代码扫描任务 script 中 CI_PROJECT_DIR 是 GitLab的环境变量,这里指的是仓库存放代码的路径,比如 CI_PROJECT_NAME 是当前仓库名。

    接下来便是编写各任务的脚本代码,这个当然就是具体问题具体编写了。

#!/bin/sh

echo "这里是代码扫描任务"

npm i codeScan -D

codeScan check ./src

if [ $? != 0 ]; then 
    echo "代码扫描失败";
    exit 1;
fi

echo "代码检查结束"

    至此一个可用的流水线服务就写完了,还是很简单的。

结合 GitLab webhook

    在实际的搭建中,可能由于 GitLab版本原因导致某些配置/字段不支持,因此需要结合 webhook 来解决。这里以我遇到的问题为例。

    我期望代码检查是在提交合并请求的时候执行,要等扫描没有问题或者扫描出来的问题被解决的情况下,该分支才允许被合入。Gitlab 可以通过配置 only 字段来解决这个实现这个操作:

only:
	- merge_request

    但还是由于版本原因,该字段不支持,因此只能另辟蹊径。

    在 GitLab中,我们可以对项目配置 webhook,配置路径在项目左侧菜单中 设置->集成。绑定项目触发的事件和一个自己的 web 服务后,GitLab 会在这个事件发生时向 web 服务发送 post 请求。比如我勾选触发器事件为合并请求事件,配置服务链接地址为 https://test.com/merge_reqest,那么就可以实现在提交合并请求时告知我的 web 服务,同时 GitLab 会携带很多有用的数据过来供我操作,那么通过配置 webhook 以及结合 GitLab API,便可以在自己的 web 服务中实现代码扫描流水线任务的触发。

    由于 webhook 需要安全令牌来验证接收信息的有效性,它将通过 HTTP 头的 X-Gitlab-Token 发送。这个 token 是在我们配置触发器时要配置的,它的生成方法是:

    接下来实现这个 web 服务。 web 服务的路由为 /merge_request,该路由处理逻辑的伪代码如下:

// headers 和 body 数据是由 GitLab 的请求带过来的数据,根据具体实现该服务的框架来获取

const token = headers['x-gitlab-token'];
const { 
	projectId,    // 该项目的id
	source_branch,    // 当前提交合并请求的分支
	target_branch,    // 要合入的目标分支
} = body;

// 要添加到 CI 中的变量,比如代码扫描中要用到的 UEDC_MERGE_REQUEST_APPROVED 字段
const variables = 'variables[UEDC_MERGE_REQUEST_APPROVED]=true&variables[UEDC_MERGE_REQUEST_IID]=123';

// 触发流水线的 api
const triggerPipeline = `[你的gitlab地址]/api/v4/projects/${projectId}/trigger/pipeline?ref=${source_branch}&token=${token}&${variables}`;

// 发送请求
http.post(triggerPipeline);

这样便可以在提交合并请求时通过 web 服务来触发流水线执行。

Comments: