GitHub Actions で Pull Request の差分に対して swift-format をかける
概要
タイトルの通りです。
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
を削除するようにしてください。
-
注記を参照 ↩︎
Discussion