GitHub Actions
每個應用程式三個工作流程,每個類型各一個任務。範本的 .github/workflows/{pr,main,release}.yaml 是真相來源;它們的註解版本位於 references/workflows.md。
pull request ──► pr.yaml 僅檢查,不發布任何內容
合併至 main ──► main.yaml 映像僅建置一次 → ghcr.io/nuvraxis/<app>:sha-<short>, :main
tag vX.Y.Z ────► release.yaml 同一映像重新標記為 :vX.Y.Z, :latest · chart X.Y.Z → OCI · GitHub Release
每個工作流程的規則
-
在頂層設定
permissions: contents: read;僅在需要的任務中放寬權限。 需要推送到 GHCR 的任務設定packages: write,僅建立 Release 的任務設定contents: write。不需要id-token: write或attestations: write:來源和 SBOM 來自 BuildKit,而非actions/attest*(後者在私有儲存庫中需要 GitHub Enterprise)。 -
僅使用
GITHUB_TOKEN。 GHCR 登入使用${{ github.actor }}/${{ secrets.GITHUB_TOKEN }};gh使用GH_TOKEN: ${{ github.token }}。CI 中不使用個人存取權杖。(從叢集拉取私有套件是另一組憑證;請參閱helm-nextjs。) -
固定動作的主要版本(
@v7)並保持 SHA 表為最新。 範本為了可讀性而使用主要版本標籤。如果組織要求固定 SHA,則將每個@vN替換為 references/action-pins.md 中的 SHA,並保留# vN.M.P註解。目前的主要版本:checkout v7, setup-node v7, pnpm/action-setup v6, setup-qemu v4, setup-buildx v4, login v4, metadata v6, build-push v7, azure/setup-helm v5。 -
工具鏈:
pnpm/action-setup在actions/setup-node之前。 action-setup 從packageManager讀取 pnpm 版本;setup-node 讀取.node-version並快取 pnpm store(cache: pnpm需要先將 pnpm 加入 PATH)。然後執行pnpm install --frozen-lockfile。絕對不要使用npm ci。 -
按工作流程和參考進行
concurrency控制;僅在 PR 上取消進行中的執行。 對 PR 的新推送會取消舊的執行。在 main 和標籤上,執行總是會完成:release.yaml 需要該確切提交的映像。 -
永遠不要輸出 secrets 或將不受信任的輸入內插到
run:中。 透過env:傳遞值並引用它們("${APP}")。${{ github.event.pull_request.title }}等內容永遠不會進入腳本內部。當任務不推送到 git 時,在 checkout 上設定persist-credentials: false。 -
每個任務都設定
timeout-minutes。 否則掛起的 Docker 建置會消耗六小時。 -
名稱使用小寫。 GHCR 拒絕大寫的儲存庫。
IMAGE: ghcr.io/nuvraxis/<app>在env中寫為小寫;scaffold 會將應用程式名稱轉為小寫。
pr.yaml
-
on: pull_request搭配types: [opened, synchronize, reopened, ready_for_review]且沒有branches過濾器,這樣針對功能分支的堆疊 PR 也會被檢查。每個任務都有if: ${{ !github.event.pull_request.draft }};標記為 ready 會觸發執行。 -
四個並行任務:
quality(biome ci --reporter=github、stylelint、turbo run typecheck test --affected、pnpm audit --audit-level high)、build(turbo run build --affected)、docker(建置一個平台,使用load: true、以唯讀模式執行並移除功能、curl/api/health)、helm(對兩個 values 檔案執行helm lint --strict和 kubeconform)。--affected需要fetch-depth: 0。 -
PR 不會推送任何內容。
push: false,唯讀快取(僅cache-from),不登入註冊表。
main.yaml
-
on: push: branches: [main]僅建置一次映像,適用於兩種架構,並推送它。docker/metadata-action的標籤:type=sha,format=short,prefix=sha-和type=raw,value=main、flavor: latest=false。latest屬於發佈版本。 -
provenance: mode=max、sbom: true、cache-from/to: type=gha,scope=<app>,mode=max。 來源和 SBOM 附加到映像索引上;release.yaml 在重新標記時會一併攜帶它們。NEXT_DEPLOYMENT_ID=${{ github.sha }}是用於偏斜保護的建置引數。 -
main.yaml 不發佈 chart 也不重新執行 PR 檢查。 分支保護需要 pr.yaml;main 僅產生成品。
release.yaml
-
on: push: tags: ['v*.*.*'],然後依序執行:- 除非標籤恰好是
vMAJOR.MINOR.PATCH且其提交是origin/main的祖先,否則失敗。 - 不要重建。 如果
ghcr.io/nuvraxis/<app>:sha-<short>不存在,則以「讓 main.yaml 完成,然後重新執行」的訊息失敗。無需回退建置。 docker buildx imagetools create --tag :vX.Y.Z --tag :latest <sha-image>:這是一個清單層級的複製,會保留兩種架構、來源和 SBOM,且摘要相同。helm package --version X.Y.Z --app-version vX.Y.Z、helm push到oci://ghcr.io/nuvraxis/charts。gh release create vX.Y.Z --verify-tag --generate-notes,並附上 chart.tgz、image-digest.txt和sbom.spdx.json。
- 除非標籤恰好是
-
發佈流程: 合併到 main → 等待 main.yaml 變綠 →
git tag vX.Y.Z && git push origin vX.Y.Z。在 main.yaml 完成之前標記會故意使步驟 2 失敗;一旦映像存在,重新執行發佈任務即可。錯誤的發佈透過新增 patch 標籤來修復,絕不透過移動標籤。
加速方法(僅在需要時使用)
- QEMU 下的 arm64 是 main.yaml 的慢速部分。將其替換為在
ubuntu-24.04-arm+ubuntu-latest上的矩陣,按摘要推送,然後使用imagetools create執行合併任務。保留標籤和單一索引。 - pr.yaml 的 Turborepo 遠端快取:參閱
pnpm-turborepo。
驗證
docker run --rm -v "$PWD:/repo" -w /repo rhysd/actionlint:latest # lint 所有工作流程
gh workflow list && gh run list --limit 5
gh run view <run-id> --log-failed
發佈之後:docker buildx imagetools inspect ghcr.io/nuvraxis/<app>:vX.Y.Z 會顯示兩個平台,而 helm show chart oci://ghcr.io/nuvraxis/charts/<app> --version X.Y.Z 會顯示 appVersion: vX.Y.Z。
來源
- https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions
- https://docs.github.com/en/actions/security-for-github-actions/security-guides/security-hardening-for-github-actions
- https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/controlling-permissions-for-github_token
- https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry
- https://github.com/pnpm/action-setup
- https://github.com/actions/setup-node
- https://github.com/docker/metadata-action
- https://github.com/docker/build-push-action
- https://docs.docker.com/build/ci/github-actions/cache/#github-cache
- https://docs.docker.com/build/metadata/attestations/
- https://docs.docker.com/reference/cli/docker/buildx/imagetools/create/
- https://helm.sh/docs/topics/registries/
- https://cli.github.com/manual/gh_release_create
- https://turborepo.dev/docs/reference/run#--affected