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 (
.editorconfig
files 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
.editorconfig
files to configure code style and analyzers (in local scenarios). - Use
.globalconfig
files to configure analyzers and distributed them through NuGet in distributed scenarios.
You can learn more about this topic in Microsoft Learn ↗.