Azure Pipeline中PR的Sonar扫描无法识别.NET特性分支新代码
问题
使用Azure Pipeline对.NET代码的Pull Request执行Sonar扫描时,扫描无法识别特性分支中的新增代码,显示零覆盖率且无新增代码记录,需要实现PR触发流水线中新增代码的分析。当前Azure Pipeline配置如下:
- script: | git config --global http.https://dev.azure.com/<company>/.extraheader "AUTHORIZATION: bearer $(System.AccessToken)" # Now fetch the PR source branch using the token git fetch origin $(System.PullRequest.SourceBranch):$(System.PullRequest.SourceBranch) git checkout $(System.PullRequest.SourceBranch) displayName: 'Fetch and Checkout PR Source Branch' env: # This exposes the system access token to the script SYSTEM_ACCESSTOKEN: $(System.AccessToken) - script: | git checkout $(System.PullRequest.SourceBranch) displayName: 'Checkout PR Source Branch' - task: DotNetCoreCLI@2 displayName: New Manifest for tool inputs: command: custom custom: 'new ' arguments: tool-manifest - task: PowerShell@2 displayName: Set the prereleaseVersionNumber variable value inputs: targetType: 'inline' script: | [string] $dateTime = (Get-Date -Format 'yyyyMMddTHHmmss') [string] $prereleaseVersionNumber = "$(stableVersionNumber)-$(Build.SourceVersion)" Write-Host "Setting the prerelease version number variable to '$prereleaseVersionNumber'." Write-Host "##vso[task.setvariable variable=prereleaseVersionNumber]$prereleaseVersionNumber" - task: PowerShell@2 displayName: Set the versionNumber to the stable or prerelease version number based on if the 'main' branch is being built or not inputs: targetType: 'inline' script: | [bool] $isMainBranch = $$(isMainBranch) [string] $versionNumber = "$(prereleaseVersionNumber)" if ($isMainBranch) { $versionNumber = "$(stableVersionNumber)" } Write-Host "Setting the version number to use to '$versionNumber'." Write-Host "##vso[task.setvariable variable=versionNumber]$versionNumber" - task: PowerShell@2 displayName: Set the name of the build (i.e. the Build.BuildNumber) inputs: targetType: 'inline' script: | [string] $buildName = "$(versionNumber)_$(Build.SourceBranchName)" Write-Host "Setting the name of the build to '$buildName'." Write-Host "##vso[build.updatebuildnumber]$buildName" - task: NuGetToolInstaller@1 displayName: 'Install NuGet 5.8' inputs: versionSpec: '5.8.x' - task: NuGetCommand@2 displayName: 'Restore packages using NuGet' inputs: restoreSolution: '**/*.csproj' - task: UseDotNet@2 displayName: Use .NET 6.0 inputs: packageType: 'sdk' version: '6.0.x' - task: DotNetCoreCLI@2 displayName: 'Add Coverlet.msbuild package' inputs: command: 'custom' custom: 'add' projects: '$(Build.SourcesDirectory)/Virtue/Virtue.API/Virtue.API.csproj' arguments: 'package coverlet.msbuild' - task: DotNetCoreCLI@2 displayName: 'dotnet restore Virtue.API' inputs: command: 'restore' projects: '$(Build.SourcesDirectory)/Virtue/Virtue.API/Virtue.API.csproj' includeNuGetOrg: true noCache: true - task: SonarCloudPrepare@1 inputs: SonarCloud: 'SonarCloud Service Connection' organization: '<company_name>' scannerMode: 'MSBuild' projectKey: 'dotnet' projectName: 'Dotnet' extraProperties: | sonar.projectBaseDir=$(Build.SourcesDirectory) sonar.exclusions=**/README.md,**/obj/**,**/*.dll sonar.inclusions=**/*.csproj sonar.cs.vscoveragexml.reportsPaths=$(Build.SourcesDirectory)/**/coverage.xml sonar.cs.opencover.reportsPaths=$(Build.SourcesDirectory)/**/coverage.opencover.xml sonar.cs.vstest.reportsPaths=$(Agent.TempDirectory)/*.trx sonar.pullrequest.key=$(System.PullRequest.PullRequestId) sonar.pullrequest.branch=$(System.PullRequest.SourceBranch) sonar.pullrequest.base=$(System.PullRequest.TargetBranch) - task: DotNetCoreCLI@2 inputs: command: 'build' projects: '**/*.csproj' arguments: '--configuration $(buildConfiguration)' - task: DotNetCoreCLI@2 displayName: 'Test ...' inputs: command: test projects: '**/*Tests/*.csproj' arguments: '--configuration $(BuildConfiguration) /p:CollectCoverage=true /p:CoverletOutputFormat=opencover --logger trx' testRunTitle: 'dotnet test' - task: PublishCodeCoverageResults@1 inputs: codeCoverageTool: 'Cobertura' summaryFileLocation: '$(Build.SourcesDirectory)/**/coverage.opencover.xml' reportDirectory: '$(Build.SourcesDirectory)/**/coverage/' - script: | dotnet tool install -g dotnet-reportgenerator-globaltool reportgenerator -reports:$(Build.SourcesDirectory)/**/coverage.opencover.xml -targetdir:$(Build.SourcesDirectory)/CoverageReport -reporttypes:"HtmlInline;Cobertura" displayName: 'Generate Coverage Report' - task: PublishTestResults@2 displayName: "Publish Test Results" inputs: testResultsFormat: VSTest testResultsFiles: "$(Build.SourcesDirectory)/**.*trx" mergeTestResults: true condition: succeededOrFailed() - task: SonarCloudAnalyze@1 inputs: sonar.analysis.level: 'DOTNET' - task: SonarCloudPublish@1 inputs: pollingTimeoutSec: '300'
修复方案
1. 修正Git分支拉取逻辑
当前流水线重复执行分支检出,且未拉取PR目标分支,导致Sonar无法对比分支差异。调整Git步骤:
- script: | git config --global http.https://dev.azure.com/<company>/.extraheader "AUTHORIZATION: bearer $(System.AccessToken)" # 拉取PR源分支和目标分支,用于Sonar差异分析 git fetch origin $(System.PullRequest.SourceBranch):$(System.PullRequest.SourceBranch) git fetch origin $(System.PullRequest.TargetBranch):$(System.PullRequest.TargetBranch) git checkout $(System.PullRequest.SourceBranch) displayName: 'Fetch and Checkout PR Branches' env: SYSTEM_ACCESSTOKEN: $(System.AccessToken)
移除重复的Checkout PR Source Branch步骤,避免分支切换冲突。
2. 调整SonarCloudPrepare核心配置
sonar.inclusions错误设置为项目文件,改为扫描源代码文件- 使用分支名称而非完整路径,避免格式不兼容
- 移除未使用的覆盖率报告路径配置
- task: SonarCloudPrepare@1 inputs: SonarCloud: 'SonarCloud Service Connection' organization: '<company_name>' scannerMode: 'MSBuild' projectKey: 'dotnet' projectName: 'Dotnet' extraProperties: | sonar.projectBaseDir=$(Build.SourcesDirectory) sonar.exclusions=**/README.md,**/obj/**,**/*.dll sonar.inclusions=**/*.cs # 替换原**/*.csproj,确保扫描源代码 sonar.cs.opencover.reportsPaths=$(Build.SourcesDirectory)/**/coverage.opencover.xml sonar.cs.vstest.reportsPaths=$(Agent.TempDirectory)/*.trx sonar.pullrequest.key=$(System.PullRequest.PullRequestId) sonar.pullrequest.branch=$(System.PullRequest.SourceBranchName) # 使用分支名称 sonar.pullrequest.base=$(System.PullRequest.TargetBranchName) # 使用分支名称
3. 确保测试覆盖率报告路径可被Sonar识别
在测试步骤中指定覆盖率报告输出目录,避免Sonar无法定位文件:
- task: DotNetCoreCLI@2 displayName: 'Test ...' inputs: command: test projects: '**/*Tests/*.csproj' arguments: '--configuration $(BuildConfiguration) /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:CoverletOutput=$(Build.SourcesDirectory)/Coverage/ --logger trx' testRunTitle: 'dotnet test'
4. 移除冗余步骤
- 删除重复的
dotnet restore Virtue.API步骤,全局NuGet Restore已覆盖所有项目 - 若未使用工具清单,删除
New Manifest for tool步骤
内容的提问来源于stack exchange,提问作者Sneha Reddy
相关产品推荐
相关产品推荐

