The YAML flow builds the solution of an Azure Function, that contains 3 projects. The unit tests are run and published, and settings are contained in the coverlet.runsettings.xml:
<?xml version=“1.0” encoding=“utf-8” ?>
<RunSettings>
<DataCollectionRunSettings>
<DataCollectors>
<DataCollector friendlyName=“XPlat code coverage”>
<Configuration>
<ExcludeByFile/>
</Configuration>
</DataCollector>
</DataCollectors>
</DataCollectionRunSettings>
</RunSettings>
Output:
Then published:
The coverage reports then need to be merged so that overall coverage rates can be extracted, I use “reportgenerator”. The merged report is also published.
Using “xmlstarlet” I extract the line coverage value from the merged report:
coverage=$(xmlstarlet sel -t -v ‘number(//coverage[1]/@line-rate)*100’ ${cobertura_file})
The value retrieved can be used on a conditional statement:
condition: and(succeeded(), ne(variables[‘Agent.JobStatus’], ‘SucceededWithIssues’), gt(variables[‘GetLineCoverage.coverage_Line’],
variables[‘coverage_Threshold’]))
In the condition above I use the populated job variables for the line coverage threshold and the line coverage from the unit tests that are run.
Here is the full demo yaml:
trigger:
none
stages:
– stage: Test_Code_Coverage
jobs:
– job: BuildJob
pool:
vmImage: ubuntu-latest
variables:
coverage_Threshold: 56.48 # static
coverage_Line: 0.00 # default
steps:
– task: UseDotNet@2
inputs:
packageType: ‘sdk’
installationPath: $(Agent.ToolsDirectory)/dotnet
installationScript: ‘install’
version: ‘7.x’
displayName: ‘Setup .NET’
– script: |
# Restore NuGet Packages
dotnet restore
displayName: ‘Restore NuGet Packages’
– script: |
# Build the solution
dotnet build –configuration ‘Release’ –no-restore
displayName: ‘Build Solution’
– task: DotNetCoreCLI@2
displayName: ‘Run Unit Tests – Release’
inputs:
command: ‘test’
arguments: ‘–no-build –configuration “Release” –logger trx –results-directory “$(Build.SourcesDirectory)/TestResults/Coverage/” –settings coverlet.runsettings.xml’
publishTestResults: false
– task: PublishTestResults@2
displayName: ‘Publish Test Results’
inputs:
testResultsFormat: VSTest
testResultsFiles: ‘**/*.trx’
searchFolder: ‘$(Build.SourcesDirectory)/TestResults/Coverage/’
– task: DotNetCoreCLI@2
displayName: ‘dotnet Tool Install “reportgenerator”‘
inputs:
command: custom
custom: tool
arguments: ‘install -g dotnet-reportgenerator-globaltool’
– script: |
reportgenerator -reports:$(Build.SourcesDirectory)/**/*cobertura.xml -targetdir:$(Build.SourcesDirectory)/MergedCodeCoverage -reporttypes:’HtmlInline_AzurePipelines;Cobertura’
displayName: ‘Merge Code Coverage Reports’
workingDirectory: $(Build.SourcesDirectory)
– task: PublishCodeCoverageResults@1
displayName: ‘Publish Merged Code Coverage Report’
inputs:
codeCoverageTool: ‘cobertura’
summaryFileLocation: ‘$(Build.SourcesDirectory)/MergedCodeCoverage/Cobertura.xml’
reportDirectory: ‘$(Build.SourcesDirectory)/CodeCoverage’
– script: |
sudo apt-get update
sudo apt-get install -y xmlstarlet
displayName: ‘Install xmlstarlet’
– script: |
# Find the Cobertura XML file and store its path in a variable
cobertura_file=$(find $(Build.SourcesDirectory)/MergedCodeCoverage/ -name ‘Cobertura.xml’ | head -n 1)
###echo “DEBUG:Report path: ${cobertura_file}”
echo “##vso[task.setvariable variable=coverage_Line]$coverage_Line”
# Check if the file exists before attempting to parse
if [ -f “${cobertura_file}” ]; then
# Extract line coverage percentage from Cobertura XML
coverage=$(xmlstarlet sel -t -v ‘number(//coverage[1]/@line-rate)*100’ ${cobertura_file})
echo “##vso[task.setvariable variable=coverage_Line;isOutput=true]$coverage” #create a new line line coverage from xml
# Print the line coverage percentage
echo “Line coverage percentage: $coverage%”
else
echo “Cobertura XML file not found.”
fi
name: GetLineCoverage
displayName: ‘Print Line Coverage’
– script: |
echo “Agent job status: $(Agent.JobStatus)”
echo “Code coverage percentage: $(GetLineCoverage.coverage_Line)% and threshold is: $COVERAGE_THRESHOLD%”
displayName: ‘Condition Checks’
– script: |
# Over code coverage pass rate?%
echo “Code coverage is above $COVERAGE_THRESHOLD% ($(GetLineCoverage.coverage_Line)%). The build succeeded.”
displayName: ‘Check Code Coverage Percentage’
condition: and(succeeded(), ne(variables[‘Agent.JobStatus’], ‘SucceededWithIssues’), gt(variables[‘GetLineCoverage.coverage_Line’], variables[‘coverage_Threshold’])) # Only run if previous tasks succeeded