tech.guitarrapc.cóm

Technical updates

dotnet format を CI で行って継続的にコードフォーマットしていく

この記事は Qiita C# Advent Calendar 2021 7日目の記事です。

Visual Studio や Rider での コードフォーマットは個人で使うにとても良く、開発上は必須といえます。 しかしチーム開発でコードフォーマットをいい感じに標準化させたい、労力かけずにフォーマット修正をかけたいと思ったときには CLI で実行できてほしいものです。

dotnet には長らく標準的なコードフォーマッタ用のCLI がありませんでしたが、.NET 6 SDK からコードフォーマッタ dotnet format が標準組み込みとなりました。

今回は C#で開発するにあたり、CI でCLIを実行してC# のコードフォーマットを自動修正する方法を紹介します。

普段からやっていると開発上でフォーマッタで困らなくなるので、塵も積もれば的な良さを感じる人がいれば幸いです。

tl;dr;

  • CI を使ってコードフォーマットをかけて変更をPR、レビューを通して自分たちのルールを見直したり、変更を取り込むという一連のフローができるようになります。
  • GitHub Actions で例を示しますが、ほかのCI でも同様に実施ができます。
  • コードフォーマットの対象 csproj やcsファイルを絞れるので、Unity など指定プロジェクトを除外することも可能です。
  • 週一程度の緩い利用からはじめて、ストレスにならない程度の運用から始めるといいでしょう。

実行例

まずはGitHub Actionsを実行して作られたPRから見てください。

github.com

f:id:guitarrapc_tech:20211207222057p:plain
dotnet format で自動でPR を作る例

f:id:guitarrapc_tech:20211207222443p:plain
PR の Files の変更一覧

この記事で紹介するGitHub Actionsを使うと、dotnet format された結果がPRで上がってきます。 PR は StatsFilesTargetProjects を示しています。ひと月あまり運用していて、ここが足りない、みたい、というフィードバックを受けてこのような形になりました。

  • Stats: パスごとの変更統計
  • Files: dotnet format がかかったファイル一覧 (場合によってファイル数が膨大になるので閉じています)
  • Target Projects: 対象の csproj 一覧

GitHub Actions のワークフロー全体像

先ほどのPR を作る GitHub Actions を示します。 このGitHub Actions は src/dotnet にある sln に基づいて、C# プロジェクトを週一/手動 でコードフォーマットします。

gist.github.com

プロジェクトが見たい場合は、元のリポジトリをどうぞ。

github.com

dotnet format のポイントは3つです。

  • dotnet format を使うには、.NET SDK 6 を setup-dotnet action でインストールします。
  • dotnet format は sln や slnf に対して実行するのがおすすめ。個別の .cs や csproj でも実行はできますが制御しやすいでしょう。
  • --exclude を使って、コードフォーマットの除外ファイルやcsprojを指定できます。複数除外もできます。

GitHub Actions の中身を軽く説明します。

  • 24行目: sln が含んでいる csproj を一覧で取得しています。
  • 34行目: PR駆動時などに、dotnet format の問題をGitHub 上で示します。
  • 38行目: ここで dotnet format をかけています。
  • 42行目~: 変更があったか、変更の統計などを取得しています。
  • 70行目: dotnet format で変更があった時だけ PR を作っています。

dotnet format を使う基本

ドキュメント

.NET 6 の dotnet format は、Microsoft Docs で紹介されているので、まずは見てみるといいでしょう。オプションも一通り説明があります。

docs.microsoft.com

リポジトリを見ると使い方がすべて乗っています、おすすめ。

github.com

サブコマンドが3つありますが、気にせず dotnet format するのがおすすめです。何も考えず dotnet format をかけられる環境を維持しましょう。

  • dotnet format whitespace: fixes whitespace
  • dotnet format style: runs code style analyzers
  • dotnet format analyzers: runs third party analyzers

.editorconfig を用意する

dotnet format は .editorconfig をフォーマットルールにするので、まずこれを用意しましょう。

.editorconfig を sln と同じ階層に置いて、C# のフォーマットルールを .editorconfig に定義すれば準備完了です。(リポジトリルートに配置しても動作しますが把握が難しくなるので避けています)

例としたリポジトリで使っている .editorconfig は Roslynチームのをベースにしています。チームごとにルールがあると思うので参考程度に。

github.com

.editorconfig 定義すると dotnet format だけじゃなく Visual Studio でも同じフォーマットルールが適用されます。dotnet format を使わなくても、チーム開発でコーディングルールを持っているところでは .ediitorconfig を活用するのが幸せです。Rider も editorconfig をサポートしています、VS Code は EditorConfig for VS Code を使いましょう。

editorconfig を書いてて悩むであろうものは severity だと思います。デフォルトでは severity: warning なルールは dotnet format 実行時に自動で修正されます。自動修正されてほしい、Visual Studio でも守ってほしいものは warning をベースにしていくといいでしょう。過激派は error もやるかもです。あるいは、dotnet format 実行時に --severity でレベルを指定できます。

OSS 開発で時々見かける、.cs ファイルごとにヘッダにライセンスを入れるとかも .editorconfigfile_header_template を定義すれば dotnet format で一発で適用できます。こんなの人のやることじゃないのでうれしいことが多いでしょう。

.NET 5 での dotnet format

.NET 5 でdotnet formatを使うには、dotnet tools を使うことになります。

www.nuget.org

.NET 6 で標準提供するにあたりコマンド体系が変わったので、この記事の GitHub Actions はそのまま使うことはできません。

.NET 5 時代のは何人か紹介されているので見るといいのではないでしょうか。

blog.shibayan.jp

www.meziantou.net

.NET 6 にするまでの過渡期にはほしいところもあるでしょう。