文章目录
- 4. 参数详解(一)
- 4.1 ``script``
- 4.2 ``image`` 指定使用Docker镜像。如 ``iamge:name`` ,暂时忽略。
- 4.3 ``before_script`` 用于定义在所有作业之前需要执行的命令,比如更新代码、安装依赖、打印调试信息之类的事情。
- 4.4 ``after_script``
- 4.5 ``stages`` 定义流水线全局可使用的阶段,阶段允许有灵活的多级管道,阶段元素的排序定义了作业执行的顺序。
- 4.6 ``stage``
- 4.7 ``only`` 和 ``except`` 用于在创建作业时对作业的限制策略。
- 4.8 ``only`` 和 ``except`` 高级用法
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
阶段的作业并行运行。 - 默认情况下,上一阶段的作业全部运行成功后才执行下一阶段的作业。
- 默认有三个阶段,
build
、test
、deploy
三个阶段,即构建
、测试
、部署
。 - 如果一个作业未定义
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 only
和 except
用于在创建作业时对作业的限制策略。
-
only
定义了哪些分支或标签(branches and tags)的作业会运行 -
except
定义了哪些分支或标签(branches and tags)的作业不会运行
下面是策略规则:
-
only
和except
可同时使用,如果在一个作业中同时定义了only
和except
,则同时only
except
进行过滤(注意,不是忽略except
条件) 。 -
only
和except
可以使用正则表达式。 -
only
和except
允许指定用于过滤forks作业的存储库路径。 -
only
和except
中可以使用特殊的关键字,如branches
、tags
、api
、external
、pipelines
、pushes
、schedules
、triggers
、web
、merge_requests
、chats
等。
only
和 except
中可以使用特殊的关键字:
关键字 | 描述释义 |
---|---|
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 only
和 except
高级用法
- ``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-pylint
、Issue-flake8
和 severe-issues
:
刚新增的三个分支,自动继承了master主干的CI RUNNER。
为了便于测试,将"sunshine"账号设置为 bluelog
项目的主程序员!
现在朝 .gitlab-ci.yml
文件中增加 only
和 except
策略。匹配 issue-
开头的分支,创建仅匹配 issue-
开头的分支:
设置后可以发现master主干没有执行 find Bugs
作业,现在只会触发同时满足CI触发按钮的条件和only条件的分支。
为了快速测试,我们对每个作业都使用 only
和 except
策略:
# 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-pylint
和 Issue-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-pylint
和 Issue-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-pylint
、 Issue-flake8
和 severe-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-pylint
、 Issue-flake8
和 severe-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分支执行 |