CI流水线配置文件参数详解(一)

文章目录

4. 参数详解(一)

4.1 script


``script`` 是作业中唯一必须的关键字参数,是运行器需要执行的脚本,如:

    build1:
      script:
        - echo "Do your build here"
        - uname -a

表示build1作业需要执行的命令是输出"Do your build here"。

.. WARNING:: Sometimes, script commands will need to be wrapped in single or double quotes. For example, commands that contain a colon (:) need to be wrapped in quotes so that the YAML parser knows to interpret the whole thing as a string rather than a “key: value” pair. Be careful when using special characters: :, {, }, \[, \], ,, &, \*, #, ?, \|, -, <, >, =, !, %, @, \`. 即使用冒号时应使用引号包裹起来,使用特殊字符时需要特别注意!!!注意如果要输出冒号字符,冒号后面不能紧接空格!!!

``image``

4.2 image 指定使用Docker镜像。如 iamge:name ,暂时忽略。

services


``services`` 指定使用Docker镜像服务。如 ``services:name`` ,暂时忽略。

``before_script``

4.3 before_script 用于定义在所有作业之前需要执行的命令,比如更新代码、安装依赖、打印调试信息之类的事情。

示例::

before_script:
  - echo "Before script section"
  - echo "运行更新或安装构建依赖项"
  - echo "打印出一些调试细节"

4.4 after_script


``after_script`` 用于定义在所有作业(即使失败)之后需要执行的命令,比如清空工作空间。

示例::

    after_script:
      - echo "After script section"
      - echo "For example you might do some cleanup here"

.. Important::

    - before_script和script在一个上下文中是串行执行的,after_script是独立执行的,即after_script与before_script/script的上下文环境不同。
    - after_script会将当前工作目录设置为默认值。
    - 由于after_script是分离的上下文,在after_script中无法看到在before_script和script中所做的修改:
    
        - 在before_script和script中的命名别名、导出变量,对after_script不可见;
        - before_script和script在工作树之外安装的软件,对after_script不可见。
    
    - 你可以在作业中定义before_script,after_script,也可以将其定义为*元素,定义为*元素将为每一个任务都执行相应阶段的脚本或命令。
    - 作业级会覆盖全局级的定义。

示例::

    before_script:
      - echo "Before script section"
      - echo "例如,您可以在这里运行更新或安装构建依赖项"
      - echo "或者,您可能会打印出一些调试细节"
    
    after_script:
      - echo "After script section"
      - echo "例如,你可以在这里做一些清理"
    
    build1:
      stage: build
      before_script:
        - echo "在构建阶段重写全局定义的before_script的Before脚本"
        - echo "安装cloc:一个从给定目录中计算不同语言的代码行数的工具"
        - yum install cloc -y
      after_script:
        - echo "在构建阶段重写全局定义的after_script的After脚本"
        - cloc --version
        - cloc .
      script:
        - echo "Do your build here"
        - cloc --version
        - cloc .
      tags:
        - bluelog

将修改上传提交,查看作业build1的控制台输出:

可以发现build1作业的 ``before_script`` 和 ``after_script`` 将全局的 ``before_script`` 和 ``after_script`` 覆盖了。


``stages``

4.5 stages 定义流水线全局可使用的阶段,阶段允许有灵活的多级管道,阶段元素的排序定义了作业执行的顺序。

  • 相同 stage 阶段的作业并行运行。
  • 默认情况下,上一阶段的作业全部运行成功后才执行下一阶段的作业。
  • 默认有三个阶段, buildtestdeploy 三个阶段,即 构建测试部署
  • 如果一个作业未定义 stage 阶段,则作业使用 test 测试阶段。
  • 默认情况下,任何一个前置的作业失败了,commit提交会标记为failed并且下一个stages的作业都不会执行。

4.6 stage


``stage`` 定义流水线中每个作业所处的阶段,处于相同阶段的作业并行执行。

