PAYATHON 2026

SonarCloud 在 monorepo 的 PR 分析中为何显示“0 New Lines”?

数据小许

结论

现有日志不足以确定唯一根因。GitHub Actions 检测到文件变化,只能证明模块筛选逻辑找到了差异;还需确认这些修改是否进入本次 SonarCloud 扫描范围,以及是否被识别为对应 PR 的新增代码。

这份配置应优先检查三个位置:matrix 各任务使用的 sonar.projectKey、扫描任务中的 Git 比较基线,以及相对于 projectBaseDir 的实际源码路径。分支名称正确、commit 是最新的,都不足以单独证明这三项正确。

这些日志能说明什么

原始日志中出现了:

SCM writing changed lines
SCM writing changed lines (done)
ANALYSIS SUCCESSFUL

这说明扫描执行到了写入 SCM 变更行信息的阶段,并完成了扫描端的报告提交。从中看不出识别到了多少变更行,还需要检查云端后台任务的处理结果。

另一条日志是:

The Python analyzer was able to leverage cached data from previous analyses for 0 out of 111 files. These files were not parsed.

这里的缓存命中数是 0 out of 111,不能据此认定 111 个文件都没有解析。应结合完整的 Python analyzer 日志确认实际分析情况。两段日志的时间不同,还需要核对它们是否属于同一个 job 和同一次扫描。

1. 核对 matrix 与 projectKey 的对应关系

目前只提供了 rest_api 的配置,尚不清楚其他模块是否也使用:

sonar.projectKey=greenshift-app_managementportal_v2

如果每个 matrix 任务只扫描一个模块,却都上传到同一个 projectKey,这些独立报告不会自动合并为分析分片。

应先确定项目组织方式:

  • 每个模块独立展示结果:为各模块建立对应的 SonarCloud 项目,分别使用唯一的 projectKey,并保持该模块在 PR 和目标分支上的扫描范围一致。
  • 整个仓库展示一个结果:使用同一个 projectKey,由一次扫描覆盖这个项目的完整源码范围。

SonarQube Cloud 的 monorepo 配置支持将同一仓库绑定到多个项目,各项目使用唯一的 key。官方 monorepo 说明

排查时先只运行 rest_api 的扫描,核对云端项目、PR 编号、分析时间和 commit。这样可以减少其他 matrix 任务对结果判断的干扰,但不能仅凭这一步认定项目 key 是根因。

2. 在扫描 job 内验证 Git 差异

模块检测 job 能计算差异,不代表扫描 job 也有相同的 Git 历史和目标分支。不同 job 的工作区需要分别检查。

SonarQube Cloud 要求 PR 源分支已 checkout、目标分支已获取、本地 .git 元数据完整,且扫描代码与远端提交一致。新增问题的识别还依赖目标分支的最新分析结果。官方 PR 分析说明

在现有 PR checkout 步骤的 with 中设置:

with:
  ref: ${{ github.event.pull_request.head.sha }}
  fetch-depth: 0

以上配置只用于 PR checkout;push 事件应使用适合该事件的 checkout 配置。扫描 action 文档也建议关闭 shallow clone。官方 action 配置

随后在仓库根目录、扫描前加入诊断步骤:

- name: Inspect PR diff
  if: github.event_name == 'pull_request'
  env:
    PR_BASE: ${{ github.base_ref }}
  run: |
    git fetch --no-tags origin "+refs/heads/${PR_BASE}:refs/remotes/origin/${PR_BASE}"
    git rev-parse HEAD
    git status --short
    git merge-base "origin/${PR_BASE}" HEAD
    git diff --name-status "origin/${PR_BASE}...HEAD"
    git diff --unified=0 "origin/${PR_BASE}...HEAD" -- rest_api/

这个示例假设 PR 的目标仓库是 origin;使用其他 remote 时需调整。

重点查看最后一条命令是否包含预期新增或修改的 Python 代码行。如果只有文件名变化、内容删除或文件重命名,不能据此确认存在可计入的新增代码行。也要确认临时修改已经提交并推送,扫描前没有脚本改写文件。

同时核对 SonarCloud 中 main 分支的分析是否成功且及时更新,项目 key 和源码路径布局是否与 PR 扫描一致。

3. 确认修改文件确实进入扫描范围

对于:

projectBaseDir: ${{ matrix.module }}/

当 matrix.module 为 rest_api 时,应检查源码目录相对于该基目录的位置,预期路径如下:

rest_api/rest_api_server
rest_api/optscale_console
rest_api/optscale_metrics
rest_api/google_calendar_client

这些路径是根据配置推导出来的,仓库结构尚未得到确认。如果这些目录实际位于仓库根目录或其他位置,就需要调整扫描基目录或源码配置。

可以临时在现有扫描参数中增加:

-Dsonar.verbose=true

检查完整日志中的实际基目录、配置文件路径、源码目录、索引文件和排除情况,并到云端 Code 页面确认被修改文件是否出现。仅检查属性文件的文字是否正确还不够。

题目中的配置明确排除了 tests、migrations 和 mock_data 等目录。如果用于验证的代码恰好放在这些位置,它不会进入当前源码分析范围。还应检查其他生效的排除设置及 SCM 忽略规则。分析范围配置说明

4. 分开处理 PR 与 push 事件

该 workflow 同时监听 pull_request 和 push,但扫描步骤始终传入 PR 参数:

sonar.pullrequest.key
sonar.pullrequest.branch
sonar.pullrequest.base

这些 GitHub 表达式在 push 事件中没有相同的 PR 上下文。保留显式参数时,应让它们只用于 PR 扫描,例如:

- name: SonarQube Scan PR
  if: github.event_name == 'pull_request'
  uses: SonarSource/sonarqube-scan-action@v7
  env:
    SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
  with:
    projectBaseDir: ${{ matrix.module }}/
    args: >-
      -Dsonar.pullrequest.key=${{ github.event.pull_request.number }}
      -Dsonar.pullrequest.branch=${{ github.head_ref }}
      -Dsonar.pullrequest.base=${{ github.base_ref }}

另为 main 的 push 配置不带上述 PR 参数的扫描,用于更新目标分支分析。这只修正了事件与参数的对应关系,不能据此断定它就是当前 PR 显示 0 行的原因。

5. 分别验证新增代码行和新增问题

即使新增代码行恢复正常,也不保证随意加入的“坏代码”一定产生 issue。应选择当前项目 Python Quality Profile 中已启用、触发条件明确的规则,在扫描范围内的普通源码文件中提交一个可复现修改。

按以下结果继续定位:

  • Git 有新增代码行,云端找不到对应文件:检查扫描路径、排除设置和项目映射。
  • 文件存在,但对应行未标记为新增:检查 Git 基线、PR 参数和当前查看的分析记录。
  • 新增行已识别,但没有 issue:检查规则是否启用、代码是否满足触发条件,以及是否存在问题忽略设置。
  • 云端结果正常,但 GitHub 没有反馈:检查仓库绑定和 PR decoration 配置。

还要确认界面上的指标确实是 New Lines,而不是 Lines to Cover 等其他指标。当前材料没有提供可核对的截图或完整扫描日志,因此不能进一步认定具体原因。

备注:内容仅供参考。