StyleCop.Analyzers integration into GitLab - c#

I have a C# project (.NET Core 3.1) and I use with it a nuget package StyleCop.Analyzers. It analises my code during builds and shows various warnings if finds any problems with my code. Now I wonder is it possible to integrate its checks into GitLab CI piplene? I would like to run this analise after each build in GitLab. How do I do it?

"run this analise after each build"
If you use code analysis from StyleCop.Analyzers by referencing the NuGet package in your projects, then code analysis is performed during compilation (build) time. There is no need for analysis after each build, because at that moment the analysis already has been done - along with the build. Any errors caused by deviations from the styling rules that you can see in Visual Studio error list or CLI will also be present in GitLab CI pipeline output, as in the end they all are compiled by the same .NET SDK.
To properly configure code analysis add StyleCop.Analyzers package reference to your project/s:
<ItemGroup>
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
Additionally, you can further configure StyleCop.Analyzers behavior with .ruleset files to e.g. opt-out some annoying styling rules:
<RuleSet Name="Rules for ClassLibrary21" Description="" ToolsVersion="15.0">
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers">
<Rule Id="SA0001" Action="None" />
</Rules>
</RuleSet>
Rule set files have to be explicitly specified in project file settings:
<PropertyGroup>
<CodeAnalysisRuleSet>..\..\StyleCop.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
Read more about rule sets in official documentation or have a look at the rule set file I use in my library on GitLab for reference.

Related

Configuring assets for analyzers packages

My solution consists of multiple projects. In the root we have Directory.Build.props
<Project>
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="SonarAnalyzer.CSharp" Version="8.51.0.59060" Condition="$(MSBuildProjectExtension) == '.csproj'">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" Condition="$(MSBuildProjectExtension) == '.csproj'">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>
These static code analyzers are using only during development. I see that I can configure assets and prevent exposing these packages. My solution structure:
ServiceA.Api.csproj
ServiceA.Core.csproj
ServiceA.Domain.csproj
ServiceA.Infrastructure.csproj
ServiceA.SDK.csproj
What are the implications for setting PrivateAssets and IncludeAssets in certain ways? What practice for the values of these makes sense in the context of analyzer packages?
If the analyzers are only used for development on the developer's machines, I recommend accepting the package references however NuGet adds them, and then conditionally only including them using the parent <ItemGroup> in your DevOps pipeline. This usually means only include them for Debug but not Release.
<ItemGroup Condition="'$(Configuration)' == 'Debug'">
...
</ItemGroup>
If that is not granular enough (e.g. when you want to build both Debug and Release locally and/or in the pipeline, or you want the analyzers to run during DevOps pipeline exection always), you can take the advice in Controlling dependency assets.
There is no one best practice for this because requirements vary. The defaults are most likely what you should start with because the defaults are chosen for a reason.
The defaults, as mentioned in the content for the above link, are
IncludeAssets --> all
ExcludeAssets --> none
PrivateAssets --> contentfiles;analyzers;build
Unless you are optimizing the size of your final solution, trying to prevent exposure of analyzers to prevent some sort of security issue or misuse, or otherwise trying to avoid some sort of problem, I would say, "just use them as they are, assets set to the values NuGet used when adding the analyzer package".

CompilationAction in Roslyn Analyzer not running on dotnet build

I have created dotnet roslyn analyzer which run on compilation.
[System.Diagnostics.CodeAnalysis.SuppressMessage("MicrosoftCodeAnalysisCorrectness", "RS1026:Enable concurrent execution", Justification = "<Pending>")]
public override void Initialize(AnalysisContext context)
{
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.ReportDiagnostics);
context.RegisterCompilationAction(AnalyzeCompilation);
}
I added it as a package to one of our projects, it didn't run.
I figured that i need to allow Entire Solution Analysis in VS2022.
Tools => Options => Text Editor => c# => Analysis => Entire Solution
Visual Studio Entire Solution Analysis feature
After i allowed it, my analyzer working correctly.
I also want it to run in our pipeline, but the analyzer not running on dotnet build .
I am not sure if it's related to Entire Solution which i allowed in VS2022 or not.
we have other analyzer which running correctly on dotnet build.
this is how our Directory.BUild.props file looks.
<Project>
<PropertyGroup>
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
<EnableNETAnalyzers>true</EnableNETAnalyzers>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.VisualStudio.Threading.Analyzers" Version="16.10.56">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>
and Microsoft.VisualStudio.Threading.Analyzers working on dotnet build.
How can i enable my Analyzer which run on ComplilationAction to work on dotnet build like it working in VS2022?

