大家好,我是此林。
代碼托管平臺 Github 我們應該比較熟悉。每次我們提交代碼到 GitHub 倉庫時,特別是開源項目,一般都會自動觸發測試腳本運行,幫你驗證代碼沒有引入新的錯誤。
這個其實就是?GitHub Actions,一般我們把 YAML 腳本定義在?.github/workflows 目錄下。
1.?什么是 GitHub Actions 自動 CI 測試?
GitHub Actions 是 GitHub 官方提供的一套自動化工作流服務,可以用來自動化代碼構建、測試、部署等流程。CI(持續集成,Continuous Integration)測試 是指在代碼每次提交或者合并請求時,自動運行項目的測試代碼,保證代碼的正確性和穩定性。
那為什么要用 GitHub Actions 自動 CI 測試?原因也很簡單:
自動化:減少人工手動測試的工作,省時省力。
快速反饋:提交代碼后馬上知道測試結果,發現問題及時修復。
保障質量:避免有問題的代碼被合并進主分支,提升代碼質量。
多平臺支持:可以在不同操作系統和環境下自動測試,比如 Windows、Linux、macOS。
免費且無縫集成:直接集成在 GitHub 倉庫,無需額外配置第三方服務。
常見的 CI 測試比如:Node.js 項目跑 npm test、
Python 項目跑 pytest、
Java 項目跑 mvn test,
還有Docker 鏡像構建和測試等等。
我們以 Seata 開源項目的 workflow s為例,作為講解。?
2. 整體結構
會看這個目錄結構:
1. build.yml
Seata 是個 Java 項目,這是 CI 主流程,主要的話包括:
-
監聽分支和PR:當代碼被推送到
2.x
,develop
,master
分支,或者針對這幾個分支發起 Pull Request 時,會自動觸發這套構建和測試流程。 -
自動運行多版本 Java 測試:針對 Java 8、17、21 三個版本分別跑測試,保證代碼兼容多個 JDK 版本。
-
做代碼質量檢查:在 Java 8 環境下執行 Checkstyle、PMD、License 檢查。
-
上傳代碼覆蓋率數據:通過 Codecov 上傳測試覆蓋率報告。
-
支持 ARM 架構構建:額外有一個任務在 ARM64 架構的 Ubuntu 容器里構建項目(跳過測試),用于生成 ARM 平臺的二進制或包。
2. rerun-build.yml
這個配置是用來 自動重跑失敗的 workflow 構建 的,只有當 build?workflow 失敗,并且重試次數還沒達到 2 次時才執行。
3.?publish-docker.yml
自動構建并發布 Docker 鏡像到 DockerHub,針對三個不同版本的 Java(8、17、21)分別構建 Docker 鏡像。
4.?publish-ossrh.yml
將構建好的 Maven 包自動發布到 Maven Central(OSSRH 倉庫)。
5.?codeql-analysis.yml
CodeQL 是 GitHub 提供的代碼靜態分析工具,能夠掃描代碼中的安全漏洞、潛在缺陷和代碼質量問題。它在每周六的 19:36(UTC 時間)定時觸發一次全量掃描。
6. license-checker.yaml
簡單點說,這個腳本配置是用來檢查依賴 License 許可的,每個文件頭部都必須加上這段注釋。
5. test.yml、test-druid.yml、test-ubuntu.yml?
這個就不多說,只有在真正 Seata 發版的時候才會觸發,主要為多版本 Spring Boot 、多版本 Druid 測試專用,用于版本兼容性測試。
3. build.yml 詳解
下面,我們來細看 build.yml。
3.1?觸發條件
name: "build"
整個工作流的名稱,在 GitHub Actions 的界面上顯示。
on:push:branches: [ 2.x, develop, master ]
配置觸發條件,當 push
到 2.x
、develop
或 master
分支時觸發。
pull_request:branches: [ 2.x, develop, master ]types: [opened, reopened, synchronize]
當有人向這些分支提交了 PR 時也會觸發 workflow,具體來說,比如這個 PR open了,或者close之后又 reopen了,synchronize 表示更新了 PR(如 rebase 后 push)。
paths-ignore:- '**.md'
如果改動只是 Markdown 文件(例如 README.md
)時?不觸發?這個工作流。
3.2 Jobs 概覽
真正 CI 的邏輯在兩個 job 里,job1 是 Java 構建和測試(多個 JDK 版本),job2 是 ARM64 編譯構建。我們重點看 job1。
services 里是啟動 Redis 和 Nacos 服務容器?,測試會用到。
然后操作系統為 Ubuntu 最新版。
strategy 里的含義:
-
使用構建矩陣:分別用 Java 8、17、21 構建。
-
fail-fast: false
表示一個失敗不會立即取消其他并行任務。
?3.3. Steps 詳解
總共有八個 steps,我們一個一個看。
1.?拉取代碼
- name: "Checkout"uses: actions/checkout@v3
2.?設置 Python 3.12(某些依賴或構建腳本可能用到)
- name: "Use Python 3.x"uses: actions/setup-python@v2with:python-version: '3.12'
3.?設置 Java,版本用的就是之前 strategy 里定義的 matrx.java。
- name: "Set up Java JDK"uses: actions/setup-java@v3.12.0with:distribution: 'zulu'java-version: ${{ matrix.java }}
4.?打印 Maven 版本
- name: "Print maven version"run: ./mvnw -version
5.?Maven 緩存,提高構建速度,緩存 .m2
目錄。
- name: "Restore local maven repository cache"uses: actions/cache/restore@v4id: cache-maven-repositorywith:path: ~/.m2/repositorykey: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ env.TODAY }}restore-keys: |${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}${{ runner.os }}-maven-
6.1 Java 8:完整測試 + PMD + License 代碼檢查
- name: "Test, Check style, Check PMD, Check license with Maven and Java8"if: matrix.java == '8'run: |./mvnw -T 4C clean test \-Dcheckstyle.skip=false -Dpmd.skip=false -Dlicense.skip=false -DredisCaseEnabled=true \-e -B -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn;
6.2 Java 17 和 21:僅測試
- name: "Test with Maven and Java${{ matrix.java }}"if: matrix.java != '8'run: |./mvnw -T 4C clean test \-e -B -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn;
7.?保存 Maven 緩存(如果前面沒命中緩存)
- name: "Save local maven repository cache"uses: actions/cache/save@v4if: steps.cache-maven-repository.outputs.cache-hit != 'true'with:path: ~/.m2/repositorykey: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ env.TODAY }}
8.?上傳覆蓋率(只在 Java 8)
- name: "Codecov"if: matrix.java == '8'uses: codecov/codecov-action@v4.0.1with:token: ${{ secrets.CODECOV_TOKEN }}version: v0.6.0env:CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
4. rerun-build.yml 詳解
這個在?build
的 workflow 失敗時,自動嘗試重新運行一次,最多嘗試 1 次。
on:workflow_run:workflows: ["build"]types:- completed
觸發條件:當 build
這個 workflow 執行“完成”(completed
)后觸發,不管成功與否。
問:之前不是說失敗的時候才觸發嗎?
答:別急,后面 jobs 里會有 if 條件判斷。
Job 條件:
只有當
build
workflow 執行失敗(failure) 時才會觸發這個 job。
run_attempt
是執行次數,如果是第一次失敗就觸發(< 2,表示最多自動 retry 一次,防止死循環)。
操作系統還是?ubuntu-latest。
- name: rerun ${{ github.event.workflow_run.id }}
?Step 名稱:會顯示在 Actions 的執行日志中。
env:GH_REPO: ${{ github.repository }}GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
?設置環境變量:
-
GH_REPO
:當前倉庫名 -
GH_TOKEN
:自動注入的 GitHub Token,用于調用 GitHub CLI
run: |gh run watch ${{ github.event.workflow_run.id }} > /dev/null 2>&1gh run rerun ${{ github.event.workflow_run.id }} --failed
執行腳本:
-
gh run watch:?
?等待build
workflow 的狀態穩定 -
gh run rerun:?
只重跑失敗的 job(節省資源)
今天的分享就到這里了。
我是此林,關注我吧,帶你看不一樣的世界!