如何按文件夹或项目组设置 SonarQube 代码复制,而不是针对单个 Azure DevOps 存储库中的整个解决方案?

How to set up SonarQube code duplication by folder or group of projects and not for the whole Solution in a single Azure DevOps repository?

在我们的产品堆栈中,我们有一个错综复杂的项目结构。

有一个主app,负责核心功能(路由、auth等),还有子模块。每个子模块由两个项目组成。

解决方案结构如下:

UI 用于 Web 内容(js、cshtml)和业务逻辑应用程序 (C#)。

我们有三个子模块(主应用程序下 运行 总共六个项目 (3modules*2projects)

我们引入了SonarQube分析,对于代码重复,默认扫描了所有六个项目,它给出了很多误报。这些模块不打算耦合,任何重叠都是有意的。在 SonarQube 中可以 exclude or include things by file folder etc,我找不到设置如何 运行 每组事物。

我们的 Azure 管道相关位如下:

- variables:
  buildConfiguration: 'Release'
  SolutionPath: 'src/Solution.sln'

steps:
- task: NuGetToolInstaller@1
  inputs:
    versionSpec: '5.11.0'
    checkLatest: true

- task: DotNetCoreCLI@2
  displayName: "Restoring Company.Department.UI Solution"
  inputs:
    command: 'restore'
    projects: '$(SolutionPath)'
    feedsToUse: 'config'
    nugetConfigPath: 'src/nuget.config'

- task: PowerShell@2
  displayName: Scan for NuGet vulnerabilities
  enabled: true
  inputs:
    targetType: inline
    script: >-
        $solutionPath = '$(SolutionPath)'

        Write-Host $solutionPath

        ($output = dotnet list "$solutionPath" package --vulnerable)

        $output

        $errors = $output | Select-String '>'

        if ($errors.Count -gt 0) {
            foreach ($err in $errors) {
                Write-Host "##vso[task.logissue type=error]Found vulnerable NuGet package $err"
            }

            exit 1
        }

        exit 0

- task: UseNode@1
  displayName: Use Node 16.x
  inputs:
    version: 16.x
    checkLatest: true

- task: SonarQubePrepare@5
  inputs:
    SonarQube: 'SonarQube'
    scannerMode: 'MSBuild'
    projectKey: 'R-Department_Department-Frontend'
    extraProperties: "# Additional properties that will be passed to the scanner, \n# Put one key=value per line, example:\n# sonar.exclusions=**/*.bin\nsonar.cs.vscoveragexml.reportsPaths=$(Agent.TempDirectory)/**/*.coveragexml\nsonar.coverage.exclusions=**/*.js,**/*.cshtml"

- task: DotNetCoreCLI@2
  displayName: "Building"
  inputs:
    command: 'build'
    projects: $(SolutionPath)
    arguments: --configuration $(buildConfiguration)

- task: DotNetCoreCLI@2
  displayName: "Running Tests"
  inputs:
      command: test
      projects: >-
        **/*Test*.csproj

        !**\*TestAdapter.dll;

        !**\obj\**
      arguments: --configuration $(buildConfiguration) --no-build --collect "Code Coverage"

- task: PowerShell@2
  displayName: Create coveragexml file
  inputs:
    targetType: inline
    script: >-
        Get-ChildItem -Recurse -Filter "*.coverage" | % {

        $outfile = "$([System.IO.Path]::GetFileNameWithoutExtension($_.FullName)).coveragexml"

        $output = [System.IO.Path]::Combine([System.IO.Path]::GetDirectoryName($_.FullName), $outfile)

        "Analyse '$($_.Name)' with output '$outfile'..."

        . $env:USERPROFILE\.nuget\packages\microsoft.codecoverage.8.0\build\netstandard1.0\CodeCoverage\CodeCoverage.exe analyze /output:$output $_.FullName

        }

        "Done"

- task: SonarQubeAnalyze@5
  displayName: Run Code Analysis

- task: SonarQubePublish@5
  displayName: Publish Quality Gate Result

更新: 到目前为止,我们尝试的是设置四个 SonarQube 项目,即本地相同的文件夹。 然后运行四次

...
- task: SonarQubePrepare@5
 ...
- task: SonarQubeAnalyze@5
- task: SonarQubePublish@5
...

三个运行同时过滤掉所有其他子项目文件夹,共享一个 第四 运行 筛选出子项目并将其 运行 用于共享项目。

在本地工作

然而,在我们的开发基础设施中,我们使用 Azure DevOps,我们无法设置指向同一个存储库的多个 SonarQube 项目。

运行 相同的 SonarQube 项目 ID 四次只会覆盖之前的 运行,您只会得到最后一个的结果。

我确信必须有一种方法可以将代码复制配置为每个文件夹或每组项目 运行。

如何设置 SonarQube 检查文件夹或每组项目的代码重复,而不是单个 Azure DevOps 存储库中的整个解决方案?

一种解决方案是创建如下内容:

我们第一次排除除 Project1 以外的所有内容 (o) 其次,我们排除除 Project2 (c) 之外的所有内容 最后我们排除了除 project3 (m) 之外的所有内容 然后我们排除所有项目并 运行 扫描除项目 1、2 和 3

之外剩下的内容

然后在SonarCube项目中进行相应的设置。

trigger: none
pr: [branch-name]

pool:
  vmImage: 'aa-latest'
  name: 'NAT'
  
variables:
  buildConfiguration: 'Release'
  SolutionPath: 'src/XXX.YYY.Frontend.sln'

steps:
- task: NuGetToolInstaller@1
  inputs:
    versionSpec: '5.11.0'
    checkLatest: true

- task: DotNetCoreCLI@2
  displayName: "Restoring XXX.YYY.UI Solution"
  inputs:
    command: 'restore'
    projects: '$(SolutionPath)'
    feedsToUse: 'config'
    nugetConfigPath: 'src/nuget.config'

- task: PowerShell@2
  displayName: Scan for NuGet vulnerabilities
  enabled: true
  inputs:
    targetType: inline
    script: >-
        $solutionPath = '$(SolutionPath)'

        Write-Host $solutionPath

        ($output = dotnet list "$solutionPath" package --vulnerable)

        $output

        $errors = $output | Select-String '>'

        if ($errors.Count -gt 0) {
            foreach ($err in $errors) {
                Write-Host "##vso[task.logissue type=error]Found vulnerable NuGet package $err"
            }

            exit 1
        }

        exit 0

- task: UseNode@1
  displayName: Use Node 16.x
  inputs:
    version: 16.x
    checkLatest: true

- task: SonarQubePrepare@5
  inputs:
    SonarQube: 'SonarQube'
    scannerMode: 'MSBuild'
    projectKey: 'RBS-YYY_YYY-Frontend'
    extraProperties: "# Additional properties that will be passed to the scanner, \n# Put one key=value per line, example:\n# sonar.exclusions=**/*.bin\nsonar.cs.vscoveragexml.reportsPaths=$(Agent.TempDirectory)/**/*.coveragexml\nsonar.coverage.exclusions=**/*.js,**/*.cshtml\nsonar.exclusions=**/MJ/m/**,**/MJ/c/**,**/MJ/o/**\nsonar.issue.ignore.multicriteria=c,m,o,shared\nsonar.issue.ignore.multicriteria.c.ruleKey=*\nsonar.issue.ignore.multicriteria.c.resourceKey=**/MJ/c/**\nsonar.issue.ignore.multicriteria.m.ruleKey=*\nsonar.issue.ignore.multicriteria.m.resourceKey=**/MJ/m/**\nsonar.issue.ignore.multicriteria.o.ruleKey=*\nsonar.issue.ignore.multicriteria.o.resourceKey=**/MJ/o/**\nsonar.issue.ignore.multicriteria.shared.ruleKey=*\nsonar.issue.ignore.multicriteria.shared.resourceKey=**/XXX.YYY.Shared.Application/**\nsonar.test.exclusions=**/*.Tests/**"

- task: DotNetCoreCLI@2
  displayName: "Building"
  inputs:
    command: 'build'
    projects: $(SolutionPath)
    arguments: --configuration $(buildConfiguration)

- task: DotNetCoreCLI@2
  displayName: "Running Tests"
  inputs:
      command: test
      projects: >-
        **/*Test*.csproj

        !**\*TestAdapter.dll;

        !**\obj\**
      arguments: --configuration $(buildConfiguration) --no-build --collect "Code Coverage"

- task: PowerShell@2
  displayName: Create coveragexml file
  inputs:
    targetType: inline
    script: >-
        Get-ChildItem -Recurse -Filter "*.coverage" | % {

        $outfile = "$([System.IO.Path]::GetFileNameWithoutExtension($_.FullName)).coveragexml"

        $output = [System.IO.Path]::Combine([System.IO.Path]::GetDirectoryName($_.FullName), $outfile)

        "Analyse '$($_.Name)' with output '$outfile'..."

        . $env:USERPROFILE\.nuget\packages\microsoft.codecoverage.8.0\build\netstandard1.0\CodeCoverage\CodeCoverage.exe analyze /output:$output $_.FullName

        }

        "Done"

- task: SonarQubeAnalyze@5
  displayName: Run Code Analysis

- task: SonarQubePublish@5
  displayName: Publish Quality Gate Result

- task: SonarQubePrepare@5
  displayName: "SonarQube Prepare (m)"
  inputs:
    SonarQube: 'SonarQube'
    scannerMode: 'MSBuild'
    projectKey: 'YYY-Frontend-m'
    extraProperties: "# Additional properties that will be passed to the scanner, \n# Put one key=value per line, example:\n# sonar.exclusions=**/*.bin\nsonar.cs.vscoveragexml.reportsPaths=$(Agent.TempDirectory)/**/*.coveragexml\nsonar.coverage.exclusions=**/*.js,**/*.cshtml\nsonar.exclusions=**/MJ/c/**,**/MJ/o/**\nsonar.issue.ignore.multicriteria=c,o,shared\nsonar.issue.ignore.multicriteria.c.ruleKey=*\nsonar.issue.ignore.multicriteria.c.resourceKey=**/MJ/c/**\nsonar.issue.ignore.multicriteria.o.ruleKey=*\nsonar.issue.ignore.multicriteria.o.resourceKey=**/MJ/o/**\nsonar.issue.ignore.multicriteria.shared.ruleKey=*\nsonar.issue.ignore.multicriteria.shared.resourceKey=**/XXX.YYY.Shared.Application/**\nsonar.test.exclusions=**/*.Tests/**"

- task: DotNetCoreCLI@2
  displayName: "Building (m)"
  inputs:
    command: 'build'
    projects: $(SolutionPath)
    arguments: --configuration $(buildConfiguration)

- task: SonarQubeAnalyze@5
  displayName: Run Code Analysis (m)

- task: SonarQubePublish@5
  displayName: Publish Quality Gate Result (m)

- task: SonarQubePrepare@5
  displayName: "SonarQube Prepare (cs)"
  inputs:
    SonarQube: 'SonarQube'
    scannerMode: 'MSBuild'
    projectKey: 'YYY-Frontend-cs'
    extraProperties: "# Additional properties that will be passed to the scanner, \n# Put one key=value per line, example:\n# sonar.exclusions=**/*.bin\nsonar.cs.vscoveragexml.reportsPaths=$(Agent.TempDirectory)/**/*.coveragexml\nsonar.coverage.exclusions=**/*.js,**/*.cshtml\nsonar.exclusions=**/MJ/m/**,**/MJ/o/**\nsonar.issue.ignore.multicriteria=m,o,shared\nsonar.issue.ignore.multicriteria.m.ruleKey=*\nsonar.issue.ignore.multicriteria.m.resourceKey=**/MJ/m/**\nsonar.issue.ignore.multicriteria.o.ruleKey=*\nsonar.issue.ignore.multicriteria.o.resourceKey=**/MJ/o/**\nsonar.issue.ignore.multicriteria.shared.ruleKey=*\nsonar.issue.ignore.multicriteria.shared.resourceKey=**/XXX.YYY.Shared.Application/**\nsonar.test.exclusions=**/*.Tests/**"

- task: DotNetCoreCLI@2
  displayName: "Building (cs)"
  inputs:
    command: 'build'
    projects: $(SolutionPath)
    arguments: --configuration $(buildConfiguration)

- task: SonarQubeAnalyze@5
  displayName: Run Code Analysis (cs)

- task: SonarQubePublish@5
  displayName: Publish Quality Gate Result (cs)

- task: SonarQubePrepare@5
  displayName: "SonarQube Prepare (o)"
  inputs:
    SonarQube: 'SonarQube'
    scannerMode: 'MSBuild'
    projectKey: 'YYY-Frontend-o'
    extraProperties: "# Additional properties that will be passed to the scanner, \n# Put one key=value per line, example:\n# sonar.exclusions=**/*.bin\nsonar.cs.vscoveragexml.reportsPaths=$(Agent.TempDirectory)/**/*.coveragexml\nsonar.coverage.exclusions=**/*.js,**/*.cshtml\nsonar.exclusions=**/MJ/c/**,**/MJ/m/**\nsonar.issue.ignore.multicriteria=m,c,shared\nsonar.issue.ignore.multicriteria.m.ruleKey=*\nsonar.issue.ignore.multicriteria.m.resourceKey=**/MJ/m/**\nsonar.issue.ignore.multicriteria.c.ruleKey=*\nsonar.issue.ignore.multicriteria.c.resourceKey=**/MJ/c/**\nsonar.issue.ignore.multicriteria.shared.ruleKey=*\nsonar.issue.ignore.multicriteria.shared.resourceKey=**/XXX.YYY.Shared.Application/**\nsonar.test.exclusions=**/*.Tests/**"

- task: DotNetCoreCLI@2
  displayName: "Building (o)"
  inputs:
    command: 'build'
    projects: $(SolutionPath)
    arguments: --configuration $(buildConfiguration)

- task: SonarQubeAnalyze@5
  displayName: Run Code Analysis (o)

- task: SonarQubePublish@5
  displayName: Publish Quality Gate Result (o)