After clean project regenerating c# files from .proto in another project

I have two projects:
Project hosts the code of the gRPC server and also the .proto files.
Project acts as the client but has also a lot of other different functionality
I want to be able to clean and build my client project, that depends on auto generated .cs files. To generate the .cs files from .proto files Google.Protobuf and Grpc.Net.ClientFactory is used.
So far I've done:
I added a service reference to my 2. project.
My 2.project.csproj looks like (for an Example.proto):
<ItemGroup Condition=" '$(TargetFramework)' == 'net48' ">
<PackageReference Include="Grpc.Core" Version="2.32.0" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1'">
<PackageReference Include="Grpc.AspNetCore" Version="2.32.0" />
<PackageReference Include="Grpc.Net.ClientFactory" Version="2.32.0" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net5.0-windows'">
<PackageReference Include="Grpc.AspNetCore" Version="2.32.0" />
<PackageReference Include="Grpc.Net.ClientFactory" Version="2.32.0" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Google.Protobuf" Version="3.13.0" />
<PackageReference Include="Grpc.Tools" Version="2.32.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<Protobuf Include="..\Project_A\Protos\Example.proto" GrpcServices="Client">
<Link>Protos\Example.proto</Link>
</Protobuf>
</ItemGroup>
When I am now changing the .protofile the client .cs files get generated in the path:
...\2.project\obj\$(ConfigurationName)\$(FrameworkName)\
This all fine when simply building the second project. But whenever the second project gets a clean rebuild the .cs files are not generated again leaving me with missing dependencies.
I would guess somewhere is a option to trigger the generation of .proto files before the build starts?
Or Should I exclude the generated files from the cleanup?
Or is there some other way to achieve this that I'm not seeing?
UPDATE:
I now moved the proto files in a seperate project and import them now using this statement:
<ItemGroup>
<Protobuf Include="..\Proto_Project\Protos\Example.proto" GrpcServices="Client" OutputDir="Protos" CompileOutputs="false">
<Link>Protos\Example.proto</Link>
</Protobuf>
</ItemGroup>
This works in that way, that everytime I change the proto, it gets reconverted in .cs.
But here is the source of my current (and also previous, as I know think) problem. Every time I rebuild the solution the protofiles get reconvertet to .cs. The problem is that this happens after the compilation of the project. This leads to missing dependencies, since the files are not present at compile time. When simply building the solution the files are not retranslated and everything works.
How can I either stop the protobuf compiler from running on rebuild, or let him run earlier?
I would advice you to decouple the two projects by moving all the .proto files to a separate code repository. Next use that repository in your other projects and generate the proto code for that project specifically. This way you can also use the backwards compatibility properties of Protobuf.
With git you can do that with git submodules. You can track the version of the proto file repo in your server and client project.

Using ANTLR4 in .NET Core without the use of external Java library?

