Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ packages/
TestResults/
OpenCover.Reports/
OpenCover.Symbols/
.coverage/
coverage/
coverage-*/
.nuget/NuGet.exe
build/nuget/
*.log
Expand Down
3 changes: 1 addition & 2 deletions .nuget/packages.config
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="CodecovUploader" version="0.7.1" />
<package id="OpenCover" version="4.6.519" />
<package id="ReportGenerator" version="5.2.0" />
<package id="xunit.runner.console" version="2.4.1" />
</packages>
</packages>
35 changes: 35 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,41 @@ You can also help by filing issues, participating in discussions and doing code
* The version of the [.NET Core SDK](https://dotnet.microsoft.com/download/dotnet-core) as specified in the global.json file at the root of this repo.
Use the init script at the root of the repo to conveniently acquire and install the right version.

## Code coverage

You can generate local coverage using the built-in scripts after running `init.ps1` and a build.

- Full coverage (Release):

```powershell
.\build\coverage-report.ps1
```

- Full coverage (Debug):

```powershell
.\build\coverage-report.ps1 -Debug
```

- Diff-focused coverage (changed files vs origin/master):

```powershell
.\build\coverage-report.ps1 -DiffOnly
```

- Diff-focused coverage against a specific base:

```powershell
.\build\coverage-report.ps1 -DiffBase origin/main -DiffOnly
```

Outputs:
- Cobertura XML: `build\coverage\OpenCover.StyleCopAnalyzers.CSharp*.xml`
- HTML report: `build\coverage\index.htm`
- Diff HTML (when requested): `build\coverage\diff\index.htm`

CI uses `dotnet test` with `coverlet.collector` and merges Cobertura reports with ReportGenerator before uploading to Codecov. The same filters are applied locally and in CI to keep results consistent. Test failures or missing coverage files will cause the coverage script to fail with a non-zero exit code.

## Implementing a diagnostic

1. To start working on a diagnostic, add a comment to the issue indicating you are working on implementing it.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.13.0" />
<PackageReference Include="coverlet.collector" Version="6.0.4" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.0.1" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" PrivateAssets="all" />
Expand All @@ -34,4 +36,4 @@
<ProjectReference Include="..\StyleCop.Analyzers.PrivateCodeFixes\StyleCop.Analyzers.PrivateCodeFixes.csproj" PrivateAssets="all" SetTargetFramework="TargetFramework=netstandard2.0" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
</ItemGroup>

</Project>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.13.0" />
<PackageReference Include="coverlet.collector" Version="6.0.4" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.4.0" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" PrivateAssets="all" />
Expand All @@ -35,4 +37,4 @@
<ProjectReference Include="..\StyleCop.Analyzers.PrivateCodeFixes\StyleCop.Analyzers.PrivateCodeFixes.csproj" PrivateAssets="all" SetTargetFramework="TargetFramework=netstandard2.0" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
</ItemGroup>

</Project>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.13.0" />
<PackageReference Include="coverlet.collector" Version="6.0.4" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.8.0" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" PrivateAssets="all" />
Expand All @@ -36,4 +38,4 @@
<ProjectReference Include="..\StyleCop.Analyzers.PrivateCodeFixes\StyleCop.Analyzers.PrivateCodeFixes.csproj" PrivateAssets="all" SetTargetFramework="TargetFramework=netstandard2.0" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
</ItemGroup>

</Project>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.13.0" />
<PackageReference Include="coverlet.collector" Version="6.0.4" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.12.0" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" PrivateAssets="all" />
Expand All @@ -37,4 +39,4 @@
<ProjectReference Include="..\StyleCop.Analyzers.PrivateCodeFixes\StyleCop.Analyzers.PrivateCodeFixes.csproj" PrivateAssets="all" SetTargetFramework="TargetFramework=netstandard2.0" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
</ItemGroup>

</Project>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.13.0" />
<PackageReference Include="coverlet.collector" Version="6.0.4" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="2.8.2" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" PrivateAssets="all" />
Expand All @@ -37,4 +39,4 @@
</None>
</ItemGroup>

</Project>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.13.0" />
<PackageReference Include="coverlet.collector" Version="6.0.4" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="3.6.0" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" PrivateAssets="all" />
Expand All @@ -35,4 +37,4 @@
<ProjectReference Include="..\StyleCop.Analyzers.PrivateCodeFixes\StyleCop.Analyzers.PrivateCodeFixes.csproj" PrivateAssets="all" SetTargetFramework="TargetFramework=netstandard2.0" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
</ItemGroup>

</Project>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.13.0" />
<PackageReference Include="coverlet.collector" Version="6.0.4" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="3.8.0" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" PrivateAssets="all" />
Expand All @@ -33,4 +35,4 @@
<ProjectReference Include="..\StyleCop.Analyzers.PrivateCodeFixes\StyleCop.Analyzers.PrivateCodeFixes.csproj" PrivateAssets="all" SetTargetFramework="TargetFramework=netstandard2.0" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
</ItemGroup>

</Project>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="1.3.2" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.CodeFix.Testing.XUnit" Version="1.1.2-beta1.23509.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.13.0" />
<PackageReference Include="coverlet.collector" Version="6.0.4" PrivateAssets="all" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="Xunit.Combinatorial" Version="1.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" PrivateAssets="all" />
Expand Down Expand Up @@ -54,4 +55,4 @@
</None>
</ItemGroup>

</Project>
</Project>
2 changes: 1 addition & 1 deletion build/build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ stages:
$packages_folder = '.\packages'
$reportgenerator_version = $packageConfig.SelectSingleNode('/packages/package[@id="ReportGenerator"]').version
$report_generator = "$packages_folder\ReportGenerator.$reportgenerator_version\tools\net47\ReportGenerator.exe"
&$report_generator -targetdir:$(Pipeline.Workspace)/coverageResults-final -reporttypes:Cobertura "-reports:$(Pipeline.Workspace)/coverageResults-*/OpenCover.*.xml"
&$report_generator -targetdir:$(Pipeline.Workspace)/coverageResults-final -reporttypes:Cobertura "-reports:$(Pipeline.Workspace)/coverageResults-*/coverage/OpenCover.*.xml"

- task: PowerShell@2
displayName: Public code coverage to codecov.io
Expand Down
122 changes: 122 additions & 0 deletions build/coverage-report.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
param (
[switch]$Debug,
[switch]$NoBuild,
[switch]$NoReport,
[switch]$AppVeyor,
[switch]$Azure,
[string]$DiffBase,
[switch]$DiffOnly
)

$ErrorActionPreference = 'Stop'

$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
Push-Location $scriptDir

try {
if (-not $NoBuild) {
if ($Debug) {
.\build.ps1 -Debug -Incremental
} else {
.\build.ps1 -Incremental
}
}

$configuration = if ($Debug) { 'Debug' } else { 'Release' }
$resultsRoot = Join-Path $scriptDir 'TestResults'
$coverageRoot = Join-Path $scriptDir 'coverage'

if (Test-Path $resultsRoot) {
Remove-Item -Recurse -Force $resultsRoot
}

if (Test-Path $coverageRoot) {
Remove-Item -Recurse -Force $coverageRoot
}

New-Item -ItemType Directory -Force -Path $resultsRoot | Out-Null
New-Item -ItemType Directory -Force -Path $coverageRoot | Out-Null

$runs = @(
@{ Lang = '6'; Project = 'StyleCop.Analyzers.Test'; Framework = 'net452' }
@{ Lang = '7'; Project = 'StyleCop.Analyzers.Test.CSharp7'; Framework = 'net46' }
@{ Lang = '8'; Project = 'StyleCop.Analyzers.Test.CSharp8'; Framework = 'net472' }
@{ Lang = '9'; Project = 'StyleCop.Analyzers.Test.CSharp9'; Framework = 'net472' }
@{ Lang = '10'; Project = 'StyleCop.Analyzers.Test.CSharp10'; Framework = 'net472' }
@{ Lang = '11'; Project = 'StyleCop.Analyzers.Test.CSharp11'; Framework = 'net472' }
@{ Lang = '12'; Project = 'StyleCop.Analyzers.Test.CSharp12'; Framework = 'net472' }
@{ Lang = '13'; Project = 'StyleCop.Analyzers.Test.CSharp13'; Framework = 'net472' }
)

foreach ($run in $runs) {
$projectPath = Join-Path $scriptDir "..\StyleCop.Analyzers\$($run.Project)\$($run.Project).csproj"
$runResultsDir = Join-Path $resultsRoot "CSharp$($run.Lang)"
New-Item -ItemType Directory -Force -Path $runResultsDir | Out-Null

$trxName = "StyleCopAnalyzers.CSharp$($run.Lang).trx"

dotnet test $projectPath `
--framework $run.Framework `
--configuration $configuration `
--no-build `
--settings (Join-Path $scriptDir 'coverlet.runsettings') `
--results-directory $runResultsDir `
--logger "trx;LogFileName=$trxName" `
--collect:"XPlat Code Coverage"

$coverageFile = Get-ChildItem -Path $runResultsDir -Recurse -Filter 'coverage.cobertura.xml' -ErrorAction SilentlyContinue | Select-Object -First 1
if (-not $coverageFile) {
throw "Coverage file not found for C# $($run.Lang) in $runResultsDir"
}

Copy-Item $coverageFile.FullName (Join-Path $coverageRoot "OpenCover.StyleCopAnalyzers.CSharp$($run.Lang).xml") -Force
}

if (-not $NoReport) {
$packageConfig = [xml](Get-Content ..\.nuget\packages.config)
$packagesFolder = '..\packages'
$reportGeneratorVersion = $packageConfig.SelectSingleNode('/packages/package[@id="ReportGenerator"]').version
$reportGenerator = "$packagesFolder\ReportGenerator.$reportGeneratorVersion\tools\ReportGenerator.exe"

&$reportGenerator -targetdir:$coverageRoot -reporttypes:Html;Cobertura "-reports:$coverageRoot\OpenCover.*.xml"
Write-Host "Open $coverageRoot\index.htm to see code coverage results."

$shouldGenerateDiff = $DiffOnly -or -not [string]::IsNullOrWhiteSpace($DiffBase)
if ($shouldGenerateDiff) {
$baseRef = if ([string]::IsNullOrWhiteSpace($DiffBase)) { 'origin/master' } else { $DiffBase }
$repoRoot = Resolve-Path (Join-Path $scriptDir '..')

try {
$diffFiles = & git -C $repoRoot diff --name-only --diff-filter=AM "$baseRef...HEAD" 2>$null | Where-Object { $_ -like '*.cs' }
if (-not $diffFiles) {
Write-Warning "No changed .cs files found relative to '$baseRef'; skipping diff coverage output."
}
else {
$diffFilters = $diffFiles | ForEach-Object {
$normalized = ($_ -replace '\\', '/')
"+**/$normalized"
}

$diffTarget = Join-Path $coverageRoot 'diff'
New-Item -ItemType Directory -Force -Path $diffTarget | Out-Null

&$reportGenerator -targetdir:$diffTarget -reporttypes:Html;TextSummary "-reports:$coverageRoot\OpenCover.*.xml" "-filefilters:$($diffFilters -join ';')"

$summaryPath = Get-ChildItem $diffTarget -Filter '*Summary.txt' -ErrorAction SilentlyContinue | Select-Object -First 1
if ($summaryPath) {
Write-Host "Diff coverage summary (relative to $baseRef):"
Get-Content $summaryPath.FullName
}

Write-Host "Diff coverage HTML: $diffTarget\index.htm"
}
}
catch {
Write-Warning "Failed to compute diff coverage relative to '$baseRef': $($_.Exception.Message)"
}
}
}
}
finally {
Pop-Location
}
17 changes: 17 additions & 0 deletions build/coverlet.runsettings
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<RunSettings>
<DataCollectionRunSettings>
<DataCollectors>
<DataCollector friendlyName="XPlat Code Coverage">
<Configuration>
<Format>cobertura</Format>
<IncludeTestAssembly>true</IncludeTestAssembly>
<SingleHit>true</SingleHit>
<Include>[StyleCop*]*</Include>
<ExcludeByAttribute>System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute</ExcludeByAttribute>
<ExcludeByFile>**/*Designer.cs</ExcludeByFile>
</Configuration>
</DataCollector>
</DataCollectors>
</DataCollectionRunSettings>
</RunSettings>
Loading
Loading