GH Actions
談談 workflow engine
最近在新的開源專案 Oak ,Gaiwan 的同仁決定採用 Forgejo 來取代 Github ,同時由於是一個 greenfield 的專案,CI/CD 尚未設置完整,我得到一個玩 GH Actions 的機會。補充說明一下:Forgejo 是一個開源軟體,在各方面都非常像 Github ,所以 GH Actions 基本上也可以在 Forgejo 上使用。
目標與起步
我的目標有兩個:
寫出一個 GH Action ,可以做 Oak 專案的測試。
寫出一個 GH Action ,可以生成 Oak 專案的文件。
使用 GH Action ,需要在 repo 下的 .github/workflows/ 資料夾下,增加 GH Action 的 yml 檔,再推到 Github 上就可以執行。主要的難度則是掌握少數常用的 GH Action 的 yml 語法。
我用的平台是 Forgejo ,所以我是用在.forgejo/workflows/ 資料夾下開發。
一開始,我自然是不嗦囉,二話不說叫 AI 幫我寫。然後,我就一而再、再而三地將 .forgejo/workflows/test.yml 推到 Forgejo 上去測。
AI 很快地就幫我寫了一個基本的雛型:
name: Test Runner
on:
push:
branches:
- main
pull_request:
branches:
- main
workflow_dispatch:
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Prepare java
uses: actions/setup-java@v4
with:
distribution: ‘zulu’
java-version: ‘11’
- name: Install clojure tools
uses: DeLaGuardo/setup-clojure@10.1
with:
# Install just one or all simultaneously
# The value must indicate a particular version of the tool, or use ‘latest’
# to always provision the latest version
cli: latest
bb: latest
- name: run Kaocha
run: |
chmod +x ./bin/kaocha
echo “--- run kaocha test ---”
./bin/kaocha然而,靠著 AI 起步雖然快,卻也很快地就進入了死胡同,怎麼問都卡在原地。後來,我還是花了一些時間搞懂原理,才開始穩定地前進。
難題
我大概遇上了幾個難題:
GH Action 執行的速度不快。
每個 step 是獨立的 shell 環境。
隱藏的環境變數陷阱。
地端執行
第一個難題的解決方案是安裝一個可在地端執行的 GH Action 的模擬程式:act
我設置的 ~/.actrc 如下:
# Workflow directory
--workflows .forgejo/workflows/
# Configure ‘act’ to use a more general, multi-architecture supporting image for node-20
-P node-20-bookworm=node:20
# Reuse containers to speed up subsequent runs
--reuse
# Set default architecture to AMD64 for better compatibility (especially on M-series chips)
--container-architecture linux/amd64
## Common Commands
#act -l # List all available jobs
#act -j $JOB_NAME # Run a specific job named JOB_NAME locally
#act push -n # Simulate a ‘push’ event, dry-run (no execution)之後,來來回回用的指令也只有兩個指令:
act -lact -j $JOB_NAME
跨 step 溝通
GH Action 的每個 step 是獨立的 shell 環境這件事一開始不是很直觀,所以我卡關了滿久的。也正因為這個設計,在不同 step 運行的程序 (process) 之間如果要溝通,就得做特殊的設計。
「跨 step 溝通」常應用於安裝軟體。比方說,因為 Forgejoe 不支援 DeLaGuardo/setup-clojure ,後來,我改成自己寫安裝 Clojure CLI 的腳本。
- name: Install Clojure Tools Manually
run: |
curl -L -O https://github.com/clojure/brew-install/releases/latest/download/linux-install.sh
chmod +x linux-install.sh
./linux-install.sh
# handling the path variables
BIN_PATH=”/usr/local/bin”
echo “$BIN_PATH” >> $GITHUB_PATH其中的 echo “$BIN_PATH” >> $GITHUB_PATH 這一句,就是將區域變數透過 workflow 變數來做跨 step 傳遞。
理解函式庫
我本來覺得 GH Action 當然會設定一些環境變數啊,這有什麼我需要特別留意嗎?看完文件就記下所有的環境變數也不太可能吧?
然而,很不幸的事情是,當我在設法透過 GH Action 做出文件時,就撞上了因為 GH Action 環境變數導致的 bug :
同樣的指令,我在地端可以順利生成 openAPI 文件;在 GH Action 上卻一定會失敗。
我除錯了許久且找不出頭緒,才在 Oak 引用的函式庫 config 裡,看到一段話。
You don’t have to provide an :env key, if not it’ll be determined by the
APP_NAME__ENVenvironment variable, or the app-name.env system property. If neither is set andCI=true(an env var set by most CI providers) then env will be test. If none of these apply then the default is dev.
結果,原來因為 GH Action 會設置 CI=true 這個環境變數,所以我的應用程式就會自動選擇 test profile 。要是沒有讀這個文件的話,我怎麼想都覺得預設值應該是 dev profile 才對。
結論
這次在 Oak 專案上使用 GH Actions (藉由 Forgejo 平台) 達成自動化測試與文件生成,是一個從 AI 輔助快速起步,到手動除錯深入理解的過程。
與我最初的想象不同的點是:要用好 GH Action 不僅只是學習 YAML 語法,更在於掌握其執行環境的隔離特性、善用地端模擬工具加速迭代,以及深入理解 CI 環境變數對應用程式依賴可能產生的潛在影響。然而,AI 還是只能協助我在 YAML 語法上快速前進,其它部分還是依賴邏輯思考與實驗。