I've followed through these instructions but I get a ton of compilation errors after the files have been compiled.
What I have done:
Created a new Console project in .NET Core 3.1.
Installed NuGet package Antlr4.
Added a new text file named example.g4 to the project, and saved it in encoding UTF-8 without signature.
Populated the grammar with some demo features.
Build Solution.
Ton of errors after successful compilation of lexer/visitor/parser/etc.
Some of those errors include the following:
The name '_interp' does not exist in the current context AntlrDemo C:\AntlrDemo\obj\Debug\netcoreapp3.1\exampleLexer.cs 45 Active
'ParserATNSimulator' does not contain a constructor that takes 2 arguments AntlrDemo C:\AntlrDemo\obj\Debug\netcoreapp3.1\exampleParser.cs 95 Active
'exampleParser.TokenNames': no suitable method found to override AntlrDemo C:\AntlrDemo\obj\Debug\netcoreapp3.1\exampleParser.cs 69 Active
What's going on?
The issue is not from the grammar - it successfully compiles in .NET Framework.
If you don't mind working with the official Antlr4 code generator and runtime, but don't want to actually download and install Java and the Antlr Tool .jar by hand, try this instead:
Install the latest NET 5, or use old NET Core.
dotnet new -i Antlr4BuildTasks.Templates
mkdir Foo
cd Foo
dotnet new antlr
dotnet build
dotnet run
This does use the Antlr4 Java tool, but it's completely hidden. You don't download the runtime, nor Java. It's all contained in the Antlr4BuildTasks tool that you just reference in your .csproj. If you want to work with an older Antlr4 version, like 4.8 or 4.7, Antlr4BuildTasks will download the tool and runtime from Maven Central and NuGet.org; you just set the versions in the .csproj file then "dotnet build".
I have another tool that generates a driver for grammar and support code for C# (both official and Harwell's version), Java, and JavaScript targets. It is now being used for CI in github.com/antlr/grammars-v4.
If you try swapping between Antlr4 (the official Antlr4) and Antlr4cs (Harwell's tool/runtime), you will find the tools and runtime are quite different. There is no shim to allow code written for one runtime to be used in the other, but I am working on one.
As far as the <PrivateAssets> code in the .csproj file, getting rid of the lines as you suggest is fine. The reason it is included is to not propagate the dependent assemblies of the build tool directly into your code. But, while the tool is only useful in building the app, not running it, <PrivateAssets> doesn't prevent the assembly for the tool itself is still being included.
--Ken
After you install Antlr4 NuGet package, the following code is added to your .csproj file:
<ItemGroup>
<PackageReference Include="Antlr4" Version="4.6.6">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
The fix was to change the above to the following:
<ItemGroup>
<PackageReference Include="Antlr4" Version="4.6.6">
<!--<PrivateAssets>all</PrivateAssets>-->
</PackageReference>
</ItemGroup>
It also seems to work by uncommenting the PrivateAssets element. But I have no idea what the actual problem is here, and if I'm doing something wrong. Can someone shine some light about it?
EDIT: Another alternative solution is to instead install the two NuGet Packages Antlr4.CodeGenerator and Antlr4.Runtime.
Hopefully, this won't cause more confusion. I just moved my C# parser library from NET Framework 4.8 to NET 5 and was able to build it without errors with this .csproj file.
I changed the target framework from net5.0 to net5.0-windows7.0 in the example below to avoid compiler warning CA1416 which protested that I was using debug print methods (based on Console.Writeline calls with param[] arguments) in my code. I wanted to keep my debugging messages so I switched from the net5.0 target.
But the plain 'net5.0' compiled okay for me (except for the warnings I just described). My simple test cases ran fine with net5.0.
Here is an excerpt from my class library file, showing that I could leave the PrivateAssets and IncludeAssets lines alone.
<PropertyGroup>
<!-- use net5.0-windows7.0 to avoid CA1416 warnings about Console Writeline calls only available in win7 and later-->
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Antlr4" Version="4.6.6">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Antlr4.Runtime" Version="4.6.6" />
</ItemGroup>
Here is an excerpt from my unit test project, showing the inclusion of Antlr4(4.6.6) and the Antlr4.Runtime(4.6.6).
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Antlr4" Version="4.6.6">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Antlr4.Runtime" Version="4.6.6" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
<PackageReference Include="MSTest.TestAdapter" Version="2.2.8" />
<PackageReference Include="MSTest.TestFramework" Version="2.2.8" />
<PackageReference Include="coverlet.collector" Version="3.1.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>

C# Source Generator - warning CS8032: An instance of analyzer cannot be created

I'm trying to build a Source Generator. Right now, just the most basic static method that returns "Hello World".
The generator project builds, but the generated code is not available, the debugger never starts, and the build output shows
CSC : warning CS8032: An instance of analyzer Generator.StaticPropertyEnum.helloWorld cannot be created from ...\bin\Debug\net5.0\Generator.StaticPropertyEnum.dll : Could not load file or assembly 'System.Runtime, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system cannot find the file specified..
Examples I'm referencing
Roslyn Team Generator Sample Project
Roslyn Team Generator Cookbook
Generator.Equals Project
How To Debug C# 9 Source Generators
I've tried
changing the TargetFramework and LanguageVersion of both the generator and test projects
referencing many version of the analyzer libraries Microsoft.CodeAnalysis.CSharp and Microsoft.CodeAnalysis.Analyzers
referencing an explicit version of Microsoft.Net.Compilers.Toolset
Adding an explicit reference to the NetStandard library
starting from scratch with an analyzer project template
looking for a generator project template (but didn't find one)
Versions
Visual Studio: version 16.8.3
.NET SDK: 5.0.101
Code
Generator.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.9.0-2.final" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.0.0" PrivateAssets="all" />
</ItemGroup>
</Project>
Test csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="1.3.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Generator.StaticPropertyEnum\Generator.StaticPropertyEnum.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false"/>
</ItemGroup>
</Project>
Generator
[Generator]
public class helloWorld : ISourceGenerator
{
public void Execute(GeneratorExecutionContext context)
{
context.AddSource("HelloWorld-generated.cs", #"
using System;
namespace HelloWorld
{
public static class Hello
{
public static string SayHello() {
return ""HelloWorld"";
}
}
}");
}
public void Initialize(GeneratorInitializationContext context)
{
#if DEBUG
if(!Debugger.IsAttached) Debugger.Launch();
#endif
}
}
Source Generators must be .NET Standard 2.0 to run in Visual Studio 2019+ or .NET Standard 1.x to run in Visual Studio 2017+.
I have source generator that targets netstandard2.0 and net5.0 for nullability support.
<TargetFrameworks>net5.0;netstandard2.0</TargetFrameworks>
<Nullable>enable</Nullable>
and sample library that targets same frameworks.
It crashes when project is being built within Visual Studio, but builds ok from the terminal.
To solve this, I've changed target framework when referencing it as a generator with SetTagetFramework and now it compiles without any warnings or errors.
<ItemGroup>
<ProjectReference Include="..\MyGenerator\MyGenerator.csproj"
OutputItemType="Analyzer" ReferenceOutputAssembly="false"
SetTargetFramework="TargetFramework=netstandard2.0" />
</ItemGroup>
as #Yair-Halberstadt mentioned in a different answer, the specific error listed is due to the fact that currently source generator projects need to target netstandard2.0.
However if you get the CS8032 error with a different assembly (for example Microsoft.CodeAnalysis, Version=3.0.x ...) your problem is probably caused by a SDK version mismatch.
For example on my computer I have SDK 5.0.302 which has version 3.10.0 of Microsoft.CodeAnalysis and Microsoft.CodeAnalysis.CSharp.
While the Generator project uses nuget to get these packages, the build of the project referencing the generator resolves these files from the SDK.
This is why reverting to 3.8.0 has worked for some commentators, the SDK version they have installed contains 3.8.0 of these references.
As crazy as it is
Close and reopen Visual Studio (2019, 2022)
If step 1 did NOT work, delete .vs folder
That solved my problem
I had to downgrade from 4.0.0 to 3.9 CodeAnalysis Sharp and Analyzers.
Removing my nuget package and adding the LAST stable version fixed that issue for me.
I could solve the same problem with
git clean -xdf
and then rebuilding the entire solution.
Warning CS8032
In my case I got this warning CS8032 in Visual Studio 2022:
##[warning]CSC(0,0): Warning CS8032: An instance of analyzer Microsoft.EntityFrameworkCore.InternalUsageDiagnosticAnalyzer cannot
be created from
C:\Windows\ServiceProfiles\NetworkService.nuget\packages\microsoft.entityframeworkcore.analyzers\7.0.2\analyzers\dotnet\cs\Microsoft.EntityFrameworkCore.Analyzers.dll
: Could not load file or assembly 'Microsoft.CodeAnalysis,
Version=4.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'.
The system cannot find the file specified..
The issue
In my project, I have had 2 packages from Microsoft.EntityFrameworkCore.SqlServer and Microsoft.EntityFrameworkCore.InMemory installed with the latest version 7.0.2, but my TargetFramework for the project was net6.0.
The solution
Target Framework and Package versions must be identical. So I have chosen to downgrade my packages to 6.0.x and the warning CS8032 disappeared.
Note
The same solution applies to Target Framework counterpart Installed Packages.

Categories