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# のコードフォーマットを自動修正する方法を紹介します。

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

概要

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

実行例

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

https://github.com/guitarrapc/githubactions-lab/pull/41

dotnet format で自動でPR を作る例

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# プロジェクトを週一/手動でコードフォーマットします。

https://gist.github.com/guitarrapc/a9569864a568f50b8a37192b2b339ca9

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

https://github.com/guitarrapc/githubactions-lab

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で紹介されているので、まずは見てみるといいでしょう。オプションも一通り説明があります。

https://docs.microsoft.com/ja-jp/dotnet/core/tools/dotnet-format

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

https://github.com/dotnet/format

サブコマンドが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チームのをベースにしています。チームごとにルールが存在するはずなので参考程度に。

https://github.com/guitarrapc/githubactions-lab/blob/main/src/dotnet/.editorconfig

.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を使うことになります。

https://www.nuget.org/packages/dotnet-format/

.NET 6で標準提供するにあたりコマンド体系が変わったので、この記事のGitHub Actionsは修正がいります。

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

https://blog.shibayan.jp/entry/20200322/1584875344

https://www.meziantou.net/enforce-dotnet-code-style-in-ci-with-dotnet-format.htm

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