天天看点

《Jenkins 2.x实践指南》读书笔记-Jenkins 2.x pipeline语法1. 大概了解Groovy2. pipeline介绍

[TOC]

可以通过Groovy教程来了解。

Jenkins pipeline其实就是基于Groovy语言实现的一种DSL(领域特定语言),用于描述整条流水线是如何进行的。流水线的内容包括执行编译、打包、测试、输出测试报告等步骤。

<code>pipeline</code>:代表整条流水线,包含整条流水线的逻辑。

<code>stage</code>部分:阶段,代表流水线的阶段。每个阶段都必须有名称。本例中,<code>build</code>就是此阶段的名称。

<code>stages</code>部分:流水线中多个<code>stage</code>的容器。<code>stages</code>部分至少包含一个<code>stage</code>。

<code>steps</code>部分:代表阶段中的一个或多个具体步骤(<code>step</code>)的容器。<code>steps</code>部分至少包含一个步骤,本例中,<code>echo</code>就是一个步骤。在一个<code>stage</code>中有且只有一个<code>steps</code>。

<code>agent</code>部分:指定流水线的执行位置(Jenkins agent)。流水线中的每个阶段都必须在某个地方(物理机、虚拟机或Docker容器)执行,<code>agent</code>部分即指定具体在哪里执行。

更多更详细pipeline步骤参考文档:

https://jenkins.io/zh/doc/pipeline/steps/

以上每一个部分(section)都是必需的,少一个,Jenkins都会报错。

众所周知,jenkins好用最大体现它的众多插件满足各种需求。并不是所有的插件都支持pipeline的。

jenkins插件兼容pipeline列表:

https://github.com/jenkinsci/pipeline-plugin/blob/master/COMPATIBILITY.md

<code>post</code>部分包含的是在整个pipeline或阶段完成后一些附加的步骤。<code>post</code>部分是可选的,所以并不包含在pipeline最简结构中。但这并不代表它作用不大。

根据pipeline或阶段的完成状态,<code>post</code>部分分成多种条件块,包括:

<code>always</code>:不论当前完成状态是什么,都执行。

<code>changed</code>:只要当前完成状态与上一次完成状态不同就执行。

<code>fixed</code>:上一次完成状态为失败或不稳定(<code>unstable</code>),当前完成状态为成功时执行。

<code>regression</code>:上一次完成状态为成功,当前完成状态为失败、不稳定或中止(<code>aborted</code>)时执行。

<code>aborted</code>:当前执行结果是中止状态时(一般为人为中止)执行。

<code>failure</code>:当前完成状态为失败时执行。

<code>success</code>:当前完成状态为成功时执行。

<code>unstable</code>:当前完成状态为不稳定时执行。

<code>cleanup</code>:清理条件块。不论当前完成状态是什么,在其他所有条件块执行完成后都执行。<code>post</code>部分可以同时包含多种条件块。以下是<code>post</code>部分的完整示例。

显然,基本结构满足不了现实多变的需求。所以,Jenkins pipeline通过各种指令(directive)来丰富自己。指令可以被理解为对Jenkins pipeline基本结构的补充。

Jenkins pipeline支持的指令有:

<code>environment</code>:用于设置环境变量,可定义在<code>stage</code>或<code>pipeline</code>部分。

<code>tools</code>:可定义在<code>pipeline</code>或<code>stage</code>部分。它会自动下载并安装我们指定的工具,并将其加入<code>PATH</code>变量中。

<code>input</code>:定义在<code>stage</code>部分,会暂停<code>pipeline</code>,提示你输入内容。

<code>options</code>:用于配置Jenkins pipeline本身的选项,比如<code>options {retry(3)}</code>指当<code>pipeline</code>失败时再重试2次。<code>options</code>指令可定义在<code>stage</code>或<code>pipeline</code>部分。

<code>parallel</code>:并行执行多个<code>step</code>。在<code>pipeline</code>插件1.2版本后,<code>parallel</code>开始支持对多个阶段进行并行执行。

<code>parameters</code>:与<code>input</code>不同,<code>parameters</code>是执行<code>pipeline</code>前传入的一些参数。

<code>triggers</code>:用于定义执行<code>pipeline</code>的触发器。

<code>when</code>:当满足<code>when</code>定义的条件时,阶段才执行。

在使用指令时,需要注意的是每个指令都有自己的“作用域”。如果指令使用的位置不正确,Jenkins将会报错。

