The Goal: gradually introduce analyzer checks
The premise of this post is to introduce .NET analyzer checks into a mono-repo for different teams.
The approach must not cause any additional build warnings until the teams opt-in their projects.
As good .NET citizens we will not put .NET-specific analyzer rules in our .editorconfig
, but use the recommended global AnalyzerConfig file.
What the heck is a global AnalyzerConfig file?
In addition to .editorconfig
files, you can provide so-called global AnalyzerConfig files.
Although global global AnalyzerConfig files have been around since .NET 5 SDK, I personally have not seen wide adoption.
I will not repeat all the differences between the two, but instead point to the official documentation and this well-written comparison.
In short: .editorconfig is for syntax, global AnalyzerConfig files are for code analysis.
The naive approach has a surprise for you
Alright, this sounds simple: add a global AnalyzerConfig file and then let each team opt into using it by setting the EnableNETAnalyzers
property in their project.
By using the default file name .globalconfig
, the project should then pick it up automatically.
Sure enough, this works for the CLI build: without EnableNETAnalyzers
set, the build does not care about the .globalconfig
, and with EnableNETAnalyzers
set, the build will pick it up automatically because of its file name.
Yay!
But, wait a minute.
Why do I get build warnings in my Visual Studio, even though I did not set EnableNETAnalyzers
?
I did not opt in, so I do not want any warnings!
Well, it seems like Visual Studio itself (tested with VS 2022 17.5) will enforce a .globalconfig
independent of whether the project has EnableNETAnalyzers
set or not.
It will thus show warnings even though the CLI build does not.
This is bad developer experience, so what do we do?
Getting consistent behavior in CLI and VS
The file needs to have a different name as to not be picked up by VS automatically.
Let’s call it code-style.config
.
Now, when we do set EnableNETAnalyzers
, the file will also not be picked up automatically.
We must explicitly add it to the GlobalAnalyzerConfigFiles
item.
To opt-in a project, the settings we must add now look like this:
<PropertyGroup> <EnableNETAnalyzers>true</EnableNETAnalyzers> </PropertyGroup> <ItemGroup> <GlobalAnalyzerConfigFiles Include="../../code-style.config" /> </ItemGroup>
While this may be fine for developers who actively author csproj
files and know a bit of MSBuild, it may be offputting for many others.
Simplifying usage to ease adoption
We thus put all of the above in a global code-style.props
file right next to the global code-style.config
file (following the rules for .props
files)
<Project> <PropertyGroup> <EnableNETAnalyzers>true</EnableNETAnalyzers> </PropertyGroup> <ItemGroup> <GlobalAnalyzerConfigFiles Include="$(MSBuildThisFileDirectory)code-style.config" /> </ItemGroup> </Project>
The teams now only have to add one line to their project to opt in:
<Import Project="../../code-style.props" />
Alright, that looks good enough.
For good measure, add a comment in the code-style.props
and/or code-style.config
about the reason for this seemingly overcomplicated approach, so that future readers do not have to be surprised again.