gitlab--workflow、rules

发布时间 2023-06-17 21:26:42作者: 邹邹很busy。

workflow

workflow 关键字适用于整个管道,并将确定是否创建管道。when :可以设置为alwaysnever . 如果未提供,则默认值always

  • if:定义变量条件
  • when:只有两个值,always 和 nevel
if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
合并请求时运行流水线
if: '$CI_PIPELINE_SOURCE == "psuh"'
提交代码运行流水线
workflow:
  rules:
    - if: '$CI_PIPELINE_SOURCE == "push"' # 当为 push 的时候才会触发,其他情况下不会触发该流水线
      when: never # 上面的条件为 true 时,永远不执行
    - when: always # 上面的条件为 false 时,永远执行

stages: # 指定运行的步骤,没有指定就顺序执行
  - build
  - deploy
  - test
  - rebase

build1: # job 的名称
  tags: 
    - k8s # 指定运行的 runner 标签
  stage: build # stage 的名称
  script:
    - echo "Do your build here"

test1:  
  stage: test
  script:
    - echo "Do a test here"
    - echo "For example run a test suite" 

rebase:
  stage: rebase
  script:
    - echo "Do another parallel test here"
    - echo "For example run a lint test"
  

deploy1:
  tags: 
    - k8s
  stage: deploy
  script:
    - echo "Do your deploy here"

当上面执行 push 操作时,才会运行流水线,否则不会运行流水线

rules

rules 可以按照设置的规则来判断是否执行流水线,也可以设置以什么样的方式执行(when)

rules 有三个关键字

  • if:判断条件,如果条件满足时执行该 job,不满足时不执行 job
  • changes:某个或多个文件改变时执行该 job,没有改变时不执行 job
  • exists:文件存在时执行该 job,不存在时不执行 job
if

if 可以使用多条件,&& 所有条件满足时才会执行该 job,|| 某个条件满足时就会执行该 job

stages: # 指定运行的顺序
  - test
  - deploy

variables:
  name: zouzou

deploy:
  tags:
    - k8s
  stage: deploy
  retry:
  parallel: 3 # 要并行运行的作业实例数
  rules:
    - if: '$name == "zouzou"' # 如果变量名等于 zouzou,则运行流水线,将流水线设置为手动执行
      when: manual
    - if: '$name == "haha"' # 如果变量名等于 haha,则延迟 10 秒执行
      when: delayed 
      start_in: "10"
    - when: on_success # 上面两个条件都不满足的话,则上个流水线成功时该流水线触发
  script:
    - echo "我是部署阶段"
  
test:
  stage: test
  script:
    - echo "我是测试阶段"

现在 name 的值是等于 zouzou的,查看流水线

将 name 的值改为 haha,在来查看流水线

changes

接受文件路径数组。 如果提交中Dockerfile文件发生的变化则为 true。触发流水线

先在项目下创建一个 Dockerfile 的文件,随便写点内容

修改 .gitlab-ci.yml 文件内容,修改后的如下

stages: # 指定运行的顺序
  - test
  - deploy

variables:
  name: haha

deploy:
  tags:
    - k8s
  stage: deploy
  retry:
  parallel: 3 # 要并行运行的作业实例数
  rules:
    - changes: # 当 Dockerfile 或者 Jenkinsfile 里的文件内容改变时,才会执行 deploy 的 job
      - Dockerfile
      - Jenkinsfile
  script:
    - echo "我是部署阶段"
  
test:
  stage: test
  script:
    - echo "我是测试阶段"

触发流水线查看下,可以看到,只有 test 的 job 触发了

这时候只有 Dockerfile 或者 Jenkinsfile 里的文件没有发生改变,deploy 的 job 都不会触发

接下来我们修改一下 Dockerfile 的内容,然后提交

提交后查看流水线

exists

接受文件路径数组。当仓库中存在指定的文件时操作

stages: # 指定运行的顺序
  - test
  - deploy

variables:
  name: haha

deploy:
  tags:
    - k8s
  stage: deploy
  retry:
  parallel: 3 # 要并行运行的作业实例数
  rules:
    - exists: # 当项目中存在 Dockerfile 或者 Jenkinsfile 文件时,才会执行 deploy 的 job
      - Dockerfile
      - Jenkinsfile
  script:
    - echo "我是部署阶段"
  
