GitHub で公開してるコードに Pull Request が来た時、思ってた以上にコーディングスタイルがバラバラで困ってたので EditorConfig を追加して CI でチェックするようにしました。
C# はみんなが Visual Studio を使っていて、大体は良い感じのコーディングスタイルになっていると思っていたらそんなことはなかったようです。Visual Studio では少し前から EditorConfig に対応しています。
リポジトリに EditorConfig を入れておけば、Visual Studio や Visual Studio Code ではいい感じに読み取ってくれて最高という世界になるはずですが、元になるファイルをどう作るかが悩みどころでした。
いろいろと試してみましたが、C# の世界では以下の 4 種類ぐらいの方法を選べそうです。
Visual Studio の設定からエクスポート
素の Visual Studio でサクッと使えるのが、設定から .editorconfig
をエクスポートする方法です。
現状のコーディングスタイルは Visual Studio の設定に従っているはずなので、ここからエクスポートすれば同じ設定を適用できます。設定からエクスポートを選ぶだけなので簡単です。
欠点としては設定項目が少ないかなという点ぐらいです。まずはここから始めるのがわかりやすそうです。
Visual Studio は .editorconfig
の IntelliSense に対応しているので、編集は比較的やりやすいですがドキュメントを確認しながらじゃないと難しいかったです。Before / After が確認できる GUI が欲しくなります。
IntelliCode を使って自動生成
IntelliCode を使うと既存のコーディングスタイルから .editorconfig
を作成することが出来ます。
この IntelliCode を使った .editorconfig
の生成はプレビュー機能なので、設定から明示的にオンにしないと有効にならないです。まだ生成される項目も少なめという印象です。
生成はソリューションエクスプローラーの追加サブメニューから行えます。ちょっとわかりにくい。
古いコードや社内の独自コーディングスタイルがある場合には便利に使えるのかもしれません。個人的には Visual Studio 標準のコーディングスタイルに従ってきたので、あまり有用ではなかったです。
ReSharper の設定からエクスポート
長く ReSharper を使ってきた人は自分用のフォーマット設定を持っていると思いますが、最近の ReSharper は .editorconfig
としてエクスポートする機能があるので簡単に設定を共有できます。
ReSharper の設定からエクスポートする場合は Tools
サブメニューから辿っていけば行えます。
この機能でエクスポートした .editorconfig
には ReSharper の独自拡張項目も含まれているので、相手が ReSharper を使っている場合には更に細かいコーディングスタイルを強制できるようになってます。
ただし、ReSharper 拡張項目に関しては後述する dotnet-format
では反映されないです。
.NET Core / Roslyn の EditorConfig を利用する
ここまで Visual Studio や ReSharper を使って .editorconfig
を生成する方法を紹介してきましたが、自分が最終的に選んだのは .NET Core / Roslyn の EditorConfig でした。
C# の世界では一番標準的なコーディングスタイルが .NET Core / Roslyn といったランタイム・コンパイラのコードだと思っています。実際に自分が書いていたコードに対して自動フォーマットを実行しましたが、ファイル最後の改行以外の差異は出ませんでした。
ちなみに C# 以外のファイルタイプに対する設定もいくつか入っているので結構便利です。
EditorConfig でのチェックを CI に入れる
ここまでで .editorconfig
は準備できているはずなので、最後に CI でチェックを行うようにしておきます。Pull Request の場合は CI で落ちるようにので、パスするまでマージ出来ないようになります。
チェックには dotnet-format
を使います。プリインストールはされないので CI では都度入れる必要がありますが、Global Tool なのでコマンド 1 つで入るため簡単です。
既に dotnet-format
と Azure Pipelines を使った定義を試している方がいたので、この定義をほぼそのまま組み込みました。--dry-run
と --check
の組み合わせは一見違和感がありますが動きました。
まだ GitHub に公開していて Azure Pipelines での CI を導入しているリポジトリ全てには設定できていないですが、利用頻度の高いリポジトリからチェックするようにしています。
Azure Pipelines での実行結果は以下のようになります。コーディングスタイルに問題があれば失敗します。
暇な時にでもテンプレートとして .gitignore
/ .editorconfig
/ azure-pipelines.yml
といった必須ファイルをメンテナンスするリポジトリでも作ろうかと思っています。