現代軟體工程實踐中,自動化已成為提升開發效率與軟體品質的核心要素。持續整合與持續佈署(Continuous Integration/Continuous Deployment,CI/CD)機制透過自動化的建置、測試與佈署流程,讓開發團隊能夠更頻繁且可靠地交付軟體。GitLab 作為一個完整的 DevOps 平台,整合了程式碼託管、問題追蹤、程式碼審查以及 CI/CD 等功能,為企業提供了端到端的軟體開發解決方案。本文將透過一個實際的專案案例,系統性地展示如何運用 GitLab 的各項功能建構完整的開發流程,從專案初始化與需求規劃開始,經過分支管理與程式碼開發,到 CI/CD Pipeline 的組態與執行,最終實現自動化的軟體交付。
企業級專案管理基礎架構
在開始任何程式碼開發之前,建立良好的專案管理基礎架構至關重要。這不僅關係到程式碼的組織方式,更影響團隊協作的效率與專案的可追溯性。GitLab 提供了完整的專案管理功能,從專案建立、群組管理到問題追蹤,這些工具能夠協助團隊建立清晰的工作流程與權責分配機制。良好的專案架構設計能夠確保隨著專案規模擴大,團隊依然能夠高效地協作與管理複雜的開發任務。
GitLab 環境準備與帳戶設定
要開始使用 GitLab 的 CI/CD 功能,首先需要準備適當的開發環境。無論是使用 GitLab.com 的軟體即服務(Software as a Service,SaaS)版本,或是企業自行架設的私有版本(Self-Managed),基本的使用流程都是相同的。對於企業用戶,建議評估是否需要自行架設 GitLab 伺服器以符合資料主權與安全性要求,特別是在金融、醫療等高度監管的產業中。自行架設雖然需要額外的維運成本,但能夠提供更高的控制權與客製化彈性。
在帳戶設定方面,除了基本的個人資訊外,SSH 金鑰的組態是確保安全存取的重要步驟。SSH 金鑰採用非對稱加密技術,讓開發者能夠在不需要每次輸入密碼的情況下,安全地與 GitLab 伺服器進行通訊。產生 SSH 金鑰對的過程涉及使用 ssh-keygen 工具,建議使用 Ed25519 演算法,因為它比傳統的 RSA 演算法提供更好的安全性與效能。產生金鑰後,需要將公鑰上傳至 GitLab 帳戶設定中,而私鑰則應妥善保管在本機電腦上,絕不應該與他人分享或提交至版本控制系統。
專案與群組架構設計
在 GitLab 中,群組(Group)是組織多個專案的容器,它提供了統一的權限管理、CI/CD 變數設定以及資源共享機制。對於企業來說,建立合理的群組架構能夠有效管理大量的專案與開發人員。典型的企業群組架構可能採用階層式設計,最上層是公司群組,下面可以根據部門、產品線或團隊建立子群組,每個子群組內再包含具體的專案。這種架構設計的優勢在於權限可以繼承,上層群組的管理員自動擁有下層所有專案的管理權限,同時 CI/CD 變數也可以在群組層級設定,讓所有子專案共享相同的組態。
以本文的範例專案「Hats for Cats」來說,這是一個電子商務平台的網頁應用程式,主要功能包含使用者認證、商品搜尋與線上購買。在實際的企業環境中,這個專案應該被放置在一個代表公司或部門的群組之下,而非直接放在個人帳戶底下。假設我們的公司名為 Acme Software,我們會先建立一個名為「acme-software」的群組,然後在這個群組下建立「hats-for-cats」專案。這樣的架構不僅符合企業管理需求,也方便未來當專案數量增加時進行統一管理。
在建立專案時,GitLab 提供了多種專案範本,包含空白專案、從範本建立或匯入既有專案。對於新專案,選擇「建立空白專案」是最常見的做法。專案的可見性設定也很重要,可以選擇私有(Private)、內部(Internal)或公開(Public)。企業內部專案通常設定為私有,只有被授權的團隊成員才能存取。初始化專案時,建議勾選「建立 README 檔案」選項,這個檔案將作為專案的說明文件,讓新加入的團隊成員能夠快速了解專案的目的與使用方式。
@startuml
!define PLANTUML_FORMAT svg
!theme _none_
skinparam dpi 300
skinparam shadowing false
skinparam linetype ortho
skinparam roundcorner 5
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam defaultFontSize 14
skinparam minClassWidth 120
package "Acme Software 企業群組架構" {
rectangle "acme-software (頂層群組)" as root {
rectangle "工程部門" as eng {
rectangle "hats-for-cats 專案" as hfc
rectangle "其他專案..." as other1
}
rectangle "營運部門" as ops {
rectangle "基礎設施專案" as infra
rectangle "監控專案" as monitor
}
rectangle "產品部門" as product {
rectangle "文件庫" as docs
rectangle "設計資源" as design
}
}
}
note right of root
頂層群組設定:
• 統一的權限管理
• 共享的 CI/CD 變數
• 公司層級的政策設定
end note
note right of hfc
專案層級設定:
• 專案特定的組態
• 分支保護規則
• Merge Request 核准流程
• CI/CD Pipeline 定義
end note
@endumlIssue Tracking 系統與需求管理
GitLab 的 Issue Tracking 系統提供了完整的需求管理與任務追蹤功能。每個 Issue 代表一個待完成的任務、功能需求或需要修復的缺陷。透過 Issue 系統,團隊能夠將複雜的專案分解成可管理的小單位,並追蹤每個任務的進度與負責人。對於「Hats for Cats」專案,我們需要先定義最小可行產品(Minimum Viable Product,MVP)的功能範圍,然後為每個核心功能建立對應的 Issue。
根據產品需求分析,MVP 版本應該包含四個核心功能。第一個是使用者登入功能,讓使用者能夠透過帳號密碼進行身分驗證,這是所有個人化功能的基礎。第二個是商品搜尋功能,使用者需要能夠根據關鍵字、分類或價格範圍來查詢商品。第三個是購物車與結帳功能,使用者能夠將商品加入購物車並完成線上付款。第四個是使用者登出功能,確保使用者能夠安全地結束會話。
在 GitLab 中建立這些 Issue 時,我們應該為每個 Issue 提供清楚的標題與詳細的描述。標題應該簡潔明瞭,通常使用動詞開頭來描述要完成的動作,例如「實作使用者登入功能」或「開發商品搜尋介面」。描述欄位則應該包含更詳細的需求說明,包括功能的具體要求、使用者故事、驗收條件以及相關的技術限制。使用 Markdown 語法可以讓描述更加結構化,例如使用清單來列出功能需求點,使用程式碼區塊來展示 API 規格。
標籤系統與優先順序管理
GitLab 的標籤(Label)系統提供了靈活的 Issue 分類機制。標籤分為兩種類型,一種是一般標籤,另一種是範疇標籤(Scoped Label)。範疇標籤使用雙冒號語法,例如「priority::high」或「status::in-progress」,這種格式的優勢在於同一個範疇下的標籤具有互斥性,一個 Issue 在同一個範疇中只能有一個標籤。這避免了標籤使用的混亂,例如一個 Issue 不可能同時標記為「priority::high」和「priority::low」。
對於「Hats for Cats」專案,我們可以建立幾個標籤體系來組織工作。首先是優先順序標籤,包含「priority::critical」、「priority::high」、「priority::medium」和「priority::low」,用來標示任務的緊急程度。其次是類型標籤,包含「type::feature」、「type::bug」、「type::refactor」,用來區分任務的性質。第三是狀態標籤,包含「status::todo」、「status::in-progress」、「status::review」、「status::done」,用來追蹤任務的進度。
此外,我們還可以建立一個「security」標籤,用來標示需要特別關注安全性的 Issue。對於登入與登出功能,應該加上這個標籤,因為身分驗證機制直接關係到系統的安全性,需要經過安全團隊的額外審查。這種做法在企業環境中特別重要,因為資安問題可能導致嚴重的商業損失與法律責任。
Issue 後設資料與工作流程整合
除了標籤外,GitLab 的 Issue 系統還提供了豐富的後設資料欄位,用來支援不同的專案管理方法論。這些欄位包括負責人(Assignee)、權重(Weight)、預估時數(Time Estimate)、截止日期(Due Date)以及里程碑(Milestone)。透過適當地填寫這些後設資料,團隊能夠更有效地規劃與追蹤工作進度。
以登入功能的 Issue 為例,我們首先將其指派給負責前端開發的工程師。權重欄位用來表示任務的相對複雜度,這是敏捷開發中的故事點(Story Point)概念。在團隊討論後,我們決定使用斐波那契數列作為權重的基準,其中一代表非常簡單的任務,三代表小型任務,五代表中型任務,八代表大型任務。登入功能涉及前端介面設計、後端 API 整合以及資料庫查詢邏輯,經評估後給予權重五,代表這是一個中等複雜度的任務。
預估時數是團隊根據經驗估算完成任務所需的工作時間。這個數字不應該包含會議、休息或其他非直接相關的時間,而是純粹的開發時間。對於登入功能,我們預估需要十五個小時,包括三小時的介面設計、五小時的後端 API 開發、三小時的整合測試,以及四小時的安全性測試與文件撰寫。截止日期的設定則需要考慮團隊的可用工時與其他任務的優先順序,確保時程的可行性。
在使用 Scrum 方法論的團隊中,這些後設資料通常在衝刺規劃會議(Sprint Planning)中確定。而使用看板(Kanban)方法的團隊則可能在任務進入待辦清單時就先填寫這些資訊。無論採用哪種方法論,重要的是團隊要有一致的共識,確保每個人對於權重、時數的理解是相同的。
@startuml
!define PLANTUML_FORMAT svg
!theme _none_
skinparam dpi 300
skinparam shadowing false
skinparam linetype ortho
skinparam roundcorner 5
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam defaultFontSize 14
skinparam minClassWidth 140
|產品經理|
start
:定義 MVP 功能需求;
:建立功能 Issue;
note right
Issue 內容包含:
• 清楚的標題
• 詳細的需求描述
• 使用者故事
• 驗收條件
end note
|開發團隊|
:進行任務評估會議;
:討論技術實作方案;
:估算工作複雜度與時數;
fork
:設定 Issue 權重;
note right: 使用斐波那契數列
fork again
:預估開發時數;
note right: 純開發時間
fork again
:設定截止日期;
note right: 考慮團隊工時
end fork
:指派負責工程師;
|專案經理|
:分配優先順序標籤;
if (需要安全審查?) then (是)
:加上 security 標籤;
|資安團隊|
:進行安全性評估;
:提供安全需求建議;
else (否)
endif
|開發團隊|
:將 Issue 加入待辦清單;
:等待開始開發;
stop
end note
end note
end note
@enduml本地開發環境建置與 Git 操作
完成專案管理架構的設定後,開發者需要將 GitLab 上的專案複製到本地電腦,才能使用熟悉的整合開發環境(Integrated Development Environment,IDE)進行程式碼開發。雖然 GitLab 提供了網頁版的程式碼編輯器,但對於複雜的開發任務,本地開發環境提供了更好的效能、更豐富的工具支援以及離線工作的能力。建立本地開發環境的過程涉及 Git 版本控制系統的操作,包括儲存庫複製、分支管理以及程式碼提交等基本操作。
SSH 金鑰設定與安全性考量
在複製專案之前,需要確保本地電腦已經正確設定 SSH 金鑰。SSH(Secure Shell)是一種加密的網路通訊協定,它使用公開金鑰加密技術來驗證使用者身分。相較於使用帳號密碼的 HTTPS 協定,SSH 提供了更好的安全性與便利性,因為開發者不需要在每次執行 Git 操作時輸入密碼。
產生 SSH 金鑰對的指令如下,建議使用 Ed25519 演算法,因為它提供了與 RSA-4096 相當的安全性,但金鑰長度更短,運算速度更快。在命令列介面中執行以下指令:
# 產生 Ed25519 演算法的 SSH 金鑰對
# -t 參數指定金鑰類型
# -C 參數加入註解,通常使用電子郵件地址
ssh-keygen -t ed25519 -C "developer@example.com"
執行這個指令後,系統會詢問金鑰的儲存位置與密碼。預設的儲存位置是使用者家目錄下的 .ssh 資料夾,檔案名稱為 id_ed25519(私鑰)與 id_ed25519.pub(公鑰)。強烈建議為私鑰設定密碼,這提供了額外的安全層級,即使私鑰檔案被盜取,沒有密碼也無法使用。設定密碼後,可以使用 ssh-agent 來快取密碼,避免每次使用時都需要輸入。
產生金鑰對後,需要將公鑰上傳至 GitLab。首先使用文字編輯器或 cat 指令查看公鑰內容:
# 顯示公鑰內容
# 公鑰是一串長字串,開頭為 ssh-ed25519
cat ~/.ssh/id_ed25519.pub
複製公鑰內容後,登入 GitLab 網頁介面,進入使用者設定中的「SSH 金鑰」頁面,將公鑰貼上並儲存。可以為金鑰設定一個有意義的標題,例如「工作筆電」或「家用電腦」,方便日後管理多個金鑰。同時可以設定金鑰的有效期限,這是安全性最佳實務,定期更換金鑰能夠降低長期使用同一金鑰的風險。
Git 儲存庫複製與初始化
設定好 SSH 金鑰後,就可以將 GitLab 專案複製到本地。在 GitLab 專案頁面上,點選「Clone」按鈕會顯示兩種複製方式的 URL,一種是 HTTPS,另一種是 SSH。由於我們已經設定了 SSH 金鑰,應該選擇 SSH URL,格式類似於「git@gitlab.com:acme-software/hats-for-cats.git」。
# 使用 SSH 協定複製 GitLab 專案
# git clone 指令會在當前目錄建立一個新資料夾
# 資料夾名稱與專案名稱相同
git clone git@gitlab.com:acme-software/hats-for-cats.git
# 進入專案目錄
# cd 是 change directory 的縮寫
cd hats-for-cats
# 查看專案目錄內容
# ls 列出所有檔案與資料夾
# -la 參數顯示隱藏檔案與詳細資訊
ls -la
複製完成後,專案目錄中會包含所有在 GitLab 上的檔案,以及一個名為 .git 的隱藏資料夾。這個 .git 資料夾包含了整個專案的版本歷史、分支資訊以及 Git 的組態檔案。絕對不要手動修改或刪除 .git 資料夾中的內容,所有的 Git 操作都應該透過 Git 指令來執行。
在本地開發環境中,建議設定一些基本的 Git 組態,這些設定會影響提交記錄的呈現與行為。以下是一些常用的組態項目:
# 設定使用者名稱
# 這個名稱會出現在提交記錄中
git config --global user.name "張小明"
# 設定電子郵件地址
# 建議使用與 GitLab 帳戶相同的電子郵件
git config --global user.email "developer@example.com"
# 設定預設的文字編輯器
# 用於編寫提交訊息
git config --global core.editor "vim"
# 設定預設的分支名稱為 main
# 現代的 Git 專案通常使用 main 而非 master
git config --global init.defaultBranch main
# 設定推送行為
# simple 模式只推送當前分支到對應的遠端分支
git config --global push.default simple
# 啟用顏色輸出
# 讓 Git 指令的輸出更易讀
git config --global color.ui auto
分支策略與工作流程設計
Git 的分支功能是支援平行開發與功能隔離的核心機制。透過分支,多個開發者可以同時進行不同功能的開發,而不會互相干擾。在企業環境中,通常會採用特定的分支策略來組織開發流程,最常見的有 Git Flow、GitHub Flow 以及 GitLab Flow。
GitLab Flow 是一種簡化的分支策略,適合採用持續佈署的團隊。在這個策略中,main 分支始終保持可佈署的狀態,所有的新功能開發都在功能分支(Feature Branch)上進行。功能分支的命名應該清楚地反映其用途,通常採用「動詞-名詞」的格式,例如「add-login-feature」、「fix-payment-bug」或「refactor-database-layer」。有些團隊會在分支名稱前加上 Issue 編號,例如「123-add-login-feature」,這樣可以直接從分支名稱追溯到對應的需求或任務。
對於「Hats for Cats」專案的登入功能開發,我們需要建立一個新的功能分支。分支的建立有兩種方式,一種是先建立分支再切換,另一種是建立並同時切換。以下展示這兩種方式的操作:
# 方式一:分別執行建立與切換
# git branch 指令建立新分支
# 此時仍停留在原本的分支上
git branch add-login-feature
# git checkout 指令切換到指定分支
# 切換後,工作目錄的檔案會更新為該分支的內容
git checkout add-login-feature
# 方式二:建立並同時切換(推薦)
# -b 參數表示建立新分支並切換
# 這個指令結合了上面兩個步驟
git checkout -b add-login-feature
# 查看目前所在的分支
# * 符號標示當前分支
# 綠色文字表示本地分支
git branch
# 查看所有分支,包含遠端分支
# -a 參數顯示所有分支
# 紅色文字表示遠端分支
git branch -a
建立本地分支後,這個分支只存在於開發者的電腦上,尚未同步到 GitLab。為了讓團隊其他成員能夠看到這個分支,以及為了備份與協作,我們需要將分支推送到遠端儲存庫:
# 第一次推送分支到遠端
# --set-upstream 參數(簡寫為 -u)建立本地分支與遠端分支的追蹤關係
# origin 是遠端儲存庫的預設名稱
# add-login-feature 是要推送的分支名稱
git push --set-upstream origin add-login-feature
# 建立追蹤關係後,後續的推送可以簡化為
# Git 會自動推送到對應的遠端分支
git push
推送完成後,在 GitLab 專案頁面的「Repository」選單下選擇「Branches」,就可以看到新建立的「add-login-feature」分支。這個分支現在已經準備好接收程式碼提交。
@startuml
!define PLANTUML_FORMAT svg
!theme _none_
skinparam dpi 300
skinparam shadowing false
skinparam linetype ortho
skinparam roundcorner 5
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam defaultFontSize 14
skinparam minClassWidth 140
|開發者|
start
:選擇要開發的功能 Issue;
:在本地建立功能分支;
note right
git checkout -b add-login-feature
end note
:推送分支到 GitLab;
note right
git push -u origin add-login-feature
end note
|GitLab|
:建立遠端分支;
:更新分支清單;
|開發者|
:開發並測試功能;
:提交程式碼變更;
note right
git add .
git commit -m "訊息"
git push
end note
|GitLab|
:接收程式碼推送;
:儲存提交記錄;
if (功能開發完成?) then (否)
|開發者|
:繼續開發;
else (是)
|開發者|
:準備建立 Merge Request;
endif
stop
@endumlMerge Request 建立與最佳實務
Merge Request(在 GitHub 中稱為 Pull Request)是 GitLab 協作流程的核心機制。它不僅是合併程式碼的工具,更是程式碼審查、知識分享以及品質控制的平台。根據 GitLab 的最佳實務建議,應該在建立功能分支後就立即建立 Merge Request,即使程式碼尚未完成。這種做法的好處是讓團隊成員能夠及早看到進行中的工作,提供回饋與建議,避免在錯誤的方向上投入太多時間。
在 GitLab 網頁介面中,進入專案的「Merge Requests」頁面,點選「New merge request」按鈕。在來源分支欄位選擇「add-login-feature」,目標分支選擇「main」,然後點選「Compare branches and continue」。接下來會進入 Merge Request 的詳細設定頁面,這裡有幾個重要的欄位需要填寫。
標題欄位應該簡潔地描述這個 Merge Request 的目的。對於尚未完成的工作,應該在標題前加上「Draft:」或「WIP:」(Work In Progress)前綴,這會讓 GitLab 將其標記為草稿狀態,阻止意外的合併。例如「Draft: 實作使用者登入功能」。當功能開發完成並通過測試後,可以移除 Draft 前綴,讓 Merge Request 進入可合併狀態。
描述欄位是詳細說明變更內容的地方。這裡應該包含功能的實作細節、採用的技術決策、已知的限制或待辦事項。更重要的是,可以使用 GitLab 的特殊語法來建立與 Issue 的關聯。輸入「Closes #X」(其中 X 是 Issue 編號)會建立一個自動化的關聯,當 Merge Request 被合併時,對應的 Issue 會自動關閉。這種機制確保了程式碼變更與需求的可追溯性,也避免了手動關閉 Issue 的繁瑣步驟。
## 變更說明
實作使用者登入功能,包含以下元件:
- 前端登入表單介面,使用 Vue.js 框架
- 後端認證 API,採用 JWT token 機制
- 資料庫查詢邏輯,使用參數化查詢防止 SQL 注入
- 單元測試與整合測試
## 技術決策
選擇 JWT 而非 Session 的原因:
- 支援無狀態架構,方便水平擴展
- 減少伺服器記憶體消耗
- 適合微服務架構的服務間認證
## 待辦事項
- [ ] 完成密碼加密功能
- [ ] 實作登入失敗重試限制
- [ ] 撰寫 API 文件
## 相關 Issue
Closes #1
除了標題與描述,Merge Request 還可以設定審查者(Reviewer)、指派人(Assignee)、標籤以及里程碑。審查者是負責檢視程式碼並提供意見的團隊成員,通常是資深工程師或技術主管。指派人則是負責這個 Merge Request 的主要開發者。標籤可以重複使用 Issue 的標籤體系,例如加上「security」標籤提醒這個變更需要安全審查。
程式碼開發與版本控制實務
建立好分支與 Merge Request 後,就可以開始實際的程式碼開發工作。在本地開發環境中撰寫程式碼,然後透過 Git 的提交與推送機制將變更同步到 GitLab。良好的版本控制實務不僅關係到程式碼的組織與追蹤,更影響團隊協作的效率與專案的可維護性。
程式碼撰寫與檔案管理
對於登入功能的開發,我們需要建立相關的程式碼檔案。以 Python 為例,我們可能需要建立一個處理使用者認證的模組。在專案根目錄建立一個名為 login.py 的檔案:
"""
使用者登入模組
提供使用者認證與 JWT token 產生功能
"""
import hashlib
import jwt
from datetime import datetime, timedelta
from typing import Optional, Dict
# JWT 密鑰,實際應用中應從環境變數讀取
SECRET_KEY = "your-secret-key-here"
# Token 有效期限設定為 24 小時
TOKEN_EXPIRY_HOURS = 24
class LoginManager:
"""
登入管理類別
負責使用者認證與 token 管理
"""
def __init__(self, database_connection):
"""
初始化登入管理器
Args:
database_connection: 資料庫連線物件
"""
self.db = database_connection
def hash_password(self, password: str) -> str:
"""
使用 SHA-256 雜湊演算法加密密碼
Args:
password: 明文密碼
Returns:
str: 加密後的密碼雜湊值
"""
# 將密碼編碼為位元組
password_bytes = password.encode('utf-8')
# 使用 SHA-256 產生雜湊值
hash_object = hashlib.sha256(password_bytes)
# 轉換為十六進位字串
return hash_object.hexdigest()
def authenticate_user(self, username: str, password: str) -> Optional[Dict]:
"""
驗證使用者帳號密碼
Args:
username: 使用者名稱
password: 密碼
Returns:
Optional[Dict]: 驗證成功回傳使用者資料,失敗回傳 None
"""
# 加密輸入的密碼
password_hash = self.hash_password(password)
# 使用參數化查詢防止 SQL 注入攻擊
# 絕不直接將使用者輸入拼接到 SQL 語句中
query = """
SELECT user_id, username, email, role
FROM users
WHERE username = ? AND password_hash = ?
"""
# 執行資料庫查詢
result = self.db.execute(query, (username, password_hash))
# 如果找到匹配的使用者記錄,回傳使用者資料
if result:
return {
'user_id': result[0],
'username': result[1],
'email': result[2],
'role': result[3]
}
# 驗證失敗回傳 None
return None
def generate_token(self, user_data: Dict) -> str:
"""
為認證成功的使用者產生 JWT token
Args:
user_data: 使用者資料字典
Returns:
str: JWT token 字串
"""
# 計算 token 過期時間
expiry_time = datetime.utcnow() + timedelta(hours=TOKEN_EXPIRY_HOURS)
# 建立 JWT payload
# 包含使用者識別資訊與過期時間
payload = {
'user_id': user_data['user_id'],
'username': user_data['username'],
'role': user_data['role'],
'exp': expiry_time
}
# 使用密鑰簽署 JWT
# algorithm 參數指定使用 HS256 演算法
token = jwt.encode(payload, SECRET_KEY, algorithm='HS256')
return token
# 示範使用方式
if __name__ == "__main__":
print("Hats for Cats 登入系統初始化完成")
print("正在準備認證服務...")
這個程式碼範例展示了基本的登入功能實作,包含密碼雜湊、使用者認證以及 JWT token 產生。在實際的企業應用中,還需要加入更多的安全機制,例如密碼強度驗證、登入失敗次數限制、雙因素認證等。程式碼中的註解詳細說明了每個函式的用途與參數,這對於團隊協作與程式碼維護非常重要。
Git 提交最佳實務
完成程式碼撰寫後,需要將變更提交到 Git 儲存庫。Git 的提交是版本控制的基本單位,每個提交都應該代表一個邏輯完整的變更。良好的提交實務包括適當的提交粒度、清楚的提交訊息以及正確的檔案選擇。
首先使用 git status 指令查看工作目錄的狀態,確認哪些檔案已被修改或新增:
# 查看工作目錄狀態
# 紅色文字表示未被追蹤或已修改但未加入暫存區的檔案
# 綠色文字表示已加入暫存區的檔案
git status
# 查看具體的變更內容
# git diff 顯示尚未加入暫存區的變更
# + 符號表示新增的行
# - 符號表示刪除的行
git diff
# 查看已加入暫存區的變更
# --staged 參數顯示即將被提交的內容
git diff --staged
確認變更內容正確後,將檔案加入暫存區。暫存區(Staging Area)是 Git 的一個重要概念,它讓開發者能夠精確控制哪些變更應該被包含在下一個提交中:
# 將特定檔案加入暫存區
# 可以多次執行以加入多個檔案
git add login.py
# 加入所有變更的檔案
# . 代表當前目錄及其子目錄下的所有變更
# 使用這個指令前應該仔細檢查變更內容
git add .
# 互動式加入變更
# -p 參數啟動互動模式
# 可以逐個確認是否加入每個變更區塊
git add -p
# 從暫存區移除檔案(不刪除檔案本身)
# 如果誤加入了不該提交的檔案
git reset HEAD login.py
加入暫存區後,執行 git commit 建立提交。提交訊息的撰寫非常重要,它是未來理解這個變更的主要依據。良好的提交訊息應該包含標題行與詳細說明:
# 簡短的提交訊息
# -m 參數直接指定訊息內容
# 適合簡單的變更
git commit -m "新增使用者登入功能的基礎模組"
# 詳細的提交訊息
# 不加 -m 參數會開啟文字編輯器
# 可以撰寫多行的詳細說明
git commit
在文字編輯器中,提交訊息應該遵循以下格式:
新增使用者登入功能的基礎模組
實作內容:
- LoginManager 類別提供認證功能
- 使用 SHA-256 雜湊演算法加密密碼
- 整合 JWT token 機制進行會話管理
- 使用參數化查詢防止 SQL 注入
技術細節:
- JWT token 有效期設定為 24 小時
- 密鑰應從環境變數讀取,避免寫死在程式碼中
- 資料庫查詢採用預處理語句
相關 Issue: #1
提交訊息的第一行是標題,應該簡潔地總結這個提交的目的,長度建議在五十個字元以內。空一行後是詳細說明,可以包含多個段落,解釋變更的原因、實作方式以及需要注意的事項。在訊息末尾加上相關 Issue 的編號,可以在 GitLab 中建立提交與 Issue 的關聯。
提交完成後,將變更推送到 GitLab:
# 推送到遠端儲存庫
# 由於已經建立了追蹤關係,直接執行 git push 即可
git push
# 如果遠端分支有其他人的提交,需要先拉取
# git pull 會自動合併遠端變更
git pull
# 解決可能的衝突後再推送
git push
推送成功後,在 GitLab 的 Merge Request 頁面就可以看到新的提交記錄。CI/CD Pipeline 也會自動觸發,開始執行測試與建置任務。
@startuml
!define PLANTUML_FORMAT svg
!theme _none_
skinparam dpi 300
skinparam shadowing false
skinparam linetype ortho
skinparam roundcorner 5
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam defaultFontSize 14
skinparam minClassWidth 140
|開發者|
start
:撰寫程式碼;
:測試功能;
if (功能正常運作?) then (否)
:除錯並修正;
:重新測試;
else (是)
endif
:查看變更狀態;
note right
git status
git diff
end note
:將變更加入暫存區;
note right
git add .
或
git add -p (互動式)
end note
:撰寫提交訊息;
note right
清楚的標題
詳細的說明
相關 Issue 編號
end note
:建立提交;
note right
git commit
end note
:推送到 GitLab;
note right
git push
end note
|GitLab|
:接收程式碼推送;
:更新 Merge Request;
:觸發 CI/CD Pipeline;
fork
:執行程式碼檢查;
fork again
:執行單元測試;
fork again
:執行整合測試;
fork again
:執行安全掃描;
end fork
:產生測試報告;
if (所有檢查通過?) then (是)
:標記 Pipeline 成功;
|開發者|
:請求程式碼審查;
else (否)
:標記 Pipeline 失敗;
|開發者|
:查看錯誤報告;
:修正問題;
:重新提交;
endif
stop
@endumlCI/CD Pipeline 組態與執行
程式碼提交到 GitLab 後,CI/CD Pipeline 的自動化流程就會啟動。Pipeline 是一系列自動化任務的集合,這些任務可能包含程式碼檢查、單元測試、整合測試、安全掃描、容器建置以及自動佈署。透過 .gitlab-ci.yml 組態檔案,開發者可以精確定義 Pipeline 的行為,包括執行的階段、每個階段的任務以及任務的執行條件。
Pipeline 架構設計原則
設計 CI/CD Pipeline 時需要考慮多個面向。首先是執行效率,Pipeline 應該盡可能快速完成,讓開發者能夠及時獲得回饋。這通常需要平行化執行不相依的任務,以及使用快取機制來避免重複的工作。其次是可靠性,Pipeline 的結果應該是穩定且可重現的,避免間歇性失敗造成的困擾。第三是可維護性,Pipeline 的組態應該清楚易懂,讓團隊成員能夠輕鬆理解與修改。
GitLab CI/CD 採用階段(Stage)與任務(Job)的架構。階段定義了 Pipeline 的執行順序,每個階段可以包含多個任務,同一階段內的任務會平行執行,只有當一個階段的所有任務都成功後,才會進入下一個階段。典型的階段設計包括建置(build)、測試(test)與佈署(deploy)三個階段,但實際應用中可能會有更細緻的劃分。
基礎 Pipeline 組態
.gitlab-ci.yml 檔案應該放置在專案的根目錄,GitLab 會在每次程式碼推送時自動讀取這個檔案並執行對應的 Pipeline。以下是一個基礎的組態範例:
# GitLab CI/CD Pipeline 組態檔案
# 定義自動化建置、測試與佈署流程
# 定義 Pipeline 的階段
# 階段按照定義的順序依序執行
# 同一階段內的任務會平行執行
stages:
- build # 建置階段:編譯程式碼、準備相依套件
- test # 測試階段:執行各種測試
- deploy # 佈署階段:部署到目標環境
# 全域變數定義
# 這些變數在所有任務中都可以使用
variables:
# Python 版本設定
PYTHON_VERSION: "3.11"
# pip 快取目錄
PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip"
# 全域快取設定
# 快取可以在不同的 Pipeline 執行之間保留檔案
# 大幅減少相依套件的下載時間
cache:
# 快取鍵值,用於識別快取
# $CI_COMMIT_REF_SLUG 是分支名稱的安全版本
key: ${CI_COMMIT_REF_SLUG}
# 要快取的路徑
paths:
- .cache/pip
- venv/
# 在所有任務執行前都會執行的腳本
# 用於環境準備工作
before_script:
# 顯示 Python 版本資訊
- python --version
# 升級 pip 到最新版本
- pip install --upgrade pip
# 安裝專案相依套件
# -r requirements.txt 從檔案讀取相依清單
- pip install -r requirements.txt
# 建置任務
build_job:
# 指定這個任務屬於 build 階段
stage: build
# 使用 Python 官方 Docker 映像
# python:3.11-slim 是輕量級版本
image: python:3.11-slim
# 任務執行的腳本
script:
# 顯示任務開始訊息
- echo "開始建置階段"
# 編譯 Python 檔案
# -m compileall 編譯所有 Python 檔案
# . 代表當前目錄
- python -m compileall .
# 執行程式碼風格檢查
# flake8 是 Python 的程式碼檢查工具
- flake8 --max-line-length=120 .
# 顯示建置完成訊息
- echo "建置階段完成"
# 產出物設定
# 產出物會被保留並傳遞給後續任務
artifacts:
# 產出物名稱
name: "build-${CI_COMMIT_SHORT_SHA}"
# 要保留的路徑
paths:
- "*.pyc"
- "__pycache__/"
# 產出物保留時間
expire_in: 1 week
# 單元測試任務
unit_test_job:
# 屬於 test 階段
stage: test
# 使用相同的 Python 映像確保環境一致
image: python:3.11-slim
script:
- echo "執行單元測試"
# 安裝測試相依套件
- pip install pytest pytest-cov
# 執行 pytest 測試
# --cov 產生程式碼覆蓋率報告
# --cov-report=term 在終端顯示報告
# --cov-report=html 產生 HTML 格式報告
- pytest --cov=. --cov-report=term --cov-report=html
- echo "單元測試完成"
# 測試報告設定
artifacts:
name: "test-report-${CI_COMMIT_SHORT_SHA}"
paths:
- htmlcov/
reports:
# JUnit 格式的測試報告
# GitLab 會解析這個報告並在 UI 中顯示
junit: report.xml
expire_in: 30 days
# 允許測試失敗但不中斷 Pipeline
# 在測試尚未完全穩定時可以設為 true
allow_failure: false
# 整合測試任務
integration_test_job:
stage: test
image: python:3.11-slim
# 服務定義
# 這個任務需要 PostgreSQL 資料庫
services:
- postgres:15
# 環境變數
# 用於連線資料庫
variables:
POSTGRES_DB: test_db
POSTGRES_USER: test_user
POSTGRES_PASSWORD: test_password
DATABASE_URL: "postgresql://test_user:test_password@postgres:5432/test_db"
script:
- echo "執行整合測試"
# 等待資料庫就緒
- apt-get update && apt-get install -y postgresql-client
- until pg_isready -h postgres -p 5432; do sleep 1; done
# 執行資料庫遷移
- python manage.py migrate
# 執行整合測試
- pytest tests/integration/
- echo "整合測試完成"
# 程式碼品質檢查任務
code_quality_job:
stage: test
image: python:3.11-slim
script:
- echo "執行程式碼品質檢查"
# 安裝程式碼品質工具
- pip install pylint mypy
# 執行 pylint 檢查
# pylint 提供詳細的程式碼品質報告
- pylint --rcfile=.pylintrc *.py
# 執行 mypy 類型檢查
# mypy 檢查 Python 的型別提示
- mypy --strict *.py
- echo "程式碼品質檢查完成"
# 允許品質檢查失敗但會顯示警告
allow_failure: true
# 安全掃描任務
security_scan_job:
stage: test
image: python:3.11-slim
script:
- echo "執行安全性掃描"
# 安裝安全掃描工具
- pip install safety bandit
# 檢查相依套件的已知漏洞
# safety check 使用資料庫比對套件版本
- safety check --json
# 掃描程式碼中的安全問題
# bandit 專門檢測 Python 的安全漏洞
- bandit -r . -f json -o bandit-report.json
- echo "安全性掃描完成"
artifacts:
name: "security-report-${CI_COMMIT_SHORT_SHA}"
paths:
- bandit-report.json
expire_in: 30 days
# 佈署到測試環境任務
deploy_staging:
stage: deploy
image: python:3.11-slim
script:
- echo "佈署到測試環境"
# 這裡是佈署腳本的佔位符
# 實際應用中會包含:
# - 連線到測試伺服器
# - 上傳應用程式檔案
# - 重新啟動服務
# - 執行健康檢查
- echo "測試環境佈署完成"
# 環境定義
# GitLab 會追蹤每個環境的佈署歷史
environment:
name: staging
url: https://staging.hats-for-cats.example.com
# 執行條件
# 只在 main 分支執行
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
when: manual # 需要手動觸發
這個組態檔案展示了一個完整的 CI/CD Pipeline 架構。透過詳細的註解,團隊成員可以清楚理解每個設定的用途與影響。在實際應用中,可以根據專案需求調整階段劃分、新增更多任務或修改執行條件。
GitLab Runner 設定與管理
GitLab Runner 是執行 CI/CD 任務的代理程式,它可以安裝在各種作業系統上,包括 Linux、Windows 與 macOS。對於使用 GitLab.com 的使用者,GitLab 提供了共享的 Runner,可以直接使用而不需要自行設定。但對於企業用戶,特別是使用自行架設 GitLab 的情況,通常需要設定專屬的 Runner 來確保資源的可用性與安全性。
設定 GitLab Runner 的過程包括幾個步驟。首先需要在執行 Runner 的伺服器上安裝 GitLab Runner 軟體,可以從 GitLab 官方網站下載對應作業系統的安裝套件。安裝完成後,需要進行註冊(Register)程序,將 Runner 與 GitLab 專案或群組建立關聯。
在 GitLab 網頁介面中,進入專案的「Settings」選單,選擇「CI/CD」,展開「Runners」區段,點選「New project runner」。這會顯示註冊 Runner 所需的 URL 與註冊權杖。在 Runner 伺服器上執行註冊指令:
# 註冊 GitLab Runner
# 這個指令會啟動互動式的設定流程
gitlab-runner register
# 依照提示輸入以下資訊:
# 1. GitLab 例項的 URL(例如:https://gitlab.com)
# 2. 註冊權杖(從 GitLab 介面複製)
# 3. Runner 描述(例如:專案專屬 Runner)
# 4. Runner 標籤(用於指定任務應該在哪個 Runner 上執行)
# 5. 執行器類型(推薦使用 docker)
# 6. 預設的 Docker 映像(例如:python:3.11)
註冊完成後,在 GitLab 介面中就可以看到新註冊的 Runner。Runner 有幾個重要的設定選項需要注意。首先是並行度(Concurrent),這決定了 Runner 可以同時執行多少個任務。其次是標籤(Tags),透過標籤可以讓特定的任務在特定的 Runner 上執行,這在需要特殊硬體或軟體環境時特別有用。第三是保護狀態(Protected),保護的 Runner 只會執行受保護分支上的任務,提供額外的安全層級。
Runner 的維運管理也很重要。需要定期檢查 Runner 的運作狀態,確保有足夠的系統資源(CPU、記憶體、磁碟空間)來執行任務。Docker 執行器會累積大量的映像與容器,需要定期清理以釋放磁碟空間。可以設定自動化的清理腳本,定期刪除未使用的 Docker 資源。
透過完整的 CI/CD Pipeline 設定,「Hats for Cats」專案實現了從程式碼提交到自動化測試與佈署的全流程自動化。每次開發者推送程式碼,Pipeline 都會自動執行程式碼檢查、單元測試、整合測試與安全掃描,確保程式碼品質。當所有檢查都通過後,可以手動觸發佈署到測試環境,讓產品團隊進行驗收測試。這種自動化機制大幅減少了人為錯誤的可能性,並加快了軟體交付的速度,讓團隊能夠更頻繁且可靠地發布新功能。
持續整合與持續佈署不僅是技術實踐,更是一種文化與思維方式的轉變。它要求團隊建立自動化優先的觀念,將重複性的工作交給機器處理,讓開發者能夠專注於創造價值的工作。透過 GitLab 提供的完整工具鏈,從專案管理、程式碼託管、程式碼審查到 CI/CD 執行,企業能夠建立高效且可靠的軟體交付流程,在快速變化的市場中保持競爭優勢。