Skip to content

Commit 822c957

Browse files
authored
Merge pull request #15 from matlab-actions/tarun/codeCovView
Changes in common-utils to support code coverage summary view in Github Actions
2 parents 89c1c92 + 03c16e6 commit 822c957

4 files changed

Lines changed: 589 additions & 15 deletions

File tree

src/codeCoverageSummary.ts

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
// Copyright 2026 The MathWorks, Inc.
2+
3+
import { readFileSync, unlinkSync, existsSync } from "fs";
4+
import * as path from "path";
5+
6+
interface CoverageMetric {
7+
Executed: number;
8+
Total: number;
9+
Percentage: number;
10+
}
11+
12+
export interface CoverageData {
13+
MetricLevel?: string;
14+
FunctionCoverage?: CoverageMetric;
15+
StatementCoverage?: CoverageMetric;
16+
DecisionCoverage?: CoverageMetric;
17+
ConditionCoverage?: CoverageMetric;
18+
MCDCCoverage?: CoverageMetric;
19+
}
20+
21+
export function getCoverageResults(
22+
runnerTemp: string,
23+
runId: string,
24+
): CoverageData | null {
25+
let coverageData = null;
26+
const coveragePath = path.join(runnerTemp, `matlabCoverageResults${runId}.json`);
27+
28+
if (existsSync(coveragePath)) {
29+
try {
30+
const coverageArray: CoverageData[] = JSON.parse(readFileSync(coveragePath, "utf8"));
31+
if (coverageArray.length !== 0) {
32+
coverageData = coverageArray[coverageArray.length - 1];
33+
}
34+
} catch (e) {
35+
console.error(
36+
`An error occurred while reading the code coverage summary file ${coveragePath}:`,
37+
e,
38+
);
39+
} finally {
40+
try {
41+
unlinkSync(coveragePath);
42+
} catch (e) {
43+
console.error(
44+
`An error occurred while trying to delete the code coverage summary file ${coveragePath}:`,
45+
e,
46+
);
47+
}
48+
}
49+
}
50+
return coverageData;
51+
}
52+
53+
function formatPercentage(percentage: number): string {
54+
if (percentage === null || percentage === undefined || isNaN(percentage)) {
55+
return '0.00%';
56+
}
57+
return percentage.toFixed(2) + '%';
58+
}
59+
60+
export function getCoverageTable(coverage: CoverageData): string {
61+
62+
// Define all possible columns
63+
const allColumns = [
64+
{ name: 'Function', data: coverage.FunctionCoverage },
65+
{ name: 'Statement', data: coverage.StatementCoverage },
66+
{ name: 'Decision', data: coverage.DecisionCoverage },
67+
{ name: 'Condition', data: coverage.ConditionCoverage },
68+
{ name: 'MC/DC', data: coverage.MCDCCoverage }
69+
];
70+
71+
// Filter to only include columns where data actually exists
72+
const visibleColumns = allColumns.filter(col => col.data !== undefined && col.data !== null);
73+
74+
// Build header row
75+
const headers = visibleColumns.map(col => `<th>${col.name}</th>`).join('');
76+
const headerRow = `<tr align="center"><th>Metric</th>${headers}</tr>`;
77+
78+
// Build percentage row
79+
const percentages = visibleColumns.map(col =>
80+
`<td>${formatPercentage(col.data!.Percentage)}</td>`
81+
).join('');
82+
const percentageRow = `<tr align="center"><td><b>Percentage</b></td>${percentages}</tr>`;
83+
84+
// Build covered/total row
85+
const coveredTotals = visibleColumns.map(col =>
86+
`<td>${col.data!.Executed}/${col.data!.Total}</td>`
87+
).join('');
88+
const coveredTotalRow = `<tr align="center"><td><b>Covered/Total</b></td>${coveredTotals}</tr>`;
89+
90+
const tableHTML = `<table>${headerRow}${percentageRow}${coveredTotalRow}</table>`;
91+
92+
return tableHTML;
93+
}

0 commit comments

Comments
 (0)