iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 9
0
DevOps

用 GitLab CI 玩轉自動化測試與佈署系列 第 9

Day09 - GitLab CI 流水線上的每個工作都要執行嗎?再談工作執行條件設定

上一篇提到了在 .gitlab-ci.yml 中使用 when 來定義依據前一關卡的執行結果執行這個工作,但 when 這個屬性只能根據之前的關卡來設定什麼時候開始只行,如果是要依據此次 Git 上的一些特徵來執行,該怎麼處理呢?

透過 onlyexcept 來根據 Git Repo 的內容執行

.gitlab-ci.yml 中可以透過 onlyexcept 兩個來設定,目前的這個工作「只在」或「不在」什麼條件下執行,且這兩個參數,都可以使用一些特別的關鍵字,如目前 GitLab 官方手冊上所說,可以使用的關鍵字如下:

關鍵字 描述
api 透過 pipelines API 啟動
branches 當目前啟動啟用流水線的 Git Reference 是一個 Git 分支時
chat 當流水線是透過 GitLab ChatOps 的指令啟動時
external 當使用的是外部的持續整合(CI)服務時(此法目前尚未找到範例,尚不知如何判斷是外部 CI 服務)
external_pull_requests 當從外部發起 Pull Request 的時候。(細部說明可自官方手冊查看).
merge_requests 只在合併請求 (merge request) 建立或更新時。細部功能可查看。手冊中 merge request pipelinesmerged results pipelinesmerge trains 三個頁面。
pipelines 使用在 multi-project pipelines 透過 API 搭配 CI_JOB_TOKENtrigger 觸發關鍵字建立。
pushes 當 Pipeline 是透過 git push 事件所觸發而建立的時候。
schedules 當為設定之排程而啟用的流水線 Pipelines.
tags 當目前啟動啟用流水線的 Git Reference 是一個 tag 時。
triggers 當流水線是透過 trigger token 啟動時。
web 當流水線是透過 Web 介面上「run pipeline」所啟動執行時。

在這邊,以 only 舉例來說:

job:
  only:
    - tags
    - triggers
    - schedules

上面的這個例子,這個工作,就只會發生在目前工作流程流水線使用的 Git Reference 上有 tags」透過 trigger 觸發時透過排程啟動時才會執行這個工作。

反之,如果是 except 則剛好相反,當 Git Reference 上有 tags 透過 trigger 觸發時透過排程啟動時才會執行這個工作,「都不執行」這個工作。

job:
  except:
    - tags
    - triggers
    - schedules

另外,除了關鍵字的使用,一般的使用上也可以針對 Git Reference 作字串的比較,目前支援 RE2 作為進階的字串比較(正規表示式 regexp 在 GitLab 11.9.4 之後停止支援),當符合條件時,執行這個工作,舉官方手冊上的例子來說:

job:
  only:
    - /^issue-.*$/

上面的這個例子,透過 RE2 的分析後,這個工作,就只會在 Git Reference 符合 issue- 開頭的時候執行。這特性也適合用在特定分支名稱才執行某些工作的場景,像是 feature 分支才需要進行原始碼格式檢查之類的工作。

另外,也可以透過 RE2 的 i 標籤來做字母大小寫同時比對,舉例來說:

job:
  only:
    - /^issue-.*$/i

上面的這個例子,不管是 git 分支名稱 ISSUE-Issue- 開頭,均會執行。

在同一個工作中 onlyexcept 是否可以同時存在?

在 GitLab CI 的設計中 onlyexcept 是可以一起使用的。但是必須要注意兩者均不存在交集的情境,當發生 onlyexcept 不存在交集的情境時,則該工作會永遠被跳過。以底下的例子:

default:
  image: ubuntu:20.04

build:
  stage: build
  script:
    - echo "BUILD_VERSION=hello" >> variable.env
    - echo "BUILD_NAME=GitLab" >> variable.env

deploy:
  stage: deploy
  script:
    - echo 'do deploy process'
  only:
    - /^master/i
  except:
    - branches

上面的這個例子流水線案例,執行在 master 分支上,而 deploy 這個工作,因為在 only 中使用了 RE2 描述 /^master/i 代表 Git Reference 名稱不分大小寫符合 master 開頭的均執行,而 except 的部分,描述了只要 Git Reference 是一個分支,就「不」執行,兩個條件在 master 上均成立,因此最終 deploy 的工作直接跳過不執行

搭配變數更進階的使用 onlyexcept

在 GitLab CI 的設計裡 onlyexcept 還可以進行更複雜的進階使用,但截至目前的 13.3 版本,都還是將這些功能都還是 alpha 階段,未來可能會移除或調整,因此在使用上要特別注意。

在進階使用裡頭,額外支援四個關鍵字:

  • refs:分之名稱
  • variables:變數對應之字串是否符合
  • changes:檔案如有變更
  • kubernetes:專案中的 kubernetes 服務是否啟動

這四個關鍵字,在 only 的使用上,彼此之間是以「 AND 並且」的條件來執行的,必須都有通過才會執行,以官方手冊上面的這個例子:

test:
  script: npm run test
  only:
    refs:
      - master
      - schedules
    variables:
      - $CI_COMMIT_MESSAGE =~ /run-end-to-end-tests/
    kubernetes: active

上面的例子表示,這個工作只有在底下的三個條件「均成立」才會執行:

  1. 分支為 master 或 透過排程執行
  2. 變數中 GIT 的 commit 訊息包含「run-end-to-end-tests」
  3. kubernetes 的服務是啟用中的

但在 except 的使用上則是「OR 或」的條件來執行,只要其中一個條件符合,則該工作就「不」執行。同樣以官方手冊上的範例:

test:
  script: npm run test
  except:
    refs:
      - master
    changes:
      - "README.md"

上面的例子,當底下的這兩個條件,只要其中一個成立,都「不」執行:

  1. 當分支為 master
  2. 當變更的檔案包含 README.md

當某些檔案有變更時,才執行或不執行某工作

在上面的例子中,可以透過 changes 這個參數來判斷哪些檔案變更,才執行或不執行什麼工作。則如果一個專案同時置放了前端與後端的原始碼,且前後端都有對應的單元測試程式,那麼就可以透過這特性,讓前端或後端的測試,僅執行在前後端對應的原始碼有變更的時候。如底下的範例,該這個 front_test 工作,僅會在對應的資料夾下有檔案變更時才進行工作 :

front_test:
  script:
    - echo 'front test'
  only:
    changes:
      - front/src/*
      - front/tests/*

如兩個執行結果,其一,因為新增了 front/srcfront/tests 底下的檔案,則front_test 有執行

有執行前端測試圖

其二,因為僅變更根目錄下的 README.md 檔案,則 front_test 不執行

沒有執行前端測試圖

總結

onlyexcept 的使用上要特別注意是否預想的條件如設計中的成立,實務使用上,會遇到 RE2 撰寫的規則實際執行後不如自己所想的,可以透過一些線上工具先做過測試確認。

關於 GitLab CI 上的條件執行,還有 rules 尚未介紹到,會出現在下一篇。我是墨嗓(陳佑竹),期待這系列的文章能夠讓人有些幫助。


上一篇
Day08 - GitLab CI 流水線上的每個工作都要執行嗎?談工作執行條件設定
下一篇
Day10 - GitLab CI 流水線上的每個工作都要執行嗎?三談工作執行的條件設定
系列文
用 GitLab CI 玩轉自動化測試與佈署31

尚未有邦友留言

立即登入留言