示例::

    # This file is a template, and might need editing before it works on your project.
    # see https://docs.gitlab.com/ce/ci/yaml/README.html for all available options
    
    
    before_script:
      - echo "Before script section"
      - echo "For example you might run an update here or install a build dependency"
      - echo "Or perhaps you might print out some debugging details"
    
    after_script:
      - echo "After script section"
      - echo "For example you might do some cleanup here"
    
    stages:
      - build
      - code_check
      - test
      - deploy
      
    build1:
      stage: build
      before_script:
        - echo "Before script in build stage that overwrited the globally defined before_script"
        - echo "Install cloc:A tool to count lines of code in various languages from a given directory."
        - yum install cloc -y
      after_script:
        - echo "After script in build stage that overwrited the globally defined after_script"
        - cloc --version
        - cloc .
      script:
        - echo "Do your build here"
        - cloc --version
        - cloc .
      tags:
        - bluelog
    
    find Bugs:
      stage: code_check
      script:
        - echo "Use Flake8 to check python code"
        - pip install flake8
        - flake8 --version
        - flake8 .
      tags:
        - bluelog
        
    test1:
      stage: test
      script:
        - echo "Do a test here"
        - echo "For example run a test suite"
      tags:
        - bluelog
    
    test2:
      stage: test
      script:
        - echo "Do another parallel test here"
        - echo "For example run a lint test"
      tags:
        - bluelog
        

我们增加一个 ``code_check`` 阶段,该阶段有一个作业 ``find Bugs`` ,该作业主要是**先安装Flake8,然后使用Flake8对Python代码进行规范检查。**
因为笔者平时主要使用代码为C++,因此这里可以选择相应的C++静态代码检测工具。

由于Flake8检查到了Python代码中的缺陷,导致find Bugs作业失败!这样可以控制开发人员提交有坏味道的代码到仓库中。(C++同样的道理)


