Test, Packages and Releases
想像一下,現在我們已經有個派遣工,會在 master 分支有異動時來幫忙打包,但是,既然已經有派遣工可用,能不能讓派遣工幫更多忙呢?
答案當然是肯定的!
使用 GitLab CI/CD 的精神就是 自由發揮,端看開發人員怎麼設計!(重責大任在自己身上,只能苦笑~
回歸到研發流程上,我習慣的研發流程是以 issue 為基礎:
- 不管是功能新增、錯誤修正... 等,只要跟變動程式碼有關,都必須基於 issue
- 一個 issue 通常會對應一個 issue 專用的分支
- 在 issue 完成之後,提交 merge request(以下簡稱 MR),審核通過後,issue 分支的內容才能被合併回 master 上
以上,就是我的日常~(現在明明就在休息,逃~
在這個研發流程中,最累人的就是 MR,總是一來一回異動無數次,每天都是 MR 地獄,不誇張!(遠目
這時,如果有派遣工,能幫上些什麼忙呢?
聰明的你想到了!是 unit test!但是我必須很誠懇的說,unit test 真的不是第一步。
第一步是要能 通過編譯!
無論是不會寫、沒有人手寫或者沒辦法寫 test case,至少也要能被無誤的編譯!(GraphQLet 就是一個實例,由於沒有架設自己的伺服器,所以目前並沒有撰寫 test case 實際去呼叫、取得結果來進行測試。)
人難免都會犯錯,這時就要讓派遣工來幫忙 ❤️~
回歸到研發流程,若多了一個測試的階段,就算不包含 unit test,無論是對 issue 的苦主或者 MR 的苦主來說,都是件很大的幫助。
- issue 的苦主不用再擔心自己 push 錯或漏 push 了什麼,因為派遣工會幫忙編譯,如果沒通過,也來得及調整!
- MR 的苦主這時多了一層保障,因為派遣工已確保了編譯正確!此時,透過人腦編譯來 review,寫下建議的你也能更心安理得!
- 假如你的團隊已經要求 unit test,那更棒了!CI/CD 界面中可以整合 JUnit 的報告!
CI/CD 流程調整|新增 Test Stage
不多說,先直接調整一版設定!
image: maven:3.6.3-jdk-11
stages:
# 新增了一個階段 test 在 build 之前
- test
- build
variables:
MAVEN_OPTS: "-Dhttps.protocols=TLSv1.2 -Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=WARN -Dorg.slf4j.simpleLogger.showDateTime=true -Djava.awt.headless=true"
MAVEN_CLI_OPTS: "--batch-mode --errors --fail-at-end --show-version -DinstallAtEnd=true -DdeployAtEnd=true"
# test 中執行 mvn 的 test 指令
test:
stage: test
script:
- mvn $MAVEN_CLI_OPTS test
build:
stage: build
only:
- master
script:
- mvn $MAVEN_CLI_OPTS package
artifacts:
name: "$CI_PROJECT_TITLE"
paths:
- target/*.jar
好的,這樣我們就加上了測試的階段。但實際運行起來的效果是如何呢?(自己測試看看會更有感覺)你會發現:
- MR 時會驅動跑 test
- 合併回 master 時會驅動跑 test -> build
但我真正想要的是什麼呢?我想要的其實是:
- MR|test
- master|build
原因是,這兩個步驟的行為有點重複,mvn 執行 package 時已經會包含 test 的效果。調整後如下:
image: maven:3.6.3-jdk-11
stages:
- test
- build
variables:
MAVEN_OPTS: "-Dhttps.protocols=TLSv1.2 -Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=WARN -Dorg.slf4j.simpleLogger.showDateTime=true -Djava.awt.headless=true"
MAVEN_CLI_OPTS: "--batch-mode --errors --fail-at-end --show-version -DinstallAtEnd=true -DdeployAtEnd=true"
test:
stage: test
# 限定在只有 MR 時會驅動
only:
- merge_requests
script:
- mvn $MAVEN_CLI_OPTS test
# 以下是 GitLab 和 JUnit 整合的方法,如果有採用 JUnit + surefile 來進行 unit test,可以將 report 整合到 MR 及 pipeline 的 UI 上
# 若不需要請自行註解掉或拿掉
artifacts:
reports:
junit:
- target/surefire-reports/TEST-*.xml
build:
stage: build
only:
- master
script:
- mvn $MAVEN_CLI_OPTS package
artifacts:
name: "$CI_PROJECT_TITLE"
paths:
- target/*.jar
這樣調整之後,就可以達成前述的效果,派遣工不重工也更省時。
有派遣工真好 ❤️~
就曾經發生過小夥伴 push 時漏了檔案,負責 MR 的我人腦編譯沒發現,MR 通過後 master 掛掉 Orz......
以前總會希望,能輕鬆的完成兩件事情:
- 希望有個服務能代管打包完的成果,但是,又不想自己架,唉~
- 希望有個方便記錄版本異動資料的機制,好快速查詢每個版本的差別到底在哪
不曉得萬能的派遣工,能不能幫上這個忙呢 😘~
答案是,辦!不!到!!! 呃...... 我的意思是~
只要用上了 GitLab Packages 和 GitLab Releases 這兩個功能就能實現喔喔喔喔喔!(偉哉 GitLab
CI/CD 流程調整|新增 Deploy Stage
在設定 CI/CD 之前,要先來對 Packages 進行設定。
為了能讓 maven 能順利將打包的產出部署到 Packages 服務,我們需要在 pom.xml
中加入以下設定:
<!-- 請放在 pom 中的第一級 -->
<repositories>
<repository>
<id>gitlab-maven</id>
<url>https://gitlab.com/api/v4/projects/${env.CI_PROJECT_ID}/packages/maven</url>
</repository>
</repositories>
<distributionManagement>
<repository>
<id>gitlab-maven</id>
<url>https://gitlab.com/api/v4/projects/${env.CI_PROJECT_ID}/packages/maven</url>
</repository>
<snapshotRepository>
<id>gitlab-maven</id>
<url>https://gitlab.com/api/v4/projects/${env.CI_PROJECT_ID}/packages/maven</url>
</snapshotRepository>
</distributionManagement>
同時,需要在 project 的新增一個 xml,GitLab 官方建議放置在 project 根目錄,命名為 ci_settings.xml
,內容全文如下:
<settings xmlns="http://maven.apache.org/SETTINGS/1.1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.1.0 http://maven.apache.org/xsd/settings-1.1.0.xsd">
<servers>
<server>
<id>gitlab-maven</id>
<configuration>
<httpHeaders>
<!-- GitLab Packages 服務認證用 -->
<property>
<name>Job-Token</name>
<value>${env.CI_JOB_TOKEN}</value>
</property>
</httpHeaders>
</configuration>
</server>
</servers>
</settings>
這些設定的目的是讓 GitLab 的派遣工,在執行 maven 的部署工作時,
- 取得正確的資源庫路徑,
- 提供認證資訊給 GitLab,以供識別是否為合法的服務使用者。
有了以上前置作業,就做好使用 Packages 的準備了!
接下來,來思考一下我們期望的流程,這個部署的步驟,會是怎麼樣被驅動的呢?同時,得問問自己,怎麼樣的產出標準得以被部署呢?
在這和大家分享一下我的經驗,以往,版本的迭代是採用了 milestone 的機制:
- 一個 milestone 中有數個 issue,issue 之間可能有相依性
- milestone 是否完成,是由團隊共同檢驗
- milestone 確定完成時,會在被當成 production 環境的分支(整合複雜的情況會開不同於 master 的分支)上以 版本號 標記 tag
換言之,是由 人 來決定是否完成了某個版本。
這麼一想,期望的流程就變得非常清楚:
- MR|test
- master|build
- tag|deploy
調整後如下:
image: maven:3.6.3-jdk-11
stages:
- test
- build
- deploy
variables:
MAVEN_OPTS: "-Dhttps.protocols=TLSv1.2 -Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=WARN -Dorg.slf4j.simpleLogger.showDateTime=true -Djava.awt.headless=true"
MAVEN_CLI_OPTS: "--batch-mode --errors --fail-at-end --show-version -DinstallAtEnd=true -DdeployAtEnd=true"
test:
stage: test
only:
- merge_requests
script:
- mvn $MAVEN_CLI_OPTS test
artifacts:
reports:
junit:
- target/surefire-reports/TEST-*.xml
build:
stage: build
only:
- master
script:
- mvn $MAVEN_CLI_OPTS package
artifacts:
name: "$CI_PROJECT_TITLE"
paths:
- target/*.jar
# 新增一個 job 叫做 maven
maven:
stage: deploy
# 在標記了 tag 時驅動
only:
- tags
# 先前設定的 ci_settings.xml 是部署 deploy 指令的重要參數
script:
- mvn $MAVEN_CLI_OPTS deploy -s ci_settings.xml
完成!
這時,只要 git 版本庫中有標記任何的 tag,派遣工就會趕來把打包成果部署到 Packages 服務中。
等等!部署都做完了,那前面提到的 Releases 又是什麼呢?
Releases 是 GitLab 提供一個附加在 tag 上的機制,在使用 GitLab UI 添加 tag 時,有一個額外的區塊叫做 Release notes
,只要填入內容,發佈 tag 時就等於釋出了一個版本。
匯總一下研發流程:
- 制定 milestone,這個 milestone 規範了某個版本要開發哪些功能
- 小型專案是否要採用 milestone 可以仔細考慮,目前 GraphQLet 是沒有使用的
- 制定要完成的 issues,進入 issue 開發循環
- 逐個開發 issue,完成 issue 後提交 MR - 派遣工幫忙 test
- 逐個審核 MR,若未通過則退回繼續調整,若通過則 merge 回 master - 派遣工幫忙 build
- 檢核 milestone,確認 milestone 目標且所有 issue 都已經完成
- 若完成,關閉 milestone
- 若未完成,回步驟 2
- 如未採用 milestone 請確保要釋出新版本的 issue 都開發完成
- 新增 tag 標記版本及版本資訊
- 派遣工幫忙 deploy
哇~這個流程感覺好棒啊!
把不需要人為邏輯判斷的例行性事務交給派遣工就對了,除了可以讓研發人更專注在研發上,更可以避免人工出錯提升整體品質!以前要是也有派遣工就好了......(遠目
Packages 的效果請參考 => GraphQLet Packages
Releases 的效果請參考 => GraphQLet Releases