const fs = require('node:fs'); const path = require('node:path'); const summaryPath = path.resolve(process.cwd(), 'coverage', 'coverage-summary.json'); const thresholds = { statements: 90, lines: 90, functions: 90, branches: 70, }; if (!fs.existsSync(summaryPath)) { console.error(`Coverage summary was not found at ${summaryPath}`); process.exit(1); } const summary = JSON.parse(fs.readFileSync(summaryPath, 'utf8')); const serviceEntries = Object.entries(summary).filter(([file]) => file.replace(/\\/g, '/').endsWith('.service.ts'), ); if (!serviceEntries.length) { console.error('Coverage summary did not contain any service files'); process.exit(1); } let failed = false; console.log(`\nRuntime service coverage (${serviceEntries.length} files):`); for (const [metric, minimum] of Object.entries(thresholds)) { const totals = serviceEntries.reduce( (result, [, coverage]) => ({ covered: result.covered + coverage[metric].covered, total: result.total + coverage[metric].total, }), { covered: 0, total: 0 }, ); const percentage = totals.total === 0 ? 100 : (totals.covered / totals.total) * 100; const formatted = percentage.toFixed(2); const status = percentage >= minimum ? 'PASS' : 'FAIL'; console.log( ` ${metric.padEnd(10)} ${formatted.padStart(6)}% ` + `(${totals.covered}/${totals.total}, required ${minimum}%) ${status}`, ); failed ||= percentage < minimum; } if (failed) { console.error('\nRuntime service coverage gate failed.'); process.exit(1); } console.log('\nRuntime service coverage gate passed.');