test:
  stage: test
  script:
    - echo "我是测试阶段"

实际项目中使用 rules 的场景

下面几个例子是我们公司实际项目中 gitlab ci 的场景

例子一:在合 pr 的时候触发 job
static_check:
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"' # 是合 pr 的时候才执行该 job
  tags:
    - docker
  stage: verify
  script: # 执行的操作
    - make clean
    - make genproto
    - go mod vendor
    - make lint
  interruptible: true

verify_import_alias:
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'  # 是合 pr 的时候才执行该 job
  stage: verify
  tags:
    - k8s
  script:
    - make verify-import-alias
  interruptible: true

演示

在我们的 main 分支下的 .gitlab-ci.yml 里写入下面内容

stages: # 指定运行的顺序
  - test
  - deploy

variables:
  name: haha

deploy:
  tags:
    - k8s
  stage: deploy
  retry:
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"' # 合 pr 时触发
  script:
    - echo "我是部署阶段"
  
test:
  stage: test
  script:
    - echo "我是测试阶段"

基于 main 分支创建一个 demo 分支,修改 demo 分支上的文件,然后提交到 demo 分支上,也可以使用 git 提交

提交后查看流水线,发现只有一个 test 的 job 触发了(要保证 demo 分支的和 main 分支的 .gitlab-ci.yml 里的文件内容一样,如果不一样会以 demo 分支的为准)

这时候我们在提交一个 pr 到 main 分支

可以看到,提交 pr 只会跑 '$CI_PIPELINE_SOURCE == "merge_request_event"' 的 job ,我们的 test job 没有触发

例子二:满足某个条件时执行
unit_test:
  rules: # 合 pr 或者提交到的分支是 main 分支。或者是创建 tag,只要满足某一个,都会触发该 job
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event" || $CI_COMMIT_BRANCH == "main" || $CI_COMMIT_TAG' 
  stage: test
  tags:
    - docker
  script:
    - make genproto
    - go mod vendor
    - make test
  interruptible: true
  coverage: '/total:\s+\(statements\)\s+\d+.\d+%/'

例子三:当往 main 分支 push 时触发
build_to_release_ci:
  rules: # 提交的分支是 main 分支并且是 push 操作时才触发该流水线,&& 条件都要满足
    - if: '$CI_COMMIT_BRANCH == "main" && $CI_PIPELINE_SOURCE == "push"' # trigger when a branch was merged into main
  retry:
    max: 2
  tags:
    - docker
  before_script:
    - docker -v #override the global before_script
    - make genall
    - go mod vendor
  stage: build
  script:
    - |
      # set envirment varible when new release publish by new tag created
      export REGISTRY_USER_NAME=$CI_REGISTRY_USER_NAME
      export REGISTRY_PASSWORD=$CI_REGISTRY_PASSWORD
      export REGISTRY_REPO="release-ci.daocloud.io/amamba"
      export REGISTRY_SERVER_ADDRESS="release-ci.daocloud.io"
      export HELM_REPO="https://release-ci.daocloud.io/chartrepo/amamba"
      make release -j2 #REGISTRY_USER_NAME and REGISTRY_PASSWORD config as Gitlab Variables
      export NPM_TOKEN=$NPM_TOKEN;make push-grpc-ts   #NPM_TOKEN has been configured as Gitlab Variable

例子四:创建 tag 或者往 main 分支上 merge 时触发
build_to_release_ci:
  rules: # 往 main 分支上 merge 或者创建 tag 的时候触发
    - if: '($CI_COMMIT_BRANCH == "main" && $CI_PIPELINE_SOURCE == "merge_request_event") || $CI_COMMIT_TAG' 
  tags:
    - docker
  before_script:
    - docker -v
  stage: build
  script:
    - |
      # set envirment varible when new release publish by new tag created
      export REGISTRY_USER_NAME=$CI_REGISTRY_USER_NAME
      export REGISTRY_PASSWORD=$CI_REGISTRY_PASSWORD
      export REGISTRY_REPO="release-ci.daocloud.io/amamba"
      export REGISTRY_SERVER_ADDRESS="release-ci.daocloud.io"
      make release #REGISTRY_USER_NAME and REGISTRY_PASSWORD config as Gitlab Variables