0

I am posting this after 2 days of trying various solutions that didn't work for me. This is mostly for my future reference, but I hope others can benefit as well. I used this source as the basis for my work, however this post was able to get Coverlet.MsBuild to work (which would have made things much easier) but for me, Coverlet.MSBuild would not generate anything no matter what I tried to do. So I had to go with Coverlet.Collect which made things a lot more complicated.

Here is how I set up my powershell to generate reports for TeamCity:

# This file is used by TeamCity build steps

$checkoutDir = $args[0]
Write-Output "`$checkoutDir       : $checkoutDir"
$donetCliExePath = $args[1]
Write-Output "`$donetCliExePath   : $donetCliExePath"
$coverageOutputPath = "$checkoutDir\coverage"
Write-Output "`coverageOutputPath : $coverageOutputPath"

# The TeamCity Build Agent runs using the LocalSystem account
# and all user profile paths are defined in an Environment
# variable $env:USERPROFILE.  All global dotnet tools are installed
# in the running users (LocalSystem) profile in the Path below:
$dotNetToolPath = "$env:USERPROFILE\.dotnet\tools"
Write-Output "`$dotNetToolPath    : $dotNetToolPath"

Set-Alias -Name DotNet -Value "$donetCliExePath"

try
{
    Write-output "Ensuring reportgenerator is available."
    & DotNet tool update --global dotnet-reportgenerator-globaltool

    # Get a list of all unit testing projects
    $testCsProjList = Get-Childitem -Recurse $checkoutDir -Filter *.Tests.Unit.csproj
    
    # Set up a job where each unit test dll is run in parallel
    # up to 10 test fixtures at a time.
    #  --collect:"XPlat Code Coverage" 2>&1 runs coverlet code coverage
    $job = $testCsProjList | foreach-Object -parallel {
        DotNet test `
        "$($_.FullName)" `
        --no-build `
        -c Release `
        -l "console;verbosity=normal" `
        --test-adapter-path "$env:USERPROFILE\.nuget\packages\xunit.runner.visualstudio\2.4.5\build\netcoreapp3.1" `
        --collect:"XPlat Code Coverage" 2>&1
    } -AsJob -ThrottleLimit 10

    Write-Output ""
    Write-output "Running unit tests and collecting code coverage..."
    Write-Output ""

    # Wait for all tasks to finish, collect all the output
    $output = $job | Wait-Job | Receive-Job

    Write-Output ""
    Write-Output "-----------------------------COMPLETE----------------------------------"
    Write-Output ""

    # Coverlet.Collector puts the coverage results in a dynamic folder.
    # Coverlet.MsBuild would not generate results at all.
    # There is no way at this time to specify the output folder
    # that coverlet.collector should use.
    # However the console output of coverlet.collector reveals where the 
    # Test results are stored. The code below finds all the output paths
    # of the tests detected in the Solution.
    $found = $output -match '\w+.*coverage.cobertura.xml'

    if ($null -eq $found) {
        throw "No Coverage Results, please view logs for details.  Exiting."
    }

    $output | Out-File -FilePath "$checkoutDir\testOutput.txt" -Force # For debugging

    if(!(Test-Path $coverageOutputPath))
    {   # Move-Item will not create the destination path if it does not
        # exist and for some silly reason this is not an optional parameter.
        # Here we ensure it exists so later we can move coverage reports here.
        New-Item -Path $coverageOutputPath -ItemType Directory -Force | Out-Null
    }

    Write-output "Moving all coverage results:"

    $found | % {
        if([string]::IsNullOrWhitespace($_))
        {
            # Regex matches stuff and puts
            # in blank results sometimes, no
            # time to figure out why.
            continue
        }

        $testResultPath = $_.Trim()
        $foundTestNames = $testResultPath -match "unit\\(.*)\\TestResults"
        $testProjectName = $matches[1] #matches is an automagic PS variable after a Regex match

        Write-Output "Moving $testProjectName coverage results to: $coverageOutputPath\$testProjectName.cobertura.xml"
        Move-Item -Path "$testResultPath" -Destination "$coverageOutputPath\$testProjectName.cobertura.xml"
    }

    Write-output "Generating TeamCity Report:"
    & "$dotNetToolPath\reportgenerator.exe" "-targetdir:$coverageOutputPath" "-reports:$coverageOutputPath\*.xml" "-reporttypes:Html"
    
    if($LastExitCode -eq 1) {
        throw "Running Unit Tests and Gathering coverage of Nexus.Api.SDK failed, please view logs for details.  Exiting."
    }
}
catch
{
    $Exception = $_;
    # Display info about exception
    $Exception | Format-List * -Force | Out-String ;
    # Display info about invocation context that cause error
    $Exception.InvocationInfo | Format-List * -Force | Out-String ;

    # Recursively Display all Inner Exceptions depth-first
    for ($i = 0; $Exception; $i++, ($Exception = $Exception.InnerException))
    {
        Write-Output ("$i" * 80) ;
        $Exception | Format-List * -Force | Out-String
    }
    throw
}

Let me know if there is an easier way to achieve the above!

Bitfiddler
  • 3,942
  • 7
  • 36
  • 51
  • If you want a code review: post on http://codereview.stackexchange.com/. If you want help with getting the Coverlet.MsBuild approach to work: please post the thing that _isn't_ working and describe the observed behavior in a bit more detail than "would not generate anything" :) – Mathias R. Jessen Aug 29 '23 at 20:12
  • I am wondering if there is a better way to do what I did. It seems very fiddly to have to build a pipeline in such a way and I find it hard to believe that Microsoft doesn't use CI. So how would I phrase this question without leaving the person answering with a considerable amount of work (if I did not provide my code)? – Bitfiddler Aug 29 '23 at 21:15
  • So with coverlet.MSBuild, what else can I add other than I was building a .NET 6 project and I followed the above blog as accurately as I could (and verified every step twice) and could not get coverlet.MsBuild to generate anything. No errors during build. No errors during running of tests. Simply nothing happens. – Bitfiddler Aug 29 '23 at 21:30
  • Also saw this: https://github.com/coverlet-coverage/coverlet/issues/1391 Which states the issue was fixed in .NET 7.0.101, we are running 7.0.400 so this 'should' not be my problem. – Bitfiddler Aug 29 '23 at 22:09
  • Another oddity is every example uses TeamcitySummary as the report type output, but again, using that option generates nothing for me. I had to use the Html report option for anything to work. – Bitfiddler Aug 30 '23 at 18:36

0 Answers0