I am currently implementing an azure DevOps pipeline for my .Net microservices.
I researched and read the sonar cloud doc, but nothing helped yet. I did generate the code coverage report using cobertura and that is working correctly in azure devops but I found out that you cannot link that type of format to sonarcloud so I was trying somehow to generate also the opencover and use it for exporting to sonarcloud, this is what I have done so far:
trigger:
- dev
- main
pool:
vmImage: ubuntu-latest
jobs:
- job: check_code_quality
steps:
- task: SonarCloudPrepare#1
displayName: 'Setup Sonar Cloud'
inputs:
SonarCloud: 'SonarCloud'
organization: '***'
scannerMode: 'MSBuild'
projectKey: '***'
projectName: '****'
extraProperties: |
sonar.exclusions=**/obj/**,**/*.dll
sonar.cs.vstest.reportsPaths=$(Agent.TempDirectory)/*.trx
sonar.cs.opencover.reportsPaths=$(Agent.TempDirectory)/**/coverage.opencover.xml
- task: DotNetCoreCLI#2
displayName: 'Build main code'
inputs:
command: build
projects: '**/*.csproj'
arguments: '--configuration Release'
- task: DotNetCoreCLI#2
displayName: 'Run unit tests'
continueOnError: true
inputs:
command: 'test'
projects: '**/*[Tt]est*/*.csproj'
testRunTitle: 'Backend Unit Testing'
arguments: '--configuration Release --collect:"XPlat Code Coverage" -- DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.Format=cobertura,opencover'
publishTestResults: true
- task: PublishCodeCoverageResults#1
displayName: 'Publish code coverage report'
inputs:
codeCoverageTool: 'Cobertura'
summaryFileLocation: '$(Agent.TempDirectory)/**/coverage.cobertura.xml'
- task: SonarCloudAnalyze#1
displayName: 'Run Sonar Analysis'
- task: SonarCloudPublish#1
displayName: 'Publish Sonar Results'
inputs:
pollingTimeoutSec: '300'
I checked the logs and I saw this:
Attachments:
/home/vsts/work/_temp/111bef07-6e19-43fe-a689-7597bc24dda3/coverage.cobertura.xml
/home/vsts/work/_temp/111bef07-6e19-43fe-a689-7597bc24dda3/coverage.opencover.xml
Also I have an issue that sonar cloud is only analyzing my test projects not the main code
I suppose that you could re-modify your dotnet test task with argument below.
arguments: '--logger trx --collect:"XPlat Code Coverage" --collect:"Code Coverage" -- DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.Format=cobertura --output $(build.artifactstagingdirectory)'
Full yaml for dotnet part as below.
steps:
- task: DotNetCoreCLI#2
displayName: 'dotnet test'
inputs:
command: 'test'
projects: 'xxx.csproj'
arguments: '--logger trx --collect:"XPlat Code Coverage" --collect:"Code Coverage" -- DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.Format=cobertura --output $(build.artifactstagingdirectory)'
publishTestResults: false
- task: PublishBuildArtifacts#1
inputs:
PathtoPublish: '$(Build.Repository.LocalPath)\{reponame}\TestResults'
ArtifactName: 'drop'
publishLocation: 'Container'
- task: PublishTestResults#2
inputs:
testResultsFormat: 'VSTest'
testResultsFiles: '**/*.trx'
- task: PublishCodeCoverageResults#1
displayName: 'Publish code coverage from $(Agent.TempDirectory)\**\coverage.cobertura.xml'
inputs:
codeCoverageTool: Cobertura
summaryFileLocation: '$(Build.Repository.LocalPath)\{reponame}\TestResults\**\coverage.cobertura.xml'
reportDirectory: '$(System.DefaultWorkingDirectory)\reports' ###please keep this setting as mine
For the sonarqube part, the sonarqube task would search for the .trx file in your agent folder.
My path is below, and you could check your local agent folder in the debug log and set the path in sonarqube task.
==================================================
Updated on 1/12
i suppose that you could find all the test result files with coverage..xml, .trx, and .coverage, you could check in pipeline artifacts drop-down list for the existence of the files and then go to your local folder again,.
Related
We made a deployment pipe and made it work on a Win machine. Then, we decided to attempt deploying it on Linux and created a new app service with Linux machine etc. Trying to reuse the previously working pipe, we made a few adaptations.
Partly, --runtime ubuntu.16.04-x64 (in the build step). Also, replacing the deployment step with the following.
- task: AzureRmWebAppDeployment#4
inputs:
ConnectionType: 'AzureRM'
azureSubscription: 'se-tyr-aux-az-con'
appType: 'webAppLinux'
WebAppName: 'app-aux-recorder'
packageForLinux: '$(System.DefaultWorkingDirectory)/**/*.zip'
RuntimeStack: 'DOTNETCORE|7.0'
StartupCommand: 'dotnet run'
Now, the content of the YAML is as follows.
pool:
vmImage: 'windows-latest'
variables:
solution: '**/*.sln'
project: '**/*.csproj'
buildPlatform: 'Any CPU'
buildConfiguration: 'Release'
steps:
- task: NuGetToolInstaller#1
- task: NuGetCommand#2
inputs:
restoreSolution: '$(solution)'
- task: DotNetCoreCLI#2
inputs:
command: 'build'
projects: '$(project)'
arguments: '/p:DeployOnBuild=true /p:target=package
/p:WebPublishMethod=Package /p:PackageAsSingleFile=true
/p:SkipInvalidConfigurations=true --runtime ubuntu.16.04-x64'
- task: AzureRmWebAppDeployment#4
inputs:
ConnectionType: 'AzureRM'
azureSubscription: 'se-tyr-aux-az-con'
appType: 'webAppLinux'
WebAppName: 'app-aux-recorder'
packageForLinux: '$(System.DefaultWorkingDirectory)/**/*.zip'
RuntimeStack: 'DOTNETCORE|7.0'
StartupCommand: 'dotnet run'
Each step reports green success. The application gets the default "some good stuff coming soon" page. However, swagger endpoint doesn't work nor does the controller method (status code 404 Not Found).
We're not sure if the application is running but fails to serve the request or if it's not been properly deployed. Checking the console (accessible during the deployment time), I can see a bunch of DLL's in the wwwroot directory's subfolders, including a file called Api (no file extension) that corresponds to the project's name.
Now sure how to investigate further. The documentation on YAMLs for Azure leaves a bit to ask and googling it gave me not much leads. We've used mostly this one and linked to it this one. They aren't of the highest quality.
Setting vmImage: 'ubuntu-latest' produced an error about the deployment not being able to find IIS instance, which suggests that we somehow made Azure think that we're targeting Windows with our deployment. However, I fail to see where we do so.
I suspect that you skipped some properties at the build step. I'm not familiar using this kind of arguments. Probably you need to pass the result of the build process to the deploy step, and, at the publish process, specify what files have to be deployed to you linux webapp.
This is the simplest way to achive it:
Deploy a .Net app (to an Azure WebApp)
steps:
- script: dotnet build --configuration $(buildConfiguration)
displayName: 'dotnet build $(buildConfiguration)'
- task: DotNetCoreCLI#2
inputs:
command: 'publish'
publishWebProjects: true
- task: AzureWebApp#1
inputs:
azureSubscription: '<Azure service connection>'
appType: 'webAppLinux'
appName: '<Name of web app>'
package: '$(System.DefaultWorkingDirectory)/**/*.zip'
As I like things clear, I would suggest to make it more explicit but at the same time more clear just doing a first and simple build step, and then a publish one to set the publish result (zip file) to a specific directory. Then, catch that zip within the AzureRmWebAppDeployment#4 step. Here, in this final step, you should use the zip result that is going to be used in the task.
This solution combines this steps:
Build project
Publish project (skip the PublishPipelineArtifact task)
Deploy to Azure webApp
Here goes an example:
variables:
solution: '**/*.sln'
project: '**/*.csproj'
buildPlatform: 'Any CPU'
buildConfiguration: 'Release'
azureSubscription: 'se-tyr-aux-az-con'
webAppName: 'app-aux-recorder'
steps:
- task: DotNetCoreCLI#2
displayName: Build
inputs:
command: build
projects: '$(project)'
arguments: '--configuration $(buildConfiguration)'
- task: DotNetCoreCLI#2
displayName: Publish
inputs:
command: publish
projects: '$(project)'
arguments: '--configuration $(buildConfiguration) -r ubuntu.16.04-x64 --self-contained true --output $(Build.ArtifactStagingDirectory)'
#this is equivalent to /p:PackageAsSingleFile=true
zipAfterPublish: true
- task: AzureRmWebAppDeployment#4
displayName: Api
inputs:
ConnectionType: 'AzureRM'
azureSubscription: '$(azureSubscription)'
appType: 'Web App on Linux'
WebAppName: '$(webAppName)'
packageForLinux: '$(Build.ArtifactStagingDirectory)/**/*.zip'
# $(Build.ArtifactStagingDirectory) is the path where de publish task set the zip
In other hand, you can create a multi-stage pipeline to deploy the Windows and linux app simultaniously.
This solution is an approach of the offical documentation:
Deploy to multiple web apps
Something similar to this:
stages:
- stage: BuildIt
jobs:
- job: BuildTheCode
pool:
vmImage: 'Ubuntu 16.04'
variables:
solution: '**/*.sln'
project: '**/*.csproj'
buildPlatform: 'Any CPU'
buildConfiguration: 'Release'
steps:
- task: DotNetCoreCLI#2
displayName: 'Build'
inputs:
command: build
projects: '$(project)'
arguments: '--configuration $(buildConfiguration)'
- task: DotNetCoreCLI#2
displayName: 'Publish'
inputs:
command: publish
projects: '**/*.csproj'
arguments: '--configuration $(buildConfiguration) --output $(Build.ArtifactStagingDirectory)'
#this is equivalent to /p:PackageAsSingleFile=true
zipAfterPublish: true
- task: PublishPipelineArtifact#1
inputs:
targetPath: '$(Build.ArtifactStagingDirectory)'
artifactName: '<artifact-name>'
- stage: Deployment
jobs:
- job: Publish to Windows
variables:
azureSubscription: 'se-tyr-aux-az-con'
webAppName: '<your-windows-webapp-name>'
steps:
# download the artifact from the previous job
- task: DownloadPipelineArtifact#2
inputs:
source: 'current'
artifact: 'drop'
path: '$(Pipeline.Workspace)'
- task: AzureRmWebAppDeployment
inputs:
ConnectionType: 'AzureRM'
azureSubscription: '$(azureSubscription)'
appType: 'webApp' #you can skip this, default value is webApp
WebAppName: '$(webAppName)'
package: '$(Pipeline.Workspace)/**/*.zip'
- job: Publish to Linux
variables:
azureSubscription: 'se-tyr-aux-az-con'
webAppName: '<your-linux-webapp-name>'
steps:
- download: 'current'
artifact: '<artifact-name>'
- task: AzureRmWebAppDeployment
inputs:
ConnectionType: 'AzureRM'
azureSubscription: '$(azureSubscription)'
appType: 'webAppLinux'
WebAppName: '$(webAppName)'
packageForLinux: '$(Pipeline.Workspace)/**/*.zip'
In my web api project I have written unit test in Specflow (MStest).
FYI: all my test cases pass.
This is the build pipeline:
- task: DotNetCoreCLI#2
displayName: 'Install ReportGenerator'
inputs:
command: custom
custom: tool
arguments: 'install --global dotnet-reportgenerator-globaltool
- task: DotNetCoreCLI#2
displayName: Test
inputs:
command: test
projects: '**/project/webApi/**/*Tests.csproj'
publishTestResults: false
arguments: '--configuration $(buildConfiguration) /p:Collect="XPlat Code Coverage" /p:CollectCoverage=true /p:CoverletOutputFormat=cobertura /p:CoverletOutput=$(Build.SourcesDirectory)/TestResults/Coverage/ "/p:MergeWith=../TestResults/coverlet.json"'
- task: PublishCodeCoverageResults#1
displayName: CodeCoverage
inputs:
codeCoverageTool: Cobertura
summaryFileLocation: '$(Build.SourcesDirectory)/**/Coverage/*.xml'
- task: reportgenerator#4
inputs:
reports: '$(Build.SourcesDirectory)/**/*.cobertura.xml'
targetdir: '$(Build.SourcesDirectory)/CoverageResults'
The xml file which has to be generated is not generated.
When tried to publish the code using Coberta
Error: the report file pattern 'D:\a\1\s/**/*.cobertura.xml' is invalid. No matching files found.
No report files specified
Here's a screenshot for illustration:
You don't need reportgenerator with the newest dotnet cli.
And pleae try with this configuration:
# You just added coverlet.collector to use 'XPlat Code Coverage'
- task: DotNetCoreCLI#2
displayName: Test
inputs:
command: test
projects: '**/*Tests/*.csproj'
arguments: '--configuration $(buildConfiguration) --collect:"XPlat Code Coverage"'
- task: PublishCodeCoverageResults#1
displayName: 'Publish code coverage'
inputs:
codeCoverageTool: Cobertura
summaryFileLocation: '$(Agent.TempDirectory)/**/coverage.cobertura.xml'
I have an azure pipeline to build and publish a c# project to a docker image.
everything works just fine but today I wanted to add a unit test this pipeline.
so I added the task for it.
as follow:
- task: UseDotNet#2
inputs:
packageType: 'sdk'
version: '5.x'
- task: DotNetCoreCLI#2
displayName: 'DotNet - Restore'
inputs:
command: 'restore'
projects: $(project)
noCache: true
versioningScheme: 'off'
vstsFeed: 'feed'
- task: DotNetCoreCLI#2
displayName: "Run unit tests - $(Build.BuildNumber)"
inputs:
command: 'test'
arguments: '--no-build --configuration $(Build.BuildNumber)'
projects: 'path/to/Tests.csproj'
publishtestResults: true
- task: DotNetCoreCLI#2
name: 'DotnetPublish'
displayName: 'dotnet - Publish'
inputs:
command: 'publish'
projects: $(project)
arguments: '-o publish/projectapi -c release'
modifyOutputPath: false
zipAfterPublish: false
publishWebProjects: false
- task: Docker#2
name: 'dockerBuildAndPush'
displayName: 'docker - Build & Push'
inputs:
repository: $(imageRepository)
Dockerfile: $(dockerfilePath)
containerRegistry: ${{ variables.dockerRegistryServiceConnection }}
buildContext: ${{ variables.buildContext }}
tags: |
$(Build.BuildNumber)
latest
when I run the pipeline, on the test task, it take less than 2 second and it returns
##[warning]No test result files were found.
and if I head to the tests tab, I see the message that there are no tests to display.
Am I doing something wrong in my pipeline configuration?
thank you so much for any help
EDIT:
There are some update about this. The issue was related to the fact that I didn't have a build task for the test csproj.
When I implemented the task and run the pipeline. I got an error about a nuget package not found (private nuget). In my vsfeed in the devops panel, I can see that package exists, but for some reason the pipeline fails because it doesn't see that package.
Did this ever happened to anyone and knows a workaround?
Try removing the --no-build from the arguments. Nothing in the pipeline before it appears to run the build. You also may need to make sure that your dotnet restore command is restoring the packages for the test project. (I can't tell from if the restore for $(project) would or not)
my problem is that I have a project created in .net core 2.2, the problem is that I am trying to deploy it with azure pipelines but when using the dotnet restore it fails continuously and ends the construction.
The error it returns is the following:
2020-11-21T20:17:30.4639428Z ##[error]**Error: The process 'C:\hostedtoolcache\windows\dotnet\dotnet.exe' failed with exit code 1**
2020-11-21T20:17:30.4652823Z ##[error]**Packages failed to restore**
2020-11-21T20:17:30.4655465Z **Info: Azure Pipelines hosted agents have been updated to contain .Net Core 3.x (3.1) SDK/Runtime along with 2.1. Unless you have locked down a SDK version for your project(s), 3.x SDK might be picked up which might have breaking behavior as compared to previous versions.**
2020-11-21T20:17:30.4656214Z Some commonly encountered changes are:
2020-11-21T20:17:30.4657227Z If you're using `Publish` command with -o or --Output argument, you will see that the output folder is now being created at root directory rather than Project File's directory. To learn about more such changes and troubleshoot, refer here: https://learn.microsoft.com/en-us/azure/devops/pipelines/tasks/build/dotnet-core-cli?view=azure-devops#troubleshooting
2020-11-21T20:17:30.4661682Z ##[section]Finishing: dotnet restore
I have tried to install version 2.2 to be used in the process before the restore, I have tried using the nuget.config and the global.json.I leave here the .yml that I have used to see if someone can give me a hand.
steps:
- task: UseDotNet#2
displayName: 'Use .NET Core sdk 2.2.x'
inputs:
version: 2.2.x
includePreviewVersions: true
performMultiLevelLookup: true
- task: DotNetCoreCLI#2
displayName: 'dotnet restore'
inputs:
command: restore
projects: '**/*.csproj'
- task: NuGetToolInstaller#0
displayName: 'Use NuGet 4.4.1'
inputs:
versionSpec: 4.4.1
checkLatest: true
- task: NuGetCommand#2
displayName: 'NuGet restore'
inputs:
restoreSolution: '$(Parameters.solution)'
- task: VSBuild#1
displayName: 'Build solution'
inputs:
solution: '$(Parameters.solution)'
msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:PackageLocation="$(build.artifactstagingdirectory)\\"'
platform: '$(BuildPlatform)'
configuration: '$(BuildConfiguration)'
- task: PublishSymbols#2
displayName: 'Publish symbols path'
inputs:
SearchPattern: '**\bin\**\*.pdb'
PublishSymbols: false
continueOnError: true
- task: PublishBuildArtifacts#1
displayName: 'Publish Artifact'
inputs:
PathtoPublish: '$(build.artifactstagingdirectory)'
ArtifactName: '$(Parameters.ArtifactName)'
condition: succeededOrFailed()
I've tested with a .net core 2.2 project using the following yaml file, and got successful result.
trigger:
- master
pool:
vmImage: 'windows-latest'
steps:
- task: UseDotNet#2
inputs:
version: '2.2.x'
includePreviewVersions: true
performMultiLevelLookup: true
- task: DotNetCoreCLI#2
inputs:
command: 'restore'
projects: '**/*.csproj'
In order to narrow down the issue, I'd like to suggest you:
Create a simple .net core 2.2 project and push to DevOps, create a pipeline for this project to see whether you can reproduce this issue.
Clone the project to local, and run dotnet restore command locally to see how's the result.
I have a C# solution where there are several unit test projects that use xUnit and an "end to end" tests project that uses NUnit. (This is intentional and fine so I'd appreciate not trying to convince me to ditch one for the other, thanks)
I use an Azure DevOps Pipeline to build, test and package my solution. This is my test step (from azure-pipelines.yml) at the moment:
- task: DotNetCoreCLI#2
displayName: 'Run tests in solution'
inputs:
command: 'test'
arguments: '--configuration $(buildConfiguration) --collect "Code coverage" --filter Category!=Integration'
publishTestResults: true
When I run this my pipeline fails with this error message:
An exception occurred while invoking executor 'executor://nunit3testexecutor/': Unexpected Word 'Category' at position 29 in selection expression.
I'm pretty sure this happens because NUnit is getting picked up and it does not understand the Category filter term. (NUnit expects the term TestCategory instead)
I tried getting the pipeline to not pick up the NUnit project (called "EndToEnd")this way:
--filter FullyQualifiedName!~EndToEnd&Category!=Integration'
But this does not work and I get the same error message.
How can I get Azure DevOps Pipelines to only run the tests in my xUnit projects in this step and not fail because of the presence of the NUnit project?
You may use projects to pick projects. I tested this against this solution and it works:
variables:
buildConfiguration: 'Release'
rootDirectory: '$(Build.SourcesDirectory)/stackoverflow/69-nunit-and-xunit'
steps:
- task: DotNetCoreCLI#2
displayName: Restore nuget packages
inputs:
command: restore
projects: '**/*.csproj'
workingDirectory: $(rootDirectory)
- task: DotNetCoreCLI#2
displayName: Test xUnit
inputs:
command: test
projects: '$(rootDirectory)/**/*XUnit.csproj'
arguments: '--configuration $(buildConfiguration)'
- task: DotNetCoreCLI#2
displayName: Test NUnit
inputs:
command: test
projects: '$(rootDirectory)/**/*NUnit.csproj'
arguments: '--configuration $(buildConfiguration)'