介绍

本文基于入门介绍,仅仅是一个语法参考。至于如何在特定的例子中运用Pipeline语法,请参考Jenkins Pipeline。从插件Pipeline plugin的2.5版本开始,Pipeline支持两种格式的语法。对于它们之间的区别请参考语法对比。

正如在入门介绍里说的,流水线最主要的就是”步骤“。基本上,就是步骤来告诉Jenkins该干什么,它是申明式和脚本式流水线语法的基础。

你可以在流水线步骤参考中,找到一份可用的步骤列表。

申明Pipeline

申明式流水线是最近添加到Jenkins流水线功能中的,这种语法更加简单。

所有合法的申明式流水线必须在 pipeline 代码块中,例如:

pipeline {
    /* insert Declarative Pipeline here */
}

在申明式流水线中,基本的语句和表达式是遵循 Groovy语法 ,但是有以下几个例外:

  • 流水线的顶层必须是一个代码块: pipeline { }
  • 不需分号作为语句的分隔符。每个语句单独占一行
  • 只能包括段落、步骤、或者赋值语句
  • 属性引用语句被当作无参数的方法调用。例如:input会当作方法input()

段落

在申明式流水线中,通常包括一个或者多个指令或者步骤。

代理agent

代理指定了整个流水线或者特定的阶段的运行环境。它必须在pipeline块的顶层定义,而在阶段中是可选的。

参数

为了支持多种情况的流水线使用场景,代理(agent)支持几种不同类型的参数。这些参数既可以在顶层的pipeline块也可以在每个阶段中使用。

any

在任意可用的代理上执行流水线。例如: agent any

none

当在顶层的pipeline块中使用时,不会有全局的代理分配给整个流水线,每个阶段都需要包含个人的代理。例如:agent none

label

根据Jenkins环境中提供的标签,确定一个可用的代理来chiding流水线或者阶段。例如:agent { label ‘my-defined-label’ }

node

agent { node { label ‘labelName’ } } 和 agent { label ‘labelName’ }一样,但是 node 允许增加选项(例如 customWorkspace)

docker

在指定的容器里执行流水线或者阶段,容器会被动态分配到预先配置好的基于Docker的流水线节点,或者通过label参数来匹配。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 必须是在多分支流水线或者从SCM中加载。约定Dockerfile 在码线的根目录中,可以是agent { dockerfile true } 。如果Dockerfile 在另外一个目录中,可以使用参数dir :agent { dockerfile { dir ‘someSubDir’ } } 。如果Dockerfile 有其他的名称,你可以通过参数filename 指定文件名称。你可以通过参数additionalBuildArgs 给命令docker build … 传递额外的选项,例如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'
    }

通用选项Common Options

有一些选项可以在多种代理实现中使用。没有指定的话,就不是必须的。

label

字符串。可以在流水线或者 stage上。

该选项可以在 node,docker 和 dockerfile中使用,但对于 node是必须的。

customWorkspace

字符串。指定工作空间,而不使用默认的。可以是相对于节点上的根工作空间,也可以是绝对路径。例如:

agent {
    node {
        label 'my-defined-label'
        customWorkspace '/some/other/path'
    }
}

该选项可以用在 node, docker 和 dockerfile。

reuseNode

布尔值,默认为false。如果为true,则在相同的工作空间中运行,而不是每次创建新的。
该选项可以在 docker 和 dockerfile中使用,而且只有在 agent 配置到单独的 stage中才能使用。

Jenkinsfile (Declarative Pipeline)

pipeline {
    agent { docker 'maven:3-alpine' } 
    stages {
        stage('Example Build') {
            steps {
                sh 'mvn -B clean verify'
            }
        }
    }
}

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
  • 阶段stages
  • 步骤steps
  • 指令Directive
  • 环境environment
  • 选项options
  • 参数parameters
  • 触发器triggers
  • 阶段stage
  • 工具tools
  • 输入input
  • 条件when

指令when 允许流水线根据条件来决定是否要执行特定的阶段。指令when 必须至少包含一个条件。如果指令when 包含多个条件,所有的条件都必须为true才可以会执行该阶段。这和allOf 条件是类似的(请参考下面的例子)。

更复杂的结构可以使用嵌套:not, allOf,或 anyOf。可以嵌套任意深度。

内置条件:

分支branch

当匹配分支名称时执行,例如: when { branch ‘master’ }。这只有在多分支流水线中才可以使用。

环境environment

当指定的环境变量值和给定的一样时执行,例如: when { environment name: ‘DEPLOY_TO’, value: ‘production’ }

表达式expression

当Groovy表达式为true时,例如: when { expression { return params.DEBUG_BUILD } }

not

当嵌套条件值为false时执行。必须包含一个条件。例如: when { not { branch ‘master’ } }

allOf

当嵌套条件为true时执行。必须至少包含一个。例如: when { allOf { branch ‘master’; environment name: ‘DEPLOY_TO’, value: ‘production’ } }

anyOf

当任意一个表达式为true时。必须至少包含一个。例如: when { anyOf { branch ‘master’; branch ‘staging’ } }

在进入阶段的代理节点之前计算when表达式

默认情况下,when 条件是在进入阶段的代理之后计算。然而,通过增加选项beforeAgent 可以改变。如果把选项beforeAgent 设置为true,就会首先计算when 条件,只有在值为true时才会进入。

示例1:

Jenkinsfile (Declarative Pipeline)

pipeline {
    agent any
    stages {
        stage('Example Build') {
            steps {
                echo 'Hello World'
            }
        }
        stage('Example Deploy') {
            when {
                branch 'production'
            }
            steps {
                echo 'Deploying'
            }
        }
    }
}

示例2:

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'
            }
        }
    }
}

示例3:

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'
            }
        }
    }
}

示例4:

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'
            }
        }
    }
}

示例5:

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'
            }
        }
    }
}

示例6:

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'
            }
        }
    }
}

并发parallel

阶段是可以并行执行的。注意,在阶段内必须要只能有一个steps 或 parallel。任何包含parallel 的阶段不能包括agent 或 tools,也不包括steps。

另外,当有一个任务失败后,你可以强制整个并行失败。只要设置参数failFast 为true就可以。

示例:

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"
                    }
                }
            }
        }
    }
}

步骤

脚本

script 可以在申明时的流水线中执行脚本时步骤。大多数情况下 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"
                    }
                }
            }
        }
    }
}

脚本化流水线

脚本化流水线可以使用普通的Groovy语法,因此,它可以实现很强大的功能。

在Jenkins流水线刚被开发出来时,采用Groovy作为基础。Jenkins已经很长时间内采用嵌入式的Groovy引擎提供了高级脚本功能给管理员和普通用户。也就是说,基于Groovy脚本的流水线指的就是脚本化流水线。

流程控制

步骤

语法对比

参考

https://jenkins.io/doc/book/pipeline/syntax/