Simon Eßlinger

How to share a .NET analyzer setup across solution and git repository borders

Published on 10/14/2024

Sharing 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:

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

You can learn more about this topic in Microsoft Learn.

Tags: dotnetcsharpnuget