YAML Pipeline with Code Coverage Conditional

YAML Pipeline with Code Coverage Conditional

 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

Leave a Reply

Your email address will not be published. Required fields are marked *