Jenkins Declarative Pipeline

丁叮盯町
12 min readOct 30, 2023

--

Jenkins Pipeline 有分為 Declarative Pipeline 和 Scripted Pipeline 兩種語法。本篇只介紹 Declarative Pipeline 語法。

Declarative Pipeline 的特點是結構化的聲明語句,各區塊的從屬關係固定,類似填寫 Jenkins 設置 Job 頁面的表單。固定格式的聲明語句,還有利於從 BlueOcean 中查看 workflow。

下圖是 Declarative Pipeline 的結構,實線框代表 mandatory,是一定要寫的,虛線框代表 optional。實際的寫法可以參見下方的 Jenkinsfile。

pipeline {
agent none
stages {
stage('Static Analysis') {
agent { node { label 'slave_1' } }
steps {
echo 'Run the static analysis to the code'
}
}
stage('Compile') {
agent { node { label 'slave_2' } }
steps {
echo 'Compile the source code'
}
}
stage('Security Check') {
agent { node { label 'slave_2' } }
steps {
echo 'Run the security check against the application'
}
}
stage('Run Unit Tests') {
agent { node { label 'slave_2' } }
steps {
echo 'Run unit tests from the source code'
}
}
stage('Run Integration Tests') {
agent { node { label 'slave_2' } }
steps {
echo 'Run only crucial integration tests from the source code'
}
}
stage('Publish Artifacts') {
agent { node { label 'slave_1' } }
steps {
echo 'Save the assemblies generated from the compilation'
}
}
}
}

下面將詳細解釋每個 Declarative Pipeline 的區塊。

agent

agent 用來指定所在區塊的運行環境,所在區塊指的是 pipeline 或者是 stage,運行環境可以是 Jenkins node 或者是 docker container。如果在 pipeline 區塊的 agent 為 none,那每個 stage 裡必須各自設置 agent。

如果運行環境為 Jenkins Node,寫法如下。label 表示 Jenkins Node 的 label,在 Jenkins 的 Node List 裡設置

agent { label 'slave_1' }

如果為 docker container,參考下方寫法

agent {
docker {
image 'images:tag'
}
}

environment

設定所在區塊(pipeline、stage)的環境變量, 寫法是以鍵值對 (key = “value”) 的方式

environment { 
CONFIG = 'xxx'
DISABLE_AUTH = 'true'
}

triggers

設定 pipeline 的觸發。一般來說,如果已經將 pipeline 與 SCM (GitHub or BitBucket) 整合,並且已設置 Webhooks,triggers 這區塊就沒那麼需要了。triggers 這邊有三個參數,分別是 cron, pollSCM 以及 upstream。

cron

cron 是定時執行。它的使用場景通常是執行一些週期性的 job,比如説 daily build。cron 的寫法有五個區段,實際的語法說明起來還有點小複雜,
姑且將 cron 的詳細說明寫在這篇

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

pollSCM

pollSCM 指的就是 polling source code management,輪詢 SCM。定期到 SCM 詢問 source code 是否有變化,如果有變化就執行。事實上,如果 source code 有變化,最好的方式應該是 SCM 主動通知 Jenkins,而不是由 Jenkins 去 polling SCM。pollSCM 的寫法和 cron 類似,在這篇一起說明。

upstream

upstream 指的是由上游任務觸發,upstream 可以讓 pipeline 自行決定由哪些上游任務觸發。如下範例就是由 job-1 和 job-2 觸發。

triggers {
cron('0 10 * * *')
upstream(upstreamProjects: "job-1,job-2", threshold: hudson.model.Result.SUCCESS)
}

參數 threshold 是用來設定上游任務的結果。如範例,就是當上游任務 SUCCESS 時觸發。hudson.model.Result 是一個 enum 包括以下值:

ABORTED:任務被手動終止
FAILURE:構建失敗
SUCCESS:構建成功
UNSTABLE:存在錯誤,但非構建失敗
NOT_BUILD:構建無法執行

options

options 可以在 pipeline 及 stage 區塊做設定,常用的有以下的參數:

options {
timestamps() //開啟時間戳
retry(3) // 設定失敗後的重試次數
quietPeriod(30)// 設定啟動前的等待秒數
timeout(time: 1, unit: 'HOURS') // 指定任務的超時時間,超時將放棄該任務
}

parameters

在 pipeline 裡可以定義多組 parameters,所有參數應該要寫在 parameters 區塊。parameters 裡可以用的參數有 string, booleanParam, text, password以及 choice。

pipeline {
agent any
parameters {
string(name: "USERNAME", defaultValue: "XXX", trim: true, description: "username parameter")
password(name: "PASSWORD", defaultValue: "***", description: "password parameter")
}
stages {
stage("Build") {
steps {
echo "Build stage."
echo "Hello $params.USERNAME"
}
}
stage("Test") {
steps {
echo "Test stage."
}
}
stage("Release") {
steps {
echo "Release stage."
}
}
}
}

如上範例,在第一次建置時不會要求輸入參數,但第一次建置後,就可以發現左邊的選單變成「帶參數建置」,第二次建置就必須輸入參數了。如果更改的 parameters 的設定,也是一樣,建置後才會生效。

stages

stages 是 pipeline 的 mandatory 區塊,是所有 stage 的集合。stages 中至少要包含一個 stage。

stage

stage 是 pipeline 真正執行工作的區塊,stage 可以定義多個,如果熟悉 Blue Ocean 的話,會發現每一個 stage 是對應 Blue Ocean 介面的一個小圓圈,如下圖。

stage 裡有許多參數和上層 pipeline 區塊裡的相同,以下一一介紹:

  • agent
    同 pipeline 的 agent。如果 pipeline agent 設置為 none,則每個 stage 中必須設置 agent。
  • environment
    同 pipeline 裡的 envitonment。
  • input
    在 stage 開始執行前,等待使用者輸入資訊,輸入完成後才會往下執行。有需要 input 的 stage 通常會搭配 when 條件,等滿足某些條件(比如說前一個 stage 建置失敗之類的),才會要求使用者輸入資訊,不然強制使用者輸入資訊的做法是不適用自動化 pipeline的。
    如下範例,是在 stage 開始前,要求使用者輸入 “First name” 才會往下執行。
pipeline {
agent none
stages {
stage('input') {
agent any
input {
message "What is your first name?"
ok "Submit"
parameters {
string(defaultValue: 'Justin', name: 'FIRST_NAME', trim: true)
}
}
steps {
echo "Good Morning, $FIRST_NAME"

}
}
}
}
  • when
    when 是用來作條件判斷的,決定所在的 stage 是否要執行。有以下的條件可以使用:

以下範例是結合了 input、when 以及下面會說明的 steps 寫的一份比較完整的 Jenkinsfile。這邊是當 “Build” stage 失敗時,會執行 “Input ticket number” stage,否則會 skip 該 stage。

預設狀況,在 stage 中會先要求 input 輸入,才會執行 when。但是可以在 when 中加上 beforeInput true ,讓 pipeline 先做 when 的判斷條件。

pipeline {
agent any
environment {
BUILD_FAILURE = false
}
stages {
stage('Clone from GitHub') {
steps {
git url: 'https://github.com/yourusername/your-repo.git'
}
}

stage('Build') {
steps {
script{
try {
error 'This stage always fails'
} catch (Exception e) {
echo 'Exception occurred: ' + e.toString()
BUILD_FAILURE = true
}
}
}
}

stage('Input Ticket Number') {
when {
beforeInput true
expression {
BUILD_FAILURE
}
}
input {
message "Is the error a known issue? If yes, please enter the ticket number"
ok "Report"
parameters {
string(defaultValue: 'xxx', name: 'NUMBER', trim: false)
}
}
steps {
echo "Known issue, ticket number: $NUMBER"
}
}
}

post {
success {
echo 'All stages passed successfully!'
}
failure {
echo 'Pipeline failed. Please input ticket number in the "Input Ticket Number" stage.'
}
}
}
  • steps
    真正的執行語句都是寫在 steps 裡的,steps 裡沒有必須設置的參數,把所有要做的事情都寫進去就是了。steps 區塊中,如果要寫 Scripted Pipeline 腳本,可以用 script{} 將 Scripted 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"
}
}
}
}
}
}
  • post
    post 用於後處理,位於 pipeline 或者 stage 內部。有以下的條件參數可以設置:
pipeline {
agent any
stages {
stage('init') {
steps {
echo 'Hello World'
}
}
}
post {
success {
echo 'success!'
sleep 2
}

always {
echo 'Done'
}
}

--

--

丁叮盯町
丁叮盯町

Written by 丁叮盯町

0 Followers

單純的程序猿,想寫些什麼記錄生活、記錄所學

No responses yet