sonarqube-quality-gate-playbook

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

SonarQube Quality Gate Playbook

SonarQube Quality Gate 实施指南

Aplicar este flujo en iteraciones pequenas y verificables. Priorizar impacto real y bajo riesgo.
以小型、可验证的迭代方式应用此流程。优先处理实际影响大且风险低的内容。

Inputs requeridos

所需输入项

Definir estos inputs antes del primer ciclo:
  • SONAR_HOST_URL
    (ejemplo:
    http://127.0.0.1:9000
    )
  • SONAR_TOKEN
    con permisos de analisis
  • SONAR_PROJECT_KEY
    y opcional
    SONAR_PROJECT_NAME
  • SONAR_NEW_CODE_REFERENCE_BRANCH
    (default:
    main
    )
  • Rutas del monorepo:
    apps/backend
    ,
    apps/frontend
    ,
    packages/*
  • Comandos de test por app (backend/frontend) con coverage
  • Rutas de reportes
    lcov.info
    por app
  • Archivo Sonar (
    sonar-project.properties
    ) o parametros equivalentes en CI
  • Patron de exclusiones de coverage y de analisis
  • Umbrales del Quality Gate (coverage, bugs, vulns, smells, duplicacion)
  • Comando de build/pipeline que no se puede romper
在第一个循环开始前定义以下输入:
  • SONAR_HOST_URL
    (示例:
    http://127.0.0.1:9000
  • 具备分析权限的
    SONAR_TOKEN
  • SONAR_PROJECT_KEY
    ,可选
    SONAR_PROJECT_NAME
  • SONAR_NEW_CODE_REFERENCE_BRANCH
    (默认值:
    main
  • 单体仓库路径:
    apps/backend
    ,
    apps/frontend
    ,
    packages/*
  • 各应用(后端/前端)带覆盖率统计的测试命令
  • 各应用的报告路径
    lcov.info
  • Sonar配置文件(
    sonar-project.properties
    )或CI中等价的参数
  • 覆盖率和分析的排除规则
  • 质量门阈值(覆盖率、Bug、漏洞、代码异味、重复率)
  • 不可被破坏的构建/流水线命令

Estrategia de priorizacion

优先级策略

Seguir este orden de trabajo:
  1. New Code primero
  2. Nuevos Bugs y Vulnerabilities
  3. Security Hotspots en estado
    TO_REVIEW
  4. Coverage en modulos criticos y tocados por el PR
  5. Nuevos Code Smells (priorizar severidad alta)
  6. Duplicacion y deuda tecnica en zonas activas
  7. Deuda historica (solo si no afecta el objetivo del sprint)
按照以下顺序开展工作:
  1. 优先处理New Code
  2. 新出现的Bug和漏洞
  3. 状态为
    TO_REVIEW
    的安全热点
  4. 关键模块及PR涉及代码的覆盖率提升
  5. 新出现的代码异味(优先处理高严重级)
  6. 活跃代码区域的重复率和技术债务
  7. 历史债务(仅在不影响迭代目标时处理)

Heuristica de impacto

影响度启发式规则

Para cada issue o archivo, calcular prioridad de manera simple:
priorityScore = (isNewCode*100) + (isBugOrVuln*80) + (isHotspotToReview*70) + severityWeight + (criticalPath*20) + (coverageGap*10) - (estimatedEffort*5)
Donde
severityWeight
puede ser: blocker
40
, critical
30
, major
20
, minor
10
.
针对每个问题或文件,简单计算优先级:
priorityScore = (isNewCode*100) + (isBugOrVuln*80) + (isHotspotToReview*70) + severityWeight + (criticalPath*20) + (coverageGap*10) - (estimatedEffort*5)
其中
severityWeight
取值:blocker
40
,critical
30
,major
20
,minor
10

Regla anti inflado de coverage

覆盖率反膨胀规则

No aceptar tests que solo suben porcentaje sin validar comportamiento:
  • Todo test nuevo debe cubrir caso feliz, caso negativo y borde
  • Prohibido snapshot-only como unica asercion
  • Evitar tests triviales de codigo sin logica
  • Si el test no falla ante un bug real, no cuenta como cobertura de valor
不接受仅提升覆盖率百分比但未验证实际行为的测试:
  • 所有新测试必须覆盖正常场景、异常场景和边界场景
  • 禁止仅使用snapshot作为唯一断言
  • 避免针对无逻辑代码的琐碎测试
  • 如果测试在真实Bug出现时不会失败,则不视为有效覆盖率

Pipeline del skill (paso a paso)

流程步骤(分步执行)

Runbook de discrepancia de cobertura (caso reutilizable)

覆盖率差异处理手册(可复用场景)

Usar este runbook cuando SonarQube muestre cobertura mucho menor a la local.
当SonarQube显示的覆盖率远低于本地统计时,使用此手册。

Sintoma tipico

典型症状

  • Local (Jest/Vitest): cobertura alta (por ejemplo >90%)
  • SonarQube: cobertura sensiblemente menor (por ejemplo 40-60%)
  • 本地(Jest/Vitest):覆盖率高(例如>90%)
  • SonarQube:覆盖率明显偏低(例如40-60%)

Causas raiz frecuentes

常见根本原因

  1. Rutas
    SF:
    con backslashes (
    \\
    ) en
    lcov.info
    generadas en Windows.
  2. SonarQube ejecutando en Linux/containers sin poder mapear rutas con
    \\
    .
  3. Packages compartidos con cobertura baja (ejemplo
    packages/utils
    ) tirando abajo el global.
  1. Windows环境生成的
    lcov.info
    文件中,
    SF:
    路径使用反斜杠(
    \
  2. SonarQube在Linux/容器环境中运行,无法映射带
    \
    的路径
  3. 共享包的覆盖率低(例如
    packages/utils
    )拉低了整体覆盖率

Diagnostico rapido

快速诊断

  1. Revisar primeras entradas
    SF:
    del
    lcov.info
    de cada app/package.
  2. Verificar en logs de
    sonar-scanner
    si hay archivos de coverage no mapeados o ignorados.
  3. Comparar cobertura por modulo (backend/frontend/packages) para detectar outliers.
Comandos sugeridos:
powershell
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
Si aparecen rutas como
SF:src\\app.ts
, normalizar antes del scan.
  1. 查看每个应用/包的
    lcov.info
    文件中前几条
    SF:
    记录
  2. sonar-scanner
    日志中检查是否有覆盖率文件未映射或被忽略
  3. 对比各模块(后端/前端/包)的覆盖率,找出异常值
建议执行的命令:
powershell
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
的路径,需在扫描前进行标准化处理。

Remediacion recomendada

推荐修复方案

  1. Normalizar rutas a forward slash (
    /
    ) en todos los
    lcov.info
    antes de
    sonar-scanner
    .
  2. Re-ejecutar tests de coverage y scan.
  3. Subir cobertura del paquete/modulo de menor porcentaje para no sesgar el global.
Ejemplo portable (
scripts/fix-lcov-paths.js
):
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);
}
Guardrail CI (fallar si quedan backslashes):
bash
if grep -q 'SF:.*\\\\' apps/backend/coverage/lcov.info; then
  echo "ERROR: Backslashes encontrados en lcov.info"
  exit 1
fi
  1. 在执行
    sonar-scanner
    前,将所有
    lcov.info
    文件中的路径统一转换为正斜杠(
    /
  2. 重新执行带覆盖率统计的测试和扫描
  3. 提升覆盖率最低的包/模块的覆盖率,避免拉低整体水平
可移植示例(
scripts/fix-lcov-paths.js
):
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防护措施(若存在反斜杠则失败):
bash
if grep -q 'SF:.*\\\\' apps/backend/coverage/lcov.info; then
  echo "ERROR: Backslashes encontrados en lcov.info"
  exit 1
fi

Paso 1: Detectar gap actual

步骤1:检测当前差距

  1. Ejecutar tests con coverage en backend/frontend/packages relevantes
  2. Ejecutar analisis SonarQube
  3. Levantar metricas e issues nuevos para priorizar
Comandos genericos:
powershell
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:"
  1. 对相关的后端/前端/包执行带覆盖率统计的测试
  2. 执行SonarQube分析
  3. 提取指标和新出现的问题以确定优先级
通用命令:
powershell
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:"

Paso 2: Generar o actualizar config Sonar

步骤2:生成或更新Sonar配置

Crear o actualizar
sonar-project.properties
en raiz con rutas reales del monorepo.
在根目录创建或更新
sonar-project.properties
文件,填写单体仓库的真实路径。

Paso 3: Asegurar lectura de coverage real

步骤3:确保覆盖率数据被正确读取

  • Verificar existencia de
    lcov.info
  • Configurar
    sonar.javascript.lcov.reportPaths
    con todas las rutas
  • Validar en logs del scanner que no haya warnings de coverage faltante
  • Verificar que lineas
    SF:
    usen
    /
    y no
    \\
  • Si hay entorno mixto Windows/Linux, correr normalizacion de paths antes del scan
  • Confirmar que packages compartidos relevantes tambien reporten coverage (no solo apps)
  • 确认
    lcov.info
    文件存在
  • 配置
    sonar.javascript.lcov.reportPaths
    参数,包含所有相关路径
  • 在扫描器日志中验证是否存在覆盖率缺失的警告
  • 确认
    SF:
    行使用
    /
    而非
    \
  • 若存在Windows/Linux混合环境,需在扫描前执行路径标准化
  • 确认相关共享包也上报了覆盖率数据(而非仅应用)

Paso 4: Ejecutar tests de forma consistente

步骤4:保持测试执行的一致性

  • Usar los mismos comandos y flags en local y CI
  • Publicar artefactos de coverage
  • No mezclar runners/flags entre entornos
  • 在本地和CI环境中使用相同的命令和参数
  • 上传覆盖率产物
  • 不同环境间不要混用运行器/参数

Paso 5: Iterar por lotes pequenos

步骤5:分小批次迭代

  • Lote A: Bugs/Vulns/Hotspots nuevos
  • Lote B: Coverage en New Code
  • Lote C: Code Smells nuevos
  • Lote D: Duplicacion/deuda en areas tocadas
  • 批次A:新出现的Bug/漏洞/安全热点
  • 批次B:New Code的覆盖率提升
  • 批次C:新出现的代码异味
  • 批次D:代码修改区域的重复率/债务处理

Generacion de tests guiada (backend y frontend)

指导性测试生成(后端和前端)

1) Identificar archivos sin cobertura

1) 识别未覆盖的文件

  • Fuente principal: SonarQube (archivos con uncovered lines en New Code)
  • Fuente secundaria:
    lcov.info
    + archivos modificados del PR
powershell
git diff --name-only origin/main...HEAD | Where-Object { $_ -match '\.(ts|tsx)$' }
  • 主要来源:SonarQube(New Code中存在未覆盖行的文件)
  • 次要来源:
    lcov.info
    + PR中修改的文件
powershell
git diff --name-only origin/main...HEAD | Where-Object { $_ -match '\.(ts|tsx)$' }

2) Elegir tipo de test correcto

2) 选择正确的测试类型

  • Unit: logica pura y funciones con pocas dependencias
  • Integration (backend): controladores + servicios + repositorios mockeados
  • Component (frontend): interacciones, estados y accesibilidad
  • E2E: solo flujos criticos, no como reemplazo de unit/component
  • 单元测试:纯逻辑和依赖较少的函数
  • 集成测试(后端):控制器+服务+模拟的仓库
  • 组件测试(前端):交互、状态和可访问性
  • E2E测试:仅针对关键流程,不可替代单元/组件测试

3) Mocking strategy

3) 模拟策略

  • DB: fake repo o base de test aislada
  • HTTP externo: mocks deterministas (sin pegar a servicios reales)
  • Tiempo/random: controlar reloj y valores aleatorios
  • Evitar mocks excesivos que oculten defectos reales
  • 数据库:使用模拟仓库或独立测试数据库
  • 外部HTTP服务:使用确定性模拟(不调用真实服务)
  • 时间/随机值:控制时钟和随机值
  • 避免过度模拟导致隐藏真实缺陷

4) Criterios minimos de calidad del test

4) 测试质量最低标准

  • Estructura Arrange/Act/Assert clara
  • Aserciones semanticas del comportamiento esperado
  • Caso feliz + negativo + borde obligatorios
  • Test estable y sin flakiness
  • Nombre orientado a comportamiento
  • 清晰的Arrange/Act/Assert结构
  • 针对预期行为的语义化断言
  • 必须覆盖正常、异常和边界场景
  • 测试稳定且无波动
  • 基于行为的命名方式

5) Naming y estructura

5) 命名和结构

  • Backend:
    *.spec.ts
  • Frontend:
    *.test.tsx
  • Patron recomendado:
    • should <resultado> when <condicion>
    • returns <error> when <input invalido>
  • 后端:
    *.spec.ts
  • 前端:
    *.test.tsx
  • 推荐命名模式:
    • should <结果> when <条件>
    • returns <error> when <无效输入>

Remediacion de Code Smells, Bugs y Security

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

Aplicar fixes quirurgicos, sin cambios de estilo masivos.
Checklist por categoria:
  • Complejidad: extraer funciones, usar early return, bajar anidacion
  • Duplicacion: consolidar utilidades y evitar copy-paste
  • Nullability: guards explicitos y defaults seguros
  • Manejo de errores: evitar
    catch
    vacio, propagar con contexto
  • Leaks/resources: cerrar timers, subscripciones, conexiones
  • Regex/DoS: evitar patrones catastróficos y limitar input
  • Dependencias inseguras: actualizar librerias vulnerables
  • Sanitizacion: validar y sanitizar input, evitar XSS/inyeccion
  • Security Hotspots: revisar y documentar resolucion por cada item
采用精准修复,避免大规模风格变更。
各分类检查清单:
  • 复杂度:提取函数、提前返回、减少嵌套
  • 重复代码:整合工具类,避免复制粘贴
  • 空值处理:显式守卫和安全默认值
  • 错误处理:避免空
    catch
    ,带上下文传播错误
  • 资源泄漏:关闭定时器、订阅、连接
  • 正则表达式/DoS:避免灾难性模式,限制输入
  • 不安全依赖:更新存在漏洞的库
  • 输入处理:验证和清洗输入,避免XSS/注入
  • 安全热点:逐一审核并记录处理结果

Reglas de exclusion y trade-offs

排除规则与权衡

Exclusiones aceptables (con justificativo):
  • **/index.ts
    sin logica
  • DTOs o types simples sin ramas
  • codigo generado (
    **/generated/**
    )
  • bootstrap minimo sin logica de negocio
Exclusiones no aceptables:
  • servicios/casos de uso/controladores con logica
  • hooks y validadores con ramas
  • codigo de autenticacion/autorizacion
  • excluir para pasar el porcentaje sin mejorar calidad
Regla: cada exclusion debe registrar el motivo tecnico.
可接受的排除项(需附理由):
  • 无逻辑的
    **/index.ts
  • 无分支的简单DTO或类型
  • 生成代码(
    **/generated/**
  • 无业务逻辑的最小启动代码
不可接受的排除项:
  • 带业务逻辑的服务/用例/控制器
  • 带分支的钩子和验证器
  • 认证/授权代码
  • 为了达标而排除代码却未提升质量
规则:每个排除项必须记录技术原因

Definicion de Done y metricas

完成标准与指标

Declarar ciclo completado solo con evidencia:
  • Quality Gate en estado
    PASSED
  • new_coverage >= 80
  • new_bugs = 0
  • new_vulnerabilities = 0
  • new_code_smells = 0
  • new_security_hotspots_reviewed = 100%
  • Duplicacion y deuda dentro de umbral del gate
  • Build y pipelines verdes
Evidencia minima a adjuntar:
  1. salida de
    sonar-scanner
    con
    sonar.qualitygate.wait=true
  2. salida de APIs de metricas/issues/hotspots
  3. cobertura por carpeta (backend/frontend/packages)
  4. resumen de issues resueltos (antes/despues)
仅在具备以下证据时,方可声明循环完成:
  • 质量门状态为
    PASSED
  • new_coverage >= 80
  • new_bugs = 0
  • new_vulnerabilities = 0
  • new_code_smells = 0
  • new_security_hotspots_reviewed = 100%
  • 重复率和债务在质量门阈值内
  • 构建和流水线正常
需附加的最低证据:
  1. sonar.qualitygate.wait=true
    参数的
    sonar-scanner
    输出
  2. 指标/问题/热点的API接口输出
  3. 各目录(后端/前端/包)的覆盖率
  4. 问题修复前后的汇总

Snippets de configuracion

配置代码片段

sonar-project.properties

sonar-project.properties

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
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 (ejemplo)

Jest后端配置示例

ts
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;
ts
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 (ejemplo)

Vitest前端配置示例

ts
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']
    }
  }
});
ts
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 (ejemplo)

GitHub Actions配置示例

yaml
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
yaml
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 (ejemplo)

GitLab CI配置示例

yaml
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
yaml
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 del skill

快速执行摘要

Usar este resumen rapido en ejecucion:
  1. correr tests con coverage
  2. correr sonar-scanner con wait del gate
  3. priorizar New Code -> Bugs/Vulns -> Hotspots -> Coverage -> Smells
  4. iterar en lotes pequenos y adjuntar evidencia
Comandos base:
  • 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
在执行时可使用以下快速摘要:
  1. 执行带覆盖率统计的测试
  2. 执行带质量门等待的sonar-scanner
  3. 优先级顺序:New Code -> Bug/漏洞 -> 安全热点 -> 覆盖率 -> 代码异味
  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

Checklist de PR

PR检查清单

  • No hay nuevos Bugs ni Vulnerabilities
  • No hay nuevos Code Smells
  • New Coverage >= 80%
  • Hotspots nuevos revisados
  • Sin exclusiones injustificadas
  • Tests con caso feliz, negativo y borde
  • Build y CI en verde
  • Evidencia de Sonar adjunta
  • lcov.info
    sin backslashes en lineas
    SF:
  • Packages compartidos sin brecha fuerte de coverage
  • 无新出现的Bug或漏洞
  • 无新出现的代码异味
  • New Coverage >= 80%
  • 新的安全热点已审核
  • 无不正当排除项
  • 测试覆盖正常、异常和边界场景
  • 构建和CI正常
  • 已附加Sonar证据
  • lcov.info
    文件的
    SF:
    行无反斜杠
  • 共享包无明显覆盖率差距

Plantillas de comandos listas para pegar

可直接复制的命令模板

powershell
$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:"
powershell
$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:"

Defaults a ajustar si hay incertidumbre

不确定时的默认配置

  • branch de New Code:
    main
  • umbral New Coverage:
    80
  • duplicacion maxima new code:
    3%
  • coverage exclusions: solo archivos sin logica
  • estrategia de lotes: 1 PR por categoria critica
  • New Code基准分支:
    main
  • New Coverage阈值:
    80
  • New Code最大重复率:
    3%
  • 覆盖率排除项:仅无逻辑的文件
  • 批次策略:每个关键分类对应一个PR