Skip to content

使用Jenkinsfile构建流水线

1. 什么是Jenkinsfile

Jenkins 流水线 (或简单的带有大写"P"的"Pipeline") 是一套插件,它支持实现和集成 continuous delivery pipelines 到Jenkins。 更多信息参见官方文档

流水线提供了一组可扩展的工具,通过 (Pipeline domain-specific language (DSL) syntax)[https://www.jenkins.io/zh/doc/book/pipeline/syntax/].对从简单到复杂的交付流水线 "作为代码" 进行建模。

2. 流水线概念

流水线 pipeline

流水线是用户定义的一个CD流水线模型 。流水线的代码定义了整个的构建过程, 他通常包括构建, 测试和交付应用程序的阶段 。

另外 , pipeline 块是 声明式流水线语法的关键部分.

节点 node

节点是一个机器 ,它是Jenkins环境的一部分 and is capable of执行流水线。

另外, node块是 脚本化流水线语法的关键部分.

阶段 stage

stage 块定义了在整个流水线的执行任务的概念性地不同的的子集(比如 "Build", "Test" 和 "Deploy" 阶段), 它被许多插件用于可视化 或Jenkins流水线目前的 状态/进展.

步骤 step

本质上 ,一个单一的任务, a step 告诉Jenkins 在特定的时间点要做_what_ (或过程中的 "step")。 举个例子,要执行shell命令 ,请使用 sh 步骤: sh 'make'。当一个插件扩展了流水线DSL, [1] 通常意味着插件已经实现了一个新的 step。

3. 流水线语法

声明式流水线基础

javascript
Jenkinsfile (Declarative Pipeline)
pipeline {
    // 在任何可用的代理上,执行流水线或它的任何阶段。
    agent any 
    stages {
        // 定义 "Build" 阶段。
        stage('Build') { 
            steps {
                // 执行与 "Build" 阶段相关的步骤。
            }
        }
        // 定义"Test" 阶段。
        stage('Test') { 
            steps {
                // 执行与"Test" 阶段相关的步骤。
            }
        }
        // 定义 "Deploy" 阶段。
        stage('Deploy') { 
            steps {
                // 执行与 "Deploy" 阶段相关的步骤。
            }
        }
    }
}

脚本化流水线基础

在脚本化流水线语法中, 一个或多个 node 块在整个流水线中执行核心工作。 虽然这不是脚本化流水线语法的强制性要求, 但它限制了你的流水线的在node块内的工作做两件事:

  1. 通过在Jenkins队列中添加一个项来调度块中包含的步骤。 节点上的执行器一空闲, 该步骤就会运行。

  2. 创建一个工作区(特定为特定流水间建立的目录),其中工作可以在从源代码控制检出的文件上完成。

javascript
Jenkinsfile (Scripted Pipeline)
// node 是脚本化流水线的一种特定语法,它指示 Jenkins 在任何可用的代理/节点上执行流水线 (和包含在其中的任何阶段)这实际上等效于 声明式流水线特定语法的`agent`。
node {  // 在任何可用的代理上,执行流水线或它的任何阶段。
    // 定义 "Build" 阶段。 stage 块 在脚本化流水线语法中是可选的。 然而, 在脚本化流水线中实现 stage 块 ,可以清楚的显示Jenkins UI中的每个 stage 的任务子集。
    stage('Build') { 
        // 执行与 "Build" 阶段相关的步骤。
    }
    // 定义 "Test" 阶段。
    stage('Test') { 
        // 执行与 "Test" 阶段相关的步骤。
    }
    // 定义 "Deploy" 阶段。
    stage('Deploy') { 
        // 执行与 "Deploy" 阶段相关的步骤。
    }
}

4. 流水线示例

javascript
Jenkinsfile (Declarative Pipeline)
// pipeline 是声明式流水线的一种特定语法,他定义了包含执行整个流水线的所有内容和指令的 "block" 。
pipeline { 
    // agent是声明式流水线的一种特定语法,它指示 Jenkins 为整个流水线分配一个执行器 (在节点上)和工作区。
    agent any 
    stages {
        // stage 是一个描述 stage of this Pipeline的语法块。如 above所述, 在脚本化流水线语法中,stage 块是可选的。
        stage('Build') { 
            // steps 是声明式流水线的一种特定语法,它描述了在这个 stage 中要运行的步骤。
            steps { 
                // sh 是一个执行给定的shell命令的流水线 step (由 Pipeline: Nodes and Processes plugin提供) 
                sh 'make' 
            }
        }
        stage('Test'){
            steps {
                sh 'make check'
                // 	junit 是另一个聚合测试报告的流水线 step (由 JUnit plugin提供)。
                junit 'reports/**/*.xml' 
            }
        }
        stage('Deploy') {
            steps {
                sh 'make publish'
            }
        }
    }
}
javascript
pipeline {
  agent any
  environment {
    CODING_DOCKER_REG_HOST = "${CCI_CURRENT_TEAM}-docker.pkg.${CCI_CURRENT_DOMAIN}"
    CODING_DOCKER_IMAGE_NAME = "${PROJECT_NAME.toLowerCase()}/${DOCKER_REPO_NAME}/${DOCKER_IMAGE_NAME}"
  }
  stages  {
    stage("检出") {
      steps {
        checkout(
          [$class: 'GitSCM',
          branches: [[name: GIT_BUILD_REF]],
          userRemoteConfigs: [[
            url: GIT_REPO_URL,
              credentialsId: CREDENTIALS_ID
            ]]]
        )
      }
    }
        
    stage('安装依赖') {
      steps {
        sh "npm install"
      }
    }
    
    stage('单元测试') {
    
     steps {
       sh "npm test"
     }
     post {
       always {
         // 收集测试报告
         junit 'reports/**/*.xml'
       }
     }
    }
    
    stage('依赖漏洞扫描') {
      steps {
        npmAuditInDir(directory: '/', collectResult: true)
      }
    }

    stage('构建镜像并推送到 CODING Docker 制品库') {
      steps {
        script {
            docker.withRegistry(
              "${CCI_CURRENT_WEB_PROTOCOL}://${CODING_DOCKER_REG_HOST}",
              "${CODING_ARTIFACTS_CREDENTIALS_ID}"
            ) {
              def dockerImage = docker.build("${CODING_DOCKER_IMAGE_NAME}:${DOCKER_IMAGE_VERSION}", "-f ${DOCKERFILE_PATH} ${DOCKER_BUILD_CONTEXT}")
              dockerImage.push()
            }
        }
      }
    }
    
    stage("部署到远端服务") {
      steps {
        script {
          def remoteConfig = [:]
          remoteConfig.name = "my-remote-server"
          remoteConfig.host = "${REMOTE_HOST}"
          remoteConfig.port = "${REMOTE_SSH_PORT}".toInteger()
          remoteConfig.allowAnyHosts = true

          withCredentials([
            sshUserPrivateKey(
              credentialsId: "${REMOTE_CRED}",
              keyFileVariable: "privateKeyFilePath"
            ),
            usernamePassword(
              credentialsId: "${CODING_ARTIFACTS_CREDENTIALS_ID}",
              usernameVariable: 'CODING_DOCKER_REG_USERNAME',
              passwordVariable: 'CODING_DOCKER_REG_PASSWORD'
            )
          ]) {
            // SSH 登录用户名
            remoteConfig.user = "${REMOTE_USER_NAME}"
            // SSH 私钥文件地址
            remoteConfig.identityFile = privateKeyFilePath

            // 请确保远端环境中有 Docker 环境
            sshCommand(
              remote: remoteConfig,
              command: "docker login -u ${CODING_DOCKER_REG_USERNAME} -p ${CODING_DOCKER_REG_PASSWORD} ${CODING_DOCKER_REG_HOST}",
              sudo: true,
            )

            sshCommand(
              remote: remoteConfig,
              command: "docker rm -f nodejs-express-app | true",
              sudo: true,
            )

            // DOCKER_IMAGE_VERSION 中涉及到 GIT_LOCAL_BRANCH / GIT_TAG / GIT_COMMIT 的环境变量的使用
            // 需要在本地完成拼接后,再传入到远端服务器中使用
            DOCKER_IMAGE_URL = sh(
              script: "echo ${CODING_DOCKER_REG_HOST}/${CODING_DOCKER_IMAGE_NAME}:${DOCKER_IMAGE_VERSION}",
              returnStdout: true
            )

            sshCommand(
              remote: remoteConfig,
              command: "docker run -d -p 3000:3000 --name nodejs-express-app ${DOCKER_IMAGE_URL}",
              sudo: true,
            )

            echo "部署成功,请到 http://${REMOTE_HOST}:3000 预览效果"
          }
        }
      }
    }
  }
}

5. 流水线配置项

pipeline

所有有效的声明式流水线必须包含在一个 pipeline 块中, 比如

javascript
pipeline {
    /* insert Declarative Pipeline here */
}

流水线顶层必须是一个 block, 特别地: pipeline

没有分号作为语句分隔符,,每条语句都必须在自己的行上。

块只能由 节段, 指令, 步骤, 或赋值语句组成。

一、节段

agent

agent 部分支持一些不同类型的参数。这些参数应用在pipeline块的顶层, 或 stage 指令内部。

md
- 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' } 或
javascript
agent {
    docker {
        image 'maven:3-alpine'
        label 'my-defined-label'
        args  '-v /tmp:/tmp'
    }
}
md
- 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
javascript
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
javascript
Jenkinsfile (Declarative Pipeline)
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'
            }
        }
    }
}