<code>options</code> 指令允许从流水线内部配置特定于流水线的选项。 流水线提供了许多这样的选项, 比如 <code>buildDiscarder</code>,但也可以由插件提供, 比如 <code>timestamps</code>.

Required

No

Parameters

None

Allowed

Only once, inside the <code>pipeline</code> block.

buildDiscarder

为最近的流水线运行的特定数量保存组件和控制台输出。例如: <code>options { buildDiscarder(logRotator(numToKeepStr: '1')) }</code>

disableConcurrentBuilds

不允许同时执行流水线。 可被用来防止同时访问共享资源等。 例如: <code>options { disableConcurrentBuilds() }</code>

overrideIndexTriggers

允许覆盖分支索引触发器的默认处理。 如果分支索引触发器在多分支或组织标签中禁用, <code>options { overrideIndexTriggers(true) }</code> 将只允许它们用于促工作。否则, <code>options { overrideIndexTriggers(false) }</code> 只会禁用改作业的分支索引触发器。

skipDefaultCheckout

在<code>agent</code> 指令中,跳过从源代码控制中检出代码的默认情况。例如: <code>options { skipDefaultCheckout() }</code>

skipStagesAfterUnstable

一旦构建状态变得UNSTABLE,跳过该阶段。例如: <code>options { skipStagesAfterUnstable() }</code>

checkoutToSubdirectory

在工作空间的子目录中自动地执行源代码控制检出。例如: <code>options { checkoutToSubdirectory('foo') }</code>

timeout

设置流水线运行的超时时间, 在此之后,Jenkins将中止流水线。例如: <code>options { timeout(time: 1, unit: 'HOURS') }</code>

retry

在失败时, 重新尝试整个流水线的指定次数。 例如: <code>options { retry(3) }</code>

timestamps

预谋所有由流水线生成的控制台输出,与该流水线发出的时间一致。 例如: <code>options { timestamps() }</code>

newContainerPerStage

当<code>agent</code>为<code>docker</code>或<code>dockerfile</code>时,指定在同一个Jenkins节点上,每个<code>stage</code>都分别运行在一个新的容器中,而不是所有<code>stage</code>都运行在同一个容器中。例如: <code>options { newContainerPerStage() }</code>

指定一个小时的全局执行超时, 在此之后,Jenkins 将中止流水线运行。

<code>stage</code> 的 <code>options</code> 指令类似于流水线根目录上的 <code>options</code> 指令。然而, <code>stage</code> -级别 <code>options</code> 只能包括 <code>retry</code>, <code>timeout</code>, 或 <code>timestamps</code> 等步骤, 或与 <code>stage</code> 相关的声明式选项,如 <code>skipDefaultCheckout</code>。

在<code>stage</code>, <code>options</code> 指令中的步骤在进入 <code>agent</code> 之前被调用或在 <code>when</code> 条件出现时进行检查。

在 <code>agent</code> 指令中跳过默认的从源代码控制中检出代码。例如: <code>options { skipDefaultCheckout() }</code>

设置此阶段的超时时间, 在此之后, Jenkins 会终止该阶段。 例如: <code>options { timeout(time: 1, unit: 'HOURS') }</code>

在失败时, 重试此阶段指定次数。 例如: <code>options { retry(3) }</code>

预谋此阶段生成的所有控制台输出以及该行发出的时间一致。例如: <code>options { timestamps() }</code>

指定 Example 阶段的执行超时时间, 在此之后,Jenkins 将中止流水线运行。

声明式pipeline是不能直接在<code>steps</code>块中写Groovy代码。

Jenkins pipeline专门提供了一个<code>script</code>步骤,你能在<code>script</code>步骤中像写代码一样写pipeline逻辑。

在script块中的其实就是Groovy代码。大多数时候,我们是不需要使用<code>script</code>步骤的。如果在<code>script</code>步骤中写了大量的逻辑,则说明你应该把这些逻辑拆分到不同的阶段,或者放到共享库中。共享库是一种扩展Jenkins pipeline的技术。

这里介绍pipeline内置的一些步骤。

deleteDir

删除当前目录,它是一个无参步骤,删除的是当前工作目录。通常它与<code>dir</code>步骤一起使用,用于删除指定目录下的内容。

dir

切换到目录。默认pipeline工作在工作空间目录下,<code>dir</code>步骤可以让我们切换到其它目录。例如:<code>dir("/var/logs") { deleteDir() }</code>

fileExists

