はなちるのマイノート

Unityをメインとした技術ブログ。自分らしくまったりやっていきたいと思いますー!

【Actions】「dorny/paths-filter」を用いてジョブ単位でのpathsを実現する

はじめに

GitHub Actionsで特定のフォルダ以下のファイルが変更されたときのみワークフローを実行するにはpathsを使うと思います。

# srcフォルダ以下のファイルが変更されたときのみ実行する
on:
  pull_request:
    paths:
      'src/**.cs'

ただjob単位で条件をつけようとすると、結構面倒です。

# 特定のファイルが変更されたときだけjobを実行したいなら以下のように if で書く
# ただしワイルドカードが利用できないので、フォルダ以下の全てのファイルが対象だとかなり大変
jobs:
  hoge:
    runs-on: ubuntu-latest
    if: contains(github.event.pull_request.changed_files, 'src/Program.cs')

そこで今回紹介するdorny/paths-filterを用いると簡単に実現できるので紹介します。

概要

path-filterジョブやステップ単位でのpaths相当の処理が簡単に利用できる機能を提供しています。

GitHub Action that enables conditional execution of workflow steps and jobs, based on the files modified by pull request, on a feature branch, or by the recently pushed commits.

Run slow tasks like integration tests or deployments only for changed components. It saves time and resources, especially in monorepo setups. GitHub workflows built-in path filters don't allow this because they don't work on a level of individual jobs or steps.

// DeepL翻訳
GitHub Action は、プルリクエスト、フィーチャーブランチ、または最近プッシュされたコミットによって変更されたファイルに基づいて、ワークフローのステップやジョブの条件付き実行を可能にします。

統合テストやデプロイのような遅いタスクを、変更されたコンポーネントに対してのみ実行します。特にモノレポのセットアップでは、時間とリソースを節約できます。GitHub ワークフローに組み込まれているパスフィルターは、個々のジョブやステップのレベルでは動作しないため、このようなことはできません。

github.com

使い方

公式ドキュメントにはjobの先頭でdorny/paths-filter@v3を利用する構成がまず紹介されています。

- uses: dorny/paths-filter@v3
  id: changes
  with:
    filters: |
      src:
        - 'src/**'

  # run only if some file in 'src' folder was changed
- if: steps.changes.outputs.src == 'true'
  run: ...

GitHub - dorny/paths-filter: Conditionally run actions based on files modified by PR, feature branch or pushed commits


ただ実用するうえでは最初に変更差分を調べるジョブを作成して、それをneedsで待ち検証する利用方法のほうが便利だと思います。

name: test
on:
  pull_request:

jobs:
  # srcフォルダ以下のファイルが変更されているかを調べて、結果をoutputsに格納する
  changes:
    runs-on: ubuntu-latest
    permissions:
      pull-requests: read
    outputs:
        src: ${{ steps.filter.outputs.src }}
    steps:
      - uses: dorny/paths-filter@v3
        id: filter
        with:
          filters: |
            src:
              - 'src/**'
  # srcフォルダ以下のファイルが変更されていないと実行されない
  test:
    needs: changes
    if: ${{ needs.changes.outputs.src == 'true' }}
    runs-on: ubuntu-latest
    permissions:
      contents: read
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-dotnet@v3
        with:
          dotnet-version: 8.0.x
      - run: dotnet restore
      - run: dotnet build --configuration Release --no-restore
      - run: dotnet test --no-restore --verbosity normal
  # いつでも実行される
  hoge:
    runs-on: ubuntu-latest
    steps:
      - run: |
          echo "hoge"

実験

src以下のファイルを変更した場合のみtestジョブが実行されることが確認できました。

ジョブがスキップされる場合 と 実行される場合

さいごに

またreadmeによりいろんな場面で利用できるサンプルがあるので、興味がある方は是非。
github.com