[持續交付實踐] pipeline:pipeline 使用之語法詳解
一、引言
jenkins pipeline語法的發展如此之快用日新月異來形容也不為過,而目前國內對jenkins pipeline關註的人還非常少,相關的文章更是稀少,唯一看到w3c有篇相關的估計是直接翻譯軟件翻的,讀下來慘不忍睹。
沒辦法,語法詳解這章我幹脆把jenkins官網上的語法說明全部翻譯了一遍,並更新了陳舊的內容(可憐了我大學四級的英語水平~),英語好的朋友也可以直接到官網閱讀。
二、語法簡介
Pipeline最基本的部分是“step”。基本上,step告訴Jenkins 要做什麽,並且作為Declarative Pipeline和Scripted Pipeline語法的基本構建塊。
Pipeline支持兩種語法:Declarative Pipeline(在Pipeline 2.5中引入,結構化方式)和Scripted Pipeline,兩者都支持建立連續輸送的Pipeline。
為與BlueOcean腳本編輯器兼容,通常建議使用Declarative Pipeline的方式進行編寫,從jenkins社區的動向來看,很明顯這種語法結構也會是未來的趨勢。
三、Declarative Pipeline
Declarative Pipeline是Jenkins Pipeline 的一個相對較新的補充, 它在Pipeline子系統之上提出了一種更為簡化和有意義的語法。
所有有效的Declarative Pipeline必須包含在一個pipeline塊內,例如:
pipeline { /* insert Declarative Pipeline here */ }
Declarative Pipeline中的基本語句和表達式遵循與Groovy語法相同的規則 ,但有以下例外:
a.Pipeline的頂層必須是塊,具體來說是:pipeline { }
b.沒有分號作為語句分隔符。每個聲明必須在自己的一行
c.塊只能包含Sections, Directives, Steps或賦值語句。
d.屬性引用語句被視為無參方法調用。所以例如,輸入被視為input()
1.Sections(章節)
Declarative Pipeline裏的Sections通常包含一個或多個Directives或 Steps
agent
該agent部分指定整個Pipeline或特定階段將在Jenkins環境中執行的位置,具體取決於該agent 部分的放置位置。該部分必須在pipeline塊內的頂層定義 ,但stage級使用是可選的。
為了支持Pipeline可能擁有的各種用例,該agent部分支持幾種不同類型的參數。這些參數可以應用於pipeline塊的頂層,也可以應用在每個stage指令內。
參數
any
在任何可用的agent 上執行Pipeline或stage。例如:agent any
none
當在pipeline塊的頂層使用none時,將不會為整個Pipeline運行分配全局agent ,每個stage部分將需要包含其自己的agent部分。
label
使用提供的label標簽,在Jenkins環境中可用的代理上執行Pipeline或stage。例如:agent { label ‘my-defined-label‘ }
node
agent { node { label ‘labelName‘ } },等同於 agent { label ‘labelName‘ },但node允許其他選項(如customWorkspace)。
docker
定義此參數時,執行Pipeline或stage時會動態供應一個docker節點去接受Docker-based的Pipelines。 docker還可以接受一個args,直接傳遞給docker run調用。例如:agent { docker ‘maven:3-alpine‘ }或
docker
agent {
docker {
image ‘maven:3-alpine‘
label ‘my-defined-label‘
args ‘-v /tmp:/tmp‘
}
}
dockerfile
使用從Dockerfile源存儲庫中包含的容器來構建執行Pipeline或stage 。為了使用此選項,Jenkinsfile必須從Multibranch Pipeline或“Pipeline from SCM"加載。
默認是在Dockerfile源庫的根目錄:agent { dockerfile true }。如果Dockerfile需在另一個目錄中建立,請使用以下dir選項:agent { dockerfile { dir ‘someSubDir‘ } }。您可以通過docker build ...使用additionalBuildArgs選項,如agent { dockerfile { additionalBuildArgs ‘--build-arg foo=bar‘ } }。
常用選項
這些是可以應用於兩個或多個agent的選項。除非明確定義,否則不需要。
label
一個字符串。標記在哪裏運行pipeline或stage
此選項適用於node,docker和dockerfile,並且 node是必需的。
customWorkspace
一個字符串。自定義運行的工作空間內。它可以是相對路徑,在這種情況下,自定義工作區將位於節點上的工作空間根目錄下,也可以是絕對路徑。例如:
customWorkspace
agent {
node {
label ‘my-defined-label‘
customWorkspace ‘/some/other/path‘
}
}
reuseNode
一個布爾值,默認為false。如果為true,則在同一工作空間中。
此選項適用於docker和dockerfile,並且僅在 individual stage中使用agent才有效。
Example
Jenkinsfile (Declarative Pipeline)
pipeline {
//Execute all the steps defined in this Pipeline within a newly created container of the given name and tag (maven:3-alpine).
agent { docker ‘maven:3-alpine‘ }
stages {
stage(‘Example Build‘) {
steps {
sh ‘mvn -B clean verify‘
}
}
}
}
Stage-level agent section
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
定義Pipeline或stage運行結束時的操作。post-condition塊支持post部件:always,changed,failure,success,unstable,和aborted。這些塊允許在Pipeline或stage運行結束時執行步驟,具體取決於Pipeline的狀態。
conditions項:
always
運行,無論Pipeline運行的完成狀態如何。
changed
只有當前Pipeline運行的狀態與先前完成的Pipeline的狀態不同時,才能運行。
failure
僅當當前Pipeline處於“失敗”狀態時才運行,通常在Web UI中用紅色指示表示。
success
僅當當前Pipeline具有“成功”狀態時才運行,通常在具有藍色或綠色指示的Web UI中表示。
unstable
只有當前Pipeline具有“不穩定”狀態,通常由測試失敗,代碼違例等引起,才能運行。通常在具有黃色指示的Web UI中表示。
aborted
只有當前Pipeline處於“中止”狀態時,才會運行,通常是由於Pipeline被手動中止。通常在具有灰色指示的Web UI中表示。
Example
post
pipeline {
agent any
stages {
stage(‘Example‘) {
steps {
echo ‘Hello World‘
}
}
}
post {
always {
echo ‘I will always say Hello again!‘
}
}
}
stages
包含一個或多個stage的序列,Pipeline的大部分工作在此執行。建議stages至少包含至少一個stage指令,用於連接各個交付過程,如構建,測試和部署等。
steps
steps包含一個或多個在stage塊中執行的step序列。
Example
stages
pipeline {
agent any
stages {
stage(‘Example‘) {
steps {
echo ‘Hello World‘
}
}
}
}
2.Directives (指令)
environment
environment指令指定一系列鍵值對,這些鍵值對將被定義為所有step或stage-specific step的環境變量,具體取決於environment指令在Pipeline中的位置。
該指令支持一種特殊的方法credentials(),可以通過其在Jenkins環境中的標識符來訪問預定義的憑據。
對於類型為“Secret Text”的憑據,該 credentials()方法將確保指定的環境變量包含Secret Text內容;對於“標準用戶名和密碼”類型的憑證,指定的環境變量將被設置為username:password。
Example
environment
pipeline {
agent any
environment {
CC = ‘clang‘
}
stages {
stage(‘Example‘) {
environment {
AN_ACCESS_KEY = credentials(‘my-prefined-secret-text‘)
}
steps {
sh ‘printenv‘
}
}
}
}
options
options指令允許在Pipeline本身內配置Pipeline專用選項。Pipeline本身提供了許多選項,例如buildDiscarder,但它們也可能由插件提供,例如 timestamps。
可用選項
buildDiscarder
pipeline保持構建的最大個數。例如:options { buildDiscarder(logRotator(numToKeepStr: ‘1‘)) }
disableConcurrentBuilds
不允許並行執行Pipeline,可用於防止同時訪問共享資源等。例如:options { disableConcurrentBuilds() }
skipDefaultCheckout
默認跳過來自源代碼控制的代碼。例如:options { skipDefaultCheckout() }
skipStagesAfterUnstable
一旦構建狀態進入了“Unstable”狀態,就跳過此stage。例如:options { skipStagesAfterUnstable() }
timeout
設置Pipeline運行的超時時間。例如:options { timeout(time: 1, unit: ‘HOURS‘) }
retry
失敗後,重試整個Pipeline的次數。例如:options { retry(3) }
timestamps
預定義由Pipeline生成的所有控制臺輸出時間。例如:options { timestamps() }
Example
options
pipeline {
agent any
options {
timeout(time: 1, unit: ‘HOURS‘)
}
stages {
stage(‘Example‘) {
steps {
echo ‘Hello World‘
}
}
}
}
parameters
parameters指令提供用戶在觸發Pipeline時的參數列表。這些參數值通過該params對象可用於Pipeline步驟,具體用法如下
可用參數
string
A parameter of a string type, for example: parameters { string(name: ‘DEPLOY_ENV‘, defaultValue: ‘staging‘, description: ‘‘) }
booleanParam
A boolean parameter, for example: parameters { booleanParam(name: ‘DEBUG_BUILD‘, defaultValue: true, description: ‘‘) }
目前只支持[booleanParam, choice, credentials, file, text, password, run, string]這幾種參數類型,其他高級參數化類型還需等待社區支持。
Example
params
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指令定義了Pipeline自動化觸發的方式。對於與源代碼集成的Pipeline,如GitHub或BitBucket,triggers可能不需要基於webhook的集成也已經存在。目前只有兩個可用的觸發器:cron和pollSCM。
cron
接受一個cron風格的字符串來定義Pipeline觸發的常規間隔,例如: triggers { cron(‘H 4/* 0 0 1-5‘) }
pollSCM
接受一個cron風格的字符串來定義Jenkins檢查SCM源更改的常規間隔。如果存在新的更改,則Pipeline將被重新觸發。例如:triggers { pollSCM(‘H 4/* 0 0 1-5‘) }
Example
triggers
pipeline {
agent any
triggers {
cron(‘H 4/* 0 0 1-5‘)
}
stages {
stage(‘Example‘) {
steps {
echo ‘Hello World‘
}
}
}
}
stage
stage指令在stages部分中,應包含stop部分,可選agent部分或其他特定於stage的指令。實際上,Pipeline完成的所有實際工作都將包含在一個或多個stage指令中。
Example
stage
pipeline {
agent any
stages {
stage(‘Example‘) {
steps {
echo ‘Hello World‘
}
}
}
}
tools
通過tools可自動安裝工具,並放置環境變量到PATH。如果agent none,這將被忽略。
Supported Tools
maven
jdk
gradle
Example
tools
pipeline {
agent any
tools {
//工具名稱必須在Jenkins 管理Jenkins → 全局工具配置中預配置。
maven ‘apache-maven-3.0.1‘
}
stages {
stage(‘Example‘) {
steps {
sh ‘mvn --version‘
}
}
}
}
when
when指令允許Pipeline根據給定的條件確定是否執行該階段。該when指令必須至少包含一個條件。如果when指令包含多個條件,則所有子條件必須為stage執行返回true。這與子條件嵌套在一個allOf條件中相同(見下面的例子)。
更復雜的條件結構可使用嵌套條件建:not,allOf或anyOf。嵌套條件可以嵌套到任意深度。
內置條件
branch
當正在構建的分支與給出的分支模式匹配時執行,例如:when { branch ‘master‘ }。請註意,這僅適用於多分支Pipeline。
environment
當指定的環境變量設置為給定值時執行,例如: when { environment name: ‘DEPLOY_TO‘, value: ‘production‘ }
expression
當指定的Groovy表達式求值為true時執行,例如: when { expression { return params.DEBUG_BUILD } }
not
當嵌套條件為false時執行。必須包含一個條件。例如:when { not { branch ‘master‘ } }
allOf
當所有嵌套條件都為真時執行。必須至少包含一個條件。例如:when { allOf { branch ‘master‘; environment name: ‘DEPLOY_TO‘, value: ‘production‘ } }
anyOf
當至少一個嵌套條件為真時執行。必須至少包含一個條件。例如:when { anyOf { branch ‘master‘; branch ‘staging‘ } }
Example
when
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‘
}
}
}
}
3.Steps(步驟)
Declarative Pipeline可以使用 Pipeline Steps reference中的所有可用步驟 ,並附加以下僅在Declarative Pipeline中支持的步驟。
script
script步驟需要一個script Pipeline,並在Declarative Pipeline中執行。對於大多數用例,script在Declarative Pipeline中的步驟不是必須的,但它可以提供一個有用的加強。
Example
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"
}
}
}
}
}
}
四、Scripted Pipeline
Groovy腳本不一定適合所有使用者,因此jenkins創建了Declarative pipeline,為編寫Jenkins管道提供了一種更簡單、更有主見的語法。但是不可否認,由於腳本化的pipeline是基於groovy的一種DSL語言,所以與Declarative pipeline相比為jenkins用戶提供了更巨大的靈活性和可擴展性。
1.流程控制
pipeline腳本同其它腳本語言一樣,從上至下順序執行,它的流程控制取決於Groovy表達式,如if/else條件語句,舉例如下:
Jenkinsfile (Scripted Pipeline)
node {
stage(‘Example‘) {
if (env.BRANCH_NAME == ‘master‘) {
echo ‘I only execute on the master branch‘
} else {
echo ‘I execute elsewhere‘
}
}
}
pipeline腳本流程控制的另一種方式是Groovy的異常處理機制。當任何一個步驟因各種原因而出現異常時,都必須在Groovy中使用try/catch/finally語句塊進行處理,舉例如下:
Jenkinsfile (Scripted Pipeline)
node {
stage(‘Example‘) {
try {
sh ‘exit 1‘
}
catch (exc) {
echo ‘Something failed, I should sound the klaxons!‘
throw
}
}
}
2.Steps
正如文檔開始所言,pipeline最核心和基本的部分就是“step”,從根本上來說,steps作為Declarative pipeline和Scripted pipeline語法的最基本的語句構建塊來告訴jenkins應該執行什麽操作。
Scripted pipeline沒有專門將steps作為它的語法的一部分來介紹,但是在Pipeline Steps reference這篇文檔中對pipeline及其插件涉及的steps做了很詳細的介紹。如有需要可參考jenkins官網對該部分的介紹Pipeline Steps reference
3.Differences from plain Groovy
由於pipeline的一些個性化需求,比如在重新啟動jenkins後要求pipeline腳本仍然可以運行,那麽pipeline腳本必須將相關數據做序列化,然而這一點 Groovy並不能完美的支持,例如collection.each { item -> /* perform operation */ }
4.Declarative pipeline和Scripted pipeline的比較
共同點:
兩者都是pipeline代碼的持久實現,都能夠使用pipeline內置的插件或者插件提供的steps,兩者都可以利用共享庫擴展。
區別:
兩者不同之處在於語法和靈活性。Declarative pipeline對用戶來說,語法更嚴格,有固定的組織結構,更容易生成代碼段,使其成為用戶更理想的選擇。但是Scripted pipeline更加靈活,因為Groovy本身只能對結構和語法進行限制,對於更復雜的pipeline來說,用戶可以根據自己的業務進行靈活的實現和擴展。
[持續交付實踐] pipeline:pipeline 使用之語法詳解