How to share a .NET analyzer setup across solution and git repository borders
Published on 10/14/2024Sharing a .NET analyzer setup across multiple projects and easily be archived using project references or a Directory.Build.props file. But how can you share an analyzer setup across multiple solutions that are maybe not even in the same git repository? Lets find out.
Local setup
When you start to develop a new product your setup is typically very simple:
A single .NET solution (.sln), that contains a single .NET project (.csproj).
To add an analyzer to your project you simply add a NuGet package reference: e.g. dotnet add package SonarAnalyzer.CSharp.
Then to configure the analyzer, you can add an EditorConfig ↗ file (.editorconfig) to your .csproj directory, and define rules:
dotnet_diagnostic.S1128.severity = none
dotnet_diagnostic.S4457.severity = suggestion
As .editorconfig files apply to all files in the same directory, including all child directories, you can also create this file on the .sln file level to apply the configuration to all projects in the solution.
In that case you still have to add a reference to the analyzer package to all projects though, else the configuration will have no effect.
An easy way to do this, is to add a Directory.Build.props ↗ file to the .sln directory that contains the reference:
<Project>
<ItemGroup>
<PackageReference Include="SonarAnalyzer.CSharp" Version="9.32.0.97167" />
</ItemGroup>
</Project>
Distributed setup
Later on during the development of your product you might start to separate your product into multiple services in different git repositories, so that teams can operate independently.
If you do not want to deal with git submodules, then you can no longer share the analyzer setup across all repositories using an .editorconfig file.
This is where global AnalyzerConfig files ↗ come in.
They have the same syntax as .editorconfig files, but they have some different properties:
- You cannot use them to configure code style settings like
indent_style = space. - They apply to all files in the project they are referenced (
.editorconfigfiles are applied based on the file tree). - They can be shared through a NuGet package ↗.
So to replicate our local setup across multiple git repositories, we have to create a NuGet package that is structure like this:
build/
MyNugetPackageName.globalconfig
MyNugetPackageName.props
MyNugetPackageName.csproj
The .globalconfig file has the same content as the .editorconfig:
dotnet_diagnostic.S1128.severity = none
dotnet_diagnostic.S4457.severity = suggestion
The .props file references the .globalconfig file:
<Project>
<ItemGroup>
<GlobalAnalyzerConfigFiles Include="$(MSBuildThisFileDirectory)MyNugetPackageName.globalconfig" />
</ItemGroup>
</Project>
The .csproj file contains the reference to the .props file and makes sure to include the .globalconfig:
<Project>
<ItemGroup>
<PackageReference Include="SonarAnalyzer.CSharp" Version="9.32.0.97167" />
</ItemGroup>
<ItemGroup>
<None Include="build/*" Pack="true" PackagePath="/build" />
</ItemGroup>
</Project>
Now all we have to do is to build, publish and reference the package where it is needed.
Bonus: Warnings as errors
If you want to teat warnings as errors in Release builds you can add a MyNugetPackageName.targets file to the build directory that contains this XML:
<Project>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
</Project>
TL;DR
- Use
.editorconfigfiles to configure code style and analyzers (in local scenarios). - Use
.globalconfigfiles to configure analyzers and distributed them through NuGet in distributed scenarios.
You can learn more about this topic in Microsoft Learn ↗.