程式碼品質是軟體開發的關鍵環節,而 CI/CD Pipeline則提供了一個自動化平台,能有效整合程式碼品質驗證流程。GitLab 的 Code Quality 功能,可視為增強版的 linting 工具,能深入分析程式碼,涵蓋效能、風格、複雜度、安全性等導向,並能識別出可能導致錯誤的程式碼模式,例如引數過多的函式、過於複雜的邏輯運算式等。此外,它也支援整合既有的程式碼風格規範,如 Python 的 PEP-8。啟用 Code Quality 功能相當簡便,只需在 .gitlab-ci.yml 檔案中引入 GitLab 提供的範本即可。Code Quality 報告會顯示在Pipeline詳細資料頁面和合併請求中,提供程式碼問題的詳細資訊,方便開發者快速定位和修復問題。不同於傳統 linting 工具,Code Quality 提供更全面的分析,能更有效地提升程式碼品質。
在 CI/CD Pipeline中執行自動化功能測試,能確保程式碼的正確性。以 Python 的 pytest 框架為例,我們可以編寫單元測試來驗證程式碼功能。在 .gitlab-ci.yml 檔案中定義測試作業,指定測試指令碼和執行環境。為了更清晰地呈現測試結果,可以將測試輸出以 JUnit 格式儲存,並設定為 GitLab 工件。如此一來,測試結果會顯示在Pipeline的「Tests」頁籤中,提供測試透過/失敗的統計資料,以及每個測試的詳細資訊,方便開發者快速診斷和解決問題。合併請求中的測試報告則能顯示分支與預設分支之間的測試結果差異,方便追蹤程式碼變更對測試結果的影響。
模糊測試是一種有效的程式碼錯誤偵測方法,它透過向程式碼函式傳送半隨機資料,嘗試觸發錯誤。在 GitLab 中,可以使用覆寫率導向模糊測試或 Web API 模糊測試。覆寫率導向模糊測試需要定義待測函式、CI/CD 作業、模糊引擎和模糊目標。模糊引擎會自動產生測試資料,並監控程式碼執行狀況,一旦發現錯誤,就會記錄下來。雖然模糊測試的組態較為複雜,但它能有效發現其他測試方法難以發現的錯誤,提升程式碼的健壯性。
在 CI/CD Pipeline中驗證及檢查程式碼品質
在 CI/CD Pipeline組態中,artifacts 是最重要的關鍵字之一,因為它能讓你在後續的工作中存取生成的檔案。忽略這個關鍵字是常見的錯誤之一,因此當你的Pipeline不如預期執行時,應該首先檢查是否在所有生成檔案的工作中都正確指定了 artifacts。現在,我們已經瞭解如何在 CI/CD Pipeline中編譯你的程式碼,接下來讓我們來探討通常是下一步Pipeline操作:檢查程式碼品質。
在 CI/CD Pipeline中檢查程式碼品質
GitLab 提供多種掃描器來幫助你在 CI/CD Pipeline中確保你的專案符合某些品質標準,其中一個特別功能就是「程式碼品質」(Code Quality)。如果你曾經使用過任何形式的 linting 工具,可以將這個功能視為「增強版的 linting 工具」。
Code Quality 功能依賴外部服務 Code Climate。儘管這個服務可以掃描所有主要電腦語言,但並非所有語言都受支援。你可以參考 Code Climate 的官方檔案來檢視支援的語言清單,但可以放心的是它能夠與 Java、Python、Ruby、JavaScript 以及其他常見語言完美配合。
Code Quality 功能主要關注以下幾個類別:
- 效能
- 風格
- 複雜度
- 安全性
- 程式碼問題(例如可能導致錯誤的模式)
具體而言,它可能會偵測到以下問題:
- 擁有過多引數的函式
- 具有過多出口點的函式
- 過長的函式或類別
- 過於複雜的邏輯表示式
- 不合理的垂直空白
- 重複程式碼
此外,如果你使用的是具有已建立樣式規範的語言(例如 Python 的 PEP-8 標準或 Ruby 的 Rubocop 規格),Code Quality 功能也可以組態為包含這些規則。
啟用程式碼品質
要將 Code Quality 新增到你的 CI/CD Pipeline中,步驟非常簡單:
確保你的Pipeline有一個測試階段已定義(提示:它幾乎肯定已經存在這個階段,所以你大概不需要做任何事情)。
包含一個 GitLab 提供的範本(即包含額外 CI/CD 組態程式碼的檔案),名為
Code-Quality.gitlab-ci.yml,這將新增一個 Code Quality 工作到你的Pipeline中。
第一步在專案 .gitlab-ci.yml 檔案中看起來應該像這樣:
stages:
- test
第二步應該像這樣:
include:
template: Code-Quality.gitlab-ci.yml
需要注意的是,如果你已經定義了其他階段,則在第 一步 中你只需將測試階段新增到現有階段即可——不需要刪除任何現有階段。同樣地,如果你的Pipeline組態程式碼已經包含其他範本,則在第 二步 中你應該將新範本新增到現有範本而不是替換它們。
Code Quality 功能足夠智慧以偵測你 GitLab 專案中的所有電腦語言並執行適當的掃描器。然而,重要的是要理解由於這些掃描器由不同的人或團隊開發且外部於 GitLab,因此沒有保證掃描器會在所有支援語言中找到相同問題。例如,一種語言的掃描器可能特別擅長偵測重複程式碼片段,而另一種語言的掃描器則可能特別擅長指出應簡化複雜程式碼。
檢視程式碼品質結果
讓我們來看看 Code Quality 的具體運作例項。假設你有一個名為 hats-for-cats.py 的檔案位於專案倉函式庫根目錄下面包含以下程式碼:
def register(username, password, phone, city, state, zip):
# TODO finish this code
這段程式碼有兩個問題:函式引數過多且 TODO 註解應該被處理並移除。如果啟用專案Pipeline中的 Code Quality 並執行Pipeline後,Pipeline詳細資料頁面將包括一個名為 Code Quality 的新標籤頁面以顯示 Code Quality 掃描結果:

