diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7bf8638..015a685 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -109,7 +109,7 @@ jobs: path: ${{ runner.temp }}/_artifacts/deployables if: always() - name: Publish code coverage results to codecov.io - run: ./azure-pipelines/publish-CodeCov.ps1 -CodeCovToken "${{ env.codecov_token }}" -PathToCodeCoverage "${{ runner.temp }}/_artifacts/coverageResults" -Name "${{ runner.os }} Coverage Results" -Flags "${{ runner.os }},${{ env.BUILDCONFIGURATION }}" + run: ./azure-pipelines/publish-CodeCov.ps1 -CodeCovToken "${{ env.codecov_token }}" -PathToCodeCoverage "${{ runner.temp }}/_artifacts/coverageResults" -Name "${{ runner.os }} Coverage Results" -Flags "${{ runner.os }}Host,${{ env.BUILDCONFIGURATION }}" -CalcNSFlags shell: pwsh timeout-minutes: 3 continue-on-error: true diff --git a/.gitignore b/.gitignore index 65f9477..3bb4991 100644 --- a/.gitignore +++ b/.gitignore @@ -140,6 +140,7 @@ _TeamCity* # Visual Studio code coverage results *.coverage *.coveragexml +/coveragereport/ # NCrunch _NCrunch_* diff --git a/azure-pipelines/Merge-CodeCoverage.ps1 b/azure-pipelines/Merge-CodeCoverage.ps1 new file mode 100644 index 0000000..6672b94 --- /dev/null +++ b/azure-pipelines/Merge-CodeCoverage.ps1 @@ -0,0 +1,42 @@ +#!/usr/bin/env pwsh + +<# +.SYNOPSIS + Merges code coverage reports. +.PARAMETER Path + The path(s) to search for Cobertura code coverage reports. +.PARAMETER Format + The format for the merged result. The default is Cobertura +.PARAMETER OutputDir + The directory the merged result will be written to. The default is `coveragereport` in the root of this repo. +#> +[CmdletBinding()] +Param( + [Parameter(Mandatory=$true)] + [string[]]$Path, + [ValidateSet('Badges', 'Clover', 'Cobertura', 'CsvSummary', 'Html', 'Html_Dark', 'Html_Light', 'HtmlChart', 'HtmlInline', 'HtmlInline_AzurePipelines', 'HtmlInline_AzurePipelines_Dark', 'HtmlInline_AzurePipelines_Light', 'HtmlSummary', 'JsonSummary', 'Latex', 'LatexSummary', 'lcov', 'MarkdownSummary', 'MHtml', 'PngChart', 'SonarQube', 'TeamCitySummary', 'TextSummary', 'Xml', 'XmlSummary')] + [string]$Format='Cobertura', + [string]$OutputDir=("$PSScriptRoot/../coveragereport") +) + +$RepoRoot = [string](Resolve-Path $PSScriptRoot/..) + +if (!(Test-Path $RepoRoot/obj/reportgenerator*)) { + dotnet tool install --tool-path $RepoRoot/obj dotnet-reportgenerator-globaltool --version 5.1.9 --configfile $PSScriptRoot/justnugetorg.nuget.config +} + +Write-Verbose "Searching $Path for *.cobertura.xml files" +$reports = Get-ChildItem -Recurse $Path -Filter *.cobertura.xml + +if ($reports) { + $reports |% { $_.FullName } |% { + # In addition to replacing {reporoot}, we also normalize on one kind of slash so that the report aggregates data for a file whether data was collected on Windows or not. + $content = Get-Content -Path $_ |% { [Regex]::Replace($_, '{reporoot}([^"]+)', { $RepoRoot + $args[0].groups[1].value.replace([IO.Path]::AltDirectorySeparatorChar, [IO.Path]::DirectorySeparatorChar) }) } + Set-Content -Path $_ -Value $content -Encoding UTF8 + } + + $Inputs = [string]::join(';', ($reports |% { Resolve-Path -relative $_.FullName })) + & "$RepoRoot/obj/reportgenerator" -reports:"$Inputs" -targetdir:$OutputDir -reporttypes:$Format +} else { + Write-Error "No reports found to merge." +} diff --git a/azure-pipelines/dotnet.yml b/azure-pipelines/dotnet.yml index 38c09e6..abdea3c 100644 --- a/azure-pipelines/dotnet.yml +++ b/azure-pipelines/dotnet.yml @@ -19,7 +19,7 @@ steps: - powershell: | $ArtifactStagingFolder = & "azure-pipelines/Get-ArtifactsStagingDirectory.ps1" $CoverageResultsFolder = Join-Path $ArtifactStagingFolder "coverageResults-$(Agent.JobName)" - azure-pipelines/publish-CodeCov.ps1 -CodeCovToken "$(codecov_token)" -PathToCodeCoverage "$CoverageResultsFolder" -Name "$(Agent.JobName) Coverage Results" -Flags "$(Agent.JobName),$(BuildConfiguration)" + azure-pipelines/publish-CodeCov.ps1 -CodeCovToken "$(codecov_token)" -PathToCodeCoverage "$CoverageResultsFolder" -Name "$(Agent.JobName) Coverage Results" -Flags "$(Agent.JobName)Host,$(BuildConfiguration)" -CalcNSFlags displayName: 📢 Publish code coverage results to codecov.io condition: ne(variables['codecov_token'], '') timeoutInMinutes: 3 diff --git a/azure-pipelines/publish-CodeCov.ps1 b/azure-pipelines/publish-CodeCov.ps1 index a115b52..1f71276 100644 --- a/azure-pipelines/publish-CodeCov.ps1 +++ b/azure-pipelines/publish-CodeCov.ps1 @@ -7,6 +7,8 @@ Path to root of code coverage files .PARAMETER Name Optional name to upload with codecoverge +.PARAMETER CalcNSFlags + Optional switch to calculate Flags from namespace of test. .PARAMETER Flags Optional flags to upload with codecoverge #> @@ -15,6 +17,7 @@ Param ( [string]$CodeCovToken, [string]$PathToCodeCoverage, [string]$Name="", + [switch]$CalcNSFlags, [string]$Flags="" ) @@ -36,6 +39,76 @@ Get-ChildItem -Recurse -Path $CodeCoveragePathWildcard | % { } Write-Host "Uploading: $relativeFilePath" -ForegroundColor Yellow + $TestTypeFlag = "" + $OSTypeFlag = "" + $FTargetFrameworkFlag = "" - & (& "$PSScriptRoot/Get-CodeCovTool.ps1") -t "$CodeCovToken" -f "$relativeFilePath" -R "$RepoRoot" -F "$Flags" -n "$Name" + if ($CalcNSFlags) + { + if ($relativeFilePath -ilike "*.Unit*") + { + $TestTypeFlag = ",Unit" + } + elseif ($relativeFilePath -ilike "*.Integration*") + { + $TestTypeFlag = ",Integration" + } + elseif ($relativeFilePath -ilike "*.Local*") + { + $TestTypeFlag = ",Local" + } + elseif ($relativeFilePath -ilike "*.Device*") + { + $TestTypeFlag = ",Device" + } + + if ($relativeFilePath -ilike "*.Windows*") + { + $OSTypeFlag = ",Windows" + } + elseif ($relativeFilePath -ilike "*.WinUI*") + { + $OSTypeFlag = ",WinUI" + } + elseif ($relativeFilePath -ilike "*.WPF*") + { + $OSTypeFlag = ",WPF" + } + elseif ($relativeFilePath -ilike "*.MacOS*") + { + $OSTypeFlag = ",MacOS" + } + elseif ($relativeFilePath -ilike "*.MacCatalyst*") + { + $OSTypeFlag = ",MacCatalyst" + } + elseif ($relativeFilePath -ilike "*.OSX*") + { + $OSTypeFlag = ",MacOS" + } + elseif ($relativeFilePath -ilike "*.Android*") + { + $OSTypeFlag = ",Android" + } + elseif ($relativeFilePath -ilike "*.IOS*") + { + $OSTypeFlag = ",IOS" + } + elseif ($relativeFilePath -ilike "*.Linux*") + { + $OSTypeFlag = ",Linux" + } + elseif ($relativeFilePath -ilike "*.NetCore*") + { + $OSTypeFlag = ",NetCore" + } + elseif ($relativeFilePath -ilike "*.Core*") + { + $OSTypeFlag = ",Core" + } + } + + Write-Host "Flags: $Flags$TargetFrameworkFlag$TestTypeFlag$OSTypeFlag" -ForegroundColor Yellow + + & (& "$PSScriptRoot/Get-CodeCovTool.ps1") -t "$CodeCovToken" -f "$relativeFilePath" -R "$RepoRoot" -F "$Flags$TargetFrameworkFlag$TestTypeFlag$OSTypeFlag" -n "$Name" } diff --git a/azure-pipelines/publish-codecoverage.yml b/azure-pipelines/publish-codecoverage.yml index 23e88a6..6e7ef21 100644 --- a/azure-pipelines/publish-codecoverage.yml +++ b/azure-pipelines/publish-codecoverage.yml @@ -15,19 +15,7 @@ steps: displayName: 🔻 Download macOS code coverage results continueOnError: true condition: ${{ parameters.includeMacOS }} -- powershell: | - dotnet tool install --tool-path obj dotnet-reportgenerator-globaltool --version 5.1.9 --configfile azure-pipelines/justnugetorg.nuget.config - Copy-Item -Recurse $(Pipeline.Workspace)/coverageResults-Windows/obj/* $(System.DefaultWorkingDirectory)/obj - Write-Host 'Substituting {reporoot} with $(System.DefaultWorkingDirectory)' - $reports = Get-ChildItem -Recurse '$(Pipeline.Workspace)/*.cobertura.xml' - $reports |% { - # In addition to replacing {reporoot}, we also normalize on one kind of slash so that the report aggregates data for a file whether data was collected on Windows or not. - $content = Get-Content -Path $_ |% { [Regex]::Replace($_, '{reporoot}([^"]+)', { '$(System.DefaultWorkingDirectory)' + $args[0].groups[1].value.replace([IO.Path]::AltDirectorySeparatorChar, [IO.Path]::DirectorySeparatorChar) }) } - Set-Content -Path $_ -Value $content -Encoding UTF8 - } - - $Inputs = [string]::join(';', ($reports |% { Resolve-Path -relative $_ })) - obj/reportgenerator -reports:"$Inputs" -targetdir:coveragereport -reporttypes:Cobertura +- powershell: azure-pipelines/Merge-CodeCoverage.ps1 -Path '$(Pipeline.Workspace)' -OutputDir coveragereport -Format Cobertura -Verbose displayName: ⚙ Merge coverage - task: PublishCodeCoverageResults@1 displayName: 📢 Publish code coverage results to Azure DevOps diff --git a/global.json b/global.json index f4e12c1..6024922 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "6.0.300", + "version": "6.0.301", "allowPrerelease": true, "rollForward": "patch" }