本次(pipeline #7)流水线由于在作业 ``find Bugs`` 检查不通过,导致整个流水线运行失败,后续的作业不会执行:

    默认情况下,GitLab Runner运行器每次只执行一个作业,只有当满足以下条件之一时,才会真正的并行执行:
    
        - 作业运行在不同的运行器上;
        - 你修改了运行器的 ``concurrent`` 设置,默认情况下 ``concurrent = 1`` 。 

``only`` 和 ``except``

4.7 onlyexcept 用于在创建作业时对作业的限制策略。

  • only 定义了哪些分支或标签(branches and tags)的作业会运行
  • except 定义了哪些分支或标签(branches and tags)的作业不会运行

下面是策略规则:

  • onlyexcept 可同时使用,如果在一个作业中同时定义了 onlyexcept ,则同时 only except 进行过滤(注意,不是忽略 except 条件) 。
  • onlyexcept 可以使用正则表达式。
  • onlyexcept 允许指定用于过滤forks作业的存储库路径。
  • onlyexcept 中可以使用特殊的关键字,如 branchestagsapiexternalpipelinespushesschedulestriggerswebmerge_requestschats 等。

onlyexcept 中可以使用特殊的关键字:

关键字 描述释义
branches 当一个分支被push上来
tags 当一个打了tag标记的Release被提交时
api 当一个pipline被第二个piplines api所触发调起(不是触发器API)
external 当使用了GitLab以外的外部CI服务,如Jenkins
pipelines 针对多项目触发器而言,当使用CI_JOB_TOKEN, 并使用gitlab所提供的api创建多个pipelines的时候
pushes 当pipeline被用户的git push操作所触发的时候
schedules 针对预定好的pipline计划而言(每日构建一类)
triggers 用触发器token创建piplines的时候
web 在GitLab WEB页面上Pipelines标签页下,按下run pipline的时候
merge_requests 当合并请求创建或更新的时候
chats 当使用GitLab ChatOps 创建作业的时候

在下面这个例子中,job将只会运行以 issue- 开始的refs(分支),然而except中指定分支不能执行,所以这个job将不会执行:

job:
  # use regexp
  only:
    - /^issue-.*$/
  # use special keyword
  except:
    - branches

匹配模式默认是大小写敏感的(case-sensitive),使用 i 标志,如 /pattern/i 可以使匹配模式大小写不敏感::

job:
  # use regexp
  only:
    - /^issue-.*$/i
  # use special keyword
  except:
    - branches

下面这个示例,仅当指定标记的tags的refs引用,或者通过API触发器的构建、或者流水线计划调度的构建才会运行:

job:
  # use special keywords
  only:
    - tags
    - triggers
    - schedules

仓库的路径(repository path)只能用于父级仓库执行作业,不能用于forks:

job:
  only:
    - branches@gitlab-org/gitlab-ce
  except:
    - master@gitlab-org/gitlab-ce
    - /^release/.*$/@gitlab-org/gitlab-ce

上面这个例子,将会在所有分支执行,但 不会在 master主干以及以release/开头的分支上执行。

  • 当一个作业没有定义 only 规则时,其默认为 only: ['branches', 'tags']
  • 如果一个作业没有定义 except 规则时,则默认 except 规则为空。

下面这个两个例子是等价的:

job:
  script: echo 'test'

转换后::

job:
  script: echo 'test'
  only: ['branches', 'tags']

… Attention::

关于正则表达式使用的说明:

- 因为 ``@`` 用于表示ref的存储库路径的开头,所以在正则表达式中匹配包含 ``@`` 字符的ref名称需要使用十六进制字符代码 ``\x40`` 。
- 仅标签和分支名称才能使用正则表达式匹配,仓库路径按字面意义匹配。
- 如果使用正则表达式匹配标签或分支名称,则匹配模式的整个引用部分都是正则表达式。
- 正则表达式必须以 ``/`` 开头和结尾,即 ``/regular expressions/`` ,因此, ``issue-/.*/`` 不会匹配以 ``issue-`` 开头的标签或分支。
- 可以在正则表达式中使用锚点 ``^$`` ,用来匹配开头或结尾,如 ``/^issue-.*$/`` 与 ``/^issue-/`` 等价, 但  ``/issue/`` 却可以匹配名称为 ``severe-issues`` 的分支,所以正则表达式的使用要谨慎!

4.8 onlyexcept 高级用法


- ``only`` 和 ``except`` 支持高级策略,``refs`` 、 ``variables`` 、 ``changes`` 、 ``kubernetes`` 四个关键字可以使用。
- 如果同时使用多个关键字,中间的逻辑是 ``逻辑与AND`` 。


``only:refs/except:refs``


- ``refs`` 策略可以使用 ``only`` 和 ``except`` 基本用法中的关键字。

下面这个例子中,deploy作业仅当流水线是计划作业或者在master主干运行::

    deploy:
      only:
        refs:
          - master
          - schedules



``only:kubernetes/except:kubernetes``


- ``kubernetes`` 策略仅支持 ``active`` 关键字。

下面这个例子中,deploy作业仅当kubernetes服务启动后才会运行:

    deploy:
      only:
        kubernetes: active

``only:variables/except:variables``

- ``variables`` 关键字用来定义变量表达式,你可以使用预定义变量、项目、组、环境变量来评估一个作业是否需要创建或运行。

下面这个例子使用了变量表达式::

    deploy:
      script: cap staging deploy
      only:
        refs:
          - branches
        variables:
          - $RELEASE == "staging"
          - $STAGING

下面这个例子,会根据提交日志信息来排除某些作业::

    end-to-end:
      script: rake test:end-to-end
      except:
        variables:
          - $CI_COMMIT_MESSAGE =~ /skip-end-to-end-tests/

``only:changes/except:changes``

- ``changes`` 策略表明一个作业只有在使用 ``git push`` 事件使文件发生变化时执行。

下面这个例子中,deploy作业仅当流水线是计划作业或者在master主干运行::

    docker build:
      script: docker build -t my-image:$CI_COMMIT_REF_SLUG .
      only:
        changes:
          - Dockerfile
          - docker/scripts/*
          - dockerfiles/**/*
          - more_scripts/*.{rb,py,sh}

上面这个例子中,一旦 ``Dockerfile`` 文件发生变化,或者 ``docker/scripts/`` 目录下的文件发生变化,或者 ``dockerfiles/`` 目录下的文件或目录发生变化,或者 ``more_scripts/`` 目录下 ``rb,py,sh`` 等脚本文件发生变化时,就会触发Docker构建。

- 也可以使用 ``glob模式匹配`` 来匹配根目录下的文件,或者任何目录下的文件。

如下示例::

    test:
      script: npm run test
      only:
        changes:
          - "*.json"
          - "**/*.sql"

.. Attention::

    在上面的示例中,``glob模式匹配`` 的字符串需要使用双引号包裹起来,否则会导致 ``.gitlab-ci.yml`` 解析错误。

下面这个例子,当md文件发生变化时,会忽略CI作业::

    build:
      script: npm run build
      except:
        changes:
          - "*.md"


.. Warning::

    记录一下官网说明中使用 ``change`` 时需要注意的两点:
    
    - Using changes with new branches and tags:When pushing a new branch or a new tag to GitLab, the policy always evaluates to true and GitLab will create a job. This feature is not connected with merge requests yet and, because GitLab is creating pipelines before a user can create a merge request, it is unknown what the target branch is at this point.
    - Using changes with merge_requests:With pipelines for merge requests, it is possible to define a job to be created based on files modified in a merge request.

在合并请求中使用 ``change`` 策略::

    docker build service one:
      script: docker build -t my-service-one-image:$CI_COMMIT_REF_SLUG .
      only:
        refs:
          - merge_requests
        changes:
          - Dockerfile
          - service-one/**/*

上面这个例子中,一旦合并请求中修改了 ``Dockerfile`` 文件或者修改了 ``service`` 目录下的文件,都会触发Docker构建。

``only`` 和 ``except`` 综合示例

我们将 bluelog 项目的描述和主题进行修改:
创建三个分支 issue-pylintIssue-flake8severe-issues

CI流水线配置文件参数详解(一)
刚新增的三个分支,自动继承了master主干的CI RUNNER。

为了便于测试,将"sunshine"账号设置为 bluelog 项目的主程序员!

现在朝 .gitlab-ci.yml 文件中增加 onlyexcept 策略。匹配 issue- 开头的分支,创建仅匹配 issue- 开头的分支:

CI流水线配置文件参数详解(一)

设置后可以发现master主干没有执行 find Bugs 作业,现在只会触发同时满足CI触发按钮的条件和only条件的分支。
为了快速测试,我们对每个作业都使用 onlyexcept 策略:

# This file is a template, and might need editing before it works on your project.
# see https://docs.gitlab.com/ce/ci/yaml/README.html for all available options


before_script:
  - echo "Before script section"
  - echo "For example you might run an update here or install a build dependency"
  - echo "Or perhaps you might print out some debugging details"

after_script:
  - echo "After script section"
  - echo "For example you might do some cleanup here"

stages:
  - build
  - code_check
  - test
  - deploy
  
build1:
  stage: build
  before_script:
    - echo "Before script in build stage that overwrited the globally defined before_script"
    - echo "Install cloc:A tool to count lines of code in various languages from a given directory."
    - yum install cloc -y
  after_script:
    - echo "After script in build stage that overwrited the globally defined after_script"
    - cloc --version
    # cloc .
  only:
    - /^issue-.*$/
  except:
    - master
  script:
    - echo "Do your build here"
    - cloc --version
    # - cloc .
  tags:
    - bluelog

find Bugs:
  stage: code_check
  only:
    - /^issue-.*$/
  except:
    - branches
  script:
    - echo "Use Flake8 to check python code"
    - pip install flake8
    - flake8 --version
    # - flake8 .
  tags:
    - bluelog
    
test1:
  stage: test
  only:
    - /^issue-.*$/
  except:
    - /issue-pylint/
  script:
    - echo "Do a test here"
    - echo "For example run a test suite"
  tags:
    - bluelog

test2:
  stage: test
  only:
    - /^issue-.*$/
  except:
    - /Issue-flake8/
  script:
    - echo "Do another parallel test here"
    - echo "For example run a lint test"
  tags:
    - bluelog
    
deploy1:
  stage: deploy
  only:
    - /^issue-.*$/
  except:
    - /severe-issues/
  script:
    - echo "Do your deploy here"
  tags:
    - bluelog

提交后,直接入库,检查master主干,并没有触发流水线作业。

统计作业流水线作业情况:

分支 流水线 build1 find Bugs test1 test2 deploy1
master 未触发
issue-pylint #22 Yes No No Yes Yes
Issue-flake8 未触发
severe-issues 未触发

解释上面的流水作业策略:

作业 规则定义 规则解释
build1 only: - /^issue-.*$/ except: - master 只在以issue-开头的分支执行,不在master主干执行
find Bugs only: - /^issue-.*$/ 、except: - branches 只在以issue-开头的分支执行,不在 branches 分支执行, 由于issue-pylint也是分支,所以在issue-pylint中也不会执行find Bugs作业
test1 only: - /^issue-.*$/ except: - /issue-pylint/ 只在以issue-开头的分支执行,不在issue-pylint分支执行,即会在除了issue-pylint分支以外的issue-开头的分支执行,也即没有分支执行
test2 only: - /^issue-.*$/ except: - /Issue-flake8/ 只在以issue-开头的分支执行,不在Issue-flake8分支执行,因此可以issue-pylint分支执行
deploy1 only: - /^issue-.*$/ except: - /severe-issues/ 只在以issue-开头的分支执行,不在severe-issues分支执行 因此可以issue-pylint分支执行

大小写不敏感匹配

好,我们再将 only 语法中加入语法大小写不敏感的 i 标志!再来做一次实验,看看最终的效果。

加入语法大小写不敏感的 i 标志:

# This file is a template, and might need editing before it works on your project.
# see https://docs.gitlab.com/ce/ci/yaml/README.html for all available options

 before_script:
  - echo "Before script section"
  - echo "For example you might run an update here or install a build dependency"
  - echo "Or perhaps you might print out some debugging details"

after_script:
  - echo "After script section"
  - echo "For example you might do some cleanup here"

stages:
  - build
  - code_check
  - test
  - deploy
  
build1:
  stage: build
  before_script:
    - echo "Before script in build stage that overwrited the globally defined before_script"
    - echo "Install cloc:A tool to count lines of code in various languages from a given directory."
    - yum install cloc -y
  after_script:
    - echo "After script in build stage that overwrited the globally defined after_script"
    - cloc --version
    # cloc .
  only:
    - /^issue-.*$/i
  except:
    - master
  script:
    - echo "Do your build here"
    - cloc --version
    # - cloc .
  tags:
    - bluelog

find Bugs:
  stage: code_check
  only:
    - /^issue-.*$/i
  except:
    - branches
  script:
    - echo "Use Flake8 to check python code"
    - pip install flake8
    - flake8 --version
    # - flake8 .
  tags:
    - bluelog
    
test1:
  stage: test
  only:
    - /^issue-.*$/i
  except:
    - /issue-pylint/
  script:
    - echo "Do a test here"
    - echo "For example run a test suite"
  tags:
    - bluelog

test2:
  stage: test
  only:
    - /^issue-.*$/i
  except:
    - /Issue-flake8/
  script:
    - echo "Do another parallel test here"
    - echo "For example run a lint test"
  tags:
    - bluelog
    
deploy1:
  stage: deploy
  only:
    - /^issue-.*$/i
  except:
    - /severe-issues/
  script:
    - echo "Do your deploy here"
  tags:
    - bluelog

预期效果: issue-pylintIssue-flake8 分支会触发流水线执行,master 主干和 severe-issues 分支不会触发流水线执行。

统计作业流水线作业情况:

分支 流水线 build1 find Bugs test1 test2 deploy1
master 未触发
issue-pylint #23 Yes No No Yes Yes
Issue-flake8 #24 Yes No Yes No Yes
severe-issues 未触发

正如我们预期的一样,issue-pylintIssue-flake8 分支会触发流水线执行,master 主干和 severe-issues 分支不会触发流水线执行:

解释上面的流水作业策略:

作业 规则定义 规则解释
build1 only: - /^issue-.*$/i except: - master 只在以issue(不区分大小写)-开头的分支执行,不在master主干执行
可以在issue-pylint和Issue-flake8分支执行
find Bugs only: - /^issue-.*$/i except: - branches 只在以issue(不区分大小写)-开头的分支执行,不在 branches 分支执行,
由于issue-pylint也是分支,所以在issue-pylint中也不会执行find Bugs作业
test1 only: - /^issue-.*$/i except: - /issue-pylint/ 只在以issue(不区分大小写)-开头的分支执行,不在issue-pylint分支执行,
即会在除了issue-pylint分支以外的issue-(不区分大小写)开头的分支执行,
可以在Issue-flake8分支执行
test2 only: - /^issue-.*$/i except: - /Issue-flake8/ 只在以issue(不区分大小写)-开头的分支执行,不在Issue-flake8分支执行,
因此可以issue-pylint分支执行
deploy1 only: - /^issue-.*$/i except: - /severe-issues/ 只在以issue(不区分大小写)-开头的分支执行,不在severe-issues分支执行
可以在issue-pylint和Issue-flake8分支执行

我们再将 only 语法中将 /^issue-.*$/ 改为 /issue/i !再来做一次实验,看看最终的效果。

不区分大小写匹配issue字符:

# This file is a template, and might need editing before it works on your project.
# see https://docs.gitlab.com/ce/ci/yaml/README.html for all available options


before_script:
  - echo "Before script section"
  - echo "For example you might run an update here or install a build dependency"
  - echo "Or perhaps you might print out some debugging details"

after_script:
  - echo "After script section"
  - echo "For example you might do some cleanup here"

stages:
  - build
  - code_check
  - test
  - deploy
  
build1:
  stage: build
  before_script:
    - echo "Before script in build stage that overwrited the globally defined before_script"
    - echo "Install cloc:A tool to count lines of code in various languages from a given directory."
    - yum install cloc -y
  after_script:
    - echo "After script in build stage that overwrited the globally defined after_script"
    - cloc --version
    # cloc .
  only:
    - /issue/i
  except:
    - master
  script:
    - echo "Do your build here"
    - cloc --version
    # - cloc .
  tags:
    - bluelog

find Bugs:
  stage: code_check
  only:
    - /issue/i
  except:
    - branches
  script:
    - echo "Use Flake8 to check python code"
    - pip install flake8
    - flake8 --version
    # - flake8 .
  tags:
    - bluelog
    
test1:
  stage: test
  only:
    - /issue/i
  except:
    - /issue-pylint/
  script:
    - echo "Do a test here"
    - echo "For example run a test suite"
  tags:
    - bluelog

test2:
  stage: test
  only:
    - /issue/i
  except:
    - /Issue-flake8/
  script:
    - echo "Do another parallel test here"
    - echo "For example run a lint test"
  tags:
    - bluelog
    
deploy1:
  stage: deploy
  only:
    - /issue/i
  except:
    - /severe-issues/
  script:
    - echo "Do your deploy here"
  tags:
    - bluelog

预期效果:不区分大小写,issue-pylintIssue-flake8severe-issues 分支分支会触发流水线执行,master 主干不会触发流水线执行。

统计作业流水线作业情况:

分支 流水线 build1 find Bugs test1 test2 deploy1
master 未触发
issue-pylint #25 Yes No No Yes Yes
Issue-flake8 #26 Yes No Yes No Yes
severe-issues #27 Yes No Yes Yes No

正如我们预期的一样,issue-pylintIssue-flake8severe-issues 分支会触发流水线执行,master 主干不会触发流水线执行:

解释上面的流水作业策略:

作业 规则定义 规则解释
build1 only: - /issue/i except: - master 只在包含issue(不区分大小写)字符的分支执行,不在master主干执行 , 因此在issue-pylint、Issue-flake8、severe-issues分支执行
find Bugs only: - /issue/i except: - branches 只在包含issue(不区分大小写)字符的分支执行,不在 branches 分支执行,所以find Bugs作业一直不会执行
test1 only: - /issue/i except: - /issue-pylint/ 只在包含issue(不区分大小写)字符的分支执行,不在包含issue-pylint字符的分支执行,即会在除了issue-pylint分支以外包含issue(不区分大小写)字符的分支执行所以可以在Issue-flake8和severe-issues分支执行,
test2 only: - /issue/i except: - /Issue-flake8/ 只在包含issue(不区分大小写)字符的分支执行,不在包含issue-flake8字符的分支执行,即会在除了issue-flake8分支以外包含issue(不区分大小写)字符的分支执行,所以可以在issue-pylint和severe-issues分支执行
deploy1 only: - /issue/i except: - /severe-issues/ 只在包含issue(不区分大小写)字符的分支执行,不在包含severe-issues字符的分支执行,即会在除了severe-issues分支以外包含issue(不区分大小写)字符的分支执行,所以可以在issue-pylint和Issue-flake8分支执行
上一篇:FromData传参形式:


下一篇:悠漓带你浅谈C语言4(字符串+转义字符+注释)