jenkins官网有关于流水线语法的文档(https://www.jenkins.io/zh/doc/book/pipeline/syntax/),但是内容比较多,难以摘取重点,也不建议大家购买实体的Jenkins的权威指南之类的,亲测因为插件更新迭代速度太快,出版的实体书远赶不上Jenkins的更新速度,使用起来会有较大的困难.
本文主要内容为声明式脚本的格式,一些常用指令和模块的使用方式及注意事项,使用的Jenkins版本是2.346.2 LTS,插件使用版本是截至2022年8月15日的最新版本的插件。
一、基本格式
pipeline{
agent any
stages{
stage ('stage1'){
steps{
......
}
}
stage ('stage2'){
steps{
......
}
}
stage ('stage3'){
steps{
......
}
}
......
}
}
- pipeline:声明式流水线的一种特定语法,它定义了包含执行整个流水线的所有内容和指令,是整个流水线必须存在的最外层的块。
- agent:声明式流水线的一种特定语法,agent指令是必须的,它只是Jenkins为流水线分配一个执行器和工作区,没有agent指定的声明式流水线是无效的,不可能完成任何工作。具体参考【二、常用指令】中的【1、agent】。
- stages:stage的集合,一个声明式流水线中有且仅有一个stages。
- stage:一个stage表示流水线中的一个执行阶段,stage块是可选的,也是可多选的。每一个stage必须有自己的标签,且标签不能重复。
- steps:声明式流水线的一种特定语法,它描述了这个stage中要运行的步骤,是一个执行单一动作的单一命令的集合。具体参考【二、常用指令】中的【2、steps】。
二、常用指令
1、agent
默认情况下agent指令必须确保源代码仓库被检出并在后续阶段的步骤中可被使用。
顶层必须定义agent,顶层定义为none时stage中也可以定义agent。
//在任何可用的代理上执行流水线或它的任何阶段
agent any
//在pipeline顶层使用none时,每个stage需要指定相应的agent,顶层有stages以外的其他模块时不能设置none
agent none
//在指定的节点运行
agent {label 'master'}
//在指定的节点的指定目录下运行
agent {
node{
label 'master'
customWorkspace 'D://temp'
}
}
//在指定的容器运行
agent{
docker{
image 'master:latest'
label 'master'
args '-v /temp:/temp'
}
}
2、steps
steps中描述了pipeline运行的步骤,当一个步骤是成功时执行下一个步骤,当任何一个步骤执行失败时,pipeline的执行结果也为失败,当所有的步骤都执行完成并且为成功时,pipeline的执行结果为成功。
step中的指令可以通过片段生成器进行转换,比如windows下的bat指令:
一个steps中可以包括多个不同类型的单一命令:
steps{
bat './HelloWord.exe'
bat 'cd ..'
bat 'copy 1.txt 2.txt'
bat 'call HelloWord.bat'
echo 'Hello World!'
}
3、post
钩子指令,在pipeline或stage完成时触发的指令,可以用于pipeline运行完成时的清理动作,也可以用于基于不同运行结果执行不同的操作。顶层的post部分保证在pipeline结束的时候运行,post部分也可以放在stage中,在这个stagge结束的时候运行,一个pipeline中可以存在多个post。
post形似switch,但是与switch不同,并不是只能完成其中一个,比如always和success同时存在时,会先执行always里面的步骤再执行success里面的步骤,如果有cleanup模块最后还会执行cleanup,这个顺序与写在post中的 前后顺序也是无关的。always的运行结果会影响流水线最终的运行结果,流水线会先执行always里的步骤,当always中的步骤执行失败时,就算先前的执行结果为success最终也只会执行failure。
post{ //post部分可以包含多种条件块,可以根据需求只设定自己需要的条件块
always{ //无论当前完成状态是什么都执行,在其他所有条件块执行之前执行
....
}
changed{ //只要当前完成状态与上一次完成状态不同就执行
....
}
fixed{ //上一次完成状态为失败或者不稳定,当前完成状态为成功时执行
....
}
regression{ //上一次完成状态为成功,当前完成状态为失败/不稳定/中止时执行
....
}
aborted{ //当前执行结果是中止状态(一般为人为中止)时执行
....
}
success{ //当前完成状态为成功时执行
....
}
failure{ //当前完成状态为失败时执行
....
}
unstable{ //当前完成状态为不稳定时执行
....
}
cleanup{ //清理条件块,不论当前完成状态是什么,在其他所有条件块执行完成后都执行
....
}
}
4、parallel
流水线中默认模块之间为串行,想要实现并行需要在要并行的几个模块外部加parallel,并行模块以stage为单位。
stages{ ⭐stage1,stage2,stage3串行
stage('stage1'){
......
}
stage('stage2'){ ⭐stage2.1,stage2.2,stage2.3并行
parallel{
stage('stage2.1'){
......
}
stage('stage2.2'){
......
}
stage('stage2.3'){
......
}
}
}
stage('stage3'){ ⭐stage3.1,stage3.2,stage3.3串行
stage('stage3.1'){
......
}
stage('stage3.2'){
......
}
stage('stage3.3'){
......
}
}
有时候在一个parallel代码块中,希望其中一个分支失败时可以退出所有的步骤,这个时候可以使用failFast选项。把failFast:true添加到parallel的步骤中即可。
stage('stage2'){
parallel{
stage('stage2.1'){
......
}
stage('stage2.2'){
......
}
stage('stage2.3'){
......
}
failFast:true ⭐一个步骤失败则退出所有步骤
}
}
5、retry、timeout、sleep、waitUntil
Jenkins中有四个指令可以用于流程控制,retry、timeout、sleep、waitUntil,因为可以进行组合使用,所以此处一起进行介绍。
-
retry:重复执行步骤,直到成功或超出设定的重试次数。
steps{ retry(3){ //最多重试3次,三次都失败则标记该阶段失败 sh 'echo "Hello Word!"' } }
-
timeout:如果执行步骤超时则退出,并且标记该阶段为失败。
steps{ timeout(time:3,unit:'MINUTES'){ //设定该步骤3分钟未完成则标记失败 sh 'echo "Hello Word!"' } }
-
sleep:这是一个基本的延时步骤,默认单位是秒,比如直接使用sleep 5,就相当于延时5秒,如果想要指定其他的时间单位,参照下图即可。
steps{ sh 'echo "Hello Word!"' sleep time:5,unit:'MINUTES' //设定延迟5分钟 sh 'echo "Hello Word!"' }
-
waitUntil:这个指令会让流水线保持一个等待状态,一直等到某件事情发生。使用这个指令要求一段步骤存在一个返回值,声明式语法想要返回一个返回值往往需要借助使用脚本式流水线的语法,因此会使用到script指令,并且可以组合脚本时语法中的try-catch或者if-else等指令进行使用,script详细用法可以参考【14、script】。
如果代码款中的过程返回false,那么这个步骤会在等待更长时间之后进行下一次尝试,下一次的等待时间为此次的等待时间乘以1.2。代码块中抛出的任何异常都会导致这个步骤立即退出并且抛出一个错误,比如步骤中要执行的脚本不存在等,如果想在抛出异常时可以继续重试,则可以使用try-catch来捕捉异常,避免流水线终止,具体示例可参考【14、script】。-
initialRecurrencePeriod :设置初始等待的等待时间,以毫秒为单位,默认为 250 毫秒。
-
quiet :如果返回值为false,会进入下一次等待,这时会显示一条信息提示下一次的等待时间:Will try again after 0.25 秒,如果quite设为true则不会显示这条消息,默认值为false。
steps{ waitUntil(initialRecurrencePeriod: 1000,quiet: true){ //初始等待时间为1秒,不显示等待时间信息 echo 'Hello World' script{ return true } } }
-
-
retry和timeout可以组合使用:
steps{ //5秒内最多重试3次 timeout(time:5,unit:'MINUTES'){ retry(3){ sh 'echo "Hello Word!"' } } } steps{ //重试3次,每次5秒超时 retry(3){ timeout(time:5,unit:'MINUTES'){ sh 'echo "Hello Word!"' } } }
如果想要设定整个流水线的retry和timeout参数,可以参考【8、options】进行配置。
-
sleep和timeout组合使用时需要注意,timeout的时间必须大于sleep的时间,如果sleep和timeout、retry组合,timeout的时间必须大于sleep*retry的时间,否则可能会出现永远无法执行成功的情况。
steps{ //最多重试3次,每次执行时间至少5秒,因此timeout设定的时间至少大于20秒 timeout(time:20,unit:'SECONDS'){ retry(3){ sh 'echo "Hello Word!"' sleep 5 sh 'echo "Hello Word!"' } } }
-
waitUntil指令如果接收到的返回值一直为false,那么永远无法退出循环,因此可以和timeout组合使用,防止waitUntil卡死流水线。
steps{ timeout(time:10,unit:'SECONDS'){ //waitUntil永远返回false,但是会在10秒后timeout退出 waitUntil(initialRecurrencePeriod: 1000,quiet: true){ echo 'Hello World' script{ return false } } } }
6、environment
这是声明式流水线中的一个可选指令,这个指令允许为环境变量指定名称和值
在流水线代码块顶部设定的environment指令适用于流水线的所有步骤,定义在stage中的environment指令只适用于stage中的步骤。
邮件的文本中的环境变量不能够被解析,邮件文本只能解析jenkens的系统变量,不能解析流水线中的自动逸环境变量。
environment{
TEST = "test"
TEST_1 = "${TEST}_1" //在定义环境变量时可以包含已经定义的变量
}
7、tools
tools指令可以让我们指定哪些工具需要在我们已经选择代理的代理节点上自动安装在配置路径下。
如果没有指定代理节点,如使用agent any/agent none,则tool指令将不会起作用。目前在声明式语法中可以指定的配置路径的只有ant、git、gradle、jdk、jgit、jgitapache、maven。
下面针对不同情况有两种配置方式,可以根据续修进行选择。
- 如果受控节点上有很多不同版本的工具在不同路径下,测试过程中可能更改测试版本,则可以创建多个名称区分不同的版本的路径,然后在流水线中进行修改即可。
在Manage Jenkins→Global Tool Configuration下可以进行全局工具的配置,图中以git为例创建新的git路径git_test(由于我实际上并没有装git,所以没有有效路径,实际使用时填写安装路径即可),假如Default中我填写jenkins所在机器的git安装路径,git_test中填写受控节点node1上的git安装路径,则可以在流水线中指定该节点的工具路径。
实际使用时可以使用更清楚的名字,比如git3.1、git3.2。
agent {label 'node1'}
tools{
git "git_test"
}
//tools也可以承接一个变量的值,甚至可以外部输入,关于parameters的相续说明可以参考【10、parameters】
agent {label 'node1'}
parameters{
string(name:'GitTool',
defaultValue:'git_test',
description:'Git Version'
)
}
tools{
git "${paras.GitTool}"
}
- 如果工具的配置路径不变,则存在一种更加简便、可以不用在流水线中使用tool就可以指定配置路径的方式,就是在配置节点时直接声明在该节点上运行时的配置路径。
使用该方法的局限性是至少要在Manage Jenkins→Global Tool Configuration中存在一个该工具的名称,否则名称的下拉选项中不会出现该工具。比如如果我想使用maven,那么至少要在Manage Jenkins→Global Tool Configuration的maven中选择新增,然后把name填上,这样配置节点时才会有这个选项。
8、options
这个命令用于制定一些属性和值,options指令的使用位置是顶层模块,所以设定的内容作用于整条流水线,可用的选项包括:
-
buildDiscarder:指定保留指令数量的流水线日志数量。
options { buildDiscarder(logRotator(numToKeepStr: '5')) }
-
disableConcurrentBuilds:不允许并发执行流水线。可以用来防止同时访问共享资源,或者防止一个较快的并发执行把一个较慢的并发执行破坏掉。使用此选项后,如果当前任务正在执行构建的过程中,则其他分支的构建申请会放入队列中排队。
-
options { disableConcurrentBuilds() }
-
overrideIndexTriggers:修改分支索引触发器的处理方式。
options { overrideIndexTriggers(true) } //如果分支索引触发器在多分支或标签中禁用, 则为当前构建进行开启。 options { overrideIndexTriggers(false) } //如果分支索引触发器在多分支或标签中开启, 则为当前构建进行禁用。
-
skipDefaultCheckout:如果使用Jenkinsfile的方式存储流水线脚本的话,在agent指令中存在一个隐式的全局代码检出checkout scm语句,因为Jenkinsfile应该与源码存放在一起,因此可以使用代码仓库的位置和分支信息。但是如果应用中不希望进行全局代码检出,则可以使用该选项删除这条隐式的checkout scm语句,从而跳过源码的自动机检出的过程。
options { skipDefaultCheckout() }
-
skipStagesAfterUnstable:如果流水线中的某一个阶段不稳定,把流水线的构建状态变成UNSTABLE,那么就不会再处理剩余阶段。
options { skipStagesAfterUnstable() }
-
checkoutToSubdirectory:在工作空间的子目录中自动检出源代码。
options { checkoutToSubdirectory('foo') }
-
timeout:设定整个流水线执行一次的时限,如果超时则整个流水线会被终止。
options { timeout(time: 1, unit: 'HOURS') }
-
retry:指定在流水线执行失败后,尝试重新运行整个流水线的次数。
options { retry(3) }
-
timestamps:添加时间戳到控制台的输出中,该选项会全局的应用到整个流水线的过程中,要使用这个选项要求安装Timestamp插件。
options { timestamps() }
这些选项中有很多选项是可以在项目构建时进行设定的,比如buildDiscarder,disableConcurrentBuilds,如果不使用Jenkinsfile,不考虑流水线的迁移问题的话,也是可以在项目的常规配置中进行配置。
9、triggers
这个指令可以指定触发流水线的触发器,可以指定的触发器有:cron、pollSCM、upstream和githubPush,以cron为例设定方式为:
triggers { cron(* 10 * * *) } //每天上午十点触发构建
如果设定的启动时间不是一个具体的值,而是一个区间,可以在区间前标记H,它的作用是使用该项目的散列值计算出一个唯一的偏移量,启动时间范围的最小值加上这个偏移量就是这个项目的实际启动时间,它的作用是避免在同一时刻启动两个不同的构建。符号H可以用于任何字段,其语法是H( start_range , end_range )。
triggers { cron(* H(10,12) * * *) } //每天上午十点到十二点之间触发构建
关于cron指令详细可以参考cron定时任务语法及实例。
这个指令的作用与构建触发器是一样的,因此如果不考虑迁移的问题也可以直接在构建项目时在构建触发器中进行配置。
我推荐使用构建触发器的原因是,在我们设定完任务周期后鼠标点一下输入框以外的位置就会出现下一次执行该项目构建的时间,方便检查是否设定正确,日程表边上的问号点开后还有cron的语法说明和举例,对于对cron语法不是特别有自信的人来说比较友好。
10、parameters
这个指令允许我们为该流水线指定项目参数,这些参数的值可能是定义时直接进行赋值,也可能由用户输入或者API调用进行赋值,如果要进行用户输入可以结合input指令进行使用,详细用法参考【11、input】。此处仅以直接赋值的方式列举所有合法类型的变量定义方法,以进行各个类型变量的格式及参数的介绍。
-
booleanParam:定义布尔型变量,参数包括:
-
name:变量名。
-
defaultValue:默认值,只存在true/false两个有效值。
-
description:变量描述。
parameters{ booleanParam( name:'TestRun', defaultValue:true, description:'Test Run ?' ) }
-
-
string:定义一个变量使用户可以输入一个字符串,参数包括:
-
name:变量名。
-
defaultValue:默认值,只存在true/false两个有效值。
-
description:变量描述。
parameters{ string( name: 'PERSON', defaultValue: 'Mr Jenkins', description: 'Who should I say hello to?' ) }
-
-
choice:定义一个可选项,允许由用户从选项列表中选择,参数包括:
-
name:变量名。
-
choices:展示给用户的选项列表,以换行符\n进行分割。
-
description:变量描述。
parameters{ choice( name:'system', choices:'Windows\nLinux', description:'System Type ?' ) }
-
-
text:定义一个变量使用户可以输入一个多行的文本,参数包括:
-
name:变量名。
-
defaultValue:默认值。
-
description:变量描述。
parameters{ text( name:'TestInput', defaultValue:'No Message', description:'Test Input text parameters.' ) }
-
-
password:定义一个变量使用户可以输入一个密码,输入的密码在界面上是加密的,但是可以通过echo输出,参数包括:
-
name:变量名。
-
defaultValue:默认值,默认值显示在界面上也是加密的。
-
description:变量描述。
parameters{ password( name:'UserPassword', defaultValue:'111111', description:'User Input Password.' ) }
-
-
run:定义一个变量使用户可以从某个构建项目中选择一个特定的运行,参数包括:
-
name:变量名。
-
projectName:想要选择运行的项目。
-
filter:选择一个构建状态进行筛选,在满足筛选条件的构建历史中选择最新的一次。
- ALL:所有的构建,包括正在运行中的构建。
- COMPLETED:完成的构建,包括不稳定的构建。
- SUCCESSFUL:成功的构建。
- STABLE:稳定的构建。
-
description:变量描述。
parameters{ run( name:'runtest', projectName:'test', filter:'SUCCESSFUL', description:'choice project to run.' ) }
-
如果不需要进行用户输入,有默认值的几个直接使用 ${params.变量名} 即可访问变量值,如果想要使用用户输入的值可以参考【11、input】中的三个示例选择合适的方式即可,另外,因为有时版本更新会导致模块内参数变化,所以可以使用片段生成器选择input模块,再添加有一个parameters模块,生成代码之后摘抄出想要的部分即可,使用片段生成器生成parameters模块也可以参考【11、input】。
除上述列出的parameters以外还有file、credentials、Subversion可供使用,但是这几项加上run经常出现问题,也经常进行版本更新导致语法变更,因此不推荐使用。
11、input
这条指令可以通过流水线获得一个用户输入,在使用时,使用片段生成器可以很简单的完成,不需要自行编写,首先选择input模块进行设定,再选择添加参数(parameters)。
下面是三个使用input的不同方法,三种方式的运行结果都是相同的,选择合适的方式即可,关于例1、例2使用时的差别可参考【13、script】。
//例1:流水线外部定义变量承接返回值
def test = input id: 'Test_input', message: 'Hello , What\'s your name', ok: 'Input finished.', parameters: [string(defaultValue: 'Mr Jenkins', description: 'Who should I say hello to?', name: 'PERSON')], submitter: 'alice,bob', submitterParameter: 'name'
pipeline {
agent any
stages {
stage('Example') {
steps {
echo "Hello, ${test['PERSON']}, I'm ${test['name']}, nice to meet you."
}
}
}
}
//例2:流水线内部定义变量承接返回值
pipeline {
agent any
stages {
stage('Example') {
steps {
script{
def test = input id: 'Test_input', message: 'Hello , What\'s your name', ok: 'Input finished.', parameters: [string(defaultValue: 'Mr Jenkins', description: 'Who should I say hello to?', name: 'PERSON')], submitter: 'alice,bob', submitterParameter: 'name'
echo "Hello, ${test['PERSON']}, I'm ${test['name']}, nice to meet you."
}
}
}
}
}
//例3:将生成的代码转化为input指令格式
pipeline {
agent any
stages {
stage('Example') {
input{
id "Test_input"
message "Hello , What\'s your name ?"
ok "Input finished."
submitter "alice,bob"
submitterParameter "name"
parameters{
string(
defaultValue: 'Mr Jenkins',
description: 'Who should I say hello to?',
name: 'PERSON'
)
}
}
steps {
echo "Hello, ${PERSON}, I'm ${name}, nice to meet you."
}
}
}
}
执行构建,按照提示进行输入:
12、libraries
这个指令允许声明式流水线导入共享库,这样共享库中的的代码就可以被流水线调用和使用。另外还有一个作用是可以在声明式流水线中使用非声明式流水线的代码,和script作用相同。
pipeline{
agent any
libraries{
lib("mylib")
lib("templib")
}
stages{
.......
}
}
这边仅对使用格式进行说明,关于共享库的详细说明后面会另外单写一篇博客进行说明,后续完成后会引用过来。
13、when
when 指令允许流水线根据给定的条件决定是否应该执行阶段,该指令必须包含至少一个条件。 when的内置条件有:
-
branch:当正在构建的分支与模式给定的分支匹配时,执行这个阶段。注意,这只适用于多分支流水线。
-
environment:当指定的环境变量是给定的值时,执行这个步骤。
-
expression:当指定的Groovy表达式评估为true时,执行这个阶段。
-
not:当嵌套条件是错误时,执行这个阶段,必须包含一个条件。
-
allOf:当所有的嵌套条件都正确时,执行这个阶段,必须包含至少一个条件。在when中如果包含多个子条件,则需所有子条件均为真整个when的判断才为真,相当于when的最外层有一个allOf。
-
anyOf:当至少有一个嵌套条件为真时,执行这个阶段,必须包含至少一个条件。
pipeline { agent any environment{ TEST_WHEN = true TEST_1 = "TEST_1_${TEST_WHEN}" TEST_2 = "TEST_2_${TEST_WHEN}" TEST_3 = "TEST_3_${TEST_WHEN}" CheckNum = "1" } stages { stage('Example') { when { environment name: 'TEST_WHEN', value: 'true' //判断一个环境变量的值 expression { env.CheckNum == '1' } //判断一个表达式的值 not{ environment name: 'TEST_WHEN', value: 'false' } //判断一个执行条件的否定 allOf{ //判断一组条件全部为真 environment name: 'TEST_1', value: 'TEST_1_true' environment name: 'TEST_2', value: 'TEST_2_true' environment name: 'TEST_3', value: 'TEST_3_true' } anyOf{ //判断一组条件至少有一项为真 environment name: 'TEST_1', value: 'TEST_1_false' environment name: 'TEST_2', value: 'TEST_2_false' environment name: 'TEST_3', value: 'TEST_3_true' } } steps { echo 'Susseccful!' } } } }
上面的例子包含了除branch以外的其他内置条件,下面的例子说明branch。首先branch具有局限性只有在多分支流水线中才可以使用,另外在判断时可以组合beforeAgent 使用,可以做到先判定是否满足when,满足的情况下才进行Agent,beforeAgent默认为false。
pipeline {
agent none
stages {
stage('Example Build') {
steps {
echo 'Hello World'
}
}
stage('Example Deploy') {
agent {
label "some-label"
}
when {
beforeAgent true //先评估是否满足when
branch 'production'
}
steps {
echo 'Deploying'
}
}
}
}
14、script
在声明式流水线中很多时候会需要使用脚本式流水线中的指令,比如使用def定义变量承接input返回值,或者用try-catch进行异常捕捉,这个时候就需要把这部分指令放入script中,此处列举一些常用的指令及其在使用script包裹时要注意的事项。
-
def:这个指令是在流水线中经常要使用的,甚至是有时必须要使用的,比如input中携带parameters时,详细可见【11、input】中例1、例2,在这两个例子中可以看到例1中def定义的变量是放在pipeline外面在全局范围内进行使用的,例2则是放在scirpt中进行定义,这边需要注意的是,在script中定义的变量作用域仅在这个script中,以之前的例2为例:
//script内部访问变量 pipeline { agent any stages { stage('Example') { steps { script{ def test = input id: 'Test_input', message: 'Hello , What\'s your name', ok: 'Input finished.', parameters: [string(defaultValue: 'Mr Jenkins', description: 'Who should I say hello to?', name: 'PERSON')], submitter: 'alice,bob', submitterParameter: 'name' echo "Hello, ${test['PERSON']}, I'm ${test['name']}, nice to meet you." ⭐可以正常输出Hello, Lily, I'm admin, nice to meet you. } } } } } //script外部访问变量 pipeline { agent any stages { stage('Example') { steps { script{ def test = input id: 'Test_input', message: 'Hello , What\'s your name', ok: 'Input finished.', parameters: [string(defaultValue: 'Mr Jenkins', description: 'Who should I say hello to?', name: 'PERSON')], submitter: 'alice,bob', submitterParameter: 'name' } echo "Hello, ${test['PERSON']}, I'm ${test['name']}, nice to meet you." ⭐会导致错误:groovy.lang.MissingPropertyException: No such property: test for class: groovy.lang.Binding } } } }
如果既想在流水线的指定位置设定放置input,又想在script外部引用返回值的话,可以使用环境变量来承接这个临时变量:
pipeline { agent any stages { stage('Example') { steps { script{ def test = input id: 'Test_input', message: 'Hello , What\'s your name', ok: 'Input finished.', parameters: [string(defaultValue: 'Mr Jenkins', description: 'Who should I say hello to?', name: 'PERSON')], submitter: 'alice,bob', submitterParameter: 'name' env.TEST_PERSON = test['PERSON'] //环境变量赋值 env.TEST_NAME = test['name'] } echo "Hello, ${TEST_PERSON}, I'm ${TEST_NAME}, nice to meet you." //调用环境变量 } } } }
-
try-catch:异常捕捉,在流水线中如果其中一个stage抛出异常,则会中止整个流水线的后续stage,但是有些问题可能式偶然发生且可忽视的,或是可以进行弥补的,这时就可以使用try-catch来捕捉异常,组合waitUntil使用可以实现retry的功能。
pipeline { agent any stages { stage('Hello') { steps { waitUntil(){ script{ try { bat './HelloWorld.bat' return true } catch (exc) { //捕捉到异常时返回false可以开始下一次循环 return false } } } } } } }
-
if-else:在声明式流水线中,使用when进行分支判断,但是借助脚本式流水线中的if-else可以更加直观的进行分支判断。
pipeline { agent any stages { stage('Example') { steps { script{ def test = input id: 'Test_input', message: 'Hello , What\'s your name', ok: 'Input finished.', parameters: [string(defaultValue: 'Mr Jenkins', description: 'Who should I say hello to?', name: 'PERSON')], submitter: 'alice,bob', submitterParameter: 'name' env.TEST_PERSON = test['PERSON'] env.TEST_NAME = test['name'] } echo "Hello, ${TEST_PERSON}, I'm ${TEST_NAME}, nice to meet you." script{ if(TEST_NAME == "admin"){ echo "I can do everything" } else{ echo "I can't do everything" } } } } } }
-
for:在声明式流水线中,默认执行顺序是串行,使用parallel可以实现并行,要实现循环和最简单的方式就是使用脚本式流水线中的for语句,其语法和c语言相同。
pipeline { agent any stages { stage('Example') { steps { script { def week = ['Monday','Therday','Wednesday','Thursday','Firday','Saturday','Sunday'] for (int i = 0; i < week.size(); ++i) { echo "Today is ${week[i]}" } } } } } }
三、常用插件模块
常用的模块想要在pipeline中使用需要生成相应的步骤指令,使用片段生成器选择自己想要的模块进行配置之后生成流水线脚本即可。
如果一个插件提供了流水线兼容步骤,它就会被包含在代码片段生成器中,因此如果想要使用流水线实现插件功能,首先还是需要在Jenkins上安装相应的插件的,代码生成器中也只显示已安装的流水线兼容的插件的指令生成方式。
1、代码检出
具体检出模块使用设置可以参考Jenkins构建本地/svn/流水线任务中【二、构建svn任务】,git和svn设定方法类似。
片段生成出来的代码通常很长一段,尤其是有多个svn信息检出时,可以根据信息内容进行换行、调整缩进,以便阅读和日后修改。
如果后期svn的账号和密码进行了变更,可以直接去凭证管理中修改,这样credentialsId就不会变,流水线就不用进行修改。
checkout(
[$class: 'SubversionSCM', additionalCredentials: [], excludedCommitMessages: '', excludedRegions: '', excludedRevprop: '', excludedUsers: '', filterChangelog: false, ignoreDirPropChanges: false, includedRegions: '',
locations: [
[cancelProcessOnExternalsFail: true, credentialsId: '71973fd6-****-****-****-88847e66b2f6', depthOption: 'infinity', ignoreExternalsOption: true, local: './test1', remote: 'svn://test_url_1'],
[cancelProcessOnExternalsFail: true, credentialsId: '71973fd6-****-****-****-88847e66b2f6', depthOption: 'infinity', ignoreExternalsOption: true, local: './test2', remote: 'svn://test_url_2'],
[cancelProcessOnExternalsFail: true, credentialsId: '71973fd6-****-****-****-88847e66b2f6', depthOption: 'infinity', ignoreExternalsOption: true, local: './test3', remote: 'svn://test_url_3']
],
quietOperation: true, workspaceUpdater: [$class: 'UpdateUpdater']
]
)
2、发送邮件
默认邮件模块与扩展邮件模块一样,在选择模块之后配置模块信息即可,这边和构建后发送大体一致,具体可以参考Jenkins配置邮件自动发送中的【五、在构建项目时加入邮件通知】,但是片段生成器中的正文格式为文本格式而非html,环境变量可以正常使用。