post

post 部分定义一个或多个steps ,这些阶段根据流水线或阶段的完成情况而 运行(取决于流水线中 post 部分的位置). post 支持以下 post-condition 块中的其中之一: always, changed, failure, success, unstable, 和 aborted。 这些条件块允许在 post 部分的步骤的执行取决于流水线或阶段的完成状态。 按照惯例, post 部分应该放在流水线的底部。 Post-condition 块包含与 steps 部分相同的steps。

Conditions
md
- 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是灰色。
javascript
Jenkinsfile (Declarative Pipeline)
pipeline {
    agent any
    stages {
        stage('Example') {
            steps {
                echo 'Hello World'
            }
        }
    }
    post { 
        always { 
            echo 'I will always say Hello again!'
        }
    }
}

stages

包含一系列一个或多个 stage 指令, stages 部分是流水线描述的大部分"work" 的位置。 建议 stages 至少包含一个 stage 指令用于连续交付过程的每个离散部分,比如构建, 测试, 和部署。

javascript
Jenkinsfile (Declarative Pipeline)
pipeline {
    agent any
    stages { 
        stage('Example') {
            steps {
                echo 'Hello World'
            }
        }
    }
}

steps

steps 部分在给定的 stage 指令中执行的定义了一系列的一个或多个steps。

