sonarqube-quality-gate-playbook
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSonarQube 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:
- (ejemplo:
SONAR_HOST_URL)http://127.0.0.1:9000 - con permisos de analisis
SONAR_TOKEN - y opcional
SONAR_PROJECT_KEYSONAR_PROJECT_NAME - (default:
SONAR_NEW_CODE_REFERENCE_BRANCH)main - Rutas del monorepo: ,
apps/backend,apps/frontendpackages/* - Comandos de test por app (backend/frontend) con coverage
- Rutas de reportes por app
lcov.info - Archivo Sonar () o parametros equivalentes en CI
sonar-project.properties - 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_KEYSONAR_PROJECT_NAME - (默认值:
SONAR_NEW_CODE_REFERENCE_BRANCH)main - 单体仓库路径:,
apps/backend,apps/frontendpackages/* - 各应用(后端/前端)带覆盖率统计的测试命令
- 各应用的报告路径
lcov.info - Sonar配置文件()或CI中等价的参数
sonar-project.properties - 覆盖率和分析的排除规则
- 质量门阈值(覆盖率、Bug、漏洞、代码异味、重复率)
- 不可被破坏的构建/流水线命令
Estrategia de priorizacion
优先级策略
Seguir este orden de trabajo:
- New Code primero
- Nuevos Bugs y Vulnerabilities
- Security Hotspots en estado
TO_REVIEW - Coverage en modulos criticos y tocados por el PR
- Nuevos Code Smells (priorizar severidad alta)
- Duplicacion y deuda tecnica en zonas activas
- Deuda historica (solo si no afecta el objetivo del sprint)
按照以下顺序开展工作:
- 优先处理New Code
- 新出现的Bug和漏洞
- 状态为的安全热点
TO_REVIEW - 关键模块及PR涉及代码的覆盖率提升
- 新出现的代码异味(优先处理高严重级)
- 活跃代码区域的重复率和技术债务
- 历史债务(仅在不影响迭代目标时处理)
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 puede ser: blocker , critical , major , minor .
severityWeight40302010针对每个问题或文件,简单计算优先级:
priorityScore = (isNewCode*100) + (isBugOrVuln*80) + (isHotspotToReview*70) + severityWeight + (criticalPath*20) + (coverageGap*10) - (estimatedEffort*5)其中取值:blocker ,critical ,major ,minor 。
severityWeight40302010Regla 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
常见根本原因
- Rutas con backslashes (
SF:) en\\generadas en Windows.lcov.info - SonarQube ejecutando en Linux/containers sin poder mapear rutas con .
\\ - Packages compartidos con cobertura baja (ejemplo ) tirando abajo el global.
packages/utils
- Windows环境生成的文件中,
lcov.info路径使用反斜杠(SF:)\ - SonarQube在Linux/容器环境中运行,无法映射带的路径
\ - 共享包的覆盖率低(例如)拉低了整体覆盖率
packages/utils
Diagnostico rapido
快速诊断
- Revisar primeras entradas del
SF:de cada app/package.lcov.info - Verificar en logs de si hay archivos de coverage no mapeados o ignorados.
sonar-scanner - 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 10Si aparecen rutas como , normalizar antes del scan.
SF:src\\app.ts- 查看每个应用/包的文件中前几条
lcov.info记录SF: - 在日志中检查是否有覆盖率文件未映射或被忽略
sonar-scanner - 对比各模块(后端/前端/包)的覆盖率,找出异常值
建议执行的命令:
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.tsRemediacion recomendada
推荐修复方案
- Normalizar rutas a forward slash () en todos los
/antes delcov.info.sonar-scanner - Re-ejecutar tests de coverage y scan.
- Subir cobertura del paquete/modulo de menor porcentaje para no sesgar el global.
Ejemplo portable ():
scripts/fix-lcov-paths.jsjs
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- 在执行前,将所有
sonar-scanner文件中的路径统一转换为正斜杠(lcov.info)/ - 重新执行带覆盖率统计的测试和扫描
- 提升覆盖率最低的包/模块的覆盖率,避免拉低整体水平
可移植示例():
scripts/fix-lcov-paths.jsjs
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
fiPaso 1: Detectar gap actual
步骤1:检测当前差距
- Ejecutar tests con coverage en backend/frontend/packages relevantes
- Ejecutar analisis SonarQube
- 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:"- 对相关的后端/前端/包执行带覆盖率统计的测试
- 执行SonarQube分析
- 提取指标和新出现的问题以确定优先级
通用命令:
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 en raiz con rutas reales del monorepo.
sonar-project.properties在根目录创建或更新文件,填写单体仓库的真实路径。
sonar-project.propertiesPaso 3: Asegurar lectura de coverage real
步骤3:确保覆盖率数据被正确读取
- Verificar existencia de
lcov.info - Configurar con todas las rutas
sonar.javascript.lcov.reportPaths - Validar en logs del scanner que no haya warnings de coverage faltante
- Verificar que lineas usen
SF: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: + archivos modificados del PR
lcov.info
powershell
git diff --name-only origin/main...HEAD | Where-Object { $_ -match '\.(ts|tsx)$' }- 主要来源:SonarQube(New Code中存在未覆盖行的文件)
- 次要来源:+ PR中修改的文件
lcov.info
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 vacio, propagar con contexto
catch - 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):
- sin logica
**/index.ts - 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 >= 80new_bugs = 0new_vulnerabilities = 0new_code_smells = 0new_security_hotspots_reviewed = 100%- Duplicacion y deuda dentro de umbral del gate
- Build y pipelines verdes
Evidencia minima a adjuntar:
- salida de con
sonar-scannersonar.qualitygate.wait=true - salida de APIs de metricas/issues/hotspots
- cobertura por carpeta (backend/frontend/packages)
- resumen de issues resueltos (antes/despues)
仅在具备以下证据时,方可声明循环完成:
- 质量门状态为
PASSED new_coverage >= 80new_bugs = 0new_vulnerabilities = 0new_code_smells = 0new_security_hotspots_reviewed = 100%- 重复率和债务在质量门阈值内
- 构建和流水线正常
需附加的最低证据:
- 带参数的
sonar.qualitygate.wait=true输出sonar-scanner - 指标/问题/热点的API接口输出
- 各目录(后端/前端/包)的覆盖率
- 问题修复前后的汇总
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.tsxproperties
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.tsxJest 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=trueyaml
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=trueGitLab 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: falseyaml
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: falseREADME del skill
快速执行摘要
Usar este resumen rapido en ejecucion:
- correr tests con coverage
- correr sonar-scanner con wait del gate
- priorizar New Code -> Bugs/Vulns -> Hotspots -> Coverage -> Smells
- iterar en lotes pequenos y adjuntar evidencia
Comandos base:
bun run --cwd apps/backend test -- --coveragebun run --cwd apps/frontend test -- --coveragesonar-scanner -Dsonar.host.url=$SONAR_HOST_URL -Dsonar.token=$SONAR_TOKEN -Dsonar.qualitygate.wait=true
在执行时可使用以下快速摘要:
- 执行带覆盖率统计的测试
- 执行带质量门等待的sonar-scanner
- 优先级顺序:New Code -> Bug/漏洞 -> 安全热点 -> 覆盖率 -> 代码异味
- 分小批次迭代并附加证据
基础命令:
bun run --cwd apps/backend test -- --coveragebun run --cwd apps/frontend test -- --coveragesonar-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
- sin backslashes en lineas
lcov.infoSF: - 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