SonarCloud code coverage failing on reading .xml summary file

Must-share information (formatted with Markdown):

  • which versions are you using (SonarQube, Scanner, Plugin, and any relevant extension)
  • what are you trying to achieve
  • what have you tried so far to achieve this
    I am using SonarCloud in my Azure pipeline running in Linux and using dotnet build and test. It is working as expected up to reading the code coverage file. It errors with this message

“Could not import coverage report ‘/home/vsts/work/_temp/folder1/folder/coverage.cobertura.xml’ because 'Missing root element in /home/vsts/work/_temp/folder/folder/coverage.cobertura.xml at line 2”

I know the report is good because I publish it into the pipeline and it shows up on the summary page of the run. I have been fighting getting SonarCloud to find the code coverage files but now it would be nice to have SonarCloud read the darn thing… :smiley:

Can anyone suggest a fix for this issue?

Hi @mpaulosky , welcome to the community.

Which language are you trying to analyze here ?

Thank you.

I’m working with C# the analysis is working fine it’s just the code coverage that it cannot seem to find. I know the code coverage is being generated because it shows up on the code coverage tab in the summary

Hi @mpaulosky,

Currently the dotnet analyzer does not support the Cobertura format. We only support VS Coverage, DotCover and OpenCover. The parameters for coverage import can be found here: Test Coverage & Execution | SonarQube Docs

What tool do you use to generate coverage? Can you please check if it can export in OpenCover format? Most of them do.

Thanks,
Costin

1 Like

Here is my Pipeline

Here are my Test settings

Here are the settings for the ReportGenerator

Finally the settings for the Publish Report task

This results in this report in the pipeline summary

Any suggestions for changes that will end up with SonarCloud having the code coverage and I still have the summary report will satisfy my expected results :sunglasses:

Additional details don’t know if they are important:

There are 5 test projects testing the 4 projects, Client, Server, Business Layer, and Data Layer.

I have read through the link you sent and the info that they sent me to. I ended up just confused more then ever mostly because of the documenting every type of code and testing and reporting types…

I also hate that in azure I can’t see where the reports are being stored and their format. So that makes it difficult to determine what paths to point the report generator and SonarCloud to.

It would be great if the support was documented in something like this

  1. Code Language
  2. Test Method
  3. Test Output type
  4. Test Report type

once that is determined lay out the settings for SonarCloud, the Test Runner, The Report Generator etc.
so the user has one place that lays out all the settings for their instance to be successful getting their testing and coverage into the locations that SonarCloud can access and still support their CI systems reporting functions.

Thanks @costin.zaharia for your response and help

Well after much reading and testing I found the solution to outputting both opencover and cobertura in my Azure and local Tests.

It was a random read the showed the using of the runsettings.xml to control the coverlet output. This simple xml file

<?xml version="1.0" encoding="utf-8" ?>
<RunSettings>
	<DataCollectionRunSettings>
		<DataCollectors>
			<DataCollector friendlyName="XPlat code coverage">
				<Configuration>
					<Format>opencover,cobertura</Format>
				</Configuration>
			</DataCollector>
		</DataCollectors>
	</DataCollectionRunSettings>
</RunSettings>

Allowed me to change my Test command to:

dotnet test --collect:“XPlat Code Coverage” --settings runsettings.xml

In the Azure Test task and it works locally as well.

This outputs both of these files:
coverage.cobertura.xml
coverage.opencover.xml

1 Like

Hi @mpaulosky,

that’s great. Are now the opencover reports imported successfully?

I had a little problem with the Test not finding the runsettings.xml files so I included them as resources in the build. That did the trick and now the opencover reports are importing correctly into SonarCloud!

Along the way I found that all the suggested /p commands did not work while running in the console which was disturbing since just about all the information I found suggested that they should. All the testing of the suggested fixes boiled down to adding the runsettings.xml and then placing them in the build directory which enabled the simple dotnet test --collect:“XPlat Code Coverage” --settings runsettings.xml command to get the output required.

Again I thank you, @costin.zaharia, for setting me on the path to finding a solution!

1 Like

