diff --git a/.gitignore b/.gitignore
index 3fe9dd0d8..6c28dd9a9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,6 +11,9 @@ packages/
TestResults/
OpenCover.Reports/
OpenCover.Symbols/
+.coverage/
+coverage/
+coverage-*/
.nuget/NuGet.exe
build/nuget/
*.log
diff --git a/.nuget/packages.config b/.nuget/packages.config
index d409bf15b..e91f8091b 100644
--- a/.nuget/packages.config
+++ b/.nuget/packages.config
@@ -1,7 +1,6 @@
-
-
\ No newline at end of file
+
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 8917cb3a6..2390847ad 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -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.
diff --git a/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp10/StyleCop.Analyzers.Test.CSharp10.csproj b/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp10/StyleCop.Analyzers.Test.CSharp10.csproj
index c156608b8..2f84ddc30 100644
--- a/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp10/StyleCop.Analyzers.Test.CSharp10.csproj
+++ b/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp10/StyleCop.Analyzers.Test.CSharp10.csproj
@@ -19,6 +19,8 @@
+
+
@@ -34,4 +36,4 @@
-
\ No newline at end of file
+
diff --git a/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp11/StyleCop.Analyzers.Test.CSharp11.csproj b/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp11/StyleCop.Analyzers.Test.CSharp11.csproj
index 0bf96cd59..4cab5414e 100644
--- a/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp11/StyleCop.Analyzers.Test.CSharp11.csproj
+++ b/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp11/StyleCop.Analyzers.Test.CSharp11.csproj
@@ -19,6 +19,8 @@
+
+
@@ -35,4 +37,4 @@
-
\ No newline at end of file
+
diff --git a/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp12/StyleCop.Analyzers.Test.CSharp12.csproj b/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp12/StyleCop.Analyzers.Test.CSharp12.csproj
index d89fa6f67..23ac82474 100644
--- a/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp12/StyleCop.Analyzers.Test.CSharp12.csproj
+++ b/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp12/StyleCop.Analyzers.Test.CSharp12.csproj
@@ -19,6 +19,8 @@
+
+
@@ -36,4 +38,4 @@
-
\ No newline at end of file
+
diff --git a/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp13/StyleCop.Analyzers.Test.CSharp13.csproj b/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp13/StyleCop.Analyzers.Test.CSharp13.csproj
index 58c62399c..0e5adc450 100644
--- a/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp13/StyleCop.Analyzers.Test.CSharp13.csproj
+++ b/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp13/StyleCop.Analyzers.Test.CSharp13.csproj
@@ -19,6 +19,8 @@
+
+
@@ -37,4 +39,4 @@
-
\ No newline at end of file
+
diff --git a/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp7/StyleCop.Analyzers.Test.CSharp7.csproj b/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp7/StyleCop.Analyzers.Test.CSharp7.csproj
index dbd38c35e..6e4a71ebe 100644
--- a/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp7/StyleCop.Analyzers.Test.CSharp7.csproj
+++ b/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp7/StyleCop.Analyzers.Test.CSharp7.csproj
@@ -19,6 +19,8 @@
+
+
@@ -37,4 +39,4 @@
-
\ No newline at end of file
+
diff --git a/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp8/StyleCop.Analyzers.Test.CSharp8.csproj b/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp8/StyleCop.Analyzers.Test.CSharp8.csproj
index 0ef285c16..23911ad73 100644
--- a/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp8/StyleCop.Analyzers.Test.CSharp8.csproj
+++ b/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp8/StyleCop.Analyzers.Test.CSharp8.csproj
@@ -19,6 +19,8 @@
+
+
@@ -35,4 +37,4 @@
-
\ No newline at end of file
+
diff --git a/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp9/StyleCop.Analyzers.Test.CSharp9.csproj b/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp9/StyleCop.Analyzers.Test.CSharp9.csproj
index 0689fdb35..56ed8f838 100644
--- a/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp9/StyleCop.Analyzers.Test.CSharp9.csproj
+++ b/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp9/StyleCop.Analyzers.Test.CSharp9.csproj
@@ -19,6 +19,8 @@
+
+
@@ -33,4 +35,4 @@
-
\ No newline at end of file
+
diff --git a/StyleCop.Analyzers/StyleCop.Analyzers.Test/StyleCop.Analyzers.Test.csproj b/StyleCop.Analyzers/StyleCop.Analyzers.Test/StyleCop.Analyzers.Test.csproj
index 1f48733c0..ec7464e5f 100644
--- a/StyleCop.Analyzers/StyleCop.Analyzers.Test/StyleCop.Analyzers.Test.csproj
+++ b/StyleCop.Analyzers/StyleCop.Analyzers.Test/StyleCop.Analyzers.Test.csproj
@@ -22,6 +22,7 @@
+
@@ -54,4 +55,4 @@
-
\ No newline at end of file
+
diff --git a/build/build-and-test.yml b/build/build-and-test.yml
index 68b911cb0..900c744a6 100644
--- a/build/build-and-test.yml
+++ b/build/build-and-test.yml
@@ -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
diff --git a/build/coverage-report.ps1 b/build/coverage-report.ps1
new file mode 100644
index 000000000..c9d2b3959
--- /dev/null
+++ b/build/coverage-report.ps1
@@ -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
+}
diff --git a/build/coverlet.runsettings b/build/coverlet.runsettings
new file mode 100644
index 000000000..40a10ddd6
--- /dev/null
+++ b/build/coverlet.runsettings
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+ cobertura
+ true
+ true
+ [StyleCop*]*
+ System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute
+ **/*Designer.cs
+
+
+
+
+
diff --git a/build/opencover-report.ps1 b/build/opencover-report.ps1
index 4e0bc3402..19b286657 100644
--- a/build/opencover-report.ps1
+++ b/build/opencover-report.ps1
@@ -1,214 +1,11 @@
param (
- [switch]$Debug,
- [switch]$NoBuild,
- [switch]$NoReport,
- [switch]$AppVeyor,
- [switch]$Azure
+ [switch]$Debug,
+ [switch]$NoBuild,
+ [switch]$NoReport,
+ [switch]$AppVeyor,
+ [switch]$Azure
)
-If (-not $NoBuild) {
- # Run a build to ensure everything is up-to-date
- If ($Debug) {
- .\build.ps1 -Debug -Incremental
- } Else {
- .\build.ps1 -Incremental
- }
-
- If (-not $?) {
- $host.UI.WriteErrorLine('Build failed; coverage analysis aborted.')
- Exit $LASTEXITCODE
- }
-}
-
-If ($Debug) {
- $Configuration = 'Debug'
-} Else {
- $Configuration = 'Release'
-}
-
-$packageConfig = [xml](Get-Content ..\.nuget\packages.config)
-$opencover_version = $packageConfig.SelectSingleNode('/packages/package[@id="OpenCover"]').version
-$reportgenerator_version = $packageConfig.SelectSingleNode('/packages/package[@id="ReportGenerator"]').version
-$xunitrunner_version = $packageConfig.SelectSingleNode('/packages/package[@id="xunit.runner.console"]').version
-
-$packages_folder = '..\packages'
-$opencover_console = "$packages_folder\OpenCover.$opencover_version\tools\OpenCover.Console.exe"
-$xunit_runner_console_net452 = "$packages_folder\xunit.runner.console.$xunitrunner_version\tools\net452\xunit.console.x86.exe"
-$xunit_runner_console_net46 = "$packages_folder\xunit.runner.console.$xunitrunner_version\tools\net46\xunit.console.x86.exe"
-$xunit_runner_console_net472 = "$packages_folder\xunit.runner.console.$xunitrunner_version\tools\net472\xunit.console.x86.exe"
-$report_generator = "$packages_folder\ReportGenerator.$reportgenerator_version\tools\ReportGenerator.exe"
-$report_folder = '.\OpenCover.Reports'
-$target_dll = "..\StyleCop.Analyzers\StyleCop.Analyzers.Test\bin\$Configuration\net452\StyleCop.Analyzers.Test.dll"
-$target_dll_csharp7 = "..\StyleCop.Analyzers\StyleCop.Analyzers.Test.CSharp7\bin\$Configuration\net46\StyleCop.Analyzers.Test.CSharp7.dll"
-$target_dll_csharp8 = "..\StyleCop.Analyzers\StyleCop.Analyzers.Test.CSharp8\bin\$Configuration\net472\StyleCop.Analyzers.Test.CSharp8.dll"
-$target_dll_csharp9 = "..\StyleCop.Analyzers\StyleCop.Analyzers.Test.CSharp9\bin\$Configuration\net472\StyleCop.Analyzers.Test.CSharp9.dll"
-$target_dll_csharp10 = "..\StyleCop.Analyzers\StyleCop.Analyzers.Test.CSharp10\bin\$Configuration\net472\StyleCop.Analyzers.Test.CSharp10.dll"
-$target_dll_csharp11 = "..\StyleCop.Analyzers\StyleCop.Analyzers.Test.CSharp11\bin\$Configuration\net472\StyleCop.Analyzers.Test.CSharp11.dll"
-$target_dll_csharp12 = "..\StyleCop.Analyzers\StyleCop.Analyzers.Test.CSharp12\bin\$Configuration\net472\StyleCop.Analyzers.Test.CSharp12.dll"
-$target_dll_csharp13 = "..\StyleCop.Analyzers\StyleCop.Analyzers.Test.CSharp13\bin\$Configuration\net472\StyleCop.Analyzers.Test.CSharp13.dll"
-
-If (Test-Path $report_folder) {
- Remove-Item -Recurse -Force $report_folder
-}
-
-mkdir $report_folder | Out-Null
-
-$register_mode = 'user'
-If ($AppVeyor) {
- $AppVeyorArg = '-appveyor'
- $register_mode = 'Path32'
-} ElseIf ($Azure) {
- $register_mode = 'Path32'
-}
-
-$exitCode = 0
-
-&$opencover_console `
- -register:$register_mode `
- -threshold:1 -oldStyle `
- -returntargetcode `
- -hideskipped:All `
- -filter:"+[StyleCop*]*" `
- -excludebyattribute:*.ExcludeFromCodeCoverage* `
- -excludebyfile:*\*Designer.cs `
- -output:"$report_folder\OpenCover.StyleCopAnalyzers.xml" `
- -target:"$xunit_runner_console_net452" `
- -targetargs:"$target_dll -noshadow $AppVeyorArg -xml StyleCopAnalyzers.xunit.xml"
-
-If (($AppVeyor -or $Azure) -and -not $?) {
- $host.UI.WriteErrorLine('Build failed; coverage analysis may be incomplete.')
- $exitCode = $LASTEXITCODE
-}
-
-&$opencover_console `
- -register:$register_mode `
- -threshold:1 -oldStyle `
- -returntargetcode `
- -hideskipped:All `
- -filter:"+[StyleCop*]*" `
- -excludebyattribute:*.ExcludeFromCodeCoverage* `
- -excludebyfile:*\*Designer.cs `
- -output:"$report_folder\OpenCover.StyleCopAnalyzers.xml" `
- -mergebyhash -mergeoutput `
- -target:"$xunit_runner_console_net46" `
- -targetargs:"$target_dll_csharp7 -noshadow $AppVeyorArg -xml StyleCopAnalyzers.CSharp7.xunit.xml"
-
-If (($AppVeyor -or $Azure) -and -not $?) {
- $host.UI.WriteErrorLine('Build failed; coverage analysis may be incomplete.')
- $exitCode = $LASTEXITCODE
-}
-
-&$opencover_console `
- -register:$register_mode `
- -threshold:1 -oldStyle `
- -returntargetcode `
- -hideskipped:All `
- -filter:"+[StyleCop*]*" `
- -excludebyattribute:*.ExcludeFromCodeCoverage* `
- -excludebyfile:*\*Designer.cs `
- -output:"$report_folder\OpenCover.StyleCopAnalyzers.xml" `
- -mergebyhash -mergeoutput `
- -target:"$xunit_runner_console_net472" `
- -targetargs:"$target_dll_csharp8 -noshadow $AppVeyorArg -xml StyleCopAnalyzers.CSharp8.xunit.xml"
-
-If (($AppVeyor -or $Azure) -and -not $?) {
- $host.UI.WriteErrorLine('Build failed; coverage analysis may be incomplete.')
- $exitCode = $LASTEXITCODE
-}
-
-&$opencover_console `
- -register:$register_mode `
- -threshold:1 -oldStyle `
- -returntargetcode `
- -hideskipped:All `
- -filter:"+[StyleCop*]*" `
- -excludebyattribute:*.ExcludeFromCodeCoverage* `
- -excludebyfile:*\*Designer.cs `
- -output:"$report_folder\OpenCover.StyleCopAnalyzers.xml" `
- -mergebyhash -mergeoutput `
- -target:"$xunit_runner_console_net472" `
- -targetargs:"$target_dll_csharp9 -noshadow $AppVeyorArg -xml StyleCopAnalyzers.CSharp9.xunit.xml"
-
-If (($AppVeyor -or $Azure) -and -not $?) {
- $host.UI.WriteErrorLine('Build failed; coverage analysis may be incomplete.')
- $exitCode = $LASTEXITCODE
-}
-
-&$opencover_console `
- -register:$register_mode `
- -threshold:1 -oldStyle `
- -returntargetcode `
- -hideskipped:All `
- -filter:"+[StyleCop*]*" `
- -excludebyattribute:*.ExcludeFromCodeCoverage* `
- -excludebyfile:*\*Designer.cs `
- -output:"$report_folder\OpenCover.StyleCopAnalyzers.xml" `
- -mergebyhash -mergeoutput `
- -target:"$xunit_runner_console_net472" `
- -targetargs:"$target_dll_csharp10 -noshadow $AppVeyorArg -xml StyleCopAnalyzers.CSharp10.xunit.xml"
-
-If (($AppVeyor -or $Azure) -and -not $?) {
- $host.UI.WriteErrorLine('Build failed; coverage analysis may be incomplete.')
- $exitCode = $LASTEXITCODE
-}
-
-&$opencover_console `
- -register:$register_mode `
- -threshold:1 -oldStyle `
- -returntargetcode `
- -hideskipped:All `
- -filter:"+[StyleCop*]*" `
- -excludebyattribute:*.ExcludeFromCodeCoverage* `
- -excludebyfile:*\*Designer.cs `
- -output:"$report_folder\OpenCover.StyleCopAnalyzers.xml" `
- -mergebyhash -mergeoutput `
- -target:"$xunit_runner_console_net472" `
- -targetargs:"$target_dll_csharp11 -noshadow $AppVeyorArg -xml StyleCopAnalyzers.CSharp11.xunit.xml"
-
-If (($AppVeyor -or $Azure) -and -not $?) {
- $host.UI.WriteErrorLine('Build failed; coverage analysis may be incomplete.')
- $exitCode = $LASTEXITCODE
-}
-
-&$opencover_console `
- -register:$register_mode `
- -threshold:1 -oldStyle `
- -returntargetcode `
- -hideskipped:All `
- -filter:"+[StyleCop*]*" `
- -excludebyattribute:*.ExcludeFromCodeCoverage* `
- -excludebyfile:*\*Designer.cs `
- -output:"$report_folder\OpenCover.StyleCopAnalyzers.xml" `
- -mergebyhash -mergeoutput `
- -target:"$xunit_runner_console_net472" `
- -targetargs:"$target_dll_csharp12 -noshadow $AppVeyorArg -xml StyleCopAnalyzers.CSharp12.xunit.xml"
-
-If (($AppVeyor -or $Azure) -and -not $?) {
- $host.UI.WriteErrorLine('Build failed; coverage analysis may be incomplete.')
- $exitCode = $LASTEXITCODE
-}
-
-&$opencover_console `
- -register:$register_mode `
- -threshold:1 -oldStyle `
- -returntargetcode `
- -hideskipped:All `
- -filter:"+[StyleCop*]*" `
- -excludebyattribute:*.ExcludeFromCodeCoverage* `
- -excludebyfile:*\*Designer.cs `
- -output:"$report_folder\OpenCover.StyleCopAnalyzers.xml" `
- -mergebyhash -mergeoutput `
- -target:"$xunit_runner_console_net472" `
- -targetargs:"$target_dll_csharp13 -noshadow $AppVeyorArg -xml StyleCopAnalyzers.CSharp13.xunit.xml"
-
-If (($AppVeyor -or $Azure) -and -not $?) {
- $host.UI.WriteErrorLine('Build failed; coverage analysis may be incomplete.')
- $exitCode = $LASTEXITCODE
-}
-
-If (-not $NoReport) {
- &$report_generator -targetdir:$report_folder -reports:$report_folder\OpenCover.*.xml
- $host.UI.WriteLine("Open $report_folder\index.htm to see code coverage results.")
-}
-
-Exit $exitCode
+Write-Warning "build/opencover-report.ps1 is deprecated; forwarding to build/coverage-report.ps1."
+& "$PSScriptRoot\coverage-report.ps1" @PSBoundParameters
+exit $LASTEXITCODE
diff --git a/build/test.yml b/build/test.yml
index 224da2fdc..e3752f085 100644
--- a/build/test.yml
+++ b/build/test.yml
@@ -68,35 +68,38 @@ jobs:
workingDirectory: '$(Build.SourcesDirectory)/build'
targetType: inline
script: |
- $packageConfig = [xml](Get-Content ..\.nuget\packages.config)
- $opencover_version = $packageConfig.SelectSingleNode('/packages/package[@id="OpenCover"]').version
- $xunitrunner_version = $packageConfig.SelectSingleNode('/packages/package[@id="xunit.runner.console"]').version
+ $results_dir = "TestResults"
+ $coverage_dir = "coverage"
+ New-Item -ItemType Directory -Force -Path $results_dir | Out-Null
+ New-Item -ItemType Directory -Force -Path $coverage_dir | Out-Null
- $packages_folder = '..\packages'
- $opencover_console = "$packages_folder\OpenCover.$opencover_version\tools\OpenCover.Console.exe"
- $xunit_runner_console_${{ parameters.FrameworkVersion }} = "$packages_folder\xunit.runner.console.$xunitrunner_version\tools\${{ parameters.FrameworkVersion }}\xunit.console.x86.exe"
- $report_folder = '.\OpenCover.Reports'
- mkdir $report_folder
- $target_dll_name = If ('${{ parameters.LangVersion }}' -Eq '6') { "StyleCop.Analyzers.Test" } Else { "StyleCop.Analyzers.Test.CSharp${{ parameters.LangVersion }}" }
- $target_dll_csharp${{ parameters.LangVersion }} = "..\StyleCop.Analyzers\$target_dll_name\bin\${{ parameters.BuildConfiguration }}\${{ parameters.FrameworkVersion }}\$target_dll_name.dll"
- &$opencover_console `
- -register:Path32 `
- -threshold:1 -oldStyle `
- -returntargetcode `
- -hideskipped:All `
- -filter:"+[StyleCop*]*" `
- -excludebyattribute:*.ExcludeFromCodeCoverage* `
- -excludebyfile:*\*Designer.cs `
- -output:"$report_folder\OpenCover.StyleCopAnalyzers.CSharp${{ parameters.LangVersion }}.xml" `
- -target:"$xunit_runner_console_${{ parameters.FrameworkVersion }}" `
- -targetargs:"$target_dll_csharp${{ parameters.LangVersion }} -noshadow -xml StyleCopAnalyzers.CSharp${{ parameters.LangVersion }}.xunit.xml"
+ $project_name = If ('${{ parameters.LangVersion }}' -Eq '6') { "StyleCop.Analyzers.Test" } Else { "StyleCop.Analyzers.Test.CSharp${{ parameters.LangVersion }}" }
+ $project_path = "..\StyleCop.Analyzers\$project_name\$project_name.csproj"
+ $trx_name = "StyleCopAnalyzers.CSharp${{ parameters.LangVersion }}.trx"
+
+ dotnet test $project_path `
+ --framework "${{ parameters.FrameworkVersion }}" `
+ --configuration "${{ parameters.BuildConfiguration }}" `
+ --no-build `
+ --settings ".\coverlet.runsettings" `
+ --results-directory $results_dir `
+ --logger "trx;LogFileName=$trx_name" `
+ --collect:"XPlat Code Coverage"
+
+ $coverage_file = Get-ChildItem -Path $results_dir -Recurse -Filter "coverage.cobertura.xml" -ErrorAction SilentlyContinue | Select-Object -First 1
+ if (-not $coverage_file) {
+ Write-Error "Coverage file not found in $results_dir"
+ exit 1
+ }
+
+ Copy-Item $coverage_file.FullName "$coverage_dir\OpenCover.StyleCopAnalyzers.CSharp${{ parameters.LangVersion }}.xml" -Force
- task: PublishTestResults@2
displayName: 📢 Publish test results
condition: always()
inputs:
- testResultsFormat: xUnit
- testResultsFiles: 'build/*.xml'
+ testResultsFormat: VSTest
+ testResultsFiles: 'build/TestResults/**/*.trx'
mergeTestResults: true
testRunTitle: 'C# ${{ parameters.LangVersion }} ${{ parameters.BuildConfiguration }}'
@@ -104,5 +107,5 @@ jobs:
- task: PublishPipelineArtifact@1
displayName: Publish code coverage
inputs:
- targetPath: $(Build.SourcesDirectory)/build/OpenCover.Reports
+ targetPath: $(Build.SourcesDirectory)/build/coverage
artifact: coverageResults-cs${{ parameters.LangVersion }}