javascript
Jenkinsfile (Declarative Pipeline)
pipeline {
    agent any
    stages {
        stage('Example') {
            steps { 
                echo 'Hello World'
            }
        }
    }
}

二、环境

environment

environment 指令制定一个 键-值对序列,该序列将被定义为所有步骤的环境变量,或者是特定于阶段的步骤, 这取决于 environment 指令在流水线内的位置。

该指令支持一个特殊的助手方法 credentials() ,该方法可用于在Jenkins环境中通过标识符访问预定义的凭证。 对于类型为 "Secret Text"的凭证, credentials() 将确保指定的环境变量包含秘密文本内容。 对于类型为 "SStandard username and password"的凭证, 指定的环境变量指定为 username:password ,并且两个额外的环境变量将被自动定义 :分别为 MYVARNAME_USR 和 MYVARNAME_PSW 。

javascript
Jenkinsfile (Declarative Pipeline)
pipeline {
    agent any
    // 	顶层流水线块中使用的 environment 指令将适用于流水线中的所有步骤。
    environment { 
        CC = 'clang'
    }
    stages {
        stage('Example') {
            // 在一个 stage 中定义的 environment 指令只会将给定的环境变量应用于 stage 中的步骤。
            environment {
                // environment 块有一个 助手方法 credentials() 定义,该方法可以在 Jenkins 环境中用于通过标识符访问预定义的凭证。
                AN_ACCESS_KEY = credentials('my-prefined-secret-text') 
            }
            steps {
                sh 'printenv'
            }
        }
    }
}