Hi Paul,

would you mind sharing the yml file? im having a similar issue to yours, and would greatly appreciate any help!

@Leonardo-Ferreira I don’t know how this will help you, I don’t use yml in building my pipeline in Azure, I use the visual interface. I exported my CI Build to yml so here you go:

# Variable 'SonarOrganization' was defined in the Variables tab
# Variable 'SonarProjectKey' was defined in the Variables tab
# Variable 'SonarProjectName' was defined in the Variables tab
variables:
- name: BuildParameters.RestoreBuildProjects
  value: '**/*.csproj'
- name: BuildParameters.UnitTestProjects
  value: '**/*Tests/*Tests.csproj'
- name: BuildParameters.pathToSources
  value: ''
trigger:
  branches:
    include:
    - '*'
  paths:
    include:
    - /
  batch: True
name: $(date:yyyyMMdd)$(rev:.r)
resources:
  repositories:
  - repository: self
    type: git
    ref: main
jobs:
- job: Phase_1
  displayName: Agent job 1
  pool:
    vmImage: ubuntu-20.04
  steps:
  - checkout: self
  - task: UseDotNet@2
    displayName: Use .NET Core sdk 5.0.x
    inputs:
      version: 5.0.x
  - task: UseDotNet@2
    displayName: Use .NET Core sdk 2.1.505 for SonarCloud
    inputs:
      version: 2.1.505
  - task: DotNetCoreCLI@2
    displayName: Restore
    inputs:
      command: restore
      projects: $(BuildParameters.RestoreBuildProjects)
  - task: SonarCloudPrepare@1
    displayName: Prepare analysis on SonarCloud
    inputs:
      SonarCloud: Redacted
      organization: Redacted
      projectKey: Redacted
      projectName: IRCER
      extraProperties: >
        extraProperties: |

        sonar.exclusions=**/obj/**,**/*.dll

        sonar.cs.opencover.reportsPaths=$(Agent.TempDirectory)/**/coverage.opencover.xml

        sonar.cs.vstest.reportsPaths=$(Agent.TempDirectory)/*.trx
  - task: DotNetCoreCLI@2
    displayName: Build
    inputs:
      projects: $(BuildParameters.RestoreBuildProjects)
      arguments: --configuration $(BuildConfiguration) --no-restore
  - task: DotNetCoreCLI@2
    displayName: Test
    inputs:
      command: test
      projects: $(BuildParameters.UnitTestProjects)
      arguments: --no-build --no-restore --configuration $(BuildConfiguration) --collect:"XPlat Code Coverage" --settings runsettings.xml
  - task: PublishCodeCoverageResults@1
    displayName: Publish code coverage
    continueOnError: True
    inputs:
      codeCoverageTool: Cobertura
      summaryFileLocation: $(Agent.TempDirectory)/**/coverage.cobertura.xml
      pathToSources: $(BuildParameters.pathToSources)
      reportDirectory: $(build.artifactstagingdirectory)/Coverage/
      failIfCoverageEmpty: true
  - task: SonarCloudAnalyze@1
    displayName: Run Code Analysis
  - task: SonarCloudPublish@1
    displayName: Publish Quality Gate Result
  - task: DotNetCoreCLI@2
    displayName: Publish Api
    enabled: False
    inputs:
      command: publish
      publishWebProjects: false
      projects: Redacted
      arguments: ' -r linux-x64 --configuration $(BuildConfiguration) --output "$(build.artifactstagingdirectory)"'
  - task: DotNetCoreCLI@2
    displayName: Publish IRCER Client
    enabled: False
    inputs:
      command: publish
      publishWebProjects: false
      projects: Redacted
      arguments: ' -r linux-x64 --configuration $(BuildConfiguration) --output "$(build.artifactstagingdirectory)"'
      zipAfterPublish: True
  - task: PublishBuildArtifacts@1
    displayName: Publish Artifact
    inputs:
      PathtoPublish: $(build.artifactstagingdirectory)
      TargetPath: '\\my\share\$(Build.DefinitionName)\$(Build.BuildNumber)'
...

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.