判断文件是否存在。<code>fileExists('/tmp/a.jar')</code>判断<code>/tmp/a.jar</code>文件是否存在。如果参数是相对路径,则判断在相对当前工作目录下,该文件是否存在。结果返回布尔类型。

isUnix

判断是否为类Unix系统。如果当前pipeline运行在一个类Unix系统上,则返回<code>true</code>。

pwd

确认当前目录。<code>pwd</code>与Linux的<code>pwd</code>命令一样,返回当前所在目录。它有一个布尔类型的可选参数:<code>tmp</code>,如果参数值为<code>true</code>,则返回与当前工作空间关联的临时目录。

writeFile

将内容写入指定文件中。

<code>writeFile</code>支持的参数有:

<code>file</code>:文件路径,可以是绝对路径,也可以是相对路径。

<code>text</code>:要写入的文件内容。

<code>encoding</code>(可选):目标文件的编码。如果留空,则使用操作系统默认的编码。如果写的是Base64的数据,则可以使用Base64编码。

readFile

读取指定文件的内容,以文本返回。

<code>readFile</code>支持的参数有:

<code>file</code>:路径,可以是绝对路径,也可以是相对路径。

<code>encoding</code>(可选):读取文件时使用的编码。

stash

保存临时文件。

<code>stash</code>步骤可以将一些文件保存起来,以便被同一次构建的其他步骤或阶段使用。如果整个pipeline的所有阶段在同一台机器上执行,则<code>stash</code>步骤是多余的。所以,通常需要<code>stash</code>的文件都是要跨Jenkins node使用的。

<code>stash</code>步骤会将文件存储在<code>tar</code>文件中,对于大文件的<code>stash</code>操作将会消耗Jenkins master的计算资源。Jenkins官方文档推荐,当文件大小为5∼100MB时,应该考虑使用其他替代方案。

<code>stash</code>步骤的参数列表如下:

<code>name</code>:字符串类型,保存文件的集合的唯一标识。

<code>allowEmpty</code>:布尔类型,允许<code>stash</code>内容为空。

<code>excludes</code>:字符串类型,将哪些文件排除。如果排除多个文件,则使用逗号分隔。留空代表不排除任何文件。

<code>includes</code>:字符串类型,<code>stash</code>哪些文件,留空代表当前文件夹下的所有文件。

<code>useDefaultExcludes</code>:布尔类型,如果为<code>true</code>,则代表使用Ant风格路径默认排除文件列表。

除了<code>name</code>参数,其他参数都是可选的。<code>excludes</code>和<code>includes</code>使用的是Ant风格路径表达式。

unstash

取出之前stash的文件。

<code>unstash</code>步骤只有一个<code>name</code>参数,即<code>stash</code>时的唯一标识。通常<code>stas</code>h与<code>unstash</code>步骤同时使用。以下是完整示例。

<code>stash</code>步骤在master节点上执行,而<code>unstash</code>步骤在node2节点上执行。

与命令相关的步骤其实是Pipeline:Nodes and Processes插件提供的步骤。由于它是Pipeline插件的一个组件,所以基本不需要单独安装。

sh

执行shell命令。

<code>sh</code>步骤支持的参数有:

<code>script</code>:将要执行的shell脚本,通常在类UNIX系统上可以是多行脚本。

<code>encoding</code>:脚本执行后输出日志的编码,默认值为脚本运行所在系统的编码。

<code>returnStatus</code>:布尔类型,默认脚本返回的是状态码,如果是一个非零的状态码,则会引发pipeline执行失败。如果<code>returnStatus</code>参数为<code>true</code>,则不论状态码是什么,pipeline的执行都不会受影响。

<code>returnStdout</code>:布尔类型,如果为<code>true</code>,则任务的标准输出将作为步骤的返回值,而不是打印到构建日志中(如果有错误,则依然会打印到日志中)。除了<code>script</code>参数,其他参数都是可选的。

<code>returnStatus</code>与<code>returnStdout</code>参数一般不会同时使用,因为返回值只能有一个。如果同时使用,则只有returnStatus参数生效。

bat、powershell

<code>bat</code>步骤执行的是Windows的批处理命令。<code>powershell</code>步骤执行的是PowerShell脚本,支持3+版本。这两个步骤支持的参数与sh步骤的一样。

error

主动报错,中止当前pipeline。

error 步骤的执行类似于抛出一个异常。它只有一个必需参数:<code>message</code>。通常省略参数:<code>error("there's an error")</code>。

