GitHub Actions

GitHub Actions 學習心得

2023-02-21

什麼是 CI/CD

CI/CD 是現代軟體開發流程中很常見的概念。CI 是 Continuous Integration,也就是持續整合,指的是開發者頻繁地將程式碼合併到主線分支,每次合併都會自動觸發建置和測試,確保程式碼的品質。CD 則有兩種解釋,一是 Continuous Delivery(持續交付),一是 Continuous Deployment(持續部署)。持續交付是指程式碼經過測試後,可以隨時手動部署到生產環境;持續部署則更進一步,測試通過後直接自動部署,完全不需要人工介入。

導入 CI/CD 的好處顯而易見:減少人工操作的錯誤、縮短從開發到上線的週期,並讓整個流程變得透明且可重複執行。

GitHub Actions 的角色

GitHub Actions 是 GitHub 提供的 CI/CD 平台,讓你可以直接在 repository 裡定義自動化流程。這些流程稱為 workflow,以 YAML 檔案的形式存放在 .github/workflows/ 目錄下。每個 workflow 可以包含多個 job,每個 job 又由多個 step 組成,step 可以是執行指令、或是呼叫現成的 action。

Workflow YAML 檔的結構

一個典型的 workflow 檔案大致由以下幾個部分組成:

name:workflow 的名稱,會顯示在 GitHub 的 Actions 頁面上。

on:定義觸發這個 workflow 的條件,是整個流程的起點。

jobs:定義實際要執行的工作,可以有多個 job,預設是並行執行,也可以透過 needs 設定依賴順序。

steps:每個 job 內部的執行步驟,依序執行,可以使用 uses 引用外部 action,或用 run 執行 shell 指令。

觸發條件 on

最常見的觸發方式是監聽 push 事件,並限定特定分支:

on:
  push:
    branches:
      - main

這樣只有當有程式碼推送到 main 分支時,workflow 才會被觸發。除了 push,還有許多其他觸發條件可以使用:

  • pull_request:當 PR 被開啟、更新或合併時觸發,通常用來跑測試。
  • schedule:使用 cron 語法設定定時執行,例如每天凌晨自動執行一次。
  • workflow_dispatch:允許從 GitHub 網頁手動觸發 workflow,適合需要手動介入的部署流程。
  • release:當 GitHub release 被建立或發布時觸發,常用於打版號和發布套件。
  • workflow_call:讓這個 workflow 可以被其他 workflow 呼叫,方便拆分和重用流程。

常用的 Actions

GitHub Marketplace 上有大量現成的 action 可以直接引用,省去自己從頭寫腳本的時間。

actions/checkout@v4:幾乎每個 workflow 都會用到的第一步。它的作用是將 repository 的程式碼 checkout 到執行 job 的虛擬機器上,讓後續的建置、測試等步驟能讀取到原始碼。沒有這個步驟,後面的指令基本上都跑不動。

- uses: actions/checkout@v4

actions/setup-node@v4:用來在執行環境中安裝指定版本的 Node.js。可以透過 with 傳入參數,例如指定 Node 版本和使用的套件管理器 cache,加快安裝速度:

- name: Setup Node
  uses: actions/setup-node@v4
  with:
    node-version: '20.x'
    cache: 'pnpm'

進階用法

steps.<step_id>.outcome — 取得步驟執行結果

有時候我們需要根據某個步驟是否成功來決定後續行為。每個 step 都有一個隱含的 outcome 屬性,值可能是 successfailurecancelledskipped。要使用這個變數,必須先給那個 step 一個 id

- name: Build
  id: build
  run: pnpm run build

- name: Notify on failure
  if: steps.build.outcome == 'failure'
  run: echo "Build failed!"

這樣就可以只在 build 失敗時執行通知,而不是讓整個 workflow 直接中斷。

needs.<job_id>.outputs — 跨 job 傳遞資料

當 workflow 有多個 job 且彼此有依賴關係時,可以透過 outputs 在 job 之間傳遞資料。一個典型的場景是先用一個 job 取得版本 tag,再將這個 tag 傳給後續的 job 使用:

jobs:
  get-tag:
    runs-on: ubuntu-latest
    outputs:
      tag: ${{ steps.set-tag.outputs.tag }}
    steps:
      - name: Set tag
        id: set-tag
        run: echo "tag=$(git describe --tags --abbrev=0)" >> $GITHUB_OUTPUT

  deploy:
    needs: get-tag
    runs-on: ubuntu-latest
    steps:
      - name: Use tag
        run: echo "Deploying version ${{ needs.get-tag.outputs.tag }}"

needs: get-tagdeploy job 等待 get-tag 完成後才執行,同時也讓 needs.get-tag.outputs.tag 這個變數可以被存取到。這種模式在需要動態產生參數(例如版本號、環境名稱)並傳遞給後續部署步驟時非常實用。

小結

GitHub Actions 把 CI/CD 流程的定義和程式碼放在同一個 repository,版本控管和協作都很方便。從基本的 push 觸發、checkout、安裝環境,到進階的跨 job 資料傳遞,這套工具已經涵蓋了大多數自動化部署的需求。花一點時間把 workflow 設定好,之後每次推送程式碼就能自動完成建置和部署,省去不少手動操作的時間。