1. 语法比较

Pipeline支持两种语法:声明式和脚本式。

1、相同点:都是"Pipeline as code"的有效实现方式;都能够使用内置于 Pipeline 或由插件提供的steps;都可以使用共享库。

2、不同点:

  • 声明式语法

Declarative pipeline鼓励声明式编程模型。通过严格和预定义的结构限制了用户可用的内容,使其变得更加简单、容易上手。

  • 脚本式语法

Scripted Pipeline 遵循更命令式的编程模型。就结构和语法的唯一限制往往由 Groovy 本身定义,而不是任何特定于 Pipeline 的系统,这使其具有极大的灵活性和可扩展性,成为高级用户和具有更复杂要求的用户的理想选择。

建议直接使用声明式语法,学习成本较低,适合大部分人入门。

2. 声明式语法介绍

2.1 语法结构

1、Sections

  • pipeline:代表整条流水线,包含整条流水线的逻辑。
  • agent:指定pipeline运行的节点,可为整个pipeline或特定stage指定运行环境,取决于所定义位置。
  • stages:pipeline中多个stage的容器,至少包含一个stage,是pipeline的主体部分。
  • steps:stage中的一个或多个具体步骤(step)的容器,steps部分至少包含一个步骤。
  • scripts:在Declarative Pipeline中,可采用script指令来执行Scripted Pipeline中的一些脚本
  • post:运行后处理步骤,根据定义的位置不同,可依据pipeline或stage的运行结果执行差异化步骤。

2、Directives

  • environment:环境变量,可定义为全局变量或特定stage中的局部变量,取决于所定义位置。
  • tools:构建工具,可为整个pipeline或特定stage指定在jenkins全局工具中定义过的工具的环境变量,支持maven、jdk、gradle等。
  • options:定义pipeline运行时的配置选项。如历史构建记录数量保留,超时时间,失败重试等操作。
  • triggers:触发器,定义pipeline运行的触发方式。
  • parameters:参数,为流水线运行时设置的参数列表。
  • stage:表示Pipeline的一个阶段,如checkout阶段,Build阶段,test阶段等,一个Pipeline中至少需要一个Stage。
  • input:交互输入,pipeline运行到input时会自动暂停,根据输入值评估是否继续。
  • when:条件判断,允许流水线根据给定的条件决定是否应该执行阶段。

2.2 语法详解

在声明式管道中有效的基本语句和表达式遵循与Groovy 语法相同的规则, 但有以下例外:

  • Pipeline 的顶层必须是一个block,具体来说:pipeline { }.

  • 没有分号作为语句分隔符。每个语句都必须在自己的行中。

  • 块只能由Sections、 DirectivesSteps或赋值语句组成。

  • 属性引用语句被视为无参数方法调用。因此,例如,input被视为input().

您可以使用 声明式指令生成器 来帮助您开始配置声明式管道中的指令和部分。

2.2.1 Sections

2.2.1.1 agent

是否必须

YES

参数

any / none / label / node / docker / dockerfile / kubernetes

描述

指定整个Pipeline或特定stage将在Jenkins环境中执行的位置,具体取决于该agent 部分的放置位置

允许 pipeline块内或stage指令内

参数说明

  • any:在任意可用的 agent 上执行Pipeline或stage
  • none:在pipeline块的顶层应用时,不会为整个 Pipeline运行分配全局代理,且每个stage中都需要自行定义agent。
  • label:在指定标签(或标签条件)的agent中执行Pipeline或stage
  • node:使用与lable类似,但node允许附加选项(例如customWorkspace)
  • docker:执行Pipeline或stage时会动态供应一个docker节点去接受Docker-based的Pipelines
  • dockerfile:使用从Dockerfile源存储库中包含的容器构建的容器执行Pipeline或stage,Jenkinsfile 必须从多分支 Pipeline或 SCM Pipeline加载。
  • kubernetes:在Kubernetes集群上部署的Pod内执行 Pipeline或stage,同样Jenkinsfile 必须从多分支 Pipeline或 SCM Pipeline加载,Pod模板在kubernetes {} 块内定义。

参考案例