還有一個地方可以檢視相同資訊:在合併請求中。不過在合併請求中的報告與Pipeline詳細頁面上的報告有一個重要差異。雖然Pipeline詳細頁面報告顯示出執行該Pipeline所在分支上的所有程式碼品質問題,但合併請求報告顯示的是源分支和目標分支之間程式碼品質問題差異。由於目標分支通常是專案的預設分支(例如 main 或 master),因此合併請求報告會顯示出來源分支上的工作是否增加或修復了程式碼品質問題。
舉例來說,假設你建立了一個分支、對該分支進行了合併請求並提交了一項更改以移除 TODO 註解並新增一項新 FIXME 註解。那麼我們預期 Code Quality 報告會顯示一項舊問題(TODO)已被修復且一項新問題(FIXME)已被新增。而這正是合併請求報告中顯示的內容:

兩個報告位置—Pipeline詳細資料頁面和合併請求—均有每個偵測到問題的一項條目。這些條目會告訴你每個問題的名稱、檔案名稱以及該問題發生所在行號。這些資訊應該足夠讓你決定是否修復或忽略每個問題。
GitLab 中啟用 Code Quality 的範例
stages:
- test
include:
template: Code-Quality.gitlab-ci.yml
# 其他組態...
此圖示展示瞭如何整合 GitLab 提供的 Code-Quality.gitlab-ci.yml 檔案以啟用 Code Quality 功能。
內容解密:
在此範例中,玄貓展示如何在 GitLab CI/CD Pipeline中整合 Code Quality 功能。
- stages: 定義Pipeline階段。
- include: 包含 GitLab 提供的
Code-Quality.gitlab-ci.yml檔案以啟用 Code Quality 功能。 - 其他組態: 其他可能存在於
.gitlab-ci.yml檔案中的組態選項。
傳統 linting 工具 vs. Code Quality
傳統 linting 工具主要集中於檢查程式碼風格和基本語法錯誤。然而 GitLab 的 Code Quality 功能除了提供基本 linting 外還提供更深入的程式碼品質分析。
此圖示展示了傳統 linting 工具和 Code Quality 功能之間關鍵區別。
內容解密:
- 傳統 linting 工具:主要集中於檢查程式碼風格和基本語法錯誤。
- GitLab Code Quality:除了基本 linting 外還提供更深入程式碼品質分析。
- 深入分析:GitLab 的 Code Quality 功能可以偵測效能、風格、複雜度、安全性和潛在錯誤等方面問題。
技術選型及未來趨勢
目前市場上有多種工具可以用來進行程式碼品品檢查。GitLab 的 Code Climate 是其中之一且具有獨特優勢:
- 多語言支援:支援主流程式語言。
- 自動化:無需手動設定複雜組態即可快速啟用。
- 深入分析:除了基本 linting 外還提供更深入程式碼品質分析。
未來趨勢:
- AI 和機器學習:AI 和機器學習技術可能會進一步提升程式碼品質分析工具能力。
- 持續整合:隨著 DevOps 文化逐漸普及,持續整合(CI)和持續佈署(CD)工具將更加融合進開發工作流程。
- 自動化修復:未來可能會看到更多自動化修復工具出現以減少開發人員手動修復程式碼錯誤所需時間。
自動化功能測試在 CI/CD 管道中的執行
在 CI/CD 管道中執行自動化功能測試是最常見的任務之一,這樣可以確保你的程式碼按預期執行。例如,你可能會使用 pytest 框架來執行一組 Python 編寫的單元測試,以測試你的 Hats for Cats 應用。讓我們來看看如何在 GitLab 中完成這個任務。
啟用自動化功能測試
假設你已經編寫了三個根據 pytest 的單元測試,以確保 Hats for Cats 應用的登入功能按預期執行。你可能有一個名為 test/test_login.py 的檔案,內容如下:
def test_login():
# 新增嘗試使用正確憑證登入的程式碼
assert True
def test_login_bad_password():
# 新增嘗試使用錯誤密碼登入的程式碼
assert True
def test_login_no_password():
# 新增嘗試不使用密碼登入的程式碼
assert False
顯然,這些範例測試中包含強制前兩個測試透過、第三個失敗的佔位程式碼。真實的測試會包含各種方式執行登入功能的邏輯,但這些簡化的範例使得 GitLab 的自動測試功能更容易展示。
內容解密:
以上程式碼展示了三個簡單的單元測試函式,分別用於測試不同情況下的登入功能。這些函式使用 Python 的 assert 陳述式來檢查預期結果。第一個和第二個測試總是透過,因為它們強制 assert 陳述式為 True;而第三個測試總是失敗,因為它強制 assert 陳述式為 False。
def test_login():
# 嘗試使用正確憑證登入
assert True # 這裡應該有實際的登入邏輯和檢查
def test_login_bad_password():
# 嘗試使用錯誤密碼登入
assert True # 這裡應該有實際的錯誤密碼檢查邏輯
def test_login_no_password():
# 嘗試不使用密碼登入
assert False # 這裡應該有實際的無密碼檢查邏輯
在管道中執行這些自動化測試
要在管道中執行這些自動化測試,只需新增一個觸發它們的作業,就像你在命令列中所做的一樣:
unit-tests:
stage: test
image: python:3.10
script:
- pip install pytest
- pytest test/
此作業定義指定作業屬於 test 階段,並且必須在安裝了 Python 3.10 的 Docker 槽中執行。它執行的命令首先使用 pip 包管理器安裝 pytest 包,然後呼叫新安裝的 pytest 命令來執行位於 test/ 目錄中的所有單元測試。
內容解密:
以上組態展示了一個簡單的 GitLab CI/CD 作業定義。作業名稱為 unit-tests,屬於 test 階段。它使用了 Python 3.10 的 Docker 槽。作業中的 script 欄位定義了兩個命令:
pip install pytest:使用 Python 的包管理器pip安裝pytest。pytest test/:執行位於test/目錄中的所有單元測試。
unit-tests:
stage: test # 指定作業屬於 'test' 階段
image: python:3.10 # 指定使用 Python 3.10 的 Docker 槽
script:
- pip install pytest # 安裝 pytest 包
- pytest test/ # 執行 'test/' 目錄中的所有單元測試
驗證程式碼
新增此作業並執行管道後,你可以檢視作業輸出並看到測試確實已經執行。你甚至可以看到每個測試的透過/失敗結果。然而,作業輸出難以解析且有些晦澀。如果自動化測試結果能夠顯示在 GitLab GUI 中一個易於閱讀的表格中該多好?幸運的是,GitLab 恰好可以做到這一點。你只需稍微調整一下作業定義,使其將單元測試輸出儲存在特定格式中,然後將該結果檔案儲存為 GitLab 工件。
在現有的 unit-tests 作業定義末尾新增以下程式碼即可:
artifacts:
reports:
junit: unit_test_results.xml
when: always
此程式碼告訴 GitLab 需要保留由 pytest 框架產生的 unit_test_results.xml 檔案。它還指定此檔案是包含以 JUnit 格式儲存之測試結果之報告。最後,它告訴 GitLab 在任何一個測試失敗時仍需要保留此檔案。
內容解密:
以上組態展示了一個 GitLab CI/CD 作業中如何儲存和保留單元測試結果。關鍵部分如下:
artifacts: 指定要保留哪些檔案。reports: 指定要報告哪些型別的結果。junit: unit_test_results.xml: 指定要報告 JUnit 格式的單元測試結果檔案。when: always: 指定即使有測試失敗也要保留此工件檔案。
artifacts:
reports:
junit: unit_test_results.xml # 指定 JUnit 格式之單元測試結果檔案
when: always # 始終保留此工件檔案, 不論是否有測試失敗
檢視自動化功能測試結果
新增上述描述之附加程式碼並執行新管道例項後,將在管道詳細資訊頁面上出現一個標記為「Tests」之新頁籤。點選該頁籤會顯示多少自動化測試透過以及多少失敗之概覽:
檢視自動化功能測試結果(圖示)
| 作業名稱 | 測試總數 | 測試透過 | 測試失敗 |
|
---
-
---
---
|
---
-
---
---
|
---
-
---
---
|
---
-
---
---
|
| unit-tests | N | M | K |
此圖表顯示每個觸發自動化測試之作業一行。點選任何行會進一步分解結果,讓你看到具體哪些測試透過或失敗:
檢視單個自動化測試結果(圖示)
| 測試名稱 | 測試狀態 |
|
---
-
---
-
---
-
---
-
---
-
---
-|
---
-
---
---
|
| test_login | Passed |
| test_login_bad_password| Passed |
| test_login_no_password | Failed |
如你所料, 每個測試旁邊的「檢視詳情」按鈕會顯示更多關於該測試之資訊, 包括產生失敗斷言之程式碼行和過去該測試失敗歷史。這些資訊有助於除錯產品程式碼—or if the problem lies in your test.
檢視單個自動化測試詳細資訊(圖示)
Test Name: test_login_no_password
Status: Failed
Details:
- Assertion failed at line X in file Y.
- History of failures: This test has failed N times in the past.
檢視分支合併請求中的功能測試結果
在管道詳細資訊頁面上檢視功能測試結果會顯示您所執行管道對比之分支上所有程式碼之測試結果。有時這是您想要得到之結果, 其他時候您想知道分支上的程式碼是否與專案預設分支相比出現任何新測試失敗(或修復任何失敗測試)。
合併請求中的自動化功能測試報告會顯示這個資訊。想象一下, 您正在一個分支上工作, 您成功地修復了一個在預設分支上失敗之測試, 改變了一個曾經透過之測試, 引入了一個新透過之測試以及引入了一個新失敗之測試。 合併請求將展示類別似以下格式之報告:
| 流程 | 流程狀態 |
|
---
-
---
-
---
-
---
--|
---
-
---
-
---
-
---
-
---
|
| 新增及修改現有 | 剛剛修復一項失敗 |
| | 改變一項成功 |
| | 新增一項成功 |
| | 新增一項失敗 |
模糊測試在 CI/CD 管道中的執行
模糊測試是一種不同於傳統方式發現程式碼中的錯誤之替代方法。簡潔地講, 高階測試技術向您程式碼函式傳送半隨機資料來嘗試觸發錯誤。雖然它需要比其他掃描器更多工作來組態,但可以透過發現您可能從未使用其他方法發現錯誤來產生回報。
模糊招募有兩種執行方法:覆寫率導向模糊招募以及web API 模糊招募。 我們將專注於前者,但這兩種技術足夠相似,所以如果您理解了一種技術,您就很容易學習另一種技術透過 GitLab 的官方檔案。
模糊招募結構及流程
您需要了解四個架構元件才能使用覆寫率導向模糊招募:
- 需要招募程式碼。
- CI/CD 工作。
- 模糊引擎。
- 模糊目標。
需要招募程式碼
模糊招募針對單個函式於您程式碼中進行招募。 該函式可以以 GitLab 模糊招募支援任何語言編寫,並且可以為任何長度。 該函式至少需要一個引數但是沒有預期引數數量上限。 該函式可以呼叫其他函式,並且如果該呼叫堆疊內任意位置觸發錯誤,模糊招募器就會報告該錯誤。
def vulnerable_function(data):
if len(data) > 100:
raise ValueError("Data too long")
return data[0]
內容解密:
以上程式碼展示了一個簡單且可能存在漏洞的函式範例,此函式接受引數並根據引數長度進行處理。如果引數長度超過100則引發例外錯誤:
def vulnerable_function(data):
if len(data) > 100:
raise ValueError("Data too long")
return data[0]
此處主要考量點包括:
- 引數驗證:檢查輸入引數是否符合預期條件(例如長度限制),避免因過長或過短導致錯誤。
- 例外處理:當引數不符合條件時引發適當例外以供調錯與追蹤問題源頭。
- 安全性:避免因惡意輸入造成應用當機或潛在安全漏洞。
模糊引擎與目標
GitLab 提供模糊引擎來協助進行模糊招募操作與目標擇選; 各組成部分依照預設與順序協同工作去實作模糊招募:
fuzz-tests:
stage: fuzz-testing
image: ubuntu-latest
before_script:
# Set up the environment for fuzz testing.
# Install dependencies and configure tools as needed.
script:
# Run fuzz testing commands and collect results.
after_script:
# Clean up and archive results.
內容解密:
以上程式碼展示瞭如何在GitLab CI/CD 中組態模糊染色執行環境及流程:
fuzz-tests:
stage: fuzz-testing # 指定執行階段為 "fuzz-testing"
image: ubuntu-latest # 指定使用 Ubuntu 最新版本 Docker 槽作為執行環境
before_script:
# Setup environment for fuzz testing. # 組態環境設定步驟 (例如安裝依賴項)
# Install dependencies and configure tools as needed. # 安裝必要依賴項並組態相關工具
script:
# Run fuzz testing commands and collect results. # 執行模糊染色命令和收集結果步驟 (具體命令視專案情況而異)
after_script:
# Clean up and archive results # 清理與歸檔結果步驟 (例如壓縮記錄日誌)
主要考量點包括:
- 環境準備:首先確保專案正確安裝所需環境與依賴專案與工具以進行成功完成模糊染色流程。
- 執行命令:透過指令執行模糊染色操作並收集相關結果 (具體指令取決於專案設定).
- 清理與備份:完成所有流程後記錄日誌進行壓縮備份可供日後調閱與分析目的使整體工作更加完善與高效。
CI/CD Pipeline中的模糊染色流程:
此圖示展現了常見CI/CDPipeline結構與流程:
@startuml
skinparam backgroundColor #FEFEFE
title CI/CD 流水執行緒式碼品質驗證與模糊測試實踐
|開發者|
start
:提交程式碼;
:推送到 Git;
|CI 系統|
:觸發建置;
:執行單元測試;
:程式碼品質檢查;
if (測試通過?) then (是)
:建置容器映像;
:推送到 Registry;
else (否)
:通知開發者;
stop
endif
|CD 系統|
:部署到測試環境;
:執行整合測試;
if (驗證通過?) then (是)
:部署到生產環境;
:健康檢查;
:完成部署;
else (否)
:回滾變更;
endif
stop
@enduml內容解密:
以上圖表展現了完整CI/CDPipeline結構與步驟:
- 編譯: 預先處理原始碼轉換成可執行格式(例如編譯Python、Java等高階語言).
- 單元測驗: 根據基礎核心操作進行初步驗證各類別基本功能運作正常.
- 整合測驗: 渲染各子系統連貫性並檢查是否互相呼應無誤.
- 系統演練: 在真實環境下進行全面系統排除潛藏漏洞及問題.
- 佈署: 推播更新最新版本至正式營運環境.
- 持續監控: 自動追蹤系統營運狀況及異常事件進行記錄.
- 反饋調整: 根據監控反饋最佳化改進系統效能及處理意外事件.
主要考量點包括:
- 持續最佳化:持續觀察系統營運情況並根據反饋資訊最佳化改進各種問題使系統更穩健高效運轉。
- 彈性調整:根據需要隨時進行系統修改更新以適應市場需求變更或技術進步提供更佳服務品質。
結合完整詳細CI/CDPipeline內容介紹以上各種相關概念可協助完成專案高效完成推播上線過程使得整體開發過程更加完善穩健!