本节是建立在 流水线入门内容的基础上,而且,应当被当作一个参考。 对于在实际示例中如何使用流水线语法的更多信息, 请参阅本章在流水线插件的2.5版本中的 使用 Jenkinsfile部分, 流水线支持两种离散的语法,具体如下对于每种的优缺点, 参见语法比较。
正如 本章开始讨论的, 流水线最基础的部分是 "步骤"。基本上, 步骤告诉 Jenkins 要做什么,以及作为声明式和脚本化流水线语法的基本构建块。
对于可用步骤的概述, 请参考 流水线步骤引用,它包含了一个构建到流水线的步骤和 插件提供的步骤的全面的列表。
声明式流水线
声明式流水线是最近添加到 Jenkins 流水线的 [1],它在流水线子系统之上提供了一种更简单,更有主见的语法。
所有有效的声明式流水线必须包含在一个 pipeline
块中, 比如:
pipeline {
/* insert Declarative Pipeline here */
}
在声明式流水线中有效的基本语句和表达式遵循与 Groovy的语法同样的规则, 有以下例外:
节段
代理
agent
部分指定了整个流水线或特定的部分, 将会在Jenkins环境中执行的位置,这取决于 agent
区域的位置。该部分必须在 pipeline
块的顶层被定义, 但是 stage 级别的使用是可选的。
Required |
Yes |
---|---|
Parameters |
|
Allowed |
In the top-level |
参数
为了支持作者可能有的各种各样的用例流水线, agent
部分支持一些不同类型的参数。这些参数应用在`pipeline`块的顶层, 或 stage
指令内部。
- any
-
在任何可用的代理上执行流水线或阶段。例如:
agent any
- none
-
当在
pipeline
块的顶部没有全局代理, 该参数将会被分配到整个流水线的运行中并且每个stage
部分都需要包含他自己的agent
部分。比如:agent none
- label
-
在提供了标签的 Jenkins 环境中可用的代理上执行流水线或阶段。 例如:
agent { label 'my-defined-label' }
- node
-
agent { node { label 'labelName' } }
和agent { label 'labelName' }
一样, 但是node
允许额外的选项 (比如customWorkspace
)。 - docker
-
使用给定的容器执行流水线或阶段。该容器将在预置的 node上,或在匹配可选定义的`label` 参数上,动态的供应来接受基于Docker的流水线。
docker
也可以选择的接受args
参数,该参数可能包含直接传递到docker run
调用的参数, 以及alwaysPull
选项, 该选项强制docker pull
,即使镜像名称已经存在。 比如:agent { docker 'maven:3-alpine' }
或agent { docker { image 'maven:3-alpine' label 'my-defined-label' args '-v /tmp:/tmp' } }
- dockerfile
-
执行流水线或阶段, 使用从源代码库包含的
Dockerfile
构建的容器。为了使用该选项,Jenkinsfile
必须从多个分支流水线中加载, 或者加载 "Pipeline from SCM." 通常,这是源代码仓库的根目录下的Dockerfile
:agent { dockerfile true }
. 如果在另一个目录下构建Dockerfile
, 使用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' } }
常见选项
有一些应用于两个或更多 agent
的实现的选项。他们不被要求,除非特别规定。
- label
-
一个字符串。该标签用于运行流水线或个别的
stage
。该选项对
node
,docker
和dockerfile
可用, `node`要求必须选择该选项。 - customWorkspace
-
一个字符串。在自定义工作区运行应用了
agent
的流水线或个别的stage
, 而不是默认值。 它既可以是一个相对路径, 在这种情况下,自定义工作区会存在于节点工作区根目录下, 或者一个绝对路径。比如:agent { node { label 'my-defined-label' customWorkspace '/some/other/path' } }
该选项对
node
,docker
和dockerfile
有用 。 - reuseNode
-
一个布尔值, 默认为false。 如果是true, 则在流水线的顶层指定的节点上运行该容器, 在同样的工作区, 而不是在一个全新的节点上。
这个选项对
docker
和dockerfile
有用, 并且只有当 使用在个别的stage
的agent
上才会有效。
示例
pipeline {
agent { docker 'maven:3-alpine' }
stages {
stage('Example Build') {
steps {
sh 'mvn -B clean verify'
}
}
}
}
在一个给定名称和标签(maven:3-alpine )的新建的容器上执行定义在流水线中的所有步骤 。 |
阶段级别的 agent
部分
pipeline {
agent none
stages {
stage('Example Build') {
agent { docker 'maven:3-alpine' }
steps {
echo 'Hello, Maven'
sh 'mvn --version'
}
}
stage('Example Test') {
agent { docker 'openjdk:8-jre' }
steps {
echo 'Hello, JDK'
sh 'java -version'
}
}
}
}
在流水线顶层定义 agent none 确保 an Executor 没有被分配。 使用 agent none 也会强制 stage 部分包含他自己的 agent 部分。 |
|
使用镜像在一个新建的容器中执行该阶段的该步骤。 | |
使用一个与之前阶段不同的镜像在一个新建的容器中执行该阶段的该步骤。 |
post
post
部分定义一个或多个steps ,这些阶段根据流水线或阶段的完成情况而 运行(取决于流水线中 post
部分的位置). post
支持以下 post-condition 块中的其中之一: always
, changed
, failure
, success
, unstable
, 和 aborted
。这些条件块允许在post
部分的步骤的执行取决于流水线或阶段的完成状态。
Required |
No |
---|---|
Parameters |
None |
Allowed |
In the top-level |
Conditions
always
-
无论流水线或阶段的完成状态如何,都允许在
post
部分运行该步骤。 changed
-
只有当前流水线或阶段的完成状态与它之前的运行不同时,才允许在
post
部分运行该步骤。 failure
-
只有当前流水线或阶段的完成状态为"failure",才允许在
post
部分运行该步骤, 通常web UI是红色。 success
-
只有当前流水线或阶段的完成状态为"success",才允许在
post
部分运行该步骤, 通常web UI是蓝色或绿色。 unstable
-
只有当前流水线或阶段的完成状态为"unstable",才允许在
post
部分运行该步骤, 通常由于测试失败,代码违规等造成。通常web UI是黄色。 aborted
-
只有当前流水线或阶段的完成状态为"aborted",才允许在
post
部分运行该步骤, 通常由于流水线被手动的aborted。通常web UI是灰色。
示例
pipeline {
agent any
stages {
stage('Example') {
steps {
echo 'Hello World'
}
}
}
post {
always {
echo 'I will always say Hello again!'
}
}
}
按照惯例, post 部分应该放在流水线的底部。 |
|
Post-condition 块包含与 steps 部分相同的steps。 |
stages
包含一系列一个或多个 stage 指令, stages
部分是流水线描述的大部分"work" 的位置。 建议 stages
至少包含一个 stage 指令用于连续交付过程的每个离散部分,比如构建, 测试, 和部署。
Required |
Yes |
---|---|
Parameters |
None |
Allowed |
Only once, inside the |
示例
pipeline {
agent any
stages {
stage('Example') {
steps {
echo 'Hello World'
}
}
}
}
stages 部分通常会遵循诸如 agent , options 等的指令。 |
steps
steps
部分在给定的 stage
指令中执行的定义了一系列的一个或多个steps。
Required |
Yes |
---|---|
Parameters |
None |
Allowed |
Inside each |
示例
pipeline {
agent any
stages {
stage('Example') {
steps {
echo 'Hello World'
}
}
}
}
steps 部分必须包含一个或多个步骤。 |
指令
environment
environment
指令制定一个 键-值对序列,该序列将被定义为所有步骤的环境变量,或者是特定于阶段的步骤, 这取决于 environment
指令在流水线内的位置。
该指令支持一个特殊的助手方法 credentials()
,该方法可用于在Jenkins环境中通过标识符访问预定义的凭证。对于类型为 "Secret Text"的凭证, credentials()
将确保指定的环境变量包含秘密文本内容。对于类型为 "SStandard username and password"的凭证, 指定的环境变量指定为 username:password
,并且两个额外的环境变量将被自动定义 :分别为 MYVARNAME_USR
和 MYVARNAME_PSW
。
Required |
No |
---|---|
Parameters |
None |
Allowed |
Inside the |
示例
pipeline {
agent any
environment {
CC = 'clang'
}
stages {
stage('Example') {
environment {
AN_ACCESS_KEY = credentials('my-prefined-secret-text')
}
steps {
sh 'printenv'
}
}
}
}
顶层流水线块中使用的 environment 指令将适用于流水线中的所有步骤。 |
|
在一个 stage 中定义的 environment 指令只会将给定的环境变量应用于 stage 中的步骤。 |
|
environment 块有一个 助手方法 credentials() 定义,该方法可以在 Jenkins 环境中用于通过标识符访问预定义的凭证。 |
options
options
指令允许从流水线内部配置特定于流水线的选项。 流水线提供了许多这样的选项, 比如 buildDiscarder
,但也可以由插件提供, 比如 timestamps
.
Required |
No |
---|---|
Parameters |
None |
Allowed |
Only once, inside the |
可用选项
- buildDiscarder
-
为最近的流水线运行的特定数量保存组件和控制台输出。例如:
options { buildDiscarder(logRotator(numToKeepStr: '1')) }
- disableConcurrentBuilds
-
不允许同时执行流水线。 可被用来防止同时访问共享资源等。 例如:
options { disableConcurrentBuilds() }
- overrideIndexTriggers
-
允许覆盖分支索引触发器的默认处理。 如果分支索引触发器在多分支或组织标签中禁用,
options { overrideIndexTriggers(true) }
将只允许它们用于促工作。否则,options { overrideIndexTriggers(false) }
只会禁用改作业的分支索引触发器。 - skipDefaultCheckout
-
在`agent` 指令中,跳过从源代码控制中检出代码的默认情况。例如:
options { skipDefaultCheckout() }
- skipStagesAfterUnstable
-
一旦构建状态变得UNSTABLE,跳过该阶段。例如:
options { skipStagesAfterUnstable() }
- checkoutToSubdirectory
-
在工作空间的子目录中自动地执行源代码控制检出。例如:
options { checkoutToSubdirectory('foo') }
- timeout
-
设置流水线运行的超时时间, 在此之后,Jenkins将中止流水线。例如:
options { timeout(time: 1, unit: 'HOURS') }
- retry
-
在失败时, 重新尝试整个流水线的指定次数。 For example:
options { retry(3) }
- timestamps
-
预谋所有由流水线生成的控制台输出,与该流水线发出的时间一致。 例如:
options { timestamps() }
Example
pipeline {
agent any
options {
timeout(time: 1, unit: 'HOURS')
}
stages {
stage('Example') {
steps {
echo 'Hello World'
}
}
}
}
指定一个小时的全局执行超时, 在此之后,Jenkins 将中止流水线运行。 |
一个完整的可用选项列表正在等待完成第 INFRA-1503次。 |
阶段选项
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') }
- retry
-
在失败时, 重试此阶段指定次数。 例如:
options { retry(3) }
- timestamps
-
预谋此阶段生成的所有控制台输出以及该行发出的时间一致。例如:
options { timestamps() }
示例
pipeline {
agent any
stages {
stage('Example') {
options {
timeout(time: 1, unit: 'HOURS')
}
steps {
echo 'Hello World'
}
}
}
}
指定 Example 阶段的执行超时时间, 在此之后,Jenkins 将中止流水线运行。 |
参数
parameters
指令提供了一个用户在触发流水线时应该提供的参数列表。这些用户指定参数的值可通过 params
对象提供给流水线步骤, 了解更多请参考示例。
Required |
No |
---|---|
Parameters |
None |
Allowed |
Only once, inside the |
可用参数
- string
-
字符串类型的参数, 例如:
parameters { string(name: 'DEPLOY_ENV', defaultValue: 'staging', description: '') }
- booleanParam
-
布尔参数, 例如:
parameters { booleanParam(name: 'DEBUG_BUILD', defaultValue: true, description: '') }
示例
pipeline {
agent any
parameters {
string(name: 'PERSON', defaultValue: 'Mr Jenkins', description: 'Who should I say hello to?')
}
stages {
stage('Example') {
steps {
echo "Hello ${params.PERSON}"
}
}
}
}
一份完整的可用参数列表正在等待 INFRA-1503的完成。 |
触发器
triggers
指令定义了流水线被重新触发的自动化方法。对于集成了源( 比如 GitHub 或 BitBucket)的流水线, 可能不需要 triggers
,因为基于 web 的集成很肯能已经存在。 当前可用的触发器是 cron
, pollSCM
和 upstream
。
Required |
No |
---|---|
Parameters |
None |
Allowed |
Only once, inside the |
- 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) }
|
示例
pipeline {
agent any
triggers {
cron('H */4 * * 1-5')
}
stages {
stage('Example') {
steps {
echo 'Hello World'
}
}
}
}
stage
stage
指令在 stages
部分进行,应该包含一个 实际上, 流水巷所做的所有实际工作都将封装进一个或多个 stage
指令中。
Required |
At least one |
---|---|
Parameters |
One mandatory parameter, a string for the name of the stage. |
Allowed |
Inside the |
示例
pipeline {
agent any
stages {
stage('Example') {
steps {
echo 'Hello World'
}
}
}
}
工具
定义自动安装和放置 PATH
的工具的一部分。如果 agent none
指定,则忽略该操作。
Required |
No |
---|---|
Parameters |
None |
Allowed |
Inside the |
支持工具
- maven
- jdk
- gradle
示例
pipeline {
agent any
tools {
maven 'apache-maven-3.0.1'
}
stages {
stage('Example') {
steps {
sh 'mvn --version'
}
}
}
}
The tool name must be pre-configured in Jenkins under Manage Jenkins → Global Tool Configuration. |
input
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
-
提示提交者提供的一个可选的参数列表。 更多信息参见 [parameters]。
示例
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
指令必须包含至少一个条件。 如果 when
指令包含多个条件, 所有的子条件必须返回True,阶段才能执行。 这与子条件在 allOf
条件下嵌套的情况相同 (参见下面的示例)。
使用诸如 not
, allOf
, 或 anyOf
的嵌套条件可以构建更复杂的条件结构 can be built 嵌套条件刻意潜逃到任意深度。
Required |
No |
---|---|
Parameters |
None |
Allowed |
Inside a |
内置条件
- 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' } }
在进入 stage
的 agent
前评估 when
默认情况下, 如果定义了某个阶段的代理,在进入该`stage` 的 agent
后该 stage
的 when
条件将会被评估。但是, 可以通过在 when
块中指定 beforeAgent
选项来更改此选项。 如果 beforeAgent
被设置为 true
, 那么就会首先对 when
条件进行评估 , 并且只有在 when
条件验证为真时才会进入 agent
。
示例
pipeline {
agent any
stages {
stage('Example Build') {
steps {
echo 'Hello World'
}
}
stage('Example Deploy') {
when {
branch 'production'
}
steps {
echo 'Deploying'
}
}
}
}
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'
}
}
}
}
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'
}
}
}
}
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'
}
}
}
}
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'
}
}
}
}
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'
}
}
}
}
并行
声明式流水线的阶段可以在他们内部声明多隔嵌套阶段, 它们将并行执行。 注意,一个阶段必须只有一个 steps
或 parallel
的阶段。 嵌套阶段本身不能包含进一步的 parallel
阶段, 但是其他的阶段的行为与任何其他 stage
相同。任何包含 parallel
的阶段不能包含 agent
或 tools
阶段, 因为他们没有相关 steps
。
另外, 通过添加 failFast true
到包含 parallel`的 `stage
中, 当其中一个进程失败时,你可以强制所有的 parallel
阶段都被终止。
示例
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"
}
}
}
}
}
}
步骤
声明式流水线可能使用在 流水线步骤引用中记录的所有可用的步骤, 它包含一个完整的步骤列表, 其中添加了下面列出的步骤,这些步骤只在声明式流水线中 only supported 。
脚本
script
步骤需要 [scripted-pipeline]块并在声明式流水线中执行。 对于大多数用例来说,应该声明式流水线中的“脚本”步骤是不必要的, 但是它可以提供一个有用的"逃生出口"。 非平凡的规模和/或复杂性的 script
块应该被转移到 共享库 。
示例
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"
}
}
}
}
}
}
脚本化流水线
脚本化流水线, 与[declarative-pipeline]一样的是, 是建立在底层流水线的子系统上的。与声明式不同的是, 脚本化流水线实际上是由 Groovy构建的通用 DSL [2]。 Groovy 语言提供的大部分功能都可以用于脚本化流水线的用户。这意味着它是一个非常有表现力和灵活的工具,可以通过它编写持续交付流水线。
流控制
脚本化流水线从 Jenkinsfile
的顶部开始向下串行执行, 就像 Groovy 或其他语言中的大多数传统脚本一样。 因此,提供流控制取决于 Groovy 表达式, 比如 if/else
条件, 例如:
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
块 , 例如:
node {
stage('Example') {
try {
sh 'exit 1'
}
catch (exc) {
echo 'Something failed, I should sound the klaxons!'
throw
}
}
}
步骤
正如 本章开始所讨论的, 流水线最基础的部分是"步骤"。从根本上说, 步骤告诉 Jenkins要做 what ,并作为声明式和脚本化流水线已发的基本构建块。
脚本化流水线 not 不引入任何特定于其语法的步骤; 流水线步骤引用 包括流水线和插件提供的步骤的完整列表。
区别普通 Groovy
为了提供 durability, 这意味着运行流水线可以在Jenkins master 重启后继续运行,脚本化的流水线序列化数据到主服务器。由于这个设计需求, 一些Groovy 习惯用语,比如 collection.each { item -> /* perform operation */ }
都不完全支持。详情参见 JENKINS-27421 和 JENKINS-26481。
语法比较
当Jenkins 流水线第一次构建时, Groovy 被选为基础。 Jenkins长期使用嵌入式 Groovy引擎来为管理员和用户提供 高级脚本功能。另外, Jenkins流水线的实现者发现 Groovy是 构建现在成为 "脚本化流水线" DSL的坚实基础 [2]。
由于它是一个功能齐全的编程环境, 脚本化流水线为Jenkins用户提供了 大量的灵活性性和可扩展性。 Groovy学习曲线通常不适合给定团队的所有成员, 因此创造了声明式流水线来为编写Jenkins流水线提供一种更简单、更有主见的语法。
两者本质上是相同的流水线子系统。 underneath. 他们都是 "流水线即代码" 的持久实现。它们都能够使用构建到流水线中或插件提供的步骤。它们都能够使用 共享库
但是它们的区别在于语法和灵活性。 声明式限制了用户使用更严格和预定义的结构, 使其成为更简单的持续交付流水线的理想选择。 脚本化提供了很少的限制, 以至于对脚本和语法的唯一限制往往是由Groovy子集本身定义的,而不是任何特定于流水线的系统, 这使他成为权利用户和那些有更复杂需求的人的理想选择。 顾名思义, 声明式流水线鼓励 声明式编程模型。 [3] 而脚本化流水线遵循一个更命令式的编程模型 [4]
https://www.cnblogs.com/YatHo/p/7856556.html
http://www.cnblogs.com/fengjian2016/p/8227532.html
https://jenkins.io/zh/doc/book/pipeline/syntax/#%E6%B5%81%E6%B0%B4%E7%BA%BF%E8%AF%AD%E6%B3%95