tool

使用预定义的工具。

如果在Global Tool Configuration(全局工具配置)中配置了工具,那么可以通过<code>tool</code>步骤得到工具路径。

<code>tool</code>步骤支持的参数有:

<code>name</code>:工具名称。

<code>type</code>(可选):工具类型,指该工具安装类的全路径类名。

每个插件的<code>type</code>值都不一样,而且绝大多数插件的文档根本不写<code>type</code>值。除了到该插件的源码中查找,还有一种方法可以让我们快速找到<code>type</code>值,就是前往Jenkins pipeline代码片段生成器中生成该<code>tool</code>步骤的代码即可。

代码块超时时间。

为timeout步骤闭包内运行的代码设置超时时间限制。如果超时,将抛出一个<code>org.jenkinsci.plugins.workflow.steps.FlowInterruptedException</code>异常。<code>timeout</code>步骤支持如下参数:

<code>time</code>:整型,超时时间。

<code>unit</code>(可选):时间单位,支持的值有<code>NANOSECONDS</code>、<code>MICROSECONDS</code>、<code>MILLISECONDS</code>、<code>SECONDS</code>、<code>MINUTES</code>(默认)、<code>HOURS</code>、<code>DAYS</code>。

<code>activity</code>(可选):布尔类型,如果值为<code>true</code>,则只有当日志没有活动后,才真正算作超时。

waitUntil

等待条件满足。

不断重复<code>waitUntil</code>块内的代码,直到条件为<code>true</code>。<code>waitUntil</code>不负责处理块内代码的异常,遇到异常时直接向外抛出。<code>waitUntil</code>步骤最好与<code>timeout</code>步骤共同使用,避免死循环。示例如下:

重复执行块

执行N 次闭包内的脚本。如果其中某次执行抛出异常,则只中止本次执行,并不会中止整个<code>retry</code>的执行。同时,在执行<code>retry</code>的过程中,用户是无法中止pipeline的。

sleep

让pipeline休眠一段时间。

<code>sleep</code>步骤可用于简单地暂停pipeline,其支持的参数有:

<code>time</code>:整型,休眠时间。

<code>unit</code>(可选):时间单位,支持的值有<code>NANOSECONDS</code>、<code>MICROSECONDS</code>、<code>MILLISECONDS</code>、<code>SECONDS</code>(默认)、<code>MINUTES</code>、<code>HOURS</code>、<code>DAYS</code>。

Jenkins提供了一个pipeline代码片段生成器,通过界面操作就可以生成代码。(只有pipeline项目有“Pipeline Syntax菜单”)

VS Code扩展:Jenkins Pipeline Linter Connector,支持对Jenkinsfile的语法检验。

使用Workspace Cleanup插件清理空间。

Ant风格路径表达式。

Apache Ant样式的路径有三种通配符匹配方法,利用它们可以组合出多种路径模式:

Wildcard

Description

<code>?</code>

匹配任意单字符

<code>*</code>

匹配0或者任意数量的字符,不包含<code>/</code>

<code>**</code>

匹配0或者更多数量的目录,不包含<code>/</code>

Ant风格路径匹配实例:

Path

<code>/app/*.x</code>

匹配(Matches)<code>app</code>路径下所有<code>.x</code>文件

<code>/app/p?ttern</code>

匹配(Matches) <code>/app/pattern</code> 和 <code>/app/pXttern</code>,但是不包括<code>/app/pttern</code>

<code>/**/example</code>

匹配项目根路径下 <code>/project/example</code>, <code>/project/foow/example</code>, 和 <code>/example</code>

<code>/app/**/dir/file.</code>

匹配(Matches) <code>/app/dir/file.jsp</code>, <code>/app/foo/dir/file.html</code>,<code>/app/foo/bar/dir/file.pdf</code>, 和 <code>/app/dir/file.java</code>

<code>/**/*.jsp</code>

匹配项目根路径下任何的<code>.jsp</code> 文件

需要注意的是,路径匹配遵循最长匹配原则(has more characters),例如<code>/app/dir/file.jsp</code>符合<code>/**/*.jsp</code>和<code>/app/dir/*.jsp</code>两个路径模式,那么最终就是根据后者来匹配。

参考资料:

[1] 《Jenkins 2.x实战指南》

[2] https://jenkins.io/zh/doc/book/pipeline/syntax/

[3] https://jenkins.io/zh/doc/pipeline/steps/