options

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

可用选项
md
- 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: 在失败时, 重新尝试整个流水线的指定次数。 例如: options { retry(3) }
- timestamps: 预谋所有由流水线生成的控制台输出,与该流水线发出的时间一致。 例如: options { timestamps() }
javascript
Jenkinsfile (Declarative Pipeline)
pipeline {
    agent any
    options {
        // 指定一个小时的全局执行超时, 在此之后,Jenkins 将中止流水线运行。
        timeout(time: 1, unit: 'HOURS') 
    }
    stages {
        stage('Example') {
            steps {
                echo 'Hello World'
            }
        }
    }
}
阶段选项

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

可选的阶段选项
md
- skipDefaultCheckout: 在 agent 指令中跳过默认的从源代码控制中检出代码。例如: options { skipDefaultCheckout() }
- timeout: 设置此阶段的超时时间, 在此之后, Jenkins 会终止该阶段。 例如: options { timeout(time: 1, unit: 'HOURS') }
- retry: 在失败时, 重试此阶段指定次数。 例如: options { retry(3) }
- timestamps: 预谋此阶段生成的所有控制台输出以及该行发出的时间一致。例如: options { timestamps() }
javascript
Jenkinsfile (Declarative Pipeline)
pipeline {
    agent any
    stages {
        stage('Example') {
            options {
                // 指定 Example 阶段的执行超时时间, 在此之后,Jenkins 将中止流水线运行。
                timeout(time: 1, unit: 'HOURS') 
            }
            steps {
                echo 'Hello World'
            }
        }
    }
}

parameters

parameters 指令提供了一个用户在触发流水线时应该提供的参数列表。这些用户指定参数的值可通过 params 对象提供给流水线步骤。

可用参数
md
- string: 字符串类型的参数, 例如: parameters { string(name: 'DEPLOY_ENV', defaultValue: 'staging', description: '') }

- booleanParam: 布尔参数, 例如: parameters { booleanParam(name: 'DEBUG_BUILD', defaultValue: true, description: '') }
javascript
Jenkinsfile (Declarative Pipeline)
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}"
            }
        }
    }
}

triggers

triggers 指令定义了流水线被重新触发的自动化方法。对于集成了源( 比如 GitHub 或 BitBucket)的流水线, 可能不需要 triggers ,因为基于 web 的集成很肯能已经存在。 当前可用的触发器是 cron, pollSCM 和 upstream。

