Tl;Dr
SwiftFormatは pre-commit に対応しているので .pre-commit-config.yaml
を作成し、
repos:
- repo: https://github.com/nicklockwood/SwiftFormat
rev: 0.44.2
hooks:
- id: swiftformat
pre-commit install
すればコミット時に適用してくれるようになる。
なぜ?
通常の iOSアプリプロジェクトであれば SwiftFormat は Xcode における Build Phases に組み込んで適用するのがセオリーといえる。
しかし、Swift Package Manager の場合、XcodeプロジェクトはPackage.swift
およびディレクトリツリーから自動生成するため、Xcodeの設定を変更するやり方はあまりベターではない(Xcode 11.4 からLSP が同梱されるようになったことから、そもそも Xcode の利用はオプショナルになりつつもある)。
そのため、Git の pre-commit でフックするやり方も考えられる。
pre-commit
pre-commit は Python製のツールで、Git の pre-commit にフックするスクリプトを管理するためのエコシステムのようなものらしい。Swift Package Manager が Swift 製のライブラリを管理するエコシステムであれば、それの pre-commit hook 版、といったところだろうか。
以下の記事がわかりやすかった。
Python製のツールpre-commitでGitのpre-commit hookを楽々管理!!
導入
pre-commit 自体は Homebrew でインストールできるので brew install pre-commit
するだけでよい。
あとは冒頭に書いたように.pre-commit-config.yaml
を作成し、pre-commit install
すれば導入は完了である。
私のリポジトリではMakefile
とBrewfile
を用意し、make setup
の1コマンドで導入できるようにしている。
setup:
brew bundle
pre-commit install
brew "pre-commit"
使い方
コミット時に SwiftFormat により変更が入った場合、コミットは失敗して変更自体はアンステージされた状態になる。
冒頭の画像の再掲となるが、 Failed
と右上に表示されているのはそういう意味である。
そのため、適用された変更はgit add
でステージした上で再度コミットする必要がある。
補足
SwiftFormat の README には通常のpre-commit hook を利用した手順も記載されている。
#!/bin/bash
git diff —diff-filter=d —staged —name-only | grep -e ‘\(.*\).swift$’ | while read line; do
swiftformat “${line}”;
git add "$line";
done
このスクリプトは swiftformat
を実行後に自動的に git add
する作りになっているため、 pre-commit のようにコミットに失敗したらステージして再度コミットする、といった手間がない。
一方、ファイル全体をgit add
されてしまう為、部分的にステージ(git add -p
)・コミットしたい場合などに、意図しなかった変更までコミットしてしまうリスクもある。
このあたりはトレードオフではあるが、個人的には pre-commit の方が安全であると感じる。
終わりに
Swift Package Manager のプロジェクトでも、SwiftFormat で一貫したコードスタイルを。