pipeline {
  agent any

  agent none

  agent { 
    label 'my-label1 && my-label2' 
  }

  agent { node { label 'labelName' } }  // 等同于 agent { label 'labelName' }

  // docker 还可以接受一个args直接传递给`docker run`调用以及一个 alwaysPull 选项
  // registryUrl和registryCredentialsId参数 有助于指定要使用的Docker注册表及其凭据
  agent {
    docker {
      image 'maven:3-alpine'
      label 'my-defined-label'
      args  '-v /tmp:/tmp'
      registryUrl 'https://myregistry.com/'
      registryCredentialsId 'myPredefinedCredentialsInJenkins'
    }
  }

  // dockerfile
  agent {
    // 等同于 to "docker build -f Dockerfile.build --build-arg version=1.0.2 ./build/
    dockerfile {
        filename 'Dockerfile.build'
        // 如果要Dockerfile在另一个目录中构建,请使用以下dir选项
        dir 'build'
        label 'my-defined-label'
        additionalBuildArgs  '--build-arg version=1.0.2'
        args '-v /tmp:/tmp'
        // 同样也接受registryUrl和registryCredentialsId参数
        registryUrl 'https://myregistry.com/'
        registryCredentialsId 'myPredefinedCredentialsInJenkins'
    }
  }

  // kubernetes: 例如如果要在其中装有Kaniko容器的容器
  agent {
    kubernetes {
      label podlabel
      yaml """
  kind: Pod
  metadata:
    name: jenkins-agent
  spec:
    containers:
    - name: kaniko
      image: gcr.io/kaniko-project/executor:debug
      imagePullPolicy: Always
      command:
      - /busybox/cat
      tty: true
      volumeMounts:
        - name: aws-secret
          mountPath: /root/.aws/
        - name: docker-registry-config
          mountPath: /kaniko/.docker
    restartPolicy: Never
    volumes:
      - name: aws-secret
        secret:
          secretName: aws-secret
      - name: docker-registry-config
        configMap:
          name: docker-registry-config
  """
  }
}

2.2.1.2 stages

是否必须

YES

参数

None

描述

stages 是 Pipeline描述的大部分“工作”所在的位置, 该部分包含一个或多个阶段指令的序列。对于连续交付过程的每个离散部分,建议stages至少包含一个阶段指令,例如Build,Test,Deploy等

允许 pipeline块内,有且仅有一次

参考案例

pipeline {
    agent any
    stages { 
        stage('Example') {
            steps {
                echo 'Hello World'
            }
        }
    }
}


2.2.1.3 steps

是否必须

YES

参数

None

描述

stage中的一个或多个具体步骤(step)的容器,steps部分至少包含一个步骤。

允许 stage指令内

steps中的一些常用操作

  • error:抛出异常,中断整个pipeline
  • timeout: 超时
  • waitUntil: 循环运行闭包内容,直到返回true,通常与timeout一起使用
  • retry:失败重试
  • sleep:睡眠,默认单位秒

pipeline{
    agent any
    stages{
        stage('stash'){
            parallel('测试') {
              stage('轮询') {
                steps{
                  timeout(time:10, unit:"SECONDS"){
                    waitUntil{
                      script{
                        def rs = sh script: 'docker version', returnStatus: true     
                        return (rs == 0)
                      }
                    }
                  }
                }
              }
              stage('重试') {
                steps{
                retry(3){
                  script{
                      sh script: 'curl https://www.baidu.com', returnStatus: true
                    }
                  sleep(3)
                }
              }
            }

            stage('错误') {
                steps{
                  retry(3){
                    error("执行失败")
                  }
              }
            }
          }
        }
    }
}

2.2.1.5 post

是否必须

NO

参数

always / changed / fixed / regression / aborted / failure / success / unstable / unsuccessful / cleanup

描述

定义Pipeline或stage运行结束时的操作, 比如消息通知、执行其他job等

允许 pipeline块内或stage指令内

参数说明

  • always :无论运行结果如何,都运行本节中的步骤。
  • changed :当前运行结果与之前的运行结果不同时才运行步骤。
  • fixed :当前运行成功并且之前的运行失败或不稳定时才运行步骤。
  • regression :当前运行失败、不稳定或中止,并且上一次运行成功时,才运行步骤。
  • aborted :当前运行中止时才运行步骤,通常是由于手动中止了 Pipeline。通常在web UI中用灰色表示。
  • failure :当前运行失败时才运行步骤,通常在Web UI中用红色表示。
  • success :当前运行成功时才运行步骤,通常在Web UI中用绿色表示。
  • unstable :当前运行不稳定(通常由测试失败,代码冲突等引起)时才运行步骤,通常在Web UI中以黄色表示。
  • unsuccessful :当前运行状态不是“成功”时才运行步骤。
  • cleanup :其他 post 过程执行完毕后执行,与pipeline和stage运行结果无关。

特殊说明:cleanup和always的区别在于,cleanup会在其他任意一个post执行之后执行。

参考案例

pipeline {
  agent any
  stages {
    stage('Example') {
      steps {
          echo 'Hello World'
      }
    }
  }
  post { 
    always { 
      echo 'I will always say Hello again!'
    }
  }
}

2.2.2 Directives

2.2.2.1 environment

是否必须

NO

参数

None

描述

environment指令指定了一系列键值对,这些键值对将被定义为所有步骤或特定阶段步骤的环境变量,具体取决于environment指令在管道中的位置。

允许 pipeline块内或stage指令内

特别说明:

  • environment中的变量将写入到Linux环境变量之中作为全局变量,在shell中可通过变量名访问,而在script pipeline脚本中则需要通过env.变量名称访问。
  • 该指令支持一种特殊的辅助方法credentials(),可用于在 Jenkins 环境中通过其标识符访问预定义的凭据。

支持的凭证类型:

  • Secret Text :设置为加密文本字符串内容
  • Secret File : 设置为临时创建的文件文件的位置, 并自动定义变量存储该文件内容。
  • Username and password : 将设置为username:password并且两个其他环境变量将自动定义为MYVARNAME_USR 和MYVARNAME_PSW。
  • SSH with Private Key : 设置为临时创建的SSH密钥文件的位置,并且可能会自动定义两个其他环境变量:MYVARNAME_USR和MYVARNAME_PSW(保留密码)。

参考案例

pipeline {
  agent any
  //定义在pipeline块中,定义的环境变量可应用于Pipeline中的所有步骤。
  environment { 
    CC = 'clang'
  }
  stages {
    stage('Example') {
      //在 stage 中定义的 environment指令只会将给定的环境变量应用于Example内的步骤。
        environment { 
          // 在environment块中credentials('凭据名称')定义的帮助程序方法通过其在Jenkins环境中的标识符来访问预定义的凭据
          AN_ACCESS_KEY = credentials('wuzz') 
        }
        steps {
          sh 'printenv'
          echo "${env.AN_ACCESS_KEY}"
          echo "${env.CC}"
        }
    }
  }
}
pipeline {
  agent any
  environment {
    APP_NAME = 'clang'
  }
  stages {
    stage('Example Username/Password') {
      environment {
        // 变量 = 将用户密码凭证赋予变量
        SERVICE_CREDS = credentials('wuzz')
      }
      steps {
        // 注意点: defined: MYVARNAME_USR and MYVARNAME_PSW respectively.
        sh 'echo "Service user is $SERVICE_CREDS_USR"'
        sh 'echo "Service password is $SERVICE_CREDS_PSW"'
        sh 'curl -u $SERVICE_CREDS http://192.168.49.22:8040'
      }
    }
    stage('Example SSH Username with private key') {
      environment {
        // 变量 = 将 `ssh private` 公密钥进行赋予变量
        SSH_CREDS = credentials('wuzz')
      }
      steps {
        // 注意点: defined: MYVARNAME_USR and MYVARNAME_PSW (holding the passphrase).
        sh 'echo "SSH private key is located at $SSH_CREDS"'
        sh 'echo "SSH user is $SSH_CREDS_USR"'
        sh 'echo "SSH passphrase is $SSH_CREDS_PSW"'
 
        // 调用内置变量 (如果变量不存在则输出null) - 值得学习注意。
        echo "${JOB_NAME}"
        echo env.'JOB_NAME'
        println(env.'JOB_NAME') 
 
        // 自定义全局变量方式(写入文件中再读取)
        script {
          sh 'touch ${APP_NAME}'
          def projectProduct = sh returnStdout: true, script: "find ${APP_NAME}"
          if ( projectProduct != '' ){
            echo "${projectProduct}"
            writeFile file: 'abc.sh', text: "${projectProduct}"
            change_id = readFile 'abc.sh'
            print(change_id)
          } else {
            error "[-Error] : projectProduct 不能为空!"
          }
        }
         
      }
    }
  }
}


2.2.2.2 options

是否必须

NO

参数

None

描述

定义流水线运行时的配置选项,常用的有 timeout()、retry()

允许 pipeline块内且只有一次

可用选项

  • buildDiscarder: 保存最近历史构建记录的数量。
    options { buildDiscarder(logRotator(numToKeepStr: '1')) }
  • disableConcurrentBuilds: 禁止管道的并发执行。可用于防止同时访问共享资源等。
    options { disableConcurrentBuilds() }
  • checkoutToSubdirectory: Jenkins从版本控制库拉取源码时,默认检出到工作空间的根目录中,此选项可以指定检出到工作空间的子目录中。
    options { checkoutToSubdirectory('foo') }
  • newContainerPerStage: 当agent为docker或dockerfile时,指定在同一个Jenkins节点上,每个stage都分别运行在一个新的容器中,而不是所有stage都运行在同一个容器中。
  • disableResume: 禁用恢复,如果控制器重新启动,则不允许pipeline恢复。
    options { disableResume() }
  • overrideIndexTriggers: 允许重写多分支流水线的触发器
    # 仅为该作业启用分支索引触发器
    options { overrideIndexTriggers(true) } 
    # 仅为此作业禁用分支索引触发器
    options { overrideIndexTriggers(false) }
  • preserveStashes:  保留最近几次构建中的stash
    options { preserveStashes(buildCount:  5) } 
  • quietPeriod: 设置 Pipeline的静默时间段(以秒为单位),以覆盖全局默认值
    options { quietPeriod(30) }
  • retry:如果失败重试整个Pipeline指定次数。该次数是指总次数包括第1次失败。
    options { retry(3) }
  • skipDefaultCheckout: 跳过默认的代码检出(暂未研究出具体用法)。
    options { skipDefaultCheckout() }
  • skipStagesAfterUnstable: 一旦构建状态变得不稳定就跳过各个阶段;
    options { skipStagesAfterUnstable() }
  • timestamps: 为Pipeline 运行生成的所有控制台输出添加时间戳。
    options { timestamps() }
  • parallelsAlwaysFailFast :将 Pipeline中所有后续并行阶段的failfast设置为true。
    options { parallelsAlwaysFailFast() }

在包含 Parallel或Matrix 的stage中也可添加 failFast true,Parallel或 Matrix中任何一个单元失败时全部终止。

  • timeout(常用): 设置 Pipeline运行的超时时间。
    options { timeout(time:  1, unit:  'HOURS') }

参考案例

# Global Timeout, Declarative Pipeline
pipeline {
    agent any
    options {
      // 将全局执行超时指定为一小时,然后Jenkins将中止 Pipeline运行。
      timeout(time: 1, unit: 'HOURS') 
    }
    stages {
        stage('Example') {
            steps {
                echo 'Hello World'
            }
        }
    }
}
Tips: 在 stage 块中支持的 options 要少于 pipeline 块中,只能使用skipDefaultCheckout,timeout,retry,timestamps 等选项


2.2.2.3 parameters

是否必须

NO

参数

None

描述

参数,为流水线运行时设置相关的参数,不需要在UI界面上额外定义。

允许 pipeline块内且只有一次

Tips :

  • 全局参数, 在shell可通过变量名访问,而在script pipeline脚本中通过params.参数名称访问,如${params.enter_txt}
  • parameters定义之后,需要手动构建一次,才会自动加载到配置好的参数化构建中。

可用参数类型:

        //布尔参数
        booleanParam(name: 'co',description: '是否检出代码',defaultValue: true )    
        //字符参数
        string(name:'branch',defaultValue:'master', description: '')    
        //多行文本
        text(name: 'enter_txt', defaultValue: 'dfdfv', description: 'Enter some information')
        //加密文本
        //password(name: 'PASSWORD', defaultValue: 'SECRET', description: 'Enter a password')
        //单选框
        choice(name: 'CHOICE', choices: ['server1', 'server2', 'server3'], description: '请选择需要集成的服务')
        //多选框
        extendedChoice defaultValue: 'server1', description: '请选择需要集成的服务', multiSelectDelimiter: ',', name: 'server', quoteValue: false, saveJSONParameterToFile: false, type: 'PT_CHECKBOX', value: 'server1,server2,server3,server4', visibleItemCount: 4        

参考案例

pipeline {
    agent any
    parameters {
        string(name: 'PERSON', defaultValue: 'Mr Jenkins', description: 'Who should I say hello to?')
        text(name: 'BIOGRAPHY', defaultValue: '', description: 'Enter some information about the person')
        booleanParam(name: 'TOGGLE', defaultValue: true, description: 'Toggle this value')
        choice(name: 'CHOICE', choices: ['One', 'Two', 'Three'], description: 'Pick something')
        password(name: 'PASSWORD', defaultValue: 'SECRET', description: 'Enter a password')
    }
    stages {
        stage('Example') {
            steps {
                echo "Hello ${params.PERSON}"
                echo "Biography: ${params.BIOGRAPHY}"
                echo "Toggle: ${params.TOGGLE}"
                echo "Choice: ${params.CHOICE}"
                echo "Password: ${params.PASSWORD}"
            }
        }
    }
}

2.2.2.4 triggers

是否必须

NO

参数

None

描述

定义Pipeline自动触发的方式

允许 pipeline块内且只有一次

Tips :

  • 全局参数, 在shell可通过变量名访问,而在script pipeline脚本中通过params.参数名称访问,如${params.enter_txt}
  • parameters定义之后,需要手动构建一次,才会自动加载到配置好的参数化构建中。

可用触发器:

  • cron : 以Linux中Cron风格的字符串,定时触发

triggers { cron('H */4 * * 1-5') }

  • pollSCM : 定时轮询SCM仓库,检测到有更新才触发

triggers { pollSCM('H */4 * * 1-5') }

  • upstream : 接受以逗号分隔的作业字符串和阈值。当字符串中的任何作业以最小阈值结束时 Pipeline将被重新触发

triggers { upstream(upstreamProjects: 'job1,job2', threshold: hudson.model.Result.SUCCESS) }

  • 其他:插件集成或其他webhook触发,如gitlab

gitlab(triggerOnPush: true, triggerOnMergeRequest: true, branchFilterType: 'All')

2.2.2.5 Jenkins cron syntax

Jenkins cron 语法遵循 cron 实用程序的语法(略有不同)。具体来说,每一行由 5 个字段组成,由 TAB 或空格分隔:

MINUTE HOUR DOM MONTH DOW

一小时内的分钟数 (0–59)

一天中的小时 (0–23)

月份中的某天 (1–31)

月份 (1–12)

星期几 (0–7),其中 0 和 7 是星期日。

运算符

*   :指定所有有效值
M-N :指定值范围
M-N/X or */X :在指定范围或整个有效范围内按X的间隔步进
A,B,…,Z :枚举多个值

Tips : 

  • H字符:在 Cron 中使用 H 字符为了使定期计划的任务在系统上产生均匀的负载,H符号可以被认为是在一定范围内的随机值。
    例如使用0 0 * * *一打日常工作将导致午夜时分大幅增加。

相反使用H H * * *仍会每天执行一次每个作业,但不是同时执行所有作业,更好地使用有限的资源。

  • @yearly,@annually,@monthly, @weekly,@daily,@midnight,并且@hourly也支持方便的别名。这些使用哈希系统进行自动平衡。
    @hourly与H * * * *相同,表示该小时中的任何时间

@midnight实际上是指在12:00 AM和2:59 AM之间的某个时间。

参考案例

#每十五分钟一次(可能在 :07, :22, :37, :52)
triggers{ cron('H/15 * * * *') }

#每小时前半段每十分钟一次(三次,可能在 :04, :14, :24)
triggers{ cron('H(0-29)/10 * * * *') }

#每两小时一次,时间为每个工作日上午 9 点 45 分至下午 3 点 45 分,整点后 45 分钟。
triggers{ cron('45 9-16/2 * * 1-5') }

#每个工作日上午 9 点到下午 5 点之间每两小时一次(可能在上午 10 点 38 分、下午 12 点 38 分、下午 2 点 38 分、下午 4 点 38 分)
triggers{ cron('H H(9-16)/2 * * 1-5') }

#除 12 月外,每月 1 日和 15 日每天一次
triggers{ cron('H H 1,15 1-11 *') }

2.2.2.6 stage

是否必须

YES

参数

steps,必填

描述

stage 指令位于stages中并且应包含Step,可选 agent或其他特定指令, 实际上pipeline所有实际工作都将包含在一个或多个stage中。

允许 在 Pipeline块 -> stages内

参考案例

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

2.2.2.7 tools

是否必须

NO

参数

None

描述

定义工具,获取通过自动安装或手动安装工具的环境变量,支持maven、jdk、gradle,工具的名称必须预先在Jenkins的系统设置->全局工具配置中定义,才可在pipeline中引用。

允许 pipeline块内或stage指令内

参考案例

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

2.2.2.8 input

是否必须

NO

参数

None

描述

交互输入,pipeline运行到input时会暂停,等待输入后,如果input 批准,stage将继续。作为input输入提供的任何参数在后续其他stage中均可用。

允许 stage指令内

配置选项

  • message
    必填,input界面提示用户的信息
  • id
    此input的可选标识符,默认为stage名称
  • ok
    input界面上“确定”按钮的可选文本
  • submitter
    允许提交此input的用户或外部组名称,多个用户可用,分隔,默认允许任何用户。
  • submitterParameter
    提交者参数
  • parameters

提示提交者提供的可选参数列表。

参考案例

pipeline {
  agent any
  stages {
    stage('Example') {
      // 方式1.此种方式只能该块有效
      input {
        message "Title : 个人信息输入"
        ok "完成提交"
        submitter "alice,bob"
        parameters {
          string(name: 'INPUT_PERSON', defaultValue: 'WeiyiGeek', description: 'Message: 请输入您的姓名?')
          string(name: 'INPUT_AGE', defaultValue: 'WeiyiGeek', description: 'Message: 请输入您的年龄?')
          choice(name: 'INPUT_SEX', choices: ['Male','Female'], description: 'Message: 请选择你的性别?')
          booleanParam(name: 'INPUT_AGREE', defaultValue: true, description: 'Message: 是否确定协议?')
        }
      }

      steps {
        // 方式2: 注意script必须包含在 steps 块之中(此种方式可以全局传递参数)
        script {
          env.git_version=input message: 'Titel: 版本', ok: '通过',parameters: [string ( name: 'git_version', trim: true, description: 'Message : 请选择要操作的应用版本?')];

          env.deploy_option = input message: 'Titel: 操作', ok: 'deploy', parameters: [choice(name: 'deploy_option', choices: ['deploy', 'rollback', 'redeploy'], description: 'Message : 请选择操作流程?')];
        }

        // 12.input 输出示例
        echo "局部可用 输出示例1: 姓名:${INPUT_PERSON}, 年龄:${INPUT_AGE}, 性别:${INPUT_SEX}, 是否同意协议: ${INPUT_AGREE}"

        echo "全局可用 输出示例(script) -> 版本 : ${env.git_version}"
        echo "全局可用 输出示例(script) -> 版本 : ${env.deploy_option}"
    }
  }

  // 采用script块中定义input可以调用不同stage中得参数值
  stage ('调用') {
    steps {
      echo "调用1 : ${env.git_version}"
      echo "调用2 : ${env.deploy_option}"
    }
  }
}
}

2.2.2.9 when

是否必须

NO

参数

条件判断,允许流水线根据给定的条件决定是否应该执行阶段,when 指令必须包含至少一个条件,如果when指令包含多个条件,则所有子条件必须返回true才能执行该阶段。

允许 stage指令内

嵌套条件:

  • allOf:所有条件为真才继续执行。

when { allOf { branch 'master'; environment name: 'DEPLOY_TO', value: 'production' } }

  • anyOf:任意一个条件为真就执行。

when { anyOf { branch 'master'; branch 'staging' } }

  • not:条件为false时才执行

when { not { branch 'master' } }

内置条件

  • branch : 当正在构建的分支与给出的分支模式匹配时执行,仅适用于多分支流水线;

when { branch 'master' }

  • environment : 当指定的环境变量设置为给定值时执行,

when { expression { return params.DEBUG_BUILD } }

  • equals : 当期望值等于实际值时执行阶段,

when { equals expected: 2, actual: currentBuild.number }

  • expression : 在指定的Groovy表达式计算为true时执行

注意:当从表达式返回字符串时,它们必须被转换为布尔值,或者返回null来计算为false。简单地返回"0"或"false"仍然会计算为"true"。

when { expression { return params.DEBUG_BUILD } }

  • Tag : 如果TAG_NAME变量匹配给定的模式则执行该阶段, 注意如果提供了一个空模式,那么阶段将在TAG_NAME变量存在时执行(与buildingTag()相同)。

when { tag "release-*" }

  • buildingTag : 执行构建构建标签的阶段.

when { buildingTag() }

  • changelog : 如果构建的SCM更改日志包含给定的正则表达式模式则执行阶段;

when { changelog '.*^\\[DEPENDENCY\\] .+$' }

  • changeset : 如果构建的SCM变更集包含一个或多个与给定模式匹配的文件,则执行阶段。

when { changeset "**/*.js" }

when { changeset pattern: ".TEST\\.java", comparator: "REGEXP" }  // 正则表达式匹配

when { changeset pattern: "*/*TEST.java", caseSensitive: true }   // 区分大小写ANT样式路径

  • changeRequest : 如果当前构建是针对“变更请求”的,则执行阶段(也称为GitHub和Bitbucket上的Pull Request,GitLab上的Merge Request,Gerrit变更等)。如果未传递任何参数,则阶段将在每个更改请求上运行

when { changeRequest() }.

可用属性: id / target / branch / fork / url / title / author / authorDisplayName / authorEmail

// 每一个都对应一个CHANGE_*环境变量,

when { changeRequest target: 'master' }.

// comparator 参数后指导属性,以指定匹配时如何计算任何模式:

// * EQUALS用于简单的字符串比较(默认值),

// * GLOB用于ANT风格的路径GLOB(与例如changeset相同),

// * REGEXP用于正则表达式匹配

when { changeRequest authorEmail: "[\\w_-.]+@example.com", comparator: 'REGEXP' }

  • triggeredBy : 在给定的参数触发当前构建时执行该阶段。

when { triggeredBy 'SCMTrigger' }

when { triggeredBy 'TimerTrigger' }

when { triggeredBy 'UpstreamCause' }

when { triggeredBy cause: "UserIdCause", detail: "vlinde" }

优先级说明

  • when在input指令前评估 : 默认情况下,如果stage中定义了input,则将在input输入后评估该stage的 when 条件。 如果beforeAgent设置为 true,将首先评估 when 条件,只有当 when 条件为 true 时才会进入input。
  • when在options指令前评估 : 同上,如果beforeOptions设置为true,将首先评估 when 条件,只有当 when 条件为 true 时才会输入options值。
  • when在stage进入agent前评估 : 同上,如果beforeAgent被设置为true,将首先评估 when 条件,只有当when条件为true时才会进入agent。

参考案例

pipeline { 
    agent none 
    stages { 
        stage('Example Build') {
            steps {
                echo 'Hello World' 
            } 
        } 
        stage('beforeinput') {
            when { 
					beforeInput true // 关键点
            		branch 'production' 
			} 
            input {
                message "Deploy to production?" 
                id "simple-input" 
            } 
            steps {
                echo 'Deploying' 
            } 
        }
        stage('beforeagent') {
            agent {label "wuzz"}
            when {
                beforeAgent true // 关键点
                branch 'production'
                }
            steps {
                echo 'Deploying'
            }
        }
        stage('beforeoption') {
            when {
                beforeOptions true // 关键点
                branch 'testing'
            }
            options {
                lock label: 'testing-deploy-envs', quantity: 1, variable: 'deployEnv'
            }
            steps {
                echo "Deploying to ${deployEnv}"
            }
        }
    }
}

参考案例

pipeline {
    agent none  // beforeAgent
    stages {
      stage('Example Build') {
        steps {
          echo 'Hello World'
        }
      }
      stage('Example Deploy') {
        // Single Condition - 单一条件
        when {
          branch 'production'
        }

        // Multiple Condition - 多重条件
        when {
          branch 'production'
          environment name: 'DEPLOY_TO', value: 'production'
        }

        // Nested condition - 嵌套条件
        when {
          allOf {
            branch 'production'
            environment name: 'DEPLOY_TO', value: 'production'
          }
        }

        // Multiple condition and nested condition - 注意点
        when {
            branch 'production'
            anyOf {
                environment name: 'DEPLOY_TO', value: 'production'
                environment name: 'DEPLOY_TO', value: 'staging'
            }
         }
        
        // Expression condition and nested condition  - 表达式条件和嵌套条件
        when {
          expression { BRANCH_NAME ==~ /(production|staging)/ }
          anyOf {
              environment name: 'DEPLOY_TO', value: 'production'
              environment name: 'DEPLOY_TO', value: 'staging'
          }
        }

        // triggeredBy
        when {
          triggeredBy "TimerTrigger"  // 当前Job设置的触发器名称进行监控
        }

        // 当前面的when都满足时采用执行该阶段步骤,否则丢弃
        steps {
            echo 'Deploying'
        }
      }
    }
}

2.2.3 Sequential Stages

声明式pipeline的stages可能有一个包含要按顺序运行的嵌套阶段列表的stage节。

  • 一个stage必须具有且只有一个steps, stages, parallel, 或者 matrix。
  • 如果stage指令嵌套在parallel 或者 matrix内,则不能在stage指令内嵌套parallel 或者 matrix。 但是,parallel 或者 matrix中的stage指令可以使用stage的所有其他功能,包括agent, tools, when等。

2.2.4 Parallel

Pipeline默认是串行,可以通过parallel配置并行构建,stage可以在他们内部声明多嵌套阶段, 它们将并行执行,一个stage只能有一个 steps 或 parallel。

  • 在包含 Parallel的stage中可添加 failFast true,Parallel中任何一个单元失败时全部终止。

参考案例

pipeline {
    agent none
    options {
        parallelsAlwaysFailFast()
    } 
    stages {
        // 非时序的阶段
        stage('Non-Sequential Stage') {
            agent {
                label 'wuzz'
            }
            steps {
                echo "On Non-Sequential Stage"
            }
        }
        // 顺序阶段
        stage('Sequential Stage') {
            agent {
                label 'wuzz'
            }
            environment {
                FOR_SEQUENTIAL = "some-value"
            }
            // 注意点1:
            stages {
                stage('In Sequential 1') {
                    steps {
                        echo "In Sequential 1"
                    }
                }
                stage('In Sequential 2') {
                    steps {
                        echo "In Sequential 2"
                    }
                }
                // 注意点2:可以使用stage的所有其他功能,包括代理、工具、when等
				stage('Parallel Stage') {
					//在任何一个阶段失败时强制终止所有并行阶段
					failFast true
					parallel {
						stage('Branch A') {
							steps {
								echo "On Branch A"
							}
						}
						stage('Branch B') {
							steps {
								echo "On Branch B"
							}
						}
						stage('Branch C') {
							stages {
								stage('Nested 1') {
									steps {
										echo "In stage Nested 1 within Branch C"
									}
								}
								stage('Nested 2') {
									steps {
										echo "In stage Nested 2 within Branch C"
									}
								}
							}
						}
					}
				}
            }
        }
    }
}

2.2.5 Matrix

matrix定义要并行运行的<名称-值>组合的多维矩阵模型。我们将把这些组合称为 Matrix 中的cell。

  • Matrix 中的每个单元可以包括一个或多个stage,使用该单元的配置按顺序运行。注意一个stage必须有且只有一个步骤、阶段、并行或 Matrix 。
  • 如果stage指令嵌套在一个并行块或 Matrix 块本身中,则不能在stage指令中嵌套一个并行块或 Matrix 块。然而,一个并行或 Matrix 块中的stage指令可以使用stage的所有其他功能,包括agent、tools、when等。
  • 在包含Matrix 的stage中可添加 failFast true,Matrix中任何一个单元失败时全部终止。

matrix组成

  • axes:轴线,指定了一个或多个axis指令。每个轴由一个名称和一个值列表组成。每个轴上的所有值都与其他轴上的值组合起来生成单元格。
     
  • excludes:排除,exclude中的axis指令生成一组组合,用于排除axes中生成的组合中需要排除的单元格。

    当处理一长串要排除的值时 exclude axis指令可以使用 notValues 代替 values.这将排除与传递给notValues的值之一不匹配的单元格。

  • stages:指定每个单元中要顺序执行的一个或多个stage

参考案例

pipeline {
    // 参数选择
    parameters {
        choice(name: 'PLATFORM_FILTER', choices: ['all', 'linux', 'windows', 'mac'], description: 'Run on specific platform')
    }
    agent none
    stages {
        stage('BuildAndTest') {
            matrix {
                agent {
                    label "wuzz"
                }
                when { anyOf {
                    // 参数选择不为空时继续执行
                    expression { params.PLATFORM_FILTER == 'all' }
                    expression { params.PLATFORM_FILTER == env.PLATFORM }
                } }
                // 2 轴 (3 x 4) 十二格组合方式
                axes {
                    axis {
                        name 'PLATFORM'
                        values 'linux', 'windows', 'mac'
                    }
                    axis {
                        name 'BROWSER'
                        values 'firefox', 'chrome', 'safari', 'edge'
                    }
                }
                // 排除指定Matrix矩阵中的值 (排除linux和safari组合,并排除使用edge浏览器的任何非windows平台。) 
                // 即 排除 (linux,safari) , (linux,edge) , (mac,edge) 三种情况
                excludes {
                    exclude {
                        axis {
                            name 'PLATFORM'
                            values 'linux'
                        }
                        axis {
                            name 'BROWSER'
                            values 'safari'
                        }
                    }
                    exclude {
                        axis {
                            name 'PLATFORM'
                            notValues 'windows'
                        }
                        axis {
                            name 'BROWSER'
                            values 'edge'
                        }
                    }
                }
                stages {
                    stage('Build') {
                        steps {
                            echo "Do Build for ${PLATFORM} - ${BROWSER}"
                        }
                    }
                    stage('Test') {
                        steps {
                            echo "Do Test for ${PLATFORM} - ${BROWSER}"
                        }
                    }
                }
            }
        }
    }
}

2.2.4 script

是否必须

NO

参数

None

描述

在Declarative Pipeline中,可采用script指令来执行Scripted Pipeline中的一些脚本

允许 stage指令内

参考案例

pipeline {
    agent any
    stages {
        stage('Example') {
          steps { 
              script {
                def browsers = ['chrome', 'firefox']
                for (int i = 0; i < browsers.size(); ++i) {
                    echo "Testing the ${browsers[i]} browser"
                }
              }
          }
        }
    }
}

2.3 Basic Steps

2.3.1 字符串和标准输出

2.3.1.1 echo

echo "Hello"

2.3.1.2 println

println "World!"

2.3.2 文件目录相关操作

2.3.2.1 isUnix

检查是否在类 Unix环境(如Linux或Mac OS X)上运行,是则返回true,否则返回false。

node {
    if(isUnix()){
     echo "is unix" 
    }
 }

2.3.2.2 pwd

查看当前路径

2.3.2.3 dir

改变当前目录,默认pipeline工作在当前job的workspace目录下,dir步骤可以让我们切换到其他目录,且在当前块中均会以此路径为base路径。

node {
    dir('123') {
        sh """ mkdir 333;cd 333;pwd """ 
    }
 }

2.3.2.4 deleteDir

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

node {
    dir('123') {
        sh 'touch 1.txt;ls'
        deleteDir()
        sh 'ls'
    }
 }

2.3.2.5 fileExists

检查给定的文件(作为当前目录的相对路径)是否存在。参数file返回 true | false 。

node {
        if(fileExists('123/1.txt') == true){
            echo "file exists"
        }
 }

2.3.2.6 writeFile

将内容写入文件

node {
        if(fileExists('123/1.txt') == true){
            

        }
    }

2.3.2.7 readFile

读取文件内容

node {
    if(fileExists('123/1.txt') == true){
		def data = readFile(file: '123/1.txt')
		println(data)
		//按行打印,打印一行之后暂停2秒
		Thread.sleep(2000)
		//按行读取
		def lines = data.readLines()
		//使用for循环遍历每行
		for (line in lines) {
			println(line)
		//假如是一个csv文件,每行都是以逗号分隔的参数,可以使用split取每一列
			String[] str;
			str = line.split(',');
			println('projectkey:' + str[0])
			println('reponame:' + str[1])
			println('giturl:' + str[2])
		}
    }
}

2.3.3 制品相关操作

2.3.3.1 stash

  • stash:暂存一些文件供稍后在构建中使用
  • unstash: 释放暂存的文件

参考案例

node {
    stash excludes: '2.txt', includes: '
', name: 'txtstash'
}
node {
    unstash 'txtstash'
}

2.3.3.2 archiveArtifacts

  • archiveArtifacts:存档构建的成品
  • archive:新版本中由archiveArtifacts取代
  • unarchive: 将存档的工件复制到工作区
node {
    archiveArtifacts allowEmptyArchive: true, artifacts: '123/*.txt', excludes: '2.txt', fingerprint: true, onlyIfSuccessful: true
}

node {
    unarchive mapping: ['123/*.txt': '222/']
}

2.3.3.3 wrap

通用构建包装器:某些特殊的步骤允许调用构建包装器(在freestyle或类似项目中也称为“环境配置”)

node {
    wrap([$class: 'TimestamperBuildWrapper']) {
    echo "hello world"
    }
}

2.3.4 命令相关操作

2.3.4.1 withEnv

设置环境变量:在块中设置一个或多个环境变量, 这些可用于该范围内生成的任何外部流程。

node {
  withEnv(['MYTOOL_HOME=/usr/local/mytool']) {
    sh '$MYTOOL_HOME/bin/start'
  }
  withEnv(['name=tester']) {
          echo "$name"
        }
}

Tips: 注意这里我们在Groovy中使用了单引号,所以变量展开是由Bourne shell完成的而不是Jenkins

2.3.4.2 withCredentials

将secret与变量对应起来。在jenkins中创建的密钥,在Pipeline中希望通过变量方式引用,可以通过withCredentials实现。

node {
    withCredentials([usernamePassword(credentialsId: 'wuzz', passwordVariable: 'password', usernameVariable: 'username')]) {
        sh 'echo $username'
    }
}

Tips: 注意这里我们在Groovy中使用了单引号,所以变量展开是由Bourne shell完成的而不是Jenkins

2.3.4.3 sh\bat\powershell

shell\bat\powershell支持的参数和步骤基本一致,以shell为例

参数说明

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

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

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

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

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

Tips : 注意采用sh执行echo 1 > 1.txt命令时然后采用readFile读取时带有换行符,解决办法:

# 方式1.采用 $? 判断命令执行成功与否。
# 方式2.采用echo命令输出到文件时加上 -n 选项。

执行shell的几种方式

  • 直接执行shell命令:sh '<shell command>'
  • 获取标准输出:result = sh(script: "<shell command>", returnStdout: true).trim()
  • 获取执行状态:result = sh(script: "<shell command>", returnStatus: true).trim()

参考案例

node {
//获取标准输出
	//方式1
	result = sh returnStdout: true ,script: "pwd" 
	result = result.trim()
	echo "$result"
	//方式2
	result = sh(script: "pwd", returnStdout: true).trim()
	echo "$result"
	//方式3
	sh "pwd > commandResult" 
	result = readFile('commandResult').trim()
	echo "$result"


//获取执行状态.net
	//方式1
	result = sh returnStatus: true ,script: "pwd" 
	echo "$result"
	//方式2
	result = sh(script: "pwd", returnStatus: true)
	echo "$result"
	//方式3
	sh 'pwd; echo $? > status' 
	def r = readFile('status')
	echo "$r"

//无需返回值,仅执行shell命令ci
	sh 'pwd'
}

2.3.5 常用循环

2.3.5.1 timeout+waitUntil

node {
    timeout(time:10, unit:"SECONDS"){
        waitUntil{
          script{
            def rs = sh script: 'pwd', returnStatus: true     
            return (rs == 0)
          }
        }
    }
}

2.3.5.2 switch

node {
timeout(time: 1, unit: 'MINUTES') {
  script {
    env.deploy_option = input message: '选择操作', ok: 'deploy',
    parameters: [choice(name: 'deploy_option', choices: ['deploy', 'rollback', 'redeploy'], description: '选择部署环境')]
    switch("${env.deploy_option}"){
        case 'deploy':
            println('1.deploy prd env')
            break;
        case 'rollback':
            println('2.rollback env')
            break;
        case 'redeploy':
            println('3.redeploy env')
            break;
        default:
            println('error env')
    }
  }
}
}

2.3.5.3 for+continue

pipeline {
    agent any
    stages {
        stage('Example') {
          steps {
              script {
                def browsers = ['chrome', 'firefox', 'ie']
                for (int i = 0; i < browsers.size(); ++i) {
                    if (i==1)
					continue
					echo "Testing the ${browsers[i]} browser"
					
                }
              }
          }
        }
    }
}

2.3.6 其他操作

2.3.6.1 catchError

捕获错误并将构建结果设置为失败。

参考案例

node {
    catchError {
        sh 'might fail'
    }
    step([$class: 'Mailer', recipients: '
zhenzhen.wu@163.com'])
}

2.3.6.2 error

主动报错中止当前 pipeline 并且避免打印堆栈跟踪信息。

参考案例

node {
try {
  sh 'might fail && whoami'
  echo 'Succeeded!'
} catch (err) {
  echo "Failed: ${err} - " + err.toString() 
  error "[-Error] : 项目部署失败 \n[-Msg] : ${err.getMessage()} "
} 
}

2.3.6.3 mail

参考案例

pipeline {
    agent any
    stages {
        stage('Hello') {
            steps {
                echo 'Hello World'
            }
        }
    }
	post {
			success {	
				step([$class: 'Mailer',
					notifyEveryUnstableBuild: true,
					recipients: 'zhenzhen.wu@163.com',
					sendToIndividuals: true])
		   }
			failure {
				step([$class: 'Mailer', recipients: 'zhenzhen.wu@163.com'])	
			  }
	}
}

2.3.6.4 retry

重试正文最多N次, 如果在块体执行过程中发生任何异常,请重试该块(最多N次)。如果在最后一次尝试时发生异常,那么它将导致中止构建(除非以某种方式捕获并处理它),不会捕获生成的用户中止。

retry(count: 5)  # 重试5次

2.3.6.5sleep

让pipeline休眠指定的一段时间 , 只需暂停管道构建直到给定的时间已经过期相当于(在Unix上)sh 'sleep…'。

sleep time: 60, unit: 'MINUTES'

2.3.6.6 getContext

从内部 API 获取上下文对象

node {
    def aaa = getContext hudson.FilePath
    echo "$aaa"
}

2.3.6.7 withContext

在块内使用来自内部 API 的上下文对象

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