相信所有的 GitLab 使用者一定都曾遇過一個狀況。即是好不容易撰寫了一份自覺完美的 .gitlab-ci.yml
,但在 git push
送出 Commit 之後,卻只得到 GitLab 介面上顯示著紅色的錯誤 yaml invalid
。(本文撰寫時,使用的 GitLab 版本為 13.8 。)
(本文同步發表於 Medium。)
(本來想要帥氣的展現 CI Pipeline,誰知道只看到 CI Pipeline 很糗的顯示 YAML 格式有錯!)
這種狀況不只會發生在 GitLab 新手,就連 GitLab 老手也經常發生。如果錯誤是因為寫錯 GitLab CI 專有的語法也就算了,畢竟 GitLab CI 越來越強大,有日漸複雜化的趨勢。但在真實情境中往往多半只是某一行 YAML 縮排沒正確對齊,導致出現 yaml invalid
,因而白白浪費了寶貴的時間。
為了幫助使用者們能夠避免上述的狀況,GitLab 目前已提供 CI Lint 功能,讓使用者可以在送出 Commit 前,事先檢查 .gitlab-ci.yml
是否撰寫正確。
CI Lint - GitLab WebUI
如想要以 WebUI 的方式使用 CI Lint,可以在 Project > CI/CD > Pipelines
介面的右上角找到它。
WebUI 使用起來非常方便,就是一個簡易的線上編輯器,我們只要將 .gitlab-ci.yml
的內容複製貼上於此,並按下 Validate
,即可得知是否撰寫正確。
按下 Validate
並通過 CI Lint 的檢查後,即可得到類似下圖的結果,CI Lint 不僅會告知你 Syntax is correct
,同時也會條列你目前規劃了哪些 CI Job。
當然,如果 .gitlab-ci.yml
撰寫有誤,CI Lint 也會告知錯誤的位置與原因。
(故意寫錯 YAML 縮排,得到上圖的結果。)
(如果 .gitlab-ci.yml
少寫了 stages:
,會得到上圖的錯誤提示。)
CI Lint - GitLab API
如果你是一位打死不用 UI 的超級硬漢工程師,那麼 GitLab CI Lint 也有提供 API 協助你檢查 .gitlab-ci.yml
。各位超級硬漢工程師可以利用 curl
將要檢查的 .gitlab-ci.yml
內容 POST 至 <your_gitlab_server>/ci/lint
即可。
除了 <your_gitlab_server>/ci/lint
之外,還有其他多個與 CI Lint 或檢查 Project 之 CI configuration 有關的 API。由於艦長沒這麼硬漢,所以 API 的詳細使用說明還請大家自行閱讀官方文件,這裡就不一一深入介紹。
(官方文件有詳細說明 POST 時,可以附加哪些 Attribute
。)
【小提醒】雖然 CI Lint 的 API 只是用來驗證
.gitlab-ci.yml
正確與否,但一樣需要通過 Authentication 才能正常使用,不然你只會得到{"message":"401 Unauthorized"}
的 Response。GitLab API 提供多種 Authentication 方式,包含 OAuth2 tokens、Personal access tokens、Project access tokens、Session cookie、GitLab CI/CD job token,大家可以根據各自的狀況自行選擇,而其中最簡單方便的方式是 Personal access tokens。
CI Lint - gitlab-ci-linter
如果你不是超級硬漢工程師,硬漢程度只達到普通等級,那麼艦長建議你可以省一點力氣,不妨試試這位 Olivier Robardet 撰寫的 gitlab-ci-linter。
gitlab-ci lint tool for validating .gitlab-ci.yml using Gitlab API. Can be used as git pre-commit hook. Can be used with custom Gitlab instance.
gitlab-ci-linter 是一個以 Go 語言撰寫的小工具,雖然它一樣是利用 GitLab API 幫我們檢查 .gitlab-ci.yml
,但透過它我們可以免去自己組合 curl
指令的步驟,可以更快速方便的完成 CI Lint 檢查。同時如上面工具簡介的描述,gitlab-ci-linter 可以很容易的整合進 git pre-commit hook
,藉此達成在送出 Commit 前就能自動觸發 CI Lint 檢查 .gitlab-ci.yml
。
作者在 Release page 只有 Build 供 linux-amd64、linux-arm 及 windows-386 這三種環境使用的版本,如果是 mac 的使用者,可以自行 Build。
# 如何在 mac 上 build gitlab-ci-linter
## 先安裝 go (這裡直接用 homebrew 安裝)
brew install go
## Clone 專案 gitlab-ci-linter
git clone git@gitlab.com:orobardet/gitlab-ci-linter.git
## 進入專案,並執行 make,最後就能在 .build/ 找到 gitlab-ci-linter
make
## 將它移動到 /usr/local/bin/,供後續使用
mv .build/gitlab-ci-linter /usr/local/bin/
安裝完畢後,讓我們隨便拿一個 .gitlab-ci.yml
來測試。
## 隨便開一個資料夾
mkdir testing_ci_lint
## 產生一個空白的 .gitlab-ci.yml
cd testing_ci_lint
touch .gitlab-ci.yml
## 執行 gitlab-ci-linter
gitlab-ci-linter
按著上述步驟執行,會得到下面的資訊。
首先 gitlab-ci-linter 會根據 .git
內記載的 remote origin 來判斷要使用哪一個 GitLab Server 的 API,如果找不到相關資訊,預設會使用 https://gitlab.com
的 API。如果你想要用自己架設 GitLab Server,那在執行時可以加上參數 --gitlab-url
或 -u
。
gitlab-ci-linter --gitlab-url <your_gitlab_server_url>
gitlab-ci-linter -u <your_gitlab_server_url>
另外因為 gitlab-ci-linter 依然是使用 GitLab API 幫我們檢查 .gitlab-ci.yml
,因此一樣有 Authentication 的問題需要解決。
讓我們先回到 gitlab.com 申請 Personal Access Token,在 Scopes 要勾選 api
。
取得 Token 之後,再次執行 gitlab-ci-linter,但要補上 --personal-access-token
或 -p
。
gitlab-ci-linter --personal-access-token <your_personal_access_token>
gitlab-ci-linter -p <your_personal_access_token>
這次就能得到正確的檢查結果。因為我們的 .gitlab-ci.yml
目前是一片空白,所以會拿到 Please provide content of .gitlab-ci.yml
的訊息。
後續各位可以嘗試修改 .gitlab-ci.yml
,在其中輸入正確或錯誤的內容,看看 gitlab-ci-linter 是否能順利幫你取得 CI Lint 的檢查結果。
(CI Lint 驗證成功,就會得到綠色的 OK
。)
gitlab-ci-linter 還有另一個功能是設置 git pre-commit hook
,如果你的 Project 尚未設置其他的 pre-commit,那麼你可以在 Project 路徑之下執行指令 gitlab-ci-linter install。gitlab-ci-linter
會幫你自動在 Project 的 .git/hooks
內新增一個名為 pre-commit
的檔案。
(該檔案其實只是指向 gitlab-ci-linter 的 link。)
透過 gitlab-ci-linter install
產生的 pre-commit
只適用在你沒有其它 git pre-commit hook
需要執行的情境。假如你在 pre-commit 階段還需要執行其他像是 Check code style、Unit testing 或 Detect credentials 的動作,那你就必須自行將 gitlab-ci-linter 整合至你既有的 pre-commit。
利用 Global pre-commit hook 在 Commit 之前自動執行 CI Lint
除了可以為單一 Project 設置 pre-commit,我們也可以考慮直接設置 Global pre-commit hook,讓所有 Project 在 Commit 之前都需要經過 CI Lint 檢查。
## 為 Global pre-commit hook 預備一個資料夾,通常會放在 User 的家目錄下
mkdir -p ~/gitconfig/hooks
## 建立 pre-commit
touch ~/gitconfig/hooks/pre-commit
## 給予執行權限
chmod +x ~/gitconfig/hooks/pre-commit
接著將以下的內容放進 ~/gitconfig/hooks/pre-commit
。
## 繼續非超硬派工程師的做法,艦長還是借助 gitlab-ci-linter。
## 記得要填寫正確的 gitlab-ci-linter 路徑,以及你的 GitLab Token。
/usr/local/bin/gitlab-ci-linter -p <your_gitlab_personal_access_token>
最後修改你的 Global Git config,並指定 hooksPath
。Global Git config 的檔案路徑通常會是 ~/.gitconfig
,開啟檔案後,修改 [core]
那一段,加入 hooksPath
。
[core]
hooksPath = ~/gitconfig/hooks
設定完畢後,如此一來每當你要 git commit
時,就必定會自動執行 CI Lint。
(就連透過 Sourcetree 這一類的 Git GUI 也會觸發 pre-commit。)
【小提醒】如果你手上的專案各式各樣,不同專案會用到的 Git hook 不盡相同,那也許 Global git hook 就不一定適用於你。針對此種情境,艦長建議大家可以研究如何讓 Global 與 Local git hook 兩者並行;或是你在撰寫或設定 Global git hook 時,可以替每一個 hook 動作都補上一些判斷式,例如先偵測專案的程式語言,再動態判斷要執行哪一個 Unit testing 指令;再不然你也可以考慮另外建立一個 Project 專門用來存放 Git hook 設定檔,每當有新的專案要開工時,就自行將 Git hook 的設定檔複製一份或連結至該專案的
.git/hooks
,將「設定 Git hook」視為是專案啟動或建立專案開發環境的一項必要動作。
結語
本文為大家介紹了 GitLab CI Lint,如果你也是 GitLab CI 的愛好者,艦長再次強烈建議一定要將 GitLab CI Lint 整合進你的 git pre-commit hook 中,養成每次送出 Commit 都會自動檢查 .gitlab-ci.yml
的好習慣,不然明明每次想要很帥的展現最新規劃完畢的 CI Pipeline,卻只在眾人面前秀出紅色的 Error 真的是很丟臉。(艦長出糗過好幾次。)
Git hook 是個好東西,特別是你看重良好團隊協作的時候。雖然本文只提及可以在 Git pre-commit hook 中加入 GitLab CI Lint,但聰明的你一定知道,其實我們可以利用 Git hook 作到更多的事情,例如為更多不同程式語言設置各種 Lint、自動修正 Code style 或檢查 Commit message 是否有按照團隊規定的格式撰寫⋯⋯。善用 Git hook 其實也是一種善用自動化工具的動作,這不僅有助於提升自身的生產力,也有助於團隊協作,希望大家都能一起當個又懶又有生產力的工程師!
你的團隊也有使用各種 Lint 或 Git hook 嗎?歡迎與我分享、或是來到 DevOps Taiwan Community 公開分享你的經驗喔。
參考資料
- https://docs.gitlab.com/ee/api/lint.html
- https://gitlab.com/orobardet/gitlab-ci-linter
- https://towardsdatascience.com/pre-commit-hooks-you-must-know-ff247f5feb7e
- https://medium.com/@ripoche.b/using-global-pre-commit-hook-to-prevent-committing-unwanted-code-edbbf957ad12
- https://mropengate.blogspot.com/2019/08/pre-commit-git-hooks_4.html
- https://dotblogs.com.tw/AceLee/2020/04/07/002126