(report: AuditReport)
| 38 | }; |
| 39 | |
| 40 | export const renderReport = (report: AuditReport): string => { |
| 41 | const lines: string[] = []; |
| 42 | lines.push('Orbit Station Audit Report'); |
| 43 | lines.push(`station: ${report.ctx.station}`); |
| 44 | lines.push(`network: ${report.ctx.network}`); |
| 45 | lines.push(''); |
| 46 | |
| 47 | const sorted = sortFindings(report.findings); |
| 48 | const grouped = groupBySeverity(sorted); |
| 49 | for (const severity of ['blocker', 'warning', 'info'] as Severity[]) { |
| 50 | const bucket = grouped.get(severity) ?? []; |
| 51 | if (bucket.length === 0) continue; |
| 52 | lines.push(`==== ${HEADER[severity]} (${bucket.length}) ====`); |
| 53 | lines.push(''); |
| 54 | for (const finding of bucket) { |
| 55 | lines.push(`[${finding.checkId}]`); |
| 56 | if (finding.location) lines.push(` ${finding.location}`); |
| 57 | lines.push(` ${finding.message}`); |
| 58 | if (finding.fix) lines.push(` fix: ${finding.fix}`); |
| 59 | lines.push(''); |
| 60 | } |
| 61 | } |
| 62 | |
| 63 | if (report.confirmations.length > 0) { |
| 64 | lines.push('==== Positive confirmations ===='); |
| 65 | for (const c of report.confirmations) lines.push(`- ${c}`); |
| 66 | lines.push(''); |
| 67 | } |
| 68 | |
| 69 | const counts = sorted.reduce( |
| 70 | (acc, f) => { |
| 71 | acc[f.severity]++; |
| 72 | return acc; |
| 73 | }, |
| 74 | { blocker: 0, warning: 0, info: 0 } as Record<Severity, number>, |
| 75 | ); |
| 76 | lines.push(`summary: ${counts.blocker} blocker, ${counts.warning} warning, ${counts.info} info`); |
| 77 | |
| 78 | return lines.join('\n'); |
| 79 | }; |
| 80 | |
| 81 | export const exitCodeFor = (report: AuditReport): number => { |
| 82 | if (report.findings.some(f => f.severity === 'blocker')) return 2; |
no test coverage detected