🔫

GitHub Actions はWHENとWHATで分割しよう

2025/03/31に公開

GitHub Actions でワークフローを作成し運用していると, いつの間にかワークフローファイルが大量に増えてしまったり, ワークフローが肥大化してしまったりということが多々あります. また大抵の場合はワークフローの中で actions/checkout のようなアクションを利用しているでしょうから, それらの依存関係の管理といったメンテナンスも必要です. そのためワークフローファイルもプロダクトコードと同様に「CLEAN」であるべきです.

どうすればワークフローファイルを「CLEAN」にできるでしょうか. 実はワークフローファイルには必ず2つの要素があります. それがイベント (WHEN) とジョブ (WHAT) です. つまりワークフローが実行される起点となるイベントを管理するワークフローファイルと実際にワークフローとして実行されるジョブを管理するワークフローファイルを分けるということです.

具体例

実際にどのように管理していくか見ていきましょう.

https://github.com/toms74209200/gist-blog/tree/2dc3171707fd41b257d382ac404dbd6374943dea/.github/workflows

このリポジトリではワークフローファイルを以下のように分けています. テストは Google の test size に従って分けています[2].

/.github
├── dependabot.yml
└── workflows
    ├── deploy-pages.yml    # GitHub Pages へのデプロイ
    ├── pullreq-actions.yml # dependabot が作成した GitHub Actions への Pull Request
    ├── pullreq-npm.yml     # dependabot が作成した npm パッケージの Pull Request
    ├── test-large.yml      # large size のテスト(E2Eテスト)
    ├── test-medium.yml     # medium size のテスト
    ├── test-small.yml      # small size のテスト
    └── test-smoke.yml      # アプリケーションのビルド検証

このように Pull Request やデプロイといった起点となるイベントとテストのような実際にワークフローとして実行したいジョブを分けています.

GitHub Actions のダッシュボード

見ての通り, ワークフローファイルのファイル名も GitHub Actions のダッシュボード上でも整然としています[3].

これを実現しているのは再利用可能なワークフローです[4][5].

イベントを管理するワークフローはどのイベントで発火するかに注目して書くようにし, 可能な限りジョブは再利用可能なワークフローを使って実行します.

.github/workflows/pullreq-npm.yml
name: Pull Request(NPM)

on:
  pull_request:
    branches:
      - master
    paths:
      - "package.json"

permissions:
  pull-requests: write
  contents: write

jobs:
  test-smoke:
    if : ${{ github.actor == 'dependabot[bot]' }}
    uses: ./.github/workflows/test-smoke.yml
    secrets: inherit
  test-small:
    if: ${{ github.actor == 'dependabot[bot]' }}
    uses: ./.github/workflows/test-small.yml
    secrets: inherit
  test-medium:
    if: ${{ github.actor == 'dependabot[bot]' }}
    uses: ./.github/workflows/test-medium.yml
    secrets: inherit
  auto-merge:
    if: ${{ github.actor == 'dependabot[bot]' }}
    runs-on: ubuntu-latest
    needs:
      - test-smoke
      - test-small
      - test-medium
    steps:
      - name: Dependabot metadata
        id: dependabot-metadata
        uses: dependabot/fetch-metadata@v2.3.0
        with:
          github-token: '${{ secrets.GITHUB_TOKEN }}'
      - name: Enable auto-merge for Dependabot PRs
        if: steps.dependabot-metadata.outputs.update-type == 'version-update:semver-patch' || steps.dependabot-metadata.outputs.update-type == 'version-update:semver-minor'
        run: gh pr merge --auto --merge "$PR_URL"
        env:
          PR_URL: ${{ github.event.pull_request.html_url }}
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

再利用可能なワークフローでは一つのことに集中できるように書きます. ワークフローごと分けてしまうことで, 前後のジョブに起因する不具合も減らすことができます.workflow_call だけでなく workflow_dispatch もつけてやると開発やデバッグに便利です.

https://github.com/toms74209200/gist-blog/blob/2dc3171707fd41b257d382ac404dbd6374943dea/.github/workflows/pullreq-npm.yml

.github/workflows/test-small.yml
name: Test of small size

on:
  workflow_call:

jobs:
  test-small:
    runs-on: ubuntu-latest
    timeout-minutes: 5
    outputs:
      status: ${{ steps.test.outputs.status }}
    steps:
      - uses: actions/checkout@v4
      - uses: oven-sh/setup-bun@v2
      - name: Install dependencies
        run: bun install
      - name: Run test
        id: test
        run: bun run test:small
        env:
          CONFIG_ID: ${{ secrets.CONFIG_ID }}
          PAT: ${{ secrets.PAT }}

https://github.com/toms74209200/gist-blog/blob/2dc3171707fd41b257d382ac404dbd6374943dea/.github/workflows/test-small.yml

各ワークフローでのオーバーヘッド

ワークフローを分けたことによって、依存関係のダウンロードやコンパイルによるオーバーヘッドが生じます. GitHub Actions の時間短縮については他でも多く解説されていることもあり, ここでは立ち入りません. ただ再利用可能なワークフローを使って細かく分けることで Actions Performance Metrics などを使った解析もやりやすいはずです. あとは公式にある通り依存関係やビルドのキャッシュを利用するといったことを地道にやっていくしかないでしょう(金で殴るのが一番).

依存関係をキャッシュしてワークフローのスピードを上げる - GitHub Docs

https://docs.github.com/ja/actions/writing-workflows/choosing-what-your-workflow-does/caching-dependencies-to-speed-up-workflows


この記事ではワークフローが実行される起点となるイベントを管理するワークフローファイルと実際にワークフローとして実行されるジョブを管理するワークフローファイルを分けることによってワークフローをより「CLEAN」に扱う方法を解説しました. 実際にワークフローを運用していくとメンテナンスやワークフローの変更で苦労する機会が少なくないです. ワークフローファイルはプロダクションコードとは異なり, テストもなく品質を保つ義務もさほどありません. ワークフローが作りっぱなしにならないためにも, 「CLEAN」なワークフローファイルを作りましょう.

脚注
  1. レガシーコードからの脱却―ソフトウェアの寿命を延ばし価値を高める9つのプラクティス, David Scott Bernstein, 吉羽 龍太郎, 永瀬 美穂, 原田 騎郎, 有野 雅士, オライリー・ジャパン, 2019 https://www.oreilly.co.jp/books/9784873118864/ ↩︎

  2. Google Testing Blog: Test Sizes https://testing.googleblog.com/2010/12/test-sizes.html ↩︎

  3. on-pullreq-***.ymljob-test-***.yml のように接頭辞を使うとさらに整然とします. ↩︎

  4. ワークフローの再利用 - GitHub Docs https://docs.github.com/ja/actions/sharing-automations/reusing-workflows ↩︎

  5. 複合アクションでも同様のことができますが, 私は複合アクションはより粒度が小さく具体的な内容の場合に利用します. 例えば特定のツールのインストールなどです. ↩︎

Discussion