jenkins_get_coverage_report
Retrieve code coverage reports from Jenkins builds to analyze test effectiveness and identify untested code areas for specific applications, packages, or classes.
Instructions
Obtener reporte de cobertura de código de un build
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| app | Yes | Nombre de la aplicación | |
| buildNumber | Yes | Número del build | |
| packageName | No | Nombre del paquete específico | |
| className | No | Nombre de la clase específica | |
| branch | No | Rama de Git (por defecto: main) |
Implementation Reference
- index.ts:253-303 (registration)Registration of the 'jenkins_get_coverage_report' MCP tool, including input schema (Zod), description, and the handler function that delegates to JenkinsService.getCoverageReport and formats the output.server.tool( "jenkins_get_coverage_report", "Obtener reporte de cobertura de código de un build", { app: z.string().describe("Nombre de la aplicación"), buildNumber: z.number().describe("Número del build"), packageName: z.string().optional().describe("Nombre del paquete específico"), className: z.string().optional().describe("Nombre de la clase específica"), branch: z.string().optional().describe("Rama de Git (por defecto: main)") }, async (args) => { try { const result = await getJenkinsService().getCoverageReport( args.app, args.buildNumber, args.packageName, args.className, args.branch || 'main' ); let coverageText: string; if ('instructionCoverage' in result) { // Es un CoverageReport (backend) coverageText = `📊 **Reporte de Cobertura - Build #${args.buildNumber}**\n\n` + `**Instrucciones:** ${result.instructionCoverage?.percentage || 0}% (${result.instructionCoverage?.covered || 0}/${result.instructionCoverage?.total || 0})\n` + `**Ramas:** ${result.branchCoverage?.percentage || 0}% (${result.branchCoverage?.covered || 0}/${result.branchCoverage?.total || 0})\n` + `**Líneas:** ${result.lineCoverage?.percentage || 0}% (${result.lineCoverage?.covered || 0}/${result.lineCoverage?.total || 0})`; } else { // Es un CoverageSummary (frontend) const summary = result as CoverageSummary; const stmtPercent = summary.statements > 0 ? ((summary.statements - summary.uncoveredStatements) / summary.statements * 100).toFixed(2) : 0; const funcPercent = summary.functions > 0 ? ((summary.functions - summary.uncoveredFunctions) / summary.functions * 100).toFixed(2) : 0; const branchPercent = summary.branches > 0 ? ((summary.branches - summary.uncoveredBranches) / summary.branches * 100).toFixed(2) : 0; coverageText = `📊 **Resumen de Cobertura - Build #${args.buildNumber}**\n\n` + `**Declaraciones:** ${stmtPercent}% (${summary.statements - summary.uncoveredStatements}/${summary.statements})\n` + `**Funciones:** ${funcPercent}% (${summary.functions - summary.uncoveredFunctions}/${summary.functions})\n` + `**Ramas:** ${branchPercent}% (${summary.branches - summary.uncoveredBranches}/${summary.branches})`; } return { content: [{ type: "text", text: coverageText }], }; } catch (error: any) { return { content: [{ type: "text", text: `❌ **Error:** ${error.message}` }], }; } } );
- tools/jenkins-service.ts:192-219 (handler)Core implementation of coverage report fetching in JenkinsService: attempts JaCoCo backend first, falls back to frontend coverage report, computes summaries based on parameters.async getCoverageReport(app: string, buildNumber: number, packageName?: string, className?: string, branch: string = 'main'): Promise<CoverageReport | CoverageSummary> { if (!validateAppName(app)) { throw new Error('Invalid app name.'); } // Primero intentar con backend (jacoco) try { const backendUrl = `${buildJobBuildUrl('', app, buildNumber, branch)}/jacoco/jacoco.exec`; await this.client.get(backendUrl); // Si existe, procesar reporte backend return await this.getCoverageReportBackend(app, buildNumber, branch); } catch (error: any) { // Si falla, intentar con frontend coverage try { const frontendReport = await this.getCoverageReportFrontend(app, buildNumber, branch); if (packageName) { return this.calculatePackageSummary(frontendReport, packageName, className); } else if (className) { return this.calculateClassSummary(frontendReport, className); } else { return this.calculateTotalSummary(frontendReport); } } catch (frontendError: any) { throw handleHttpError(frontendError, `Failed to get coverage report for app: ${app}, build: ${buildNumber}, branch: ${branch}`); } } }
- tools/jenkins-service.ts:300-322 (helper)Helper function to compute total coverage summary from frontend coverage report data.private calculateTotalSummary(report: CoverageReportFront): CoverageSummary { const summary: CoverageSummary = { statements: 0, functions: 0, branches: 0, uncoveredStatements: 0, uncoveredFunctions: 0, uncoveredBranches: 0 }; Object.values(report.files).forEach(file => { summary.statements += Object.keys(file.statementMap).length; summary.functions += Object.keys(file.fnMap).length; summary.branches += Object.keys(file.branchMap).length; // Calcular no cubiertos summary.uncoveredStatements += Object.values(file.s).filter(v => v === 0).length; summary.uncoveredFunctions += Object.values(file.f).filter(v => v === 0).length; summary.uncoveredBranches += Object.values(file.b).flat().filter(v => v === 0).length; }); return summary; }
- common/types.ts:118-125 (schema)TypeScript interfaces for CoverageSummary and CoverageReport used in the tool's input/output handling.export interface CoverageSummary { statements: number; functions: number; branches: number; uncoveredStatements: number; uncoveredFunctions: number; uncoveredBranches: number; }
- tools/jenkins-service.ts:277-288 (helper)Helper to fetch and process JaCoCo backend coverage report (currently returns placeholder).private async getCoverageReportBackend(app: string, buildNumber: number, branch: string = 'main'): Promise<CoverageReport> { const jacocoUrl = `${buildJobBuildUrl('', app, buildNumber, branch)}/jacoco/jacoco.exec`; const response = await this.client.get(jacocoUrl, { responseType: 'arraybuffer' }); // Aquí deberías procesar el archivo jacoco.exec // Por simplicidad, devolvemos un reporte básico return { instructionCoverage: { covered: 0, missed: 0, percentage: 0, total: 0 }, branchCoverage: { covered: 0, missed: 0, percentage: 0, total: 0 }, lineCoverage: { covered: 0, missed: 0, percentage: 0, total: 0 } }; }