GitHub Actions でディレクトリの差分ごとにジョブを制御する
やりたいこと
モノレポ で CI を走らせる場合、フロントエンド に差分があったらフロントエンドのテストを、バックエンド に差分があったらバックエンドのテストを… のように実行を細かく制御したい場合がある。 参考
まず…
ひとつのワークフローで書き切りたい場合やより細かい制御を行う場合、以下のサンプルが参考になります。
想定するディレクトリ構成
code:project-tree
webapp/
.git/
frontend/
src/
Makefile
backend/
src/
Makefile
作成したワークフロー
code: .github/workflows/test.yml
name: Test
on: pull_request
jobs:
# ディレクトリごとに差分をチェックする
check-diff:
runs-on: ubuntu-latest
outputs:
should-test-frontend: ${{ steps.count-changed-files.outputs.frontend != '0' }}
should-test-backend: ${{ steps.count-changed-files.outputs.backend != '0' }}
steps:
- uses: actions/checkout@v4
- run: git fetch origin ${{ github.base_ref }} --depth=1
- id: count-changed-files
run: |
count-changed-files() {
relative_path=$1
git diff --name-only origin/${{ github.base_ref }} HEAD --relative $relative_path | wc -l
}
# $GITHUB_OUTPUT への書き込みに tee コマンドを利用しているのは標準出力を見てデバッグするため
echo "frontend=$(count-changed-files ./frontend)" | tee -a $GITHUB_OUTPUT
echo "backend=$(count-changed-files ./backend)" | tee -a $GITHUB_OUTPUT
test-frontend:
runs-on: ubuntu-latest
needs: check-diff
# ジョブごとスキップする
if: ${{ fromJSON(needs.check-diff.outputs.should-test-frontend) }}
steps:
- uses: actions/checkout@v4
- run: make test
working-directory: frontend
test-backend:
runs-on: ubuntu-latest
needs: check-diff
steps:
- uses: actions/checkout@v4
# 特定のステップのみスキップする
- if: ${{ fromJSON(needs.check-diff.outputs.should-test-backend) }}
run: make test
working-directory: backend
NOTE
GitHub Actions の outputs はすべての出力を文字列として扱う。
そのため、値を数値, 真偽値として扱うには fromJSON のような関数を利用してデシリアライズする必要がある。
あとがき
最近のソフトウェアはかゆいところに手の届く設計となっていて、非常に便利。
なにかできないことがあって困ったら、ソフトウェアより自分を疑うほうが早い印象。