📌

【GitHub Actions】 monorepoでデプロイ依存関係を維持しつつ差分があるパッケージのみデプロイする

に公開

背景

monorepo で複数パッケージを管理している時、依存関係を保ちつつ差分があるパッケージのみをデプロイしたいことがあります。例えば (DB のマイグレーション) → (API デプロイ) → (フロントデプロイ) のような処理順序があったとして、PR に DB のマイグレーションは候補のファイルがないためスキップしたいが、API には差分があるためデプロイしたい、と言ったことがあった場合に単純に needs を書くだけではマイグレーションをスキップしてしまうと後続の処理が全てスキップされてしまいます。イメージとしては下のような依存関係を保ちつつ必要な部分だけデプロイしたいです。

イメージ

サンプルコード

name: monorepo-deploy-sample
on:
push:
branches: [main]

jobs:
  check-diff:
  runs-on: ubuntu-latest
  outputs:
    migrate: ${{ steps.migrate.outputs.changed }}
    api: ${{ steps.api.outputs.changed }}
    app: ${{ steps.app.outputs.changed }}
    steps:
      - uses: actions/checkout@v4
        with:
        fetch-depth: 0
      - id: migrate
        run: |
          if git diff --name-only ${{ github.event.before }} ${{ github.sha }} | grep '^apps/db/'; then
            echo "changed=true" >> $GITHUB_OUTPUT
            else
            echo "changed=false" >> $GITHUB_OUTPUT
          fi
      - id: api
        run: |
          if git diff --name-only ${{ github.event.before }} ${{ github.sha }} | grep '^apps/api/'; then
            echo "changed=true" >> $GITHUB_OUTPUT
            else
            echo "changed=false" >> $GITHUB_OUTPUT
          fi
      - id: app
        run: |
          if git diff --name-only ${{ github.event.before }} ${{ github.sha }} | grep '^apps/app/'; then
            echo "changed=true" >> $GITHUB_OUTPUT
            else
            echo "changed=false" >> $GITHUB_OUTPUT
          fi

migrate:
  needs: check-diff
  if: needs.check-diff.outputs.migrate == 'true'
  runs-on: ubuntu-latest
  steps:
    - run: echo "🗄️ Run DB migration"

deploy-api:
  needs: [migrate]
  if: needs.check-diff.outputs.api == 'true' &&
    !failure() && !cancelled() &&
    (needs.migrate.result == 'success' || needs.migrate.result == 'skipped')
  runs-on: ubuntu-latest
  steps:
    - run: echo "🚀 Deploy api"

deploy-app:
  needs: [deploy-api]
  if: needs.check-diff.outputs.app == 'true' &&
    !failure() && !cancelled() &&
    (needs.deploy-api.result == 'success' || needs.deploy-api.result == 'skipped')
  runs-on: ubuntu-latest
  steps:
    - run: echo "🚀 Deploy app"

解説

(needs.migrate.result == 'success' || needs.migrate.result == 'skipped')

を条件に加え、「成功したか あるいは スキップだったら続行」というロジックにしています。

!failure() && !cancelled()

念の為ジョブ自体が失敗・キャンセルされた場合は実行しないよう条件を加えています。

Discussion