🙄

Github Actionsのpushトリガでは思った通りの動きにならない場合

2022/11/05に公開

私はこれまでPR中に動いてほしいテストのようなワークフローのトリガとなるイベントにpushを選択していました。

例えばgoの自動テストでは以下のような記述です。

on:
  push:
    paths:
      - **/*.go
# ...

しかし、これでは同じPRブランチのなかでコミットによって実行されるワークフローが変わってしまっていました。

実行されるワークフローが減る場合

例えば、以下のようなコミット履歴を持つリポジトリでtopicブランチでPRを作成したとします。

このリポジトリではコミット1の時点で2つのワークフローが追加されています。

  1. ファイルA.txtのpushをトリガとするワークフローA
  2. ファイルB.txtのpushをトリガとするワークフローB

この時、コミット3でA.txtのみを変更しプッシュした場合にはワークフローAのみが実行されます。
そしてコミット4で変更されたのがB.txtのみの場合はワークフローBのみとなります。

githubのPRページでチェックされるワークフローは最新のコミットで実行されたワークフローのみなのでワークフローAが失敗していてもチェックしてくれません。(コミットの横にも✅や×等で成否の確認は出来ますがワークフローやコミットが増えると複雑になっていきます)

実行されるワークフローが増える場合

また、実行されるワークフローが増える場合もあります。
先程と同じように以下のようなコミット履歴を持つリポジトリでtopicブランチでPRを作成したとします。

このリポジトリでもコミット1の時点で2つのワークフローが追加されています。

  1. ファイルA.txtのpushをトリガとするワークフローA
  2. ファイルB.txtのpushをトリガとするワークフローB

コミット3の時点で変更されたファイルはA.txtのみなのでワークフローAのみが実行されます。
しかし、この変更をしている間にコミット4でA.txtとB.txtの変更が行われたのでtopicとmainの間でコンフリクトが発生したため、これを解消しつつマージを行いました。
その結果、マージコミットではワークフローAとワークフローBが実行されてしまいました。

原因

pushがトリガの場合、常にHEADとそのひとつ前の差分を見るようです。
なのでpushをトリガにしたワークフローの場合はコミット5のプッシュでコミット4との差分を確認します。

解決方法

これらの問題はtopicブランチの最新のコミットとmainブランチからの分岐点で差分を検出してくれるトリガを設定すれば良さそうです。

githubの公式ページにpull requestではマージ元との差分を取ってくれるというような記載がありました。

https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-comparing-branches-in-pull-requests#three-dot-and-two-dot-git-diff-comparisons

There are two comparison methods for the git diff command; two-dot (git diff A..B) and three-dot (git diff A...B). By default, pull requests on GitHub show a three-dot diff.

Three-dot Git diff comparison
The three-dot comparison shows the difference between the latest common commit of both branches (merge base) and the most recent version of the topic branch.

差分の取得はトリガをpull_requestにすれば良さそうです。
また、topicブランチのpush毎にワークフローを起動したい場合は以下のリンクの通りsynchronizeアクションを使えば良さそうです。

https://docs.github.com/ja/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#webhook-payload-object

ここまでで以下のようなトリガを設定すれば期待通りの挙動を行うことが分かりました。
typesに書かれているアクションは指定しなくてもpull_requestをトリガに指定すればデフォルトで設定されているようです。

on:
    pull_request:
        types:
            - synchronize
            - open
            - reopen
        pathes:
            - A.txt

以上です。

モノレポであればファイルの種類が多くそれぞれに適用すべきワークフローが変わってくるため、トリガがプッシュでは対応出来ていないことが特に多くあるかと思います。

この記事が参考になれば幸いです。

Discussion