🤖

GitHub Actions で Pull Request の差分に対して swift-format をかける

2024/04/18に公開

概要

タイトルの通りです。
GitHub Actions で Pull Request 時に swift-format でコードフォーマットを実行する方法をまとめました。
YAML をコピペすれば動くはずです。[1]

先に結論

  • 下記の YAML を .github/workflows/swift-format.yml に配置すれば動作します
  • main ブランチへの Pull Request 時に発火します
  • PR での変更された .swift ファイルに swift-format をかけて git commit & push します

経緯

https://zenn.dev/worlddowntown/articles/fde932c555f801 では Git Hooks で swift-format を実行する方法を書きましたが、ドキュメントに書いたり、Makefile 簡略化してもすべての人が設定してくれるとは限りません。

個人に頼らずコードフォーマットを自動化したかったので、GitHub Actions でやってみました。

ポイント

brew install swift-format

actions/cache を使ってみたりもしましたが、毎回 brew install swift-format にかかる時間が 5秒 程度なので cache は使っていません。

必要な履歴だけ checkout する

actions/checkout のデフォルトでは先頭のコミットしか取得しません。
Pull Request の全コミットの差分ファイルを特定するために、 actions/checkout に fetch-depth: 0 を指定する方法もありますが、これはリポジトリの全ての歴史を checkout するため、リポジトリによっては時間がかかってしまいます。

下記のように fetch-depth: <Pull Request のコミット数 + 1> となるようにして、必要最小限の checkout となるように調整しています。

元ネタ: https://github.com/actions/checkout/issues/552#issuecomment-1167086216

      - name: PR commits + 1
        id: pre_fetch_depth
        run: echo "depth=$(( ${{ github.event.pull_request.commits }} + 1 ))" >> "${GITHUB_OUTPUT}"
      - name: Checkout PR branch and all PR commits
        uses: actions/checkout@v4
        with:
          ref: ${{ github.event.pull_request.head.ref }}
          fetch-depth: ${{ steps.pre_fetch_depth.outputs.depth }} # (PR の commits + 1) 個 checkout する

Pull Request で変更があった .swift ファイルを抽出

git diff の --diff-filter オプションで Added (A), Copied (C), Modified (M), Renamed (R) なファイルを抽出しています。

      - name: Find swift files to format
        run: |
          SWIFT_FILES=()
          while IFS="" read -r file; do SWIFT_FILES+=("${file}"); done < <(git diff --name-only --diff-filter=ACMR ${{ github.event.pull_request.base.sha }} -- "*.swift")

注記

Gist の swift-format.yml ではプロジェクトルートに .swift-format があることを前提としています。
これは swift-format の設定ファイルで、必須ではありません。
必要に応じて ファイルを用意するか、swift-format コマンドから --configuration .swift-format を削除するようにしてください。

脚注
  1. 注記を参照 ↩︎

Discussion