mcpField
S
sonarqube-quality-gate-playbook

sonarqube-quality-gate-playbook

github.com/agustinalbonico测试与质量052 次安装7 周前更新
代码仓库

关于 sonarqube-quality-gate-playbook

该技能为使用 SonarQube 的团队提供质量门禁处理手册,适用于管理单体仓库中的测试覆盖率、缺陷和安全问题。它强调按影响分批处理,并通过分析结果和覆盖率证据验证改进。

主要功能

  1. 01按优先级处理新增代码问题
  2. 02诊断并修复 lcov 路径映射
  3. 03制定测试与覆盖率策略
  4. 04分批修复缺陷、安全问题和代码异味
  5. 05用质量门禁及证据确认完成

适用场景

  1. 01排查 SonarQube 覆盖率低于本地的问题
  2. 02为后端和前端补充有行为断言的测试
  3. 03在 CI 中推进质量门禁并汇总结果

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/agustinalbonico/ai-customizations --skill sonarqube-quality-gate-playbook

安装后在 Claude Code 中输入/sonarqube-quality-gate-playbook确认已加载。

详细介绍

SonarQube 质量门禁操作手册

通过小步、可验证的迭代执行此流程。优先考虑实际影响和低风险。

所需输入

在第一个周期开始前定义以下输入:

  • SONAR_HOST_URL(例如:http://127.0.0.1:9000)
  • 具有分析权限的 SONAR_TOKEN
  • SONAR_PROJECT_KEY 和可选的 SONAR_PROJECT_NAME
  • SONAR_NEW_CODE_REFERENCE_BRANCH(默认值:main)
  • Monorepo 路径:apps/backend、apps/frontend、packages/*
  • 各应用(backend/frontend)的测试命令及覆盖率
  • 各应用的 lcov.info 报告路径
  • Sonar 配置文件(sonar-project.properties)或 CI 中的等效参数
  • 覆盖率排除规则和分析排除规则
  • Quality Gate 阈值(覆盖率、漏洞、缺陷、代码异味、重复代码)
  • 不能破坏的构建/流水线命令

优先级策略

按以下顺序开展工作:

  1. 优先处理新增代码
  2. 新增缺陷和漏洞
  3. 状态为 TO_REVIEW 的 Security Hotspots
  4. 关键模块和 PR 涉及模块的覆盖率
  5. 新增代码异味(优先处理严重程度高的项)
  6. 活跃区域的重复代码和技术债务
  7. 历史债务(仅在不影响当前迭代目标时处理)
影响评估启发式

为每个问题或文件简单计算优先级:

priorityScore = (isNewCode*100) + (isBugOrVuln*80) + (isHotspotToReview*70) + severityWeight + (criticalPath*20) + (coverageGap*10) - (estimatedEffort*5)

其中,severityWeight 可以是:blocker 40、critical 30、major 20、minor 10。

防止虚增覆盖率规则

不接受只提高百分比、不验证行为的测试:

  • 每个新增测试都必须覆盖正常情况、负面情况和边界情况
  • 禁止只使用 snapshot 作为唯一断言
  • 避免为没有逻辑的代码编写无意义的测试
  • 如果测试无法在真实缺陷出现时失败,就不算有价值的覆盖率

技能流水线(逐步执行)

覆盖率差异操作手册(可复用案例)

当 SonarQube 显示的覆盖率远低于本地结果时,使用此操作手册。

典型症状
  • 本地(Jest/Vitest):覆盖率高(例如 >90%)
  • SonarQube:覆盖率明显较低(例如 40-60%)
常见根因
  1. 在 Windows 上生成的 lcov.info 中,SF: 路径包含反斜杠(\\)。
  2. SonarQube 在 Linux/容器中运行,无法映射包含 \\ 的路径。
  3. 共享包覆盖率较低(例如 packages/utils),拉低了全局覆盖率。
快速诊断
  1. 检查各应用/包的 lcov.info 中开头的 SF: 条目。
  2. 检查 sonar-scanner 日志,确认是否存在无法映射或被忽略的覆盖率文件。
  3. 比较各模块(backend/frontend/packages)的覆盖率,找出异常项。

建议命令:

Get-Content "apps\\backend\\coverage\\lcov.info" | Select-String "^SF:" | Select-Object -First 10
Get-Content "apps\\frontend\\coverage\\lcov.info" | Select-String "^SF:" | Select-Object -First 10

如果出现 SF:src\\app.ts 这样的路径,请在扫描前进行规范化。

建议的修复措施
  1. 在运行 sonar-scanner 前,将所有 lcov.info 中的路径规范化为正斜杠(/)。
  2. 重新运行覆盖率测试和扫描。
  3. 提高覆盖率最低的包/模块的覆盖率,避免全局数据产生偏差。

可移植示例(scripts/fix-lcov-paths.js):

const fs = require('node:fs');

const reports = [
  'apps/backend/coverage/lcov.info',
  'apps/frontend/coverage/lcov.info',
  'packages/utils/coverage/lcov.info'
];

for (const reportPath of reports) {
  if (!fs.existsSync(reportPath)) continue;
  const content = fs.readFileSync(reportPath, 'utf8');
  const normalized = content.replace(/\\\\/g, '/');
  fs.writeFileSync(reportPath, normalized);
}

CI 防护检查(如果仍有反斜杠则失败):

if grep -q 'SF:.*\\\\' apps/backend/coverage/lcov.info; then
  echo "ERROR: Backslashes encontrados en lcov.info"
  exit 1
fi
步骤 1:检测当前差距
  1. 对 backend/frontend/相关 packages 运行覆盖率测试
  2. 运行 SonarQube 分析
  3. 获取指标和新增问题,以确定优先级

通用命令:

bun run --cwd apps/backend test -- --coverage
bun run --cwd apps/frontend test -- --coverage

sonar-scanner `
  -Dsonar.host.url=$env:SONAR_HOST_URL `
  -Dsonar.token=$env:SONAR_TOKEN `
  -Dsonar.projectKey=$env:SONAR_PROJECT_KEY `
  -Dsonar.qualitygate.wait=true

curl -4 -s "$env:SONAR_HOST_URL/api/measures/component?component=$env:SONAR_PROJECT_KEY&metricKeys=coverage,new_coverage,bugs,new_bugs,vulnerabilities,new_vulnerabilities,code_smells,new_code_smells,duplicated_lines_density,new_duplicated_lines_density" -u "$env:SONAR_TOKEN:"

curl -4 -s "$env:SONAR_HOST_URL/api/issues/search?componentKeys=$env:SONAR_PROJECT_KEY&resolved=false&inNewCodePeriod=true&types=BUG,VULNERABILITY,CODE_SMELL&ps=500" -u "$env:SONAR_TOKEN:"

curl -4 -s "$env:SONAR_HOST_URL/api/hotspots/search?projectKey=$env:SONAR_PROJECT_KEY&status=TO_REVIEW&ps=500" -u "$env:SONAR_TOKEN:"
步骤 2:生成或更新 Sonar 配置

在根目录创建或更新 sonar-project.properties,并填写 Monorepo 的实际路径。

步骤 3:确保读取真实覆盖率
  • 确认 lcov.info 文件存在
  • 使用所有路径配置 sonar.javascript.lcov.reportPaths
  • 检查扫描器日志,确认没有缺少覆盖率报告的警告
  • 确认 SF: 行使用 /,而不是 \\
  • 如果环境混合使用 Windows/Linux,请在扫描前运行路径规范化
  • 确认相关共享包也报告了覆盖率,而不只是应用
步骤 4:以一致的方式运行测试
  • 在本地和 CI 中使用相同的命令和标志
  • 发布覆盖率制品
  • 不要在不同环境中混用运行器和标志
步骤 5:分批迭代
  • 批次 A:新增 Bug/漏洞/安全热点
  • 批次 B:新代码覆盖率
  • 批次 C:新增代码异味
  • 批次 D:已修改区域中的重复代码/技术债

后端和前端的引导式测试生成

1)识别未覆盖的文件

  • 主要来源:SonarQube(新代码中存在未覆盖行的文件)
  • 次要来源:lcov.info + PR 中已修改的文件
git diff --name-only origin/main...HEAD | Where-Object { $_ -match '\.(ts|tsx)$' }

2)选择正确的测试类型

  • Unit:纯逻辑和依赖较少的函数
  • Integration(后端):控制器 + 服务 + 模拟仓库
  • Component(前端):交互、状态和无障碍
  • E2E:仅用于关键流程,不要用来替代 unit/component 测试

3)Mock 策略

  • DB:模拟仓库或隔离的测试数据库
  • 外部 HTTP:使用确定性模拟(不调用真实服务)
  • 时间/随机数:控制时钟和随机值
  • 避免过度使用模拟,以免掩盖真实缺陷

4)测试的最低质量标准

  • Arrange/Act/Assert 结构清晰
  • 使用有意义的断言检查预期行为
  • 必须包含正常、负面和边界用例
  • 测试稳定,不会间歇性失败
  • 名称应体现行为

5)命名和结构

  • 后端:*.spec.ts
  • 前端:*.test.tsx
  • 推荐模式:
    • should <结果> when <条件>
    • returns <错误> when <无效输入>

修复代码异味、Bug 和安全问题

采用针对性修复,避免大规模风格调整。

分类检查清单:

  • 复杂度:提取函数、使用 early return、减少嵌套
  • 重复代码:整合实用工具,避免复制粘贴
  • 可空性:添加显式 guard 和安全默认值
  • 错误处理:避免空的 catch,在传播错误时提供上下文
  • 泄漏/资源:关闭计时器、订阅和连接
  • 正则表达式/DoS:避免灾难性模式并限制输入
  • 不安全依赖:更新存在漏洞的库
  • 清理:验证并清理输入,避免 XSS/注入
  • Security Hotspots:逐项审查并记录解决方式

排除规则和权衡

可接受的排除项(需说明理由):

  • 没有逻辑的 **/index.ts
  • 没有分支的简单 DTO 或 types
  • 生成的代码(**/generated/**)
  • 不包含业务逻辑的最小化启动代码

不可接受的排除项:

  • 包含逻辑的服务/用例/控制器
  • 包含分支的 hooks 和验证器
  • 认证/授权代码
  • 为达到百分比而排除代码,却不提升质量

规则:每项排除都必须记录技术原因。

Done 定义和指标

只有具备证据时,才能声明周期已完成:

  • Quality Gate 状态为 PASSED
  • new_coverage >= 80
  • new_bugs = 0
  • new_vulnerabilities = 0
  • new_code_smells = 0
  • new_security_hotspots_reviewed = 100%
  • 重复代码和技术债处于 gate 阈值内
  • 构建和流水线均通过

必须附上的最低限度证据:

  1. 带有 sonar.qualitygate.wait=true 的 sonar-scanner 输出
  2. 指标/问题/安全热点 API 的输出
  3. 按文件夹划分的覆盖率(backend/frontend/packages)
  4. 已解决问题摘要(修复前/后)

配置代码片段

sonar-project.properties
sonar.projectKey=my-org_my-monorepo
sonar.projectName=my-monorepo
sonar.sourceEncoding=UTF-8

sonar.sources=apps/backend/src,apps/frontend/src,packages
sonar.tests=apps/backend,apps/frontend,packages
sonar.test.inclusions=**/*.spec.ts,**/*.test.ts,**/*.test.tsx,**/*.spec.tsx

sonar.javascript.lcov.reportPaths=apps/backend/coverage/lcov.info,apps/frontend/coverage/lcov.info
sonar.newCode.referenceBranch=main

sonar.exclusions=**/dist/**,**/build/**,**/node_modules/**,**/*.d.ts
sonar.coverage.exclusions=**/index.ts,**/*.dto.ts,**/generated/**,**/*.stories.tsx
Jest backend(示例)
import type { Config } from 'jest';

const config: Config = {
  preset: 'ts-jest',
  testEnvironment: 'node',
  collectCoverage: true,
  coverageDirectory: 'coverage',
  coverageReporters: ['text', 'lcov', 'html'],
  collectCoverageFrom: [
    'src/**/*.{ts,tsx}',
    '!src/**/*.dto.ts',
    '!src/**/index.ts',
    '!src/**/generated/**'
  ]
};

export default config;
Vitest frontend(示例)
import { defineConfig } from 'vitest/config';

export default defineConfig({
  test: {
    environment: 'jsdom',
    coverage: {
      provider: 'v8',
      reporter: ['text', 'lcov', 'html'],
      reportsDirectory: './coverage',
      include: ['src/**/*.{ts,tsx}'],
      exclude: ['src/**/*.stories.tsx', 'src/**/index.ts']
    }
  }
});
GitHub Actions(示例)
name: quality-gate

on:
  pull_request:
  push:
    branches: [main]

jobs:
  quality:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - uses: oven-sh/setup-bun@v2
      - run: bun install --frozen-lockfile

      - name: Backend tests with coverage
        run: bun run --cwd apps/backend test -- --coverage

      - name: Frontend tests with coverage
        run: bun run --cwd apps/frontend test -- --coverage

      - name: Normalize lcov paths (Windows/Linux safe)
        run: node scripts/fix-lcov-paths.js

      - name: Validate lcov path format
        run: |
          if grep -q 'SF:.*\\\\' apps/backend/coverage/lcov.info; then
            echo "ERROR: Backslashes encontrados en backend lcov.info"
            exit 1
          fi

      - name: Build
        run: bun run build

      - name: SonarQube Scan
        env:
          SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
        run: |
          sonar-scanner \
            -Dsonar.host.url=$SONAR_HOST_URL \
            -Dsonar.token=$SONAR_TOKEN \
            -Dsonar.qualitygate.wait=true
GitLab CI(示例)
stages:
  - test
  - quality

variables:
  GIT_DEPTH: "0"

test_and_build:
  stage: test
  image: oven/bun:1
  script:
    - bun install --frozen-lockfile
    - bun run --cwd apps/backend test -- --coverage
    - bun run --cwd apps/frontend test -- --coverage
    - node scripts/fix-lcov-paths.js
    - bun run build
  artifacts:
    when: always
    paths:
      - apps/backend/coverage/
      - apps/frontend/coverage/

sonarqube:
  stage: quality
  image: sonarsource/sonar-scanner-cli:latest
  dependencies:
    - test_and_build
  script:
    - sonar-scanner -Dsonar.host.url=$SONAR_HOST_URL -Dsonar.token=$SONAR_TOKEN -Dsonar.qualitygate.wait=true
  allow_failure: false

技能 README

执行时使用这份快速摘要:

  1. 运行带 coverage 的测试
  2. 运行 sonar-scanner 并等待质量门禁结果
  3. 优先级:New Code -> Bugs/Vulns -> Hotspots -> Coverage -> Smells
  4. 分小批次迭代并附上证据

基本命令:

  • bun run --cwd apps/backend test -- --coverage
  • bun run --cwd apps/frontend test -- --coverage
  • sonar-scanner -Dsonar.host.url=$SONAR_HOST_URL -Dsonar.token=$SONAR_TOKEN -Dsonar.qualitygate.wait=true

PR 检查清单

  • 没有新增 Bugs 或 Vulnerabilities
  • 没有新增 Code Smells
  • New Coverage >= 80%
  • 已审查新增 Hotspots
  • 没有缺乏正当理由的排除项
  • 测试涵盖成功、失败和边界情况
  • Build 和 CI 均通过
  • 已附上 Sonar 证据
  • lcov.info 中 SF: 行不含反斜杠
  • 共享 Packages 不存在明显的 coverage 缺口

可直接粘贴的命令模板

$env:SONAR_HOST_URL="http://127.0.0.1:9000"
$env:SONAR_TOKEN="<token>"
$env:SONAR_PROJECT_KEY="<project-key>"

bun run --cwd apps/backend test -- --coverage
bun run --cwd apps/frontend test -- --coverage
bun run build

sonar-scanner `
  -Dsonar.host.url=$env:SONAR_HOST_URL `
  -Dsonar.token=$env:SONAR_TOKEN `
  -Dsonar.projectKey=$env:SONAR_PROJECT_KEY `
  -Dsonar.qualitygate.wait=true

curl -4 -s "$env:SONAR_HOST_URL/api/measures/component?component=$env:SONAR_PROJECT_KEY&metricKeys=new_coverage,new_bugs,new_vulnerabilities,new_code_smells,new_duplicated_lines_density" -u "$env:SONAR_TOKEN:"

不确定时可调整的默认值

  • New Code 分支:main
  • New Coverage 阈值:80
  • new code 最大重复率:3%
  • coverage exclusions:仅限不含逻辑的文件
  • 批次策略:每个关键类别一个 PR

评论

支持 Markdown