CI 模板

CI 模板说明 #

Pulse CI 的模板配置语法参考 Gitlab CI,语法跟 .gitlab-ci.yml 类似

CI 模板通过声明式的配置,定义了流水线的执行过程

Git repo 的 CI 执行时,会读取模板的配置,然后开始 CI 的执行过程

目前仅支持通过 Gitlab Repo 统一管理所有的模板(版本控制,权限控制)

CI 模板配置关键字 #

模板配置通过 yaml 描述(运行时 parse 为 json 解析执行),模板里配置的关键字包括全局关键字和 job 级别的关键字

全局关键字如下:

关键字 含义
default job 关键字的全局默认值
stages 流水线的执行阶段
variables 流水线级别的变量配置,所有 job 共享
workflow 控制流水线的行为

job 关键字如下:

关键字 含义
artifacts job 执行成功后的产物
cache job 的缓存
extends job 继承的 job 配置
rules 控制 job 是否进入当前流水线
script job 运行时执行的 shell 脚本
stage job 运行在哪个阶段
when job 的执行时机

全局关键字 #

default #

为某些 job 关键字 提供全局默认配置,现阶段支持配置的 job 关键字如下

  1. image

workflow #

用于控制 Pipeline 的行为

workflow.rules #

用于控制 pipeline 是否会被创建,当所有 rules 都非 true 时,pipeline 不会被创建

variables #

流水线级别的变量配置,所有 job 共享,分为普通变量和系统变量两种类型

普通变量主要用于控制 job 的执行行为,由模板配置者定义并在 job 块里使用。系统变量由 Pulse CI 读取,用于控制 CI 系统的行为

系统变量主要有以下几个:

deploy_window #

允许执行 CI 的时间窗口, 当前 CI 触发的服务器时间,必需在当前变量配置的时间窗口范围内

no_deploy_window #

不允许执行 CI 的时间窗口,当前 CI 触发的服务器时间,必需在当前变量配置的时间窗口范围外

当跟 deploy_window 同时存在时,以 deploy_window 为准

envs #

当前模板支持发布到的环境,在流水线创建时,可选取这里预设的环境,选取后通过 $PULSE_CI_DEPLOY_ENV 变量,注入到当前流水线的执行环境中

可根据这个变量值,用于控制 job 的执行环境,配置示例:

envs:
  - test1
  - test4
  - name: integration
    need_approval: "yes"
  - name: pre
    need_approval: "yes"
  - name: prod
    # 是否需要审批,如果有 manual job 只限制 manual job,否则限制当前流水线所有 job
    need_approval: "yes"
    # 是否受发布时间窗口限制,如果有 manual job 只限制 manual job,否则限制当前流水线所有 job
    deploy_window_limit: "yes"

单个环境可额外配置 need_approval, deploy_window_limit 属性,作用如配置示例所示

stages #

流水线的执行要经过哪些阶段,每阶段按序执行,一个阶段可以有多个 Job,每个 Job 并发执行

配置示例:

stages:
  - prepare # 注意,用户定义的模板里不要有这个 stage
  - instalal
  - build
  - deploy

注意,prepare 为保留 stage,用于统计拉代码,拉镜像的时间,用户定义的模板里不要有这个 stage

Job 关键字 #

artifacts #

Job 的构建产物

在 Job 的 script 和 cache 逻辑执行完后,将 artifacts 压缩并上传到 api server

cache #

Job 的缓存

配置示例

cache-job:
  stage: final
  script:
    - echo "This job builds a cache."
    - yarn

  cache:
    key:
      files:
        - yarn.lock
        - package.json

    skip_scripts_if_found: "yes"
    paths:
      - node_modules
    # 上传缓存
    policy: push

cache.key.files #

cache.policy #

值可为 pull, push, 或 pull-push

当 cache.policy 的值为 pull 时

  1. 根据 cache.key.files 配置的文件,计算 sha 值, 从 api server 获取当前 sha 值对应的文件,并下载到当前执行环境中
  2. 如果缓存下载到了本地,且 cache.skip_scripts_if_found 的配置为 ‘yes’,则跳过 script 的执行

当 cache.policy 的值为 push 时

  1. 先执行 script 的内容
  2. script 执行成功后,将 paths 里声明的文件路径压缩,并根据 key 的配置计算 sha 值,上传到 manager

当 cache.policy 的值为 pull-push 时

  1. 根据 cache.key.files 配置的文件,计算 sha 值, 从 manager 获取当前 sha 值对应的文件,并下载到当前执行环境中
  2. 如果缓存下载到了本地,且 cache.skip_scripts_if_found 的配置为 ‘yes’,则跳过 script 的执行,否则执行 script
  3. script 执行成功后,并根据 key.files 的配置计算 sha 值,并将当前 sha 值跟 manager 校验,决定是否上传缓存,如果 sha 值已存在则不执行缓存逻辑

rules #

控制 Job 是否进入到当前 Pipeline

Job 默认都是会进到 pipeline,仅当有一条 rule.if 的 shell 执行 exitCode 非 0 时,Job 不会进到 pipeline

示例:

job:
  script: echo "Hello, Rules!"
  # 没有 rules,默认进入 pipeline
  rules:
    # 有 rules,任意一个 if 为 false, 则不会进入到 pipeline;
    # 换言之,所有 if 都得满足条件才会进入到 pipeline
    - if: $PULSE_CI_DEPLOY_ENV == "prod"
    - if: $PULSE_CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $PULSE_CI_DEPLOY_BRANCH == "main'

script #

Job 执行的 Shell 命令,控制 Job 执行时的行为

stage #

控制 Job 在哪个 Stage 执行

when #

控制 Job 进入 Pipeline 后的执行条件

变量设置 #

流水线的静态行为通过模板默认配置控制,动态行为由变量控制,变量分三个级别: 模板变量 项目变量 流水线变量

变量配置后,运行时会被注入到 CI 的运行环境中,可在 job 的 script , rules 块里读取,

变量优先级 流水线变量 > 项目变量 > 模板变量,优先级由高到低

模板变量 #

在 CI 模板里配,变量对当前模板生效,所有用到这个模板的 repo 在 CI 执行时都可在运行环境中读到该变量

项目变量 #

在项目设置里配,仅对当前项目生效,变量同 key 会覆盖模板级别变量

流水线变量 #

创建流水线时指定,优先级最高

CI 模板类型定义 #

如下使用 typescript 描述 CI 模板的类型

type foo: string

CI 模板完整示例 #

# 全局默认配置
default:
  # 提供当前 pipeline 所有 job 的 scripts 执行的运行环境
  image: node:14

# 全局环境变量定义,所有 job 都可以读取
variables:
  var_foo: foo
  # 允许发布的时间窗口
  deploy_window:
    - 14:00 ~ 17:00
    - 10:00 ~ 12:00
  # 不允许发布的时间窗口,跟上面这个不能同时存在,同时存在以 deploy_window 为准
  no_deploy_window:
    - 9:00 ~ 17:00
  # 提供流水线的发布环境选项
  envs:
    - test1
    - test4
    - name: integration
      need_approval: "yes"
    - name: pre
      need_approval: "yes"
    - name: prod
      # 是否需要审批,如果有 manual job 只限制 manual job,否则限制当前流水线所有 job
      need_approval: "yes"
      # 是否受发布时间窗口限制,如果有 manual job 只限制 manual job,否则限制当前流水线所有 job
      deploy_window_limit: "yes"

# 当前 pipeline 所需的 stage,按序从上至下执行
stages:
  - lint
  - test
  - build
  - deploy
  - final

prepare_dependencies:
  stage: prepare
  cache:
    key: yarn.lock
    paths:
      - node_modules
    # 下载缓存
    policy: pull
    # 如果有 cache 跳过脚本
    skip_scripts_if_found: "yes"
  script:
    - echo "This job only downloads cache"
    - echo "Downloading dependencies..."
    - yarn

# 单个 job
lint_code:
  # job 属于哪个 stage
  stage: lint
  # job 运行时执行的 shell 脚本
  script: npm run lint

test_node_12:
  # job 执行依赖的 docker image,覆盖全局默认的 image
  image: node:12
  stage: test
  # 可以有多行 script,按序从上至下执行,
  # 任一 script 执行后 exitCode 非 0,则终止 job 的执行,job failed
  script:
    - uname -a
    - echo 'hello'

test_node_14:
  image: node:14
  stage: test
  script: echo 'node 14'

build_code:
  stage: build
  script: npm run build
  # job 进入 pipeline 需满足的条件
  rules:
    - if $PULSE_CI_DEPLOY_ENV != "prod"
  # job 执行后的产物
  artifacts:
    # 产物的路径
    paths:
      - dist/

build_code_prod:
  stage: build
  script: npm run build:prod
  rules:
    - if $PULSE_CI_DEPLOY_ENV == "prod"
  artifacts:
    paths:
      - dist/

deploy_to_test:
  stage: deploy
  image: deploy_scp_image
  script: echo "deploy to test"
  rules:
    - if $CI_TRIGGER_ENV != prod

cache-job:
  stage: final
  script:
    - echo "This job builds a cache."
  cache:
    key: yarn.lock
    paths:
      - node_modules
    # 上传缓存
    policy: push

deploy_to_prod:
  stage: deploy
  image: deploy_oss_image
  script: echo "deploy to prod"
  rules:
    - if $CI_TRIGGER_ENV == prod
  # job 不会自动执行,需要手动触发
  when: manual