md
- 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) }`
javascript
Jenkinsfile (Declarative Pipeline)
pipeline {
    agent any
    triggers {
        cron('H */4 * * 1-5')
    }
    stages {
        stage('Example') {
            steps {
                echo 'Hello World'
            }
        }
    }
}

stage

stage 指令在 stages 部分进行,应该包含一个 实际上, 流水巷所做的所有实际工作都将封装进一个或多个 stage 指令中。

javascript
Jenkinsfile (Declarative Pipeline)
pipeline {
    agent any
    stages {
        stage('Example') {
            steps {
                echo 'Hello World'
            }
        }
    }
}

tools

定义自动安装和放置 PATH 的工具的一部分。如果 agent none 指定,则忽略该操作。

支持工具:maven/jdk/gradle

javascript
Jenkinsfile (Declarative Pipeline)
pipeline {
    agent any
    tools {
        maven 'apache-maven-3.0.1' 
    }
    stages {
        stage('Example') {
            steps {
                sh 'mvn --version'
            }
        }
    }
}

input

stage 的 input 指令允许你使用 input step提示输入。 在应用了 options 后,进入 stage 的 agent 或评估 when 条件前, stage 将暂停。 如果 input 被批准, stage 将会继续。 作为 input 提交的一部分的任何参数都将在环境中用于其他 stage。

配置项
md
- message: 必需的。 这将在用户提交 input 时呈现给用户。
- id: input 的可选标识符, 默认为 stage 名称。
- ok: `input`表单上的"ok" 按钮的可选文本。
- submitter: 可选的以逗号分隔的用户列表或允许提交 input 的外部组名。默认允许任何用户。
- submitterParameter: 环境变量的可选名称。如果存在,用 submitter 名称设置。
- parameters: 提示提交者提供的一个可选的参数列表。 更多信息参见 [parameters]。
javascript
Jenkinsfile (Declarative Pipeline)
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 嵌套条件可以嵌套到任意深度。

默认情况下, 如果定义了某个阶段的代理,在进入该stage 的 agent 后该 stage 的 when 条件将会被评估。但是, 可以通过在 when 块中指定 beforeAgent 选项来更改此选项。 如果 beforeAgent 被设置为 true, 那么就会首先对 when 条件进行评估 , 并且只有在 when 条件验证为真时才会进入 agent 。

内置条件
md
- 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' } }
javascript
Jenkinsfile (Declarative Pipeline)
pipeline {
    agent any
    stages {
        stage('Example Build') {
            steps {
                echo 'Hello World'
            }
        }
        stage('Example Deploy') {
            when {
                branch 'production'
            }
            steps {
                echo 'Deploying'
            }
        }
    }
}
javascript
Jenkinsfile (Declarative Pipeline)
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'
            }
        }
    }
}
javascript
Jenkinsfile (Declarative Pipeline)
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'
            }
        }
    }
}
javascript
Jenkinsfile (Declarative Pipeline)
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'
            }
        }
    }
}
javascript
Jenkinsfile (Declarative Pipeline)
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'
            }
        }
    }
}
javascript
Jenkinsfile (Declarative Pipeline)
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'
            }
        }
    }
}

三、步骤

script

script 步骤需要 [scripted-pipeline]块并在声明式流水线中执行。 对于大多数用例来说,应该声明式流水线中的“脚本”步骤是不必要的, 但是它可以提供一个有用的"逃生出口"。 非平凡的规模和/或复杂性的 script 块应该被转移到 共享库 。

javascript
Jenkinsfile (Declarative Pipeline)
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"
                    }
                }
            }
        }
    }
}
javascript
Jenkinsfile (Scripted Pipeline)
node {
    stage('Example') {
        if (env.BRANCH_NAME == 'master') {
            echo 'I only execute on the master branch'
        } else {
            echo 'I execute elsewhere'
        }
    }
}
javascript
Jenkinsfile (Scripted Pipeline)
node {
    stage('Example') {
        try {
            sh 'exit 1'
        }
        catch (exc) {
            echo 'Something failed, I should sound the klaxons!'
            throw
        }
    }
}

四、并行

声明式流水线的阶段可以在他们内部声明多隔嵌套阶段, 它们将并行执行。 注意,一个阶段必须只有一个 steps 或 parallel 的阶段。 嵌套阶段本身不能包含进一步的 parallel 阶段, 但是其他的阶段的行为与任何其他 stage 相同。 任何包含 parallel 的阶段不能包含 agent 或 tools 阶段, 因为他们没有相关 steps。

另外, 通过添加 failFast true 到包含 parallel 的 stage 中, 当其中一个进程失败时,你可以强制所有的 parallel 阶段都被终止。

javascript
Jenkinsfile (Declarative Pipeline)
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"
                    }
                }
            }
        }
    }
}