總結(jié):四個Pipeline腳本式與聲明式語法差異
如果您閱讀此博客文章,則很有可能正在尋找有關(guān)腳本化和聲明性管道之間的實際差異的信息,對嗎?那你找不到更好的地方了。我將向您展示這兩者之間的四個最實際的區(qū)別。和我待幾分鐘,享受旅程!
為什么要有兩種管道類型?
- 腳本化管道是Jenkins中作為代碼的管道的第一個實現(xiàn)。即使它使用底層的管道子系統(tǒng),它還是或多或少地設(shè)計為使用Groovy構(gòu)建的通用DSL。這意味著它不具有固定的結(jié)構(gòu),并且由您決定如何定義管道邏輯。
- 聲明性管道更自以為是,其結(jié)構(gòu)是明確定義的??赡芸雌饋碛行┚窒?。
但實際上,您可以使用腳本化或聲明性管道來實現(xiàn)相同的目的。那么選擇哪一個呢?如果您問我這個問題,我會說使用聲明性管道。以下內(nèi)容這就是為什么。
1.管道啟動時的代碼驗證
- pipeline {
- agent any
- stages {
- stage("Build") {
- steps {
- echo "Some code compilation here..."
- }
- }
- stage("Test") {
- steps {
- echo "Some tests execution here..."
- echo 1
- }
- }
- }
- }
如果我們嘗試運(yùn)行以下管道,則驗證將很快使構(gòu)建失敗。該日志顯示只能與觸發(fā)String參數(shù),所以我們得到這樣的錯誤。

請注意,管道沒有執(zhí)行任何階段,只是失敗了。這可能為我們節(jié)省了很多時間-想象一下執(zhí)行Build階段幾分鐘,而只是獲取echo步驟希望得到的信息java.lang.String而不是java.lang.Integer。
現(xiàn)在,讓我們看一下與該示例等效的腳本管道。
- node {
- stage("Build") {
- echo "Some code compilation here..."
- }
- stage("Test") {
- echo "Some tests execution here..."
- echo 1
- }
- }
該管道執(zhí)行相同的階段和相同的步驟。但是,有一個明顯的區(qū)別。讓我們執(zhí)行它,看看它產(chǎn)生什么結(jié)果。

它按預(yù)期失敗。但是這次是執(zhí)行Build階段,也是Test階段的第一步。如您所見,沒有驗證管道代碼。在這種情況下,聲明式管道可以更好地處理此類用例。
2.從指定步驟重新開始
聲明式管道具有的另一個很酷的功能是“從階段重新啟動”。讓我們修復(fù)上一個示例中的管道,看看是否只能重新啟動Test階段。
- pipeline {
- agent any
- stages {
- stage("Build") {
- steps {
- echo "Some code compilation here..."
- }
- }
- stage("Test") {
- steps {
- echo "Some tests execution here..."
- }
- }
- }
- }
讓我們執(zhí)行它。

在這里您可以看到已選擇測試階段。在右側(cè)的步驟列表上方,有一個名為“重新啟動測試”的選項。讓我們單擊它并查看結(jié)果。

如您所見,Jenkins跳過了Build階段(它使用了先前構(gòu)建中的工作空間),并從Test階段開始了下一個管道執(zhí)行。當(dāng)您執(zhí)行一些外部測試并且由于遠(yuǎn)程環(huán)境的某些問題而導(dǎo)致測試失敗時,這可能會很有用。您可以使用測試環(huán)境解決問題,然后重新運(yùn)行該階段,而無需重建所有工件。(在這種情況下,應(yīng)用程序的代碼未更改。)
現(xiàn)在,讓我們看一下腳本化管道示例。
- node {
- stage("Build") {
- echo "Some code compilation here..."
- }
- stage("Test") {
- echo "Some tests execution here..."
- }
- }
如您所見,沒有重新啟動選項。聲明式管道與腳本式管道-2:0。
3.聲明式管道options塊
兩種管道類型都支持第三個功能,但是我認(rèn)為聲明性管道更好地處理了它。假設(shè)我們將以下功能添加到上一個管道中。
- 控制臺日志中的時間戳。
- ANSI顏色輸出。
- 在1分鐘的超時構(gòu)建階段,2分鐘超時的測試階段。
聲明式管道如下所示。
- pipeline {
- agent any
- options {
- timestamps()
- ansiColor("xterm")
- }
- stages {
- stage("Build") {
- options {
- timeout(time: 1, unit: "MINUTES")
- }
- steps {
- sh 'printf "\\e[31mSome code compilation here...\\e[0m\\n"'
- }
- }
- stage("Test") {
- options {
- timeout(time: 2, unit: "MINUTES")
- }
- steps {
- sh 'printf "\\e[31mSome tests execution here...\\e[0m\\n"'
- }
- }
- }
- }
讓我們運(yùn)行它。

這是控制臺日志。
- Started by user Szymon Stepniak
- Running in Durability level: MAX_SURVIVABILITY
- [Pipeline] Start of Pipeline
- [Pipeline] node
- Running on Jenkins in /home/wololock/.jenkins/workspace/pipeline-sandbox
- [Pipeline] {
- [Pipeline] timestamps
- [Pipeline] {
- [Pipeline] ansiColor
- [Pipeline] {
- [Pipeline] stage
- [Pipeline] { (Build)
- [Pipeline] timeout
- 15:10:04 Timeout set to expire in 1 min 0 sec
- [Pipeline] {
- [Pipeline] sh
- 15:10:04 + printf '\e[31mSome code compilation here...\e[0m\n'
- 15:10:04 Some code compilation here...
- [Pipeline] }
- [Pipeline] // timeout
- [Pipeline] }
- [Pipeline] // stage
- [Pipeline] stage
- [Pipeline] { (Test)
- [Pipeline] timeout
- 15:10:04 Timeout set to expire in 2 min 0 sec
- [Pipeline] {
- [Pipeline] sh
- 15:10:05 + printf '\e[31mSome tests execution here...\e[0m\n'
- 15:10:05 Some tests execution here...
- [Pipeline] }
- [Pipeline] // timeout
- [Pipeline] }
- [Pipeline] // stage
- [Pipeline] }
- [Pipeline] // ansiColor
- [Pipeline] }
- [Pipeline] // timestamps
- [Pipeline] }
- [Pipeline] // node
- [Pipeline] End of Pipeline
- Finished: SUCCESS
在聲明性管道中,選項與管道腳本邏輯分開。該腳本管道也支持timestamps,ansiColor和timeout選項,但它需要一個不同的代碼。這是使用腳本化管道表達(dá)的相同管道。
- node {
- timestamps {
- ansiColor("xterm") {
- stage("Build") {
- timeout(time: 1, unit: "MINUTES") {
- sh 'printf "\\e[31mSome code compilation here...\\e[0m\\n"'
- }
- }
- stage("Test") {
- timeout(time: 2, unit: "MINUTES") {
- sh 'printf "\\e[31mSome tests execution here...\\e[0m\\n"'
- }
- }
- }
- }
- }
我想你看到了問題。在這里,我們僅使用timestamps和ansiColorJenkins插件。想象再添加一個或兩個插件。聲明式與腳本式,3:0。
4.用when塊跳過階段。
在此博客文章中我最后要提到的是when聲明性管道支持的塊。讓我們改進(jìn)前面的示例并添加以下條件:
- 僅在等于時執(zhí)行測試階段。env.FOO``bar
這是聲明性管道代碼的外觀。
- pipeline {
- agent any
- options {
- timestamps()
- ansiColor("xterm")
- }
- stages {
- stage("Build") {
- options {
- timeout(time: 1, unit: "MINUTES")
- }
- steps {
- sh 'printf "\\e[31mSome code compilation here...\\e[0m\\n"'
- }
- }
- stage("Test") {
- when {
- environment name: "FOO", value: "bar"
- }
- options {
- timeout(time: 2, unit: "MINUTES")
- }
- steps {
- sh 'printf "\\e[31mSome tests execution here...\\e[0m\\n"'
- }
- }
- }
- }
然后執(zhí)行它。

該測試如預(yù)期階段被跳過。現(xiàn)在,讓我們嘗試在腳本化管道示例中執(zhí)行相同的操作。
- node {
- timestamps {
- ansiColor("xterm") {
- stage("Build") {
- timeout(time: 1, unit: "MINUTES") {
- sh 'printf "\\e[31mSome code compilation here...\\e[0m\\n"'
- }
- }
- if (env.FOO == "bar") {
- stage("Test") {
- timeout(time: 2, unit: "MINUTES") {
- sh 'printf "\\e[31mSome tests execution here...\\e[0m\\n"'
- }
- }
- }
- }
- }
- }
如您所見,我們必須使用if-condition來檢查是否env.FOO等于bar,然后才添加Test階段。(不幸的是,這并不是真正的跳過。)讓我們運(yùn)行它,看看結(jié)果如何。

這是不同的結(jié)果。在腳本化管道用例中,甚至不會呈現(xiàn)“ 測試”階段。在我看來,這可能會帶來一些不必要的混亂,聲明性管道會更好地處理它。聲明式與腳本式,4:0。
結(jié)論
這是我在聲明性和腳本化Jenkins管道之間的四大區(qū)別。這些不是唯一的區(qū)別,我想您的列表可能看起來有些不同。你的選擇是什么?您更喜歡聲明性管道還是腳本化管道?