Declarative Pipeline
声明性流水线在管道子系统之上提供了一种更简单、更有主见的语法。
1 | pipeline { |
2 | /* insert Declarative Pipeline*/ |
3 | } |
在声明性流水线中有效的基本语句和表达式遵循与Groovy语法相同的规则,有以下例外:
- 流水线的顶层必须是一个块,特别是: pipeline{}
- 没有分号作为语句分隔符,每个语句都必须在自己的行上
- 块只能由Section,Directives, Steps, or 赋值语句组成
- 属性引用语句被视为无参数方法调用
Sections
agent
agent位于pipeline块的顶层和每个stage块的顶层
参数
any:执行pipeline或stage在任何可用的agent,agent any
none:当pipeline块顶层为none,不分配全局agent代理,需要每个stage块分配agent,agent none
label:使用提供的标签在Jenkins环境中可用的agent上执行pipeline或stage,agent {label ‘define-label’}
node:代理node与label相同,只不过node允许额外的选项,agent {node {label ‘labelName’}}
docker:执行pipeline或stage,使用给定的容器,该容器将在预先配置的节点上动态地供应,以接受基于docker的pipeline,或在匹配可选定义的标签参数的节点上。
1
agent {
2
docker {
3
image 'python:3.6.2'
4
label 'my-defined-label'
5
args '-v /tmp:/tmp'
6
}
7
}
dockerfile:执行管道,或阶段,使用由源存储库中包含的Dockerfile构建的容器。为了使用这个选项,Jenkinsfile必须从多个分支管道中加载,或者从SCM中加载一条管道。
1
agent {
2
// Equivalent to 'docker build -f Dockerfile -t test:1.0.2 ./build/'
3
dockerfile {
4
filename 'Dockerfile'
5
dir 'build'
6
label 'my-defined-label'
7
additionalBuildArgs '-t test:1.0.2'
8
}
9
}
通用选项
label:用于运行管道或单个阶段的标签,这个选项对于node,docker,dockerfile是有效的,对于node是必须的。
customWorkspace:运行管道或单独的阶段,该代理应用于这个自定义工作区,而不是默认的。它可以是相对路径,在这种情况下,自定义工作区将位于节点的工作区根之下,或者是绝对路径。
1
agent {
2
node {
3
label 'my-defined-label'
4
customWorkspace '/some/other/path'
5
}
6
}
reuseNode:布尔值,如果是true,则在管道顶层指定的节点上运行容器,在同一个工作区中,而不是完全在一个新节点上。这个选项对于docker和dockerfile是有效的,并且只有在单独的阶段使用代理时才有效果。
post
post部分定义了一个或多个附加步骤,这些步骤在管道或阶段的运行完成时运行(取决于管道内的post部分的位置)。post可以支持以下条件块之一:总是、更改、失败、成功、不稳定和中止。这些条件块根据管道或阶段的完成状态。
- always: 不管管道或阶段的运行完成状态如何,在post部分运行这些步骤。
- changed: 如果当前管道或阶段的运行与之前的运行有不同的完成状态,则只运行post中的步骤。
- failure: 只有在当前管道或阶段的运行有“失败”状态时才运行post中的步骤,通常在web UI中表示为红色。
- success: 只有当当前管道或阶段的运行具有“成功”状态时,才运行post中的步骤,通常在web UI中以蓝色或绿色表示。
- unstable: 如果当前管道或阶段的运行状态为“不稳定”状态,通常是由测试失败、代码违规等引起的,那么只在post中运行这些步骤。
- aborted: 只有在当前管道或阶段的运行有“中止”状态时才运行post中的步骤,通常是由于管道被手动中止。这通常用web UI中的灰色表示。
stages
包含一个或多个阶段指令的序列,阶段部分是管道所描述的大部分“工作”的位置。
1 | pipeline { |
2 | agent any |
3 | stages { |
4 | stage('Test') { |
5 | steps { |
6 | sh 'echo "Hello World!"' |
7 | } |
8 | } |
9 | } |
10 | } |
steps
steps部分定义了给定的阶段指令中执行的一系列的一个或多个步骤。
environment
环境指令指定一个键-值对序列,该序列将被定义为所有步骤的环境变量,或者是特定于阶段的步骤,具体取决于环境指令位于管道内的位置。
1 | pipeline { |
2 | agent any |
3 | environment { |
4 | CC = 'clang' |
5 | } |
6 | stages { |
7 | stage('Example') { |
8 | environment { |
9 | AN_ACCESS_KEY=credentials('secret-text') |
10 | } |
11 | steps{ |
12 | sh 'printenv' |
13 | } |
14 | } |
15 | } |
16 | } |
options
options指令允许从管道内部配置特定于管道的选项。
- buildDiscarder: 为最近的管道运行的特定数量保存工件和控制台输出options{buildDiscarder(logRotator(numToKeepStr: ‘1’))}
- disableConcurrentBuilds: 不允许同时执行管道,对于防止同时访问共享资源可能有用 options {disableConcurrentBuilds()}
- overrideIndexTriggers: 允许重写分支索引触发器的默认处理,如果分支索引触发器在多分支或组织标签中禁用,options {overrideIndexTriggers(true)}只允许它们用于此工作,否则,options {overrideIndexTriggers(false)}只会禁用该作业的分支索引触发器
- skipDefaultCheckout: 在agent指令中,跳过从源代码控制中检出代码。options { skipDefaultCheckout() }
- skipStagesAfterUnstable: 跳过stage一旦构建状态变得不稳定。 options {skipStagesAfterUnstable()}
- checkoutToSubdirectory: 在工作空间的子目录中执行自动源代码控制签出。options {checkoutToSubdirectory(‘foo’)}
- timeout: 设置管道运行的超时时间,在此之后,Jenkins将中止管道。options {timeout(time: 1, unit: ‘HOURS’)}
- retry: 在失败时,重新尝试整个管道的指定次数。options {retry(3)}
- timestamps:所有由管道生成的控制台输出,与该管道发出的时间一致。options {timestamps()}
1
pipeline {
2
agent any
3
options {
4
timeout(time: 1,unit: 'HOURS')
5
}
6
stages {
7
stage('Example') {
8
steps {
9
echo 'Hello World'
10
}
11
}
12
}
13
}
stage中可以使用的options:
- skipDefaultCheckout
- timeout
- retry
- timestamps
parameters
参数指令提供了一个用户在触发管道时应该提供的参数列表。
- string: 参数的字符类型 parameters {string(name: ‘DEPLO_YENV’,defaultValue: ‘staging’,description: ‘’)}
- booleanParam:参数的布尔类型 parameters {booleanParam(name: ‘DEBUG_BUILD’,defaultValue: true,description: ‘’)}
1 | pipeline { |
2 | agent any |
3 | parameters { |
4 | string(name:'PERSON',defaultValue: 'Mr Jenkins',description: 'Who should I say hello to?') |
5 | } |
6 | stages { |
7 | stage('Example') { |
8 | steps { |
9 | echo "Hello ${params.PERSON}" |
10 | } |
11 | } |
12 | } |
13 | } |
triggers
触发器指令定义了重新触发管道的自动化方式。
- cron: 接受cron样式的字符串来定义要重新触发管道的常规间隔。triggers { cron(‘H */4 * * 1-5’) }
- pollSCM: 接受一个cron样式的字符串来定义一个固定的间隔,在这个间隔中,Jenkins应该检查新的源代码更改。如果新的变化存在,管道将被重新触发。triggers { pollSCM(‘H */4 * * 1-5’) }
- upstream: 接受逗号分隔的工作字符串和阈值。当字符串中的任何作业以最小阈值结束时,管道将被重新触发。triggers { upstream(upstreamProjects: ‘job1,job2’, threshold: hudson.model.Result.SUCCESS) }
1 | pipeline { |
2 | agent any |
3 | triggers { |
4 | cron('H */4 * * 1-5') |
5 | } |
6 | stage('Example') { |
7 | steps { |
8 | echo 'Hello World' |
9 | } |
10 | } |
11 | } |
stage
stage指令在stages部分中进行,应该包含一个步骤部分、一个可选的代理部分或其他特定于阶段的指令。
tools
一节定义自动安装和放置路径的工具。
支持的工具:
- maven
- jdk
- gradle
1 | pipeline { |
2 | agent any |
3 | tools { |
4 | maven 'apache-maven-3.0.1' |
5 | } |
6 | stages { |
7 | stage('Example') { |
8 | steps { |
9 | sh 'mvn --version' |
10 | } |
11 | } |
12 | } |
13 | } |
input
一个阶段的输入指令允许您使用输入步骤提示输入。
- message: 必须,这将在用户提交输入时呈现给用户
- id: 此输入的可选标识符,默认为阶段名称。
- ok: 输入表单上的“ok”按钮的可选文本。
- submitter: 允许提交此输入的用户或外部组名的可选逗号分隔列表。默认允许任何用户。
- submitterParameter: 一个环境变量的可选名称,如果存在,则用submitter名称设置。
- parameters: 一个可选的参数列表,以提示提交者提供。有关更多信息,请参见参数。
1 | pipeline { |
2 | agent any |
3 | stages { |
4 | stage('Example') { |
5 | input { |
6 | message "Should we continue?" |
7 | ok "Yes, we should." |
8 | submitter "alice,bob" |
9 | parameters { |
10 | string(name: 'PERSON', defaultValue: 'Mr Jenkins', description: 'Who should I say hello to?') |
11 | } |
12 | } |
13 | steps { |
14 | echo "Hello, ${PERSON}, nice to meet you." |
15 | } |
16 | } |
17 | } |
18 | } |
when
when指令允许管道决定是否应该根据给定的条件执行阶段。当指令必须包含至少一个条件时。如果当指令包含多个条件时,所有子条件必须返回true,以便执行。这与子条件在所有条件下嵌套的情况相同。
- branch:当正在构建的分支与给定的分支模式匹配时,执行这个阶段,when { branch ‘master’ },适合多分支
- environment:在将指定的环境变量设置为给定值时执行该阶段。when { environment name: ‘DEPLOY_TO’, value: ‘production’ }
- expression:当指定的Groovy表达式计算为true时,执行阶段。when { expression { return params.DEBUG_BUILD } }
- not:当嵌套条件为假时执行阶段。when { not {branch ‘master’} }
- allOf:当所有嵌套条件为真时。when { allOf { branch ‘master’; environment name: ‘DEPLOY_TO’, value: ‘production’ } }
- anyOf:当所有嵌套条件至少一个条件为真时。when { anyOf { branch ‘master’; branch ‘staging’ } }
1 | pipeline { |
2 | agent any |
3 | stages { |
4 | stage('Build') { |
5 | steps { |
6 | echo 'Hello World' |
7 | } |
8 | } |
9 | stage('Deploy') { |
10 | when { |
11 | branch 'production' |
12 | } |
13 | steps { |
14 | echo 'Deploying' |
15 | } |
16 | } |
17 | } |
18 | } |
1 | pipeline { |
2 | agent any |
3 | environment { |
4 | name='DEPLOY_TO' |
5 | } |
6 | stages { |
7 | stage('Build') { |
8 | steps { |
9 | echo 'Hello World' |
10 | } |
11 | } |
12 | stage('Deploy') { |
13 | when { |
14 | branch 'production' |
15 | environment name: 'name',value: 'DEPLOY_TO' |
16 | } |
17 | steps { |
18 | echo 'Deploy' |
19 | } |
20 | } |
21 | } |
22 | } |
1 | pipeline { |
2 | agent any |
3 | environment { |
4 | name='DEPLOY_TO' |
5 | } |
6 | stages { |
7 | stage('Build') { |
8 | steps { |
9 | echo 'Hello World' |
10 | } |
11 | } |
12 | stage('Deploy') { |
13 | when { |
14 | allOf{ |
15 | branch 'production' |
16 | environment name: 'name',value: 'DEPLOY_TO' |
17 | } |
18 | } |
19 | steps { |
20 | echo 'Deploy' |
21 | } |
22 | } |
23 | } |
24 | } |
1 | pipeline { |
2 | agent any |
3 | environment { |
4 | name='DEPLOY_TO' |
5 | } |
6 | stages { |
7 | stage('Build') { |
8 | steps { |
9 | echo 'Hello World' |
10 | } |
11 | } |
12 | stage('Deploy') { |
13 | when { |
14 | anyOf{ |
15 | branch 'production' |
16 | environment name: 'name',value: 'DEPLOY_TO' |
17 | } |
18 | } |
19 | steps { |
20 | echo 'Deploy' |
21 | } |
22 | } |
23 | } |
24 | } |
1 | pipeline { |
2 | agent any |
3 | environment { |
4 | name='DEPLOY_TO' |
5 | } |
6 | stages { |
7 | stage('Build') { |
8 | steps { |
9 | echo 'Hello World' |
10 | } |
11 | } |
12 | stage('Deploy') { |
13 | when { |
14 | expression {BRANCH_NAME ==~ /(production|staging)/} |
15 | anyOf{ |
16 | branch 'production' |
17 | environment name: 'name',value: 'DEPLOY_TO' |
18 | } |
19 | } |
20 | steps { |
21 | echo 'Deploy' |
22 | } |
23 | } |
24 | } |
25 | } |
1 | pipeline { |
2 | agent none |
3 | stages { |
4 | stage('Build') { |
5 | steps { |
6 | echo 'Hello World' |
7 | } |
8 | } |
9 | stage('Deploy') { |
10 | agent { |
11 | label 'some-label' |
12 | } |
13 | when { |
14 | beforeAgent true |
15 | branch 'production' |
16 | } |
17 | steps { |
18 | echo 'Deploying' |
19 | } |
20 | } |
21 | } |
22 | } |
Parallel
声明式管道中的阶段可以声明它们内部的多个嵌套阶段,它们将并行执行。failFas true声明其中一个失败,全部abort。
1 | pipeline { |
2 | agent any |
3 | stages { |
4 | stage('Non-Parallel') { |
5 | steps { |
6 | echo 'stage first' |
7 | } |
8 | } |
9 | stage('Parallel') { |
10 | when { |
11 | branch 'master' |
12 | } |
13 | failFast true |
14 | parallel { |
15 | stage('Branch A') { |
16 | agent { |
17 | label 'from-branch-a' |
18 | } |
19 | steps { |
20 | echo 'On Branch A' |
21 | } |
22 | } |
23 | stage('Branch B') { |
24 | agent { |
25 | label 'from-branch-b' |
26 | } |
27 | steps { |
28 | echo 'On Branch B' |
29 | } |
30 | } |
31 | } |
32 | } |
33 | } |
34 | } |
steps
声明式管道可以使用管道步骤引用中记录的所有可用步骤,其中包含一个完整的步骤列表。
script
脚本步骤需要一个脚本化的管道,并在声明式管道中执行。
1 | pipeline { |
2 | agent any |
3 | stages { |
4 | stage('Example') { |
5 | steps { |
6 | echo 'Hello World' |
7 | script { |
8 | def browsers=['chrome','firefox'] |
9 | for (int i=0;i<browsers.size();++i) { |
10 | echo 'Testing the ${browsers[i]} browser' |
11 | } |
12 | } |
13 | } |
14 | } |
15 | } |
16 | } |
Scripted Pipeline
脚本化的管道,比如声明式管道,是建立在底层管道子系统之上的。不同于声明性的,脚本化的管道实际上是用Groovy构建的通用DSL。Groovy语言提供的大部分功能都可以用于脚本化管道的用户,这意味着它可以是一个非常有表现力和灵活的工具,可以通过它编写持续的交付管道。
流控制
1 | node { |
2 | stage('Example') { |
3 | if (env.BRANCH_NAME == 'master') { |
4 | echo 'I only execute on the master branch' |
5 | } else { |
6 | echo 'I execute elsewhere' |
7 | } |
8 | |
9 | } |
10 | } |
1 | node { |
2 | stage('Example') { |
3 | try { |
4 | sh 'exit 1' |
5 | } |
6 | catch (exc) { |
7 | echo 'Something failed' |
8 | } |
9 | finally { |
10 | echo 'close' |
11 | } |
12 | } |
13 | } |