Groovy 字符串插值不应该与凭据一起使用。
Groovy 字符串插值可以通过特殊字符将恶意命令注入命令解释器。所以要使用单引号('),避免 Groovy 插值。
官网地址:Pipeline Syntax
声明式流水线是 Jenkins 流水线1的一个相对较新的补充,它在流水线子系统之上提供了一种更加简化和固执己见的语法。
声明式管道必须包含在 pipeline {} 模块里面
pipeline {
/* insert Declarative Pipeline here */
}
该 agent
部分指定整个管道或特定阶段将在 Jenkins 环境中执行的位置,具体取决于该 agent
部分的放置位置。该部分必须在块内的顶层定义 pipeline,但阶段级别的使用是可选的。
在将代理添加到顶层或阶段级时存在一些细微差别,这是在应用 options
指令时出现的。
在管道最外层声明的 agents
中,在进入代理后调用选项。例如:当使用 timeout
时,它将仅应用于代理内的执行。
node("myAgent") {
timeout(unit: 'SECONDS', time: 5) {
stage("One"){
sleep 10
echo 'hello'
}
}
}
在 agents
内声明的代理中,在进入代理和检查任何 when
条件之前调用选项。在这种情况下,当使用 timeout
时,它在分配代理之前应用。
timeout(unit: 'SECONDS', time: 5) {
stage("One"){
node {
sleep 10
echo 'Hello'
}
}
}
此超时将包括代理设置时间。由于超时包括代理供应时间,因此在代理分配延迟的情况下,管道可能会失败。
为了支持管道作者可能拥有的各种各样的用例,agent
部分支持几种不同类型的参数。这些参数可以应用于 pipeline
块的顶层,也可以应用于每个 stage
指令。
any
在任何可用代理上执行管道或阶段。例如:agent any
none
当在 pipeline 块的顶部没有全局代理,该参数将会被分配到整个流水线的运行中并且每个 stage
部分都需要包含他自己的 agent
部分。比如: agent none
label
在提供了标签的 Jenkins 环境中可用的代理上执行流水线或阶段。 例如: agent { label 'my-defined-label' }
也可以使用标签条件。例如:agent { label 'my-label1 && my-label2' }
或 agent { label 'my-label1 || my-label2' }
node
agent { node { label 'labelName' } }
行为与 agent { label 'labelName' }
相同,但 node 允许附加选项(例如:customWorkspace
)。
docker
使用给定的容器执行管道或阶段,该容器将在预先配置为接受基于 Docker 的管道的节点上或在与可选定义的参数匹配的节点上动态配置。还可以选择接受一个参数,该参数可能包含直接传递给调用的参数,以及一个选项,即使图像名称已经存在,也会强制执行。例如:labeldockerargsdocker runalwaysPulldocker pullagent { docker 'maven:3.8.1-adoptopenjdk-11' }
或
agent {
docker {
image 'maven:3.8.1-adoptopenjdk-11'
label 'my-defined-label'
args '-v /tmp:/tmp'
}
}
docker 还可以选择接受 registryUrl 和 registryCredentialsId 参数,这将有助于指定要使用的 Docker Registry 及其凭据。该参数 registryCredentialsId 可以单独用于 docker hub 内的私有存储库。例如:
agent {
docker {
image 'myregistry.com/node'
label 'my-defined-label'
registryUrl 'https://myregistry.com/'
registryCredentialsId 'myPredefinedCredentialsInJenkins'
}
}
dockerfile
Dockerfile 使用从源存储库中包含的容器构建的容器执行管道或阶段。为了使用此选项,Jenkinsfile 必须从 Multibranch Pipeline 或来自 SCM 的 Pipeline 加载。通常这是 Dockerfile 在源存储库的根目录中:agent { dockerfile true }
。如果 Dockerfile 在另一个目录中构建 a,请使用 dir 选项:agent { dockerfile { dir 'someSubDir' } }
。如果您 Dockerfile 有其他名称,则可以使用 filename 选项指定文件名。您可以使用选项将其他参数传递给 docker build …
命令 additionalBuildArgs
,例如:agent { dockerfile { additionalBuildArgs '--build-arg foo=bar' } }
。例如:带有文件的存储库,需要 build/Dockerfile.build 一个构建参数 version:
agent {
// Equivalent to "docker build -f Dockerfile.build --build-arg version=1.0.2 ./build/
dockerfile {
filename 'Dockerfile.build'
dir 'build'
label 'my-defined-label'
additionalBuildArgs '--build-arg version=1.0.2'
args '-v /tmp:/tmp'
}
}
dockerfile 还可以选择接受 registryUrl 和 registryCredentialsId 参数,这将有助于指定要使用的 Docker Registry 及其凭据。例如:
agent {
dockerfile {
filename 'Dockerfile.build'
dir 'build'
label 'my-defined-label'
registryUrl 'https://myregistry.com/'
registryCredentialsId 'myPredefinedCredentialsInJenkins'
}
}
kubernetes
在 Kubernetes 集群上部署的 pod 内执行管道或阶段。为了使用此选项,Jenkinsfile 必须从 Multibranch Pipeline 或来自 SCM 的 Pipeline 加载。Pod 模板在 kubernetes {}
块内定义。例如:如果您想要一个里面有 Kaniko 容器的 pod,您可以这样定义它:
agent {
kubernetes {
defaultContainer 'kaniko'
yaml '''
kind: Pod
spec:
containers:
- name: kaniko
image: gcr.io/kaniko-project/executor:debug
imagePullPolicy: Always
command:
- sleep
args:
- 99d
volumeMounts:
- name: aws-secret
mountPath: /root/.aws/
- name: docker-registry-config
mountPath: /kaniko/.docker
volumes:
- name: aws-secret
secret:
secretName: aws-secret
- name: docker-registry-config
configMap:
name: docker-registry-config
'''
}
}
您需要 aws-secret
为 Kaniko 创建一个秘密,以便能够使用 ECR 进行身份验证。这个秘密应该包含 ~/.aws/credentials。另一个卷是一个 ConfigMap,它应该包含您的 ECR 注册表的端点。例如:
{
"credHelpers": {
"<your-aws-account-id>.dkr.ecr.eu-central-1.amazonaws.com": "ecr-login"
}
}
参考以下示例:https://github.com/jenkinsci/kubernetes-plugin/blob/master/examples/kaniko.groovy
这些是可以应用于两个或多个 agent
实现的一些选项。除非明确说明,否则它们不是必需的。
label
一个字符串。该标签用于运行 Pipeline 或个别的 stage。
此选项对 node、docker 和 dockerfile 有效,并且对于 node 是必需的。
customWorkspace
一个字符串。在自定义工作区运行应用了 agent
的流水线或个别的 stage
,而不是默认的。它可以是相对路径,在这种情况下,自定义工作区将位于节点上的工作区根目录下,也可以是绝对路径。例如:
agent {
node {
label 'my-defined-label'
customWorkspace '/some/other/path'
}
}
此选项对 node、docker 和 dockerfile 有效。
reuseNode
布尔值,默认为 false。如果为 true,则在同一工作区中的 Pipeline 顶层指定的节点上运行容器,而不是完全在新节点上运行。
此选项对 docker
和 dockerfile
有效,并且只有当使用在个别的 stage
的 agent
上才会有效。
args
一个字符串。要传递给的运行时参数 docker run
。
此选项对 docker
和 dockerfile
有效。
示例 1:Docker 代理,声明式管道
pipeline {
agent { docker 'maven:3.8.1-adoptopenjdk-11' }
stages {
stage('Example Build') {
steps {
sh 'mvn -B clean verify'
}
}
}
}
maven:3.8.1-adoptopenjdk-11
)的新创建容器中执行此管道中定义的所有步骤。示例 2:阶段级代理部分
pipeline {
agent none
stages {
stage('Example Build') {
agent { docker 'maven:3.8.1-adoptopenjdk-11' }
steps {
echo 'Hello, Maven'
sh 'mvn --version'
}
}
stage('Example Test') {
agent { docker 'openjdk:8-jre' }
steps {
echo 'Hello, JDK'
sh 'java -version'
}
}
}
}
agent none
在 Pipeline 的顶层进行定义可确保不会不必要地分配 Executor 。使用 agent none
还强制每个 stage
部分包含自己的 agent
部分。该 post
部分定义了在管道或阶段运行完成时运行的一个或多个附加步骤(取决于该 post
部分在管道中的位置)。post
可以支持以下任何后置条件块:always
,changed
,fixed
,regression
,aborted
,failure
,success
,unstable
,unsuccessful
和 cleanup
。这些条件块允许根据管道或阶段的完成状态在每个条件内执行步骤。条件块按如下所示的顺序执行。
always
无论 Pipeline 或阶段的完成状态如何,都允许在 post
部分运行该步骤。
changed
只有当前 Pipeline 或阶段的完成状态与它之前的运行不同时,才允许在 post
部分运行该步骤。
fixed
只有当前 Pipeline 或阶段的运行成功并且之前的运行失败或不稳定时才运行该步骤。
regression
只有当前 Pipeline 或阶段的运行处于失败、不稳定或中止且上一次运行成功时才运行该步骤。
aborted
只有当前 Pipeline 或阶段的运行处于 “中止” 状态时才运行该步骤,通常是由于流水线被手动中止。这通常在 Web UI 中用灰色表示。
failure
只有当前 Pipeline 或阶段的运行处于 “失败” 状态时才运行该步骤,通常在 Web UI 中用红色表示。
success
只有当前 Pipeline 或阶段的运行处于 “成功” 状态时才运行步骤,通常在 Web UI 中以蓝色或绿色表示。
unstable
只有当前 Pipeline 或阶段的运行处于 “不稳定” 状态时才运行步骤,这通常是由测试失败、代码违规等引起的。这通常在 Web UI 中用黄色表示。
unsuccessful
只有当前 Pipeline 或阶段的运行没有 “成功” 状态时才运行步骤。这通常在 Web UI 中表示,具体取决于前面提到的状态。
cleanup
在评估 post
所有其他条件后运行此条件中的步骤,无论管道或阶段的状态如何。
示例 3:Post 部分,声明性管道
pipeline {
agent any
stages {
stage('Example') {
steps {
echo 'Hello World'
}
}
}
post {
always {
echo 'I will always say Hello again!'
}
}
}
按照惯例,该
post
部分应放置在管道的末端。后置条件块包含与步骤部分相同的步骤。
该部分包含一系列一个或多个阶段指令,stages
是流水线描述的大部分 “工作” 所在的位置。建议至少为持续交付过程的每个离散部分(例如:构建、测试和部署)stages
包含一个阶段指令。
示例 4:阶段,声明式管道
pipeline {
agent any
stages {
stage('Example') {
steps {
echo 'Hello World'
}
}
}
}
该
stages
部分通常遵循诸如agent
,options
等指令。
steps
部分在给定的 stage
指令中执行的定义了一系列的一个或多个 steps
。
示例 5:单步声明式管道
pipeline {
agent any
stages {
stage('Example') {
steps {
echo 'Hello World'
}
}
}
}
该
steps
部分必须包含一个或多个步骤。
该 environment
指令指定了一系列键值对,这些键值对将被定义为所有步骤或特定阶段步骤的环境变量,具体取决于 environment
指令在管道中的位置。
该指令支持一种特殊的辅助方法 credentials()
,可用于在 Jenkins 环境中通过其标识符访问预定义的凭据。
Secret Text
指定的环境变量将设置为 Secret Text 内容
Secret File
指定的环境变量将设置为临时创建的 File 文件的位置
Username and password
指定的环境变量将被设置为 username:password
并自动定义另外两个环境变量分别为:MYVARNAME_USR
和 MYVARNAME_PSW
。
SSH with Private Key
指定的环境变量将设置为临时创建的 SSH 密钥文件的位置,并且可能会自动定义两个额外的环境变量:MYVARNAME_USR
和 MYVARNAME_PSW
(保存密码)。
不支持的凭据类型会导致管道失败并显示消息为:
org.jenkinsci.plugins.credentialsbinding.impl.CredentialNotFoundException: No suitable binding handler could be found for type <unsupportedType>.
示例 6:秘密文本凭证,声明性管道
pipeline {
agent any
environment {
CC = 'clang'
}
stages {
stage('Example') {
environment {
AN_ACCESS_KEY = credentials('my-predefined-secret-text')
}
steps {
sh 'printenv'
}
}
}
}
environment
指令将适用于流水线中的所有步骤。environment
指令只会将给定的环境变量应用于 stage
中的步骤。environment
块有一个助手方法 credentials()
定义,该方法可以在 Jenkins 环境中用于通过标识符访问预定义的凭证。示例 7:用户名和密码凭证
pipeline {
agent any
stages {
stage('Example Username/Password') {
environment {
SERVICE_CREDS = credentials('my-predefined-username-password')
}
steps {
sh 'echo "Service user is $SERVICE_CREDS_USR"'
sh 'echo "Service password is $SERVICE_CREDS_PSW"'
sh 'curl -u $SERVICE_CREDS https://example.com'
}
}
stage('Example SSH Username with private key') {
environment {
SSH_CREDS = credentials('my-predefined-ssh-creds')
}
steps {
sh 'echo "SSH private key is located at $SSH_CREDS"'
sh 'echo "SSH user is $SSH_CREDS_USR"'
sh 'echo "SSH passphrase is $SSH_CREDS_PSW"'
}
}
}
}
该 options
指令允许从流水线本身配置流水线特定的选项。Pipeline 提供了许多这些选项,例如:buildDiscarder
,但它们也可能由插件提供,例如:timestamps
。
buildDiscarder
为最近 Pipeline 运行特定数量保留工件和控制台输出。例如:options { buildDiscarder(logRotator(numToKeepStr: '1')) }
options {
buildDiscarder logRotator(artifactDaysToKeepStr: '', artifactNumToKeepStr: '5', daysToKeepStr: '5', numToKeepStr: '10')
}
checkoutToSubdirectory
在工作区的子目录中执行自动源代码控制检出。例如:options { checkoutToSubdirectory('foo') }
disableConcurrentBuilds
禁止管道的并发执行。可用于防止同时访问共享资源等。例如:options { disableConcurrentBuilds() }
disableResume
如果控制器重新启动,则不允许管道恢复。例如:options { disableResume() }
newContainerPerStage
与 docker 或 dockerfile 顶级代理一起使用。指定后,每个阶段将在同一节点上的新容器实例中运行,而不是所有阶段都在同一容器实例中运行。
overrideIndexTriggers
允许覆盖分支索引触发器的默认处理。如果在多分支或组织标签处禁用分支索引触发器,options { overrideIndexTriggers(true) }
则仅针对该作业启用它们。否则,options { overrideIndexTriggers(false) }
将仅禁用此作业的分支索引触发器。
preserveStashes
保留已完成构建的存储,以用于阶段重新启动。例如:options { preserveStashes() }
保留最近完成的构建中的存储,或 options { preserveStashes(buildCount: 5) }
保留五个最近完成的构建中的存储。
quietPeriod
设置管道的静默期(以秒为单位),覆盖全局默认值。例如:options { quietPeriod(30) }
retry
失败时,重试整个管道指定的次数。例如:options { retry(3) }
skipDefaultCheckout
agent 默认情况下,在指令中跳过从源代码管理中检出代码。例如:options { skipDefaultCheckout() }
skipStagesAfterUnstable
一旦构建状态变为 UNSTABLE,就跳过阶段。例如:options { skipStagesAfterUnstable() }
timeout
为流水线运行设置一个超时时间,之后 Jenkins 应该中止流水线。例如:options { timeout(time: 1, unit: 'HOURS') }
示例 8:全局超时,声明式管道
pipeline {
agent any
options {
timeout(time: 1, unit: 'HOURS')
}
stages {
stage('Example') {
steps {
echo 'Hello World'
}
}
}
}
timestamps
将在此阶段生成的所有控制台输出添加到发出该行的时间。例如:options { timestamps() }
parallelsAlwaysFailFast
为管道中的所有后续并行阶段设置 failfast true
。例如:options { parallelsAlwaysFailFast() }
stage
的 options
指令类似于流水线根目录上的 options
指令。然而,stage
-级别 options
只能包括 retry
,timeout
或 timestamps
等步骤, 或与 stage
相关的声明式选项,如:skipDefaultCheckout
。
在 stage
,options
指令中的步骤在进入 agent
之前被调用或在 when
条件出现时进行检查。
skipDefaultCheckout
在 agent
指令中跳过默认的从源代码控制中检出代码。例如:options { skipDefaultCheckout() }
timeout
设置此阶段的超时时间,在此之后,Jenkins 会终止该阶段。例如:options { timeout(time: 1, unit: 'HOURS') }
示例 9:阶段超时,声明式管道
pipeline {
agent any
stages {
stage('Example') {
options {
timeout(time: 1, unit: 'HOURS')
}
steps {
echo 'Hello World'
}
}
}
}
retry
失败时,重试此阶段指定的次数。例如:options { retry(3) }
timestamps
将在此阶段生成的所有控制台输出添加到发出该行的时间。例如:options { timestamps() }
该 parameters 指令提供了用户在触发管道时应提供的参数列表。这些用户指定参数的值通过 params 对象可用于管道步骤。
string
字符串类型的参数,例如:parameters { string(name: 'DEPLOY_ENV', defaultValue: 'staging', description: '') }
text
一个文本参数,可以包含多行,换行使用 \n,例如:parameters { text(name: 'DEPLOY_TEXT', defaultValue: 'One\nTwo\nThree\n', description: '') }
booleanParam
一个布尔参数,例如:parameters { booleanParam(name: 'DEBUG_BUILD', defaultValue: true, description: '') }
choice
一个选择参数,例如:parameters { choice(name: 'CHOICES', choices: ['one', 'two', 'three'], description: '') }
password
一个密码参数,例如:parameters { password(name: 'PASSWORD', defaultValue: 'SECRET', description: 'A secret password') }
示例 10:参数,声明式管道
pipeline {
agent any
parameters {
string(name: 'PERSON', defaultValue: 'Mr Jenkins', description: 'Who should I say hello to?')
text(name: 'BIOGRAPHY', defaultValue: 'my demo', description: 'Enter some information about the person')
booleanParam(name: 'TOGGLE', defaultValue: true, description: 'Toggle this value')
choice(name: 'CHOICE', choices: ['One', 'Two', 'Three'], description: 'Pick something')
password(name: 'PASSWORD', defaultValue: 'SECRET', description: 'Enter a password')
}
stages {
stage('Example') {
steps {
echo "Hello ${params.PERSON}"
echo "Biography: ${params.BIOGRAPHY}"
echo "Toggle: ${params.TOGGLE}"
echo "Choice: ${params.CHOICE}"
echo "Password: ${params.PASSWORD}"
}
}
}
}
注意:需要手动触发一次任务,让 Jenkins 加载 pipeline 后,trigger 指令才会生效。
该 triggers
指令定义了重新触发管道的自动化方式。对于与 GitHub 或 BitBucket 等源集成的管道,triggers
可能没有必要,因为基于 webhook 的集成可能已经存在。当前可用的触发器 cron
是 pollSCM
和 upstream
。
cron
接受一个 cron
风格的字符串来定义管道应该被重新触发的定期间隔,例如:triggers { cron('H */4 * * 1-5') }
pollSCM
接受 pollSCM
样式的字符串来定义 Jenkins 应检查新源更改的定期间隔。如果存在新的更改,管道将被重新触发。例如:triggers { pollSCM('H */4 * * 1-5') }
upstream
接受逗号分隔的作业字符串和阈值。当字符串中的任何作业以最小阈值完成时,管道将被重新触发。例如:triggers { upstream(upstreamProjects: 'job1,job2', threshold: hudson.model.Result.SUCCESS) }
hudson.model.Result 是一个枚举,包括以下值:
示例 11:触发器,声明式管道
pipeline {
agent any
triggers {
cron('H */4 * * 1-5')
}
stages {
stage('Example') {
steps {
echo 'Hello World'
}
}
}
}
Jenkins cron 语法遵循 cron 实用程序的语法(略有不同)。具体来说,每一行由 5 个字段组成,由 TAB 或空格分隔:
MINUTE | HOUR | DOM | MONTH | DOW |
---|---|---|---|---|
一小时内的分钟数 (0–59) | 一天中的小时 (0–23) | 月份中的某天 (1–31) | 月份 (1–12) | 星期几 (0–7),其中 0 和 7 是星期日 |
要为一个字段指定多个值,可以使用以下运算符。按照优先顺序,
为了允许定期调度的任务在系统上产生均匀的负载,H 应尽可能使用符号(用于 “哈希”)。例如:使用 0 0 * * *
十几个日常工作会在午夜导致一个大的峰值。相比之下,使用 H H * * *
仍然会每天执行一次每个作业,但不是同时执行一次,更好地使用有限的资源。
该 H 符号可以与范围一起使用。例如:H H(0-7) * * *
表示 12:00 AM(午夜)到 7:59 AM 之间的某个时间。您还可以使用带 H、或不带范围的步长间隔。
该 H 符号可以被认为是一个范围内的随机值,但它实际上是作业名称的散列,而不是随机函数,因此该值对于任何给定项目都保持稳定。
请注意,对于月份字段,由于月份长度不同,短周期(例如:*/3
或 H/3
不会在大多数月份结束时始终如一)工作。例如:*/3
将在长月的第 1、4、…31 天运行,然后在下个月的第二天再次运行。哈希值始终在 1-28 范围内选择,因此 H/3
在月底运行之间会产生 3 到 6 天的间隔。(较长的周期也会有不一致的长度,但效果可能相对不太明显。)
空行和以 #
开头的行将作为注释被忽略。
此外,还支持 @yearly
、@annually
、@monthly
、@weekly
、@daily
、@midnight
和 @hourly
作为方便的别名。这些使用哈希系统进行自动平衡。例如:@hourly
与 H * * * *
并且可能表示一小时内的任何时间相同。@midnight
实际上是指 12:00 AM 到 2:59 AM 之间的某个时间。
表 1:Jenkins cron 语法示例
要求 | 语法 |
---|---|
每十五分钟一次(可能在 :07, :22, :37, :52) | triggers{ cron('H/15 * * * *') } |
每小时前半段每十分钟一次(三次,可能在 :04, :14, :24) | triggers{ cron('H(0-29)/10 * * * *') } |
每两小时一次,时间为每个工作日上午 9 点 45 分至下午 3 点 45 分,整点后 45 分钟。 | triggers{ cron('45 9-16/2 * * 1-5') } |
每个工作日上午 9 点到下午 5 点之间每两小时一次(可能在上午 10 点 38 分、下午 12 点 38 分、下午 2 点 38 分、下午 4 点 38 分) | triggers{ cron('H H(9-16)/2 * * 1-5') } |
除 12 月外,每月 1 日和 15 日每天一次 | triggers{ cron('H H 1,15 1-11 *') } |
该 stage
指令位于该 stages
部分中,并且应该包含一个步骤部分、一个可选 agent 部分或其他特定于阶段的指令。实际上,流水线完成的所有实际工作都将包含在一个或多个 stage
指令中。
示例 12:阶段,声明式管道
pipeline {
agent any
stages {
stage('Example') {
steps {
echo 'Hello World'
}
}
}
}
定义用于自动安装和放置在 PATH
。如果指定 agent none
,则忽略。
示例 13:工具,声明式管道
pipeline {
agent any
tools {
maven 'apache-maven-3.0.1'
}
stages {
stage('Example') {
steps {
sh 'mvn --version'
}
}
}
}
工具名称必须在 Jenkins 中的 Manage Jenkins → Global Tool Configuration 下预先配置。
stage
的 input
指令允许您使用 input step
提示输入。在应用了 options
后,进入 stage
的 agent
或评估 when
条件前,stage
将暂停。如果 input
被批准, stage
将会继续。作为 input
提交的一部分的任何参数都将在环境中用于其他 stage
。
message
必需的。这将在用户提交 input
时呈现给用户。
id
input
的可选标识符,默认为 stage
名称。
ok
input
表单上的 ok 按钮的可选文本。
submitter
可选的以逗号分隔的用户列表或允许提交 input
的外部组名。默认允许任何用户。
不能有空格
submitterParameter
环境变量的可选名称。如果存在,用 submitter
名称设置。
parameters
提示提交者提供的一个可选的参数列表。
示例 14:输入步骤,声明性管道
pipeline {
agent any
stages {
stage('Example') {
input {
message "Should we continue?"
ok "Yes, we should."
submitter "alice,bob"
parameters {
string(name: 'PERSON', defaultValue: 'Mr Jenkins', description: 'Who should I say hello to?')
}
}
steps {
echo "Hello, ${PERSON}, nice to meet you."
}
}
}
}
该 when
指令允许管道根据给定条件确定是否应执行阶段。该 when
指令必须至少包含一个条件。如果 when
指令包含多个条件,则所有子条件都必须返回 true
才能执行阶段。这就像子条件嵌套在 allOf
条件中一样(参见下面的示例)。如果使用 anyOf
条件,请注意一旦找到第一个 “真” 条件,该条件就会跳过剩余的测试。
可以使用嵌套条件构建更复杂的条件结构:not
、allOf
或 anyOf
。嵌套条件可以嵌套到任意深度。
branch
当正在构建的分支与给定的分支模式(ANT 样式路径 glob)匹配时执行阶段,例如:when { branch 'master' }
。请注意,这仅适用于多分支管道。
可以在属性之后添加可选参数 comparator,以指定如何评估任何模式以进行匹配:EQUALS 对于简单的字符串比较,GLOB(默认)对于 ANT 样式路径 glob(example 与 changeset 相同),或 REGEXP 对于正则表达式匹配。例如:when { branch pattern: "release-\\d+", comparator: "REGEXP"}
buildingTag
在构建 build 标签时执行阶段。例子:when { buildingTag() }
changelog
如果构建的 SCM 更改日志包含给定的正则表达式模式,则执行该阶段,例如:when { changelog '.*^\\[DEPENDENCY\\] .+$' }
changeset
如果构建的 SCM 变更集包含一个或多个与给定模式匹配的文件,则执行该阶段。例子:when { changeset "**/*.js" }
可以在属性之后添加可选参数 comparator 以指定如何评估任何模式以进行匹配:EQUALS 对于简单的字符串比较,GLOB(默认)对于 ANT 样式路径 glob 不区分大小写,这可以使用参数关闭,caseSensitive 或者 REGEXP 正则表达式匹配。例如:when { changeset pattern: ".TEST\\.java", comparator: "REGEXP" }
或 when { changeset pattern: "*/*TEST.java", caseSensitive: true }
changeRequest
如果当前构建是针对 “更改请求”(也称为 GitHub 和 Bitbucket 上的拉取请求、GitLab 上的合并请求、Gerrit 中的更改等),则执行该阶段。当没有传递参数时,阶段会在每个更改请求上运行,例如:when { changeRequest() }
。
通过向更改请求添加带有参数的过滤器属性,可以使该阶段仅在匹配的更改请求上运行。可能的属性是 id, target, branch, fork, url, title, author, authorDisplayName, 和 authorEmail
。其中每一个都对应一个 CHANGE_*
环境变量,例如:when { changeRequest target: 'master' }
。
可以在属性之后添加可选参数 comparator 以指定如何评估任何模式以进行匹配:EQUALS 用于简单的字符串比较(默认),GLOB 用于 ANT 样式路径 glob(example 与 changeset 相同)或 REGEXP 用于正则表达式匹配。例子:when { changeRequest authorEmail: "[\\w_-.]+@example.com", comparator: 'REGEXP' }
environment
当指定环境变量设置为给定值时执行该阶段,例如:when { environment name: 'DEPLOY_TO', value: 'production' }
equals
执行期望值等于实际值的阶段,例如:when { equals expected: 2, actual: currentBuild.number }
expression
当指定的 Groovy 表达式计算结果为 true 时执行该阶段,例如:when { expression { return params.DEBUG_BUILD } }
请注意,从表达式返回字符串时,必须将它们转换为 “布尔值” 或返回 null 计算结果为 false。简单地返回 “0” 或 “false” 仍将评估为 “true”。
tag
TAG_NAME 如果变量与给定模式匹配,则执行该阶段。示例:when { tag "release-*" }
。如果提供了空模式,则如果 TAG_NAME 变量存在(与 buildingTag()
相同),则阶段将执行。
可以在属性之后添加可选参数 comparator,以指定如何评估任何模式以进行匹配:EQUALS 对于简单的字符串比较,GLOB(默认)对于 ANT 样式路径 glob(example 与 changeset 相同),或 REGEXP 对于正则表达式匹配。例如:when { tag pattern: "release-\\d+", comparator: "REGEXP"}
not
当嵌套条件为假时执行阶段。必须包含一个条件。例如:when { not { branch 'master' } }
allOf
当所有嵌套条件都为真时执行该阶段。必须包含至少一个条件。例如:when { allOf { branch 'master'; environment name: 'DEPLOY_TO', value: 'production' } }
anyOf
当至少一个嵌套条件为真时执行该阶段。必须包含至少一个条件。例如:when { anyOf { branch 'master'; branch 'staging' } }
triggeredBy
当前构建被给定的参数触发时执行阶段。例如:
stage
的 agent
前评估 when
默认情况下, 如果定义了某个阶段的代理,在进入该 stage
的 agent
后该 stage
的 when
条件将会被评估。但是, 可以通过在 when
块中指定 beforeAgent
选项来更改此选项。 如果 beforeAgent
被设置为 true
, 那么就会首先对 when
条件进行评估 , 并且只有在 when
条件验证为真时才会进入 agent
。
input
之前进行评估 when
默认情况下,如果定义了一个阶段,则不会在进入 input
之前评估的 when
条件。但是,这可以通过 beforeInput
在 when
块中指定选项来更改。如果 beforeInput
设置为 true
,将首先评估 when
条件,只有当 when
条件评估为 true
时才会进入 input
。
beforeAgent true
优先于beforeInput true
。
options
之前进行评估 when
默认情况下,将在进入 options
后评估 whena
的条件(如果已定义)。但是,这可以通过在 when
块中指定 beforeOptions
选项来更改。如果设置为 true
,将首先评估 when
条件,并且仅当 when
条件评估为 true
时才会进入。
beforeAgent true
和beforeInput true
优先于beforeOptions true
。
示例 15:单一条件,声明式管道
pipeline {
agent any
stages {
stage('Example Build') {
steps {
echo 'Hello World'
}
}
stage('Example Deploy') {
when {
branch 'production'
}
steps {
echo 'Deploying'
}
}
}
}
示例 16:多条件,声明性管道
pipeline {
agent any
stages {
stage('Example Build') {
steps {
echo 'Hello World'
}
}
stage('Example Deploy') {
when {
branch 'production'
environment name: 'DEPLOY_TO', value: 'production'
}
steps {
echo 'Deploying'
}
}
}
}
示例 17:嵌套条件(与前面示例相同的行为)
pipeline {
agent any
stages {
stage('Example Build') {
steps {
echo 'Hello World'
}
}
stage('Example Deploy') {
when {
allOf {
branch 'production'
environment name: 'DEPLOY_TO', value: 'production'
}
}
steps {
echo 'Deploying'
}
}
}
}
示例 18:多重条件和嵌套条件
pipeline {
agent any
stages {
stage('Example Build') {
steps {
echo 'Hello World'
}
}
stage('Example Deploy') {
when {
branch 'production'
anyOf {
environment name: 'DEPLOY_TO', value: 'production'
environment name: 'DEPLOY_TO', value: 'staging'
}
}
steps {
echo 'Deploying'
}
}
}
}
示例 19:表达式条件和嵌套条件
pipeline {
agent any
stages {
stage('Example Build') {
steps {
echo 'Hello World'
}
}
stage('Example Deploy') {
when {
expression { BRANCH_NAME ==~ /(production|staging)/ }
anyOf {
environment name: 'DEPLOY_TO', value: 'production'
environment name: 'DEPLOY_TO', value: 'staging'
}
}
steps {
echo 'Deploying'
}
}
}
}
示例 20:beforeAgent
pipeline {
agent none
stages {
stage('Example Build') {
steps {
echo 'Hello World'
}
}
stage('Example Deploy') {
agent {
label "some-label"
}
when {
beforeAgent true
branch 'production'
}
steps {
echo 'Deploying'
}
}
}
}
示例 21:beforeInput
pipeline {
agent none
stages {
stage('Example Build') {
steps {
echo 'Hello World'
}
}
stage('Example Deploy') {
when {
beforeInput true
branch 'production'
}
input {
message "Deploy to production?"
id "simple-input"
}
steps {
echo 'Deploying'
}
}
}
}
示例 22:beforeOptions
pipeline {
agent none
stages {
stage('Example Build') {
steps {
echo 'Hello World'
}
}
stage('Example Deploy') {
when {
beforeOptions true
branch 'testing'
}
options {
lock label: 'testing-deploy-envs', quantity: 1, variable: 'deployEnv'
}
steps {
echo "Deploying to ${deployEnv}"
}
}
}
}
示例 23:triggeredBy
pipeline {
agent none
stages {
stage('Example Build') {
steps {
echo 'Hello World'
}
}
stage('Example Deploy') {
when {
triggeredBy "TimerTrigger"
}
steps {
echo 'Deploying'
}
}
}
}
声明性管道中的阶段可能有一个 stages
部分,其中包含要按顺序运行的嵌套阶段的列表。请注意,一个阶段必须只有 steps
、stages
、parallel
或 matrix
中的一个。如果 stage
指令嵌套在 parallel
块或 matrix
块本身内,则不可能在 stage
指令内嵌套 parallel
块或 matrix
块。然而,parallel
块或 matrix
块中的 stage
指令可以使用 stage
的所有其他功能,包括 agent
,tools
,when
等。
示例 24:顺序阶段,声明式管道
pipeline {
agent none
stages {
stage('Non-Sequential Stage') {
agent {
label 'for-non-sequential'
}
steps {
echo "On Non-Sequential Stage"
}
}
stage('Sequential') {
agent {
label 'for-sequential'
}
environment {
FOR_SEQUENTIAL = "some-value"
}
stages {
stage('In Sequential 1') {
steps {
echo "In Sequential 1"
}
}
stage('In Sequential 2') {
steps {
echo "In Sequential 2"
}
}
stage('Parallel In Sequential') {
parallel {
stage('In Parallel 1') {
steps {
echo "In Parallel 1"
}
}
stage('In Parallel 2') {
steps {
echo "In Parallel 2"
}
}
}
}
}
}
}
}
声明式流水线的阶段可以在他们内部声明多个嵌套阶段, 它们将并行执行。注意,一个阶段必须只有一个 steps
或 parallel
的阶段。嵌套阶段本身不能包含进一步的 parallel
阶段, 但是其他的阶段的行为与任何其他 stage
相同。任何包含 parallel
的阶段不能包含 agent
或 tools
阶段, 因为他们没有相关 steps
。
另外, 通过添加
failFast true
到包含parallel
的stage
中,当其中一个进程失败时,您可以强制所有的parallel
阶段都被终止。添加另一个选项failfast
是在管道定义中添加一个选项:parallelsAlwaysFailFast()
在脚本式流水线中,failFast true
需要换成failFast: true
示例 25:并行阶段,声明式管道
pipeline {
agent any
stages {
stage('Non-Parallel Stage') {
steps {
echo 'This stage will be executed first.'
}
}
stage('Parallel Stage') {
when {
branch 'master'
}
failFast true
parallel {
stage('Branch A') {
agent {
label "for-branch-a"
}
steps {
echo "On Branch A"
}
}
stage('Branch B') {
agent {
label "for-branch-b"
}
steps {
echo "On Branch B"
}
}
stage('Branch C') {
agent {
label "for-branch-c"
}
stages {
stage('Nested 1') {
steps {
echo "In stage Nested 1 within Branch C"
}
}
stage('Nested 2') {
steps {
echo "In stage Nested 2 within Branch C"
}
}
}
}
}
}
}
}
示例 26:parallelsAlwaysFailFast
pipeline {
agent any
options {
parallelsAlwaysFailFast()
}
stages {
stage('Non-Parallel Stage') {
steps {
echo 'This stage will be executed first.'
}
}
stage('Parallel Stage') {
when {
branch 'master'
}
parallel {
stage('Branch A') {
agent {
label "for-branch-a"
}
steps {
echo "On Branch A"
}
}
stage('Branch B') {
agent {
label "for-branch-b"
}
steps {
echo "On Branch B"
}
}
stage('Branch C') {
agent {
label "for-branch-c"
}
stages {
stage('Nested 1') {
steps {
echo "In stage Nested 1 within Branch C"
}
}
stage('Nested 2') {
steps {
echo "In stage Nested 2 within Branch C"
}
}
}
}
}
}
}
}
声明性管道中的阶段可能有一个 matrix
部分,定义要并行运行的 name-value 组合的多维矩阵。我们将这些组合称为矩阵中的 “单元”。矩阵中的每个单元可以包括一个或多个使用该单元的配置顺序运行的阶段。请注意,一个阶段必须只有 steps
、stages
、parallel
或 matrix
中的一个。如果 stage
指令嵌套在 parallel
块或 matrix
块本身内,则不可能在 stage
指令内嵌套 parallel
块或 matrix
块。然而,parallel
块或 matrix
块中的 stage
指令可以使用 stage
的所有其他功能,包括包括 agent
,tools
,when
等。
此外,当任何一个 matrix
单元出现故障时,可以通过将 failFast true
添加到包含矩阵的 stage
,强制所有 matrix
单元中止。添加 failfast
的另一个选项是向管道定义添加一个选项:parallelsAlwaysFailFast()
matrix
部分必须包括 axes
部分和 stages
部分。axes
部分定义 matrix
中每个axes
的值。stages
部分定义了在每个单元中顺序运行的 stage
列表。matrix
可能有一个排除部分,用于从 matrix
中删除无效单元格。stage
上可用的许多指令,包括 agent
,tools
,when
等,也可以添加到 matrix
中,以控制每个单元的行为。
该 axes
部分指定了一个或多个 axis
指令。每个都 axis
包含一个 name 和一个列表 values。每个轴的所有值都与其他值组合以生成单元格。
示例 27:具有 3 个单元的单轴
matrix {
axes {
axis {
name 'PLATFORM'
values 'linux', 'mac', 'windows'
}
}
// ...
}
示例 28:具有 12 个单元的两轴(三乘四)
matrix {
axes {
axis {
name 'PLATFORM'
values 'linux', 'mac', 'windows'
}
axis {
name 'BROWSER'
values 'chrome', 'edge', 'firefox', 'safari'
}
}
// ...
}
示例 29:具有 24 个单元的三轴矩阵(三乘四乘二)
matrix {
axes {
axis {
name 'PLATFORM'
values 'linux', 'mac', 'windows'
}
axis {
name 'BROWSER'
values 'chrome', 'edge', 'firefox', 'safari'
}
axis {
name 'ARCHITECTURE'
values '32-bit', '64-bit'
}
}
// ...
}
stages
部分指定在每个单元格中顺序执行的一个或多个 stage
。
示例 30:具有 3 个单元的单轴,每个单元运行三个阶段 - “构建”、“测试” 和 “部署”
matrix {
axes {
axis {
name 'PLATFORM'
values 'linux', 'mac', 'windows'
}
}
stages {
stage('build') {
// ...
}
stage('test') {
// ...
}
stage('deploy') {
// ...
}
}
}
示例 31:具有 12 个单元的两轴(三乘四)
matrix {
axes {
axis {
name 'PLATFORM'
values 'linux', 'mac', 'windows'
}
axis {
name 'BROWSER'
values 'chrome', 'edge', 'firefox', 'safari'
}
}
stages {
stage('build-and-test') {
// ...
}
}
}
可选的 excludes
部分允许作者指定一个或多个 excludes
过滤器表达式,这些表达式选择要从扩展的矩阵单元集(也称为稀疏)中排除的单元。过滤器使用一个或多个 exclude axis
指令的基本指令结构构造,每个指令都有一个 name 和 values 列表。
excludes
中的 axis
指令生成一组组合(类似于生成矩阵单元)。匹配 excludes
组合中所有值的矩阵单元将从矩阵中删除。如果提供了多个 exclude
指令,则分别计算每个指令以删除单元格。
在处理要 excludes
的一长串值时,exclude axis
指令可以使用 notValues
而不是 values
。这些将排除与传递给 notValues
的值之一不匹配的单元格。
示例 32:具有 24 个单元的三轴矩阵,不包括 “32 位,mac”(不包括 4 个单元)
matrix {
axes {
axis {
name 'PLATFORM'
values 'linux', 'mac', 'windows'
}
axis {
name 'BROWSER'
values 'chrome', 'edge', 'firefox', 'safari'
}
axis {
name 'ARCHITECTURE'
values '32-bit', '64-bit'
}
}
excludes {
exclude {
axis {
name 'PLATFORM'
values 'mac'
}
axis {
name 'ARCHITECTURE'
values '32-bit'
}
}
}
// ...
}
排除 linux
和 safari
的组合,并排除使用边缘浏览器的任何非 windows
平台。
例 33:包含 24 个单元格的三轴矩阵,不包括 “32位,mac” 和无效的浏览器组合(不包括 9 个单元格)
matrix {
axes {
axis {
name 'PLATFORM'
values 'linux', 'mac', 'windows'
}
axis {
name 'BROWSER'
values 'chrome', 'edge', 'firefox', 'safari'
}
axis {
name 'ARCHITECTURE'
values '32-bit', '64-bit'
}
}
excludes {
exclude {
// 4 cells
axis {
name 'PLATFORM'
values 'mac'
}
axis {
name 'ARCHITECTURE'
values '32-bit'
}
}
exclude {
// 2 cells
axis {
name 'PLATFORM'
values 'linux'
}
axis {
name 'BROWSER'
values 'safari'
}
}
exclude {
// 3 more cells and '32-bit, mac' (already excluded)
axis {
name 'PLATFORM'
notValues 'windows'
}
axis {
name 'BROWSER'
values 'edge'
}
}
}
// ...
}
Matrix
允许用户通过在 Matrix
自身下添加阶段级指令,有效地配置每个单元的整体环境。这些指令的行为与它们在舞台上的行为相同,但它们也可以接受矩阵为每个单元提供的值。
axis
和 exclude
指令定义组成矩阵的静态单元格集。这组组合是在管道运行开始之前生成的。另一方面,“每单元” 指令在运行时进行评估。
这些指令包括:
示例 34:完整的矩阵示例,声明性管道
pipeline {
agent none
parameters {
choice(name: 'PLATFORM_FILTER', choices: ['all', 'linux', 'windows', 'mac'], description: 'Run on specific platform')
}
stages {
stage('BuildAndTest') {
matrix {
agent {
label "${PLATFORM}-agent"
}
when {
anyOf {
expression { params.PLATFORM_FILTER == 'all' }
expression { params.PLATFORM_FILTER == env.PLATFORM }
}
}
axes {
axis {
name 'PLATFORM'
values 'linux', 'windows', 'mac'
}
axis {
name 'BROWSER'
values 'firefox', 'chrome', 'safari', 'edge'
}
}
excludes {
exclude {
axis {
name 'PLATFORM'
values 'linux'
}
axis {
name 'BROWSER'
values 'safari'
}
}
exclude {
axis {
name 'PLATFORM'
notValues 'windows'
}
axis {
name 'BROWSER'
values 'edge'
}
}
}
stages {
stage('Build') {
steps {
echo "Do Build for ${PLATFORM} - ${BROWSER}"
}
}
stage('Test') {
steps {
echo "Do Test for ${PLATFORM} - ${BROWSER}"
}
}
}
}
}
}
}
添加了下面列出的步骤,这些步骤只在声明式流水线中 only supported 。
该 script
步骤采用脚本管道块并在声明性管道中执行该块。对于大多数用例,script
在声明式管道中该步骤应该是不必要的,但它可以提供有用的 “逃生出口”。非平凡大小和/或复杂性的 script
块应该移到共享库中。
示例 35:声明式管道中的脚本块
pipeline {
agent any
stages {
stage('Example') {
steps {
echo 'Hello World'
script {
def browsers = ['chrome', 'firefox']
for (int i = 0; i < browsers.size(); ++i) {
echo "Testing the ${browsers[i]} browser"
}
}
}
}
}
}
Scripted Pipeline
与 Declarative Pipeline
一样,构建在底层 Pipeline 子系统之上。与声明式不同,Scripted Pipeline
实际上是使用 Groovy
构建的通用 DSL2。Groovy
语言提供的大多数功能都可供 Scripted Pipeline
的用户使用,这意味着它可以是一个非常富有表现力和灵活的工具,可以用来创建持续交付管道。
Scripted Pipeline
从上到下依次执行 Jenkinsfile
,就像 Groovy
或其他语言中的大多数传统脚本一样。因此,提供流控制依赖于 Groovy
表达式,例如:if/else
条件
示例 36:条件语句 if,脚本管道
node {
stage('Example') {
if (env.BRANCH_NAME == 'master') {
echo 'I only execute on the master branch'
} else {
echo 'I execute elsewhere'
}
}
}
可以管理脚本化管道流控制的另一种方式是使用 Groovy
的异常处理支持。当步骤由于某种原因失败时,它们会抛出异常。错误处理行为必须使用 Groovy
中的 try/catch/finally
块,例如:
示例 37:Try-Catch 块,脚本化管道
node {
stage('Example') {
try {
sh 'exit 1'
}
catch (exc) {
echo 'Something failed, I should sound the klaxons!'
throw
}
}
}
正如开头所说的,Pipeline 最基本的部分是 Steps
。从根本上说,步骤告诉 Jenkins 要做什么,并作为声明式和脚本化流水线语法的基本构建块。
Scripted Pipeline
没有引入任何特定于其语法的步骤;流水线步骤参考 包含流水线和插件提供的完整步骤列表。
为了提供持久性,这意味着运行管道可以在 Jenkins 控制器重新启动后继续存在,脚本化管道必须将数据序列化回控制器。由于此设计要求,某些 Groovy 惯用语如:collection.each { item → /* perform operation */ }
不完全支持。
最初创建 Jenkins Pipeline 时,选择了 Groovy 作为基础。Jenkins 长期以来一直提供嵌入式 Groovy 引擎,为管理员和用户提供高级脚本功能。此外,Jenkins Pipeline 的实现者发现 Groovy 是构建现在称为 “脚本化管道” DSL2 的坚实基础。
由于它是一个功能齐全的编程环境,Scripted Pipeline 为 Jenkins 用户提供了极大的灵活性和可扩展性。Groovy 学习曲线通常不适用于给定团队的所有成员,因此创建声明式管道是为了为创作 Jenkins 管道提供更简单和更有主见的语法。
两者基本上是相同的管道子系统。它们都是 “管道即代码” 的持久实现。他们都能够使用内置于 Pipeline 或由插件提供的步骤。两者都可以使用 共享库
然而,它们的不同之处在于语法和灵活性。声明式通过更严格和预定义的结构限制了用户可用的内容,使其成为更简单的持续交付管道的理想选择。Scripted 提供的限制很少,就结构和语法的唯一限制往往由 Groovy 本身定义,而不是任何特定于 Pipeline 的系统,这使其成为高级用户和具有更复杂要求的用户的理想选择。顾名思义,声明式管道鼓励声明式编程模型3。而脚本化管道遵循更命令式的编程模型4。
Version 2.5 of the “Pipeline plugin” introduces support for Declarative Pipeline syntax ↩︎