はじめに
個人でiOSアプリ開発を行なっている田中幹久です。
SwiftFormatとは
コードをプロジェクト全体で統一できるツールです。
複数人での共同編集では必須の機能だと考えています。
これは手動での実行のほかに、ビルド時での自動実行などもできます。
その中でもコミット時の自動実行の方法も紹介したいと思います。
備忘録も兼ねてこの記事を書きます。
例えば、以下のような場合。
//サンプル1(修正前)
if [].count == 0 {}
//サンプル2(修正後)
if [].isEmpty {}
このようなケースで、SwiftFormatを実装すると、どちらか一方に統一できます。
他にも、変数名のルールであったり、改行のタイミングなどなど細かくカスタムできます。
実装手順
1. BuildToolsの導入
File>New>Packageから、BuildToolsを追加します。
以下のようにAdd toとGroupを設定してください。
以下のようになれば成功です。
BuilrToolsは初期設定のままで良いです。
2. SwiftFormatのインストール
brew install swiftformat
3. SwiftFormatパッケージの導入
SPMで以下のURLをコピペして実装してください。
Add to targetは変更しなくて良いです。
https://github.com/nicklockwood/SwiftFormat.git
4. 必要なファイルの作成
4.1 SwiftFormat設定ファイル
プロジェクトルートに.swiftformatファイルを作成し、以下の内容をコピペしてください。
# swift-format configuration file
# Rule List: https://github.com/nicklockwood/SwiftFormat/blob/master/Rules.md
# --------------------
# File Options
# --------------------
--swiftversion 5.6
--exclude Pods,Carthage,BuildTools
# --------------------
# Formatting Options
# --------------------
# 複数行の配列や辞書などで、最後のカンマを強制的に削除する
--commas inline
# "0...9" のような範囲演算子の周りにスペースを入れない
--ranges no-space
# 空白に関する設定
--trimwhitespace always
# 引数が複数ある場合、引数ごとに改行する
--wraparguments before-first
# インデントをスペース4つに設定
--indent 4
# --------------------
# Opt-in Rules (有効化するルール)
# --------------------
# import文をアルファベット順にソートする
--sorted-patterns
# .count == 0 を .isEmpty に置換する
--enable isEmpty
# ----------------------------------------------------
# Disabled Rules (デフォルトから無効化しているルール)
# ----------------------------------------------------
--disable enumNamespaces
--disable extensionAccessControl
--disable preferKeyPath
--disable redundantExtensionACL
--disable redundantObjc
--disable redundantReturn
--disable redundantSelf
--disable semicolons # 行末のセミコロンを自動削除しない
--disable strongOutlets
--disable strongifiedSelf
--disable todos # FIXME/TODOコメントに関するルールを無効化
--disable typeSugar # [Int] を Array<Int> に変換しない
--disable unusedArguments # 未使用の引数に `_` を自動付与しない
--disable void # () を Void に変換しない
--disable wrapMultilineStatementBraces
4.2 GitHooksディレクトリの作成
次は、コミット時に自動でSwiftFormatを実行する設定です。
mkdir -p GitHooks
4.3 pre-commitフックの作成
GitHooks/pre-commitファイルを作成し、以下の内容をコピペしてください:
#!/bin/sh
# 新プロジェクトへの実装手順
#1. git config --local core.hooksPath GitHooks
# 現在のブランチを取得
CURRENT_BRANCH=$(git branch --show-current)
# mainブランチの場合はスキップ
if [ "$CURRENT_BRANCH" = "main" ]; then
echo "🔒 mainブランチのため、pre-commitフックをスキップします。"
exit 0
fi
# Homebrewでインストールしたswiftformatを直接呼び出す
# 'command -v'でコマンドの存在を確認
if ! command -v swiftformat &> /dev/null
then
echo "⛔️ swiftformatコマンドが見つかりません。"
echo " 'brew install swiftformat' を実行してインストールしてください。"
exit 1
fi
echo "✅ SwiftFormatのチェックを実行します..."
# ステージングされたSwiftファイルのみを対象にする
STAGED_SWIFT_FILES=$(git diff --diff-filter=d --staged --name-only | grep -e '\(.*\).swift$')
if [ -z "$STAGED_SWIFT_FILES" ]; then
echo "Swiftファイルはコミット対象外です。スキップします。"
exit 0
fi
# まずは--lintでチェックだけ行う
echo "フォーマットをチェック中..."
echo "$STAGED_SWIFT_FILES" | xargs swiftformat --lint
if [ $? -eq 0 ]; then
echo "✨ 全てのファイルが整形済みです。コミットを完了します。"
exit 0
fi
# lintでエラーがあった場合、フォーマットを適用してコミットを中断
echo "⚠️ フォーマットの乱れを検出しました。自動修正します..."
echo "$STAGED_SWIFT_FILES" | xargs swiftformat
echo "⛔️ ファイルが自動修正されました。再度 'git add' してコミットし直してください。"
exit 1
4.4 実行権限の付与
以下のコマンドを打たないと実行されません。
プロジェクトのパスで以下のコマンドを実行してください。
chmod +x GitHooks/pre-commit
4.5 GitHooksのパス設定
git config --local core.hooksPath GitHooks
5. 手動実行用スクリプトの作成(オプション)
プロジェクトルートにformat.shファイルを作成し、以下の内容をコピペしてください:
#!/bin/bash
# SwiftFormat実行スクリプト
# 使用方法: ./format.sh [ファイル名]
set -e
# プロジェクトルートディレクトリに移動
cd "$(dirname "$0")"
# SwiftFormatの実行
if [ $# -eq 0 ]; then
# 全ファイルをフォーマット
echo "全Swiftファイルをフォーマットしています..."
swiftformat .
else
# 指定されたファイルをフォーマット
echo "ファイル $1 をフォーマットしています..."
swiftformat "$1"
fi
echo "フォーマット完了!"
実行権限を付与:
chmod +x format.sh
動作確認
1. 基本的な動作確認
# SwiftFormatが正常に動作するかテスト
swiftformat --version
# 設定ファイルが正しく読み込まれるかテスト
swiftformat SwiftfomatSample/ContentView.swift --dryrun
2. GitHooksの動作確認
テスト用ブランチの作成
# 新しいブランチを作成
git checkout -b test-swiftformat
フォーマットが崩れたコードの作成
意図的にフォーマットを崩したコードを作成します。
うまく設定ができていたらコミットでステージに上げた時にErrorFormatFnctionの.count == 0が.isEmptyに置き換わるはずです。
以下の手順で、手動で実行することもできます。
import SwiftUI
struct ContentView: View {
var body: some View {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundStyle(.tint)
Text("Hello, world!")
}
.padding()
}
private func ErrorFormatFnction() {
if [].count == 0 {}
}
}
#Preview {
ContentView()
}
トラブルシューティング
よくある問題と解決方法
1. SwiftFormatコマンドが見つからない
# エラーメッセージ
⛔️ swiftformatコマンドが見つかりません。
# 解決方法
brew install swiftformat
2. 設定ファイルの構文エラー
# エラーメッセージ
error: Unknown option --spacearoundoperators
# 解決方法
最新のSwiftFormatの正しいオプション名を使用
--no-space-operators # 正しいオプション名
3. GitHooksが動作しない
# 確認事項
git config --local core.hooksPath # GitHooksが表示されるか
ls -la GitHooks/pre-commit # ファイルが存在し、実行権限があるか
4. mainブランチでフックがスキップされる
これは正常な動作です。mainブランチでの意図しない変更を防ぐための仕組みです。



