C# linting in Azure DevOps pipelines
The year is 2020 and linting (aka static analysis) has made its way to modern C#. As opposed to weakly-typed languages like JavaScript and Python where it’s used to catch stylistic and programming errors that are otherwise detectable only at runtime, or result from the burden of unconstrained freedom that such languages bestow upon unsuspecting engineers, in a more enterprise solutions powered by C# and its strongly-typed brethren linting has made a comeback as a policy tool in the CI/CD quality gates, to be run in parallel along with security and dependency scan jobs. Since Microsoft has finally embraced EditorConfig
for all Roslyn-powered projects in VS 2019 16.3+ (and analyzer toolset 3.3+), we don’t need to write ugly .ruleset
files anymore to trigger build errors or to regulate the severity of violations. We can mix and choose many available analyzer packages like the StyleCop, the Roslynator, the port of the well-known FxCop for CAXXXX rules, or some obscure and specialized ones like Meziantou and VisualStudio.Threading. There are several possibilities as to how this can integrated into a build pipeline, so let’s investigate!
Treat warnings as errors
We assume .editorconfig
is configured properly in the solution. If we want to enforce e.g. StyleCop
on all projects in the solution we simply create a Directory.Build.props
at the solution level like so:
The TreatWarningsAsErrors
element set to true
will force builds to fail if any of the configured rules are violated. Alternatively, we can specify that as a parameter in the (CI) build script:
The Directory.Build.props
file could also be pulled during pipeline execution from an external source if it is not present in the repository, or the pipeline can have the TreatWarningsAsErrors
element enforced as a simple XML transformation in case it is turned off by default in the development branch.
dotnet format
dotnet format is a global dotnet tool that can read editorconfig files, check them for violations (--check
), and even apply fixes (--fix-style
, -fix-analyzers
). When running in a checking mode, it will return a non-zero exit code when violations are detected, which will in turn force the Azure DevOps pipeline to fail. We can use it in YAML like so:
Build Quality Checks
Build Quality Checks task can be installed for free on an Azure DevOps organization. It enables various quality gates for the tasks that precede it, such as checking for warnings in the build output and failing if they occur:
warningFilters
option could be used to look only for e.g. StyleCop warnings using JavaScript regexes: /##\[warning\].+SA.+:/i
, or e.g. for FxCop-style warnings /##\[warning\].+CA.+:/i
, and ignore the junk produced by other tasks, or other types of warnings. In that case, inclusiveFiltering
should be set to true
as well.
Manually checking the build output
We can write an inline PowerShell task that will capture the output of the build command, parse the number of warnings and fail the pipeline manually if any are detected. If necessary, the build command output could be captured in a separate task into a pipeline-scoped variable, so that we don’t mix these two processes.