Skip to content

Commit 2264147

Browse files
committed
fix(actions/parse-ci-reports-path): auto-pattern detection and parser accepted paths conflict
Signed-off-by: Emilien Escalle <emilien.escalle@escemi.com>
1 parent c530581 commit 2264147

15 files changed

Lines changed: 171 additions & 17 deletions

actions/parse-ci-reports/src/parsers/AstroCheckParser.js

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,25 @@ const ANSI_PATTERN = new RegExp(`${String.fromCharCode(27)}\\[[0-9;]*m`, "g");
1212
* Parser for output generated by `astro check`
1313
*/
1414
export class AstroCheckParser extends BaseParser {
15-
canParse(_filePath, content) {
15+
canParse(filePath, content) {
1616
if (!content) {
1717
return false;
1818
}
1919

2020
const sanitized = this.#stripAnsi(content);
21-
if (LOCATION_PATTERN.test(sanitized)) {
21+
const hasAstroMarkers =
22+
LOCATION_PATTERN.test(sanitized) ||
23+
ASTRO_HEADER_PATTERNS.some((pattern) => pattern.test(sanitized));
24+
25+
if (hasAstroMarkers) {
2226
return true;
2327
}
2428

25-
return ASTRO_HEADER_PATTERNS.some((pattern) => pattern.test(sanitized));
29+
const normalizedPath = filePath.toLowerCase();
30+
const hasSupportedName =
31+
this.matchesAutoPatterns(filePath) || normalizedPath.includes("astro");
32+
33+
return hasSupportedName;
2634
}
2735

2836
getPriority() {

actions/parse-ci-reports/src/parsers/AstroCheckParser.test.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,14 @@ Result (26 files):
2323
- 0 hints`;
2424

2525
describe("AstroCheckParser", () => {
26+
it("keeps auto-pattern path detection synchronized", () => {
27+
const parser = new AstroCheckParser();
28+
const filePath = "application/humanize-astro-check-report.log";
29+
30+
assert.ok(parser.matchesAutoPatterns(filePath));
31+
assert.ok(parser.canParse(filePath, SAMPLE_ERROR));
32+
});
33+
2634
it("identifies astro check diagnostics", () => {
2735
const parser = new AstroCheckParser();
2836

actions/parse-ci-reports/src/parsers/BaseParser.js

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ export const ReportCategory = {
1212
* Follows the Strategy pattern for different report formats
1313
*/
1414
export class BaseParser {
15+
constructor() {
16+
this._autoPatternRegexCache = null;
17+
}
18+
1519
/**
1620
* Build glob patterns for file basenames matched anywhere in the workspace.
1721
* @param {string[]} baseNames - File basenames to match
@@ -66,6 +70,52 @@ export class BaseParser {
6670
return extensions.map((extension) => `**/*.${extension}`);
6771
}
6872

73+
/**
74+
* Check if a file path matches this parser auto-detection patterns.
75+
* @param {string} filePath - Path to evaluate
76+
* @returns {boolean} True if path matches any auto pattern
77+
*/
78+
matchesAutoPatterns(filePath) {
79+
if (!filePath) {
80+
return false;
81+
}
82+
83+
const normalizedPath = this._normalizeFilePath(filePath).toLowerCase();
84+
const matchers = this._getAutoPatternRegexes();
85+
86+
return matchers.some((matcher) => matcher.test(normalizedPath));
87+
}
88+
89+
_getAutoPatternRegexes() {
90+
if (this._autoPatternRegexCache) {
91+
return this._autoPatternRegexCache;
92+
}
93+
94+
const patterns = this.getAutoPatterns();
95+
this._autoPatternRegexCache = patterns.map((pattern) =>
96+
this._globToRegex(pattern),
97+
);
98+
99+
return this._autoPatternRegexCache;
100+
}
101+
102+
_normalizeFilePath(filePath) {
103+
return String(filePath).replace(/\\/g, "/");
104+
}
105+
106+
_globToRegex(pattern) {
107+
const escapedPattern = pattern
108+
.toLowerCase()
109+
.replace(/[-[\]{}()+?.,\\^$|#\s]/g, "\\$&")
110+
.replace(/\*\*\//g, "<<<ANY_DIR_PREFIX>>>")
111+
.replace(/\*\*/g, "<<<ANY_DIR>>>")
112+
.replace(/\*/g, "[^/]*")
113+
.replace(/<<<ANY_DIR_PREFIX>>>/g, "(?:.*/)?")
114+
.replace(/<<<ANY_DIR>>>/g, ".*");
115+
116+
return new RegExp(`^${escapedPattern}$`, "i");
117+
}
118+
69119
/**
70120
* Parse a report file
71121
* @param {string} content - The file content

actions/parse-ci-reports/src/parsers/CheckStyleParser.js

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,14 @@ export class CheckStyleParser extends BaseParser {
1616
}
1717

1818
canParse(filePath, content) {
19-
return (
20-
(filePath.toLowerCase().includes("checkstyle") ||
21-
filePath.endsWith(".xml")) &&
22-
content.includes("<checkstyle") &&
23-
content.includes("<file")
24-
);
19+
const normalizedPath = filePath.toLowerCase();
20+
const hasSupportedName =
21+
this.matchesAutoPatterns(filePath) ||
22+
normalizedPath.includes("checkstyle") ||
23+
normalizedPath.endsWith(".xml");
24+
const hasCheckstyleRoot = /<\s*checkstyle\b/i.test(content);
25+
26+
return hasSupportedName && hasCheckstyleRoot;
2527
}
2628

2729
getPriority() {

actions/parse-ci-reports/src/parsers/CoberturaParser.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,14 @@ export class CoberturaParser extends BaseParser {
1616
}
1717

1818
canParse(filePath, content) {
19+
const normalizedPath = filePath.toLowerCase();
20+
const hasSupportedName =
21+
this.matchesAutoPatterns(filePath) ||
22+
normalizedPath.includes("cobertura") ||
23+
normalizedPath.includes("coverage");
24+
1925
return (
20-
(filePath.toLowerCase().includes("cobertura") ||
21-
filePath.toLowerCase().includes("coverage")) &&
26+
hasSupportedName &&
2227
content.includes("<coverage") &&
2328
content.includes("line-rate")
2429
);

actions/parse-ci-reports/src/parsers/ESLintParser.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,15 @@ import { ReportData, LintIssue } from "../models/ReportData.js";
66
* Standard format for ESLint output
77
*/
88
export class ESLintParser extends BaseParser {
9-
canParse(_filePath, content) {
9+
canParse(filePath, content) {
10+
const normalizedPath = filePath.toLowerCase();
11+
const hasSupportedName =
12+
this.matchesAutoPatterns(filePath) || normalizedPath.endsWith(".json");
13+
14+
if (!hasSupportedName) {
15+
return false;
16+
}
17+
1018
try {
1119
const data = JSON.parse(content);
1220
// ESLint format is an array of file results

actions/parse-ci-reports/src/parsers/JUnitParser.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,14 @@ export class JUnitParser extends BaseParser {
1717
}
1818

1919
canParse(filePath, content) {
20+
const normalizedPath = filePath.toLowerCase();
21+
const hasSupportedName =
22+
this.matchesAutoPatterns(filePath) ||
23+
normalizedPath.includes("junit") ||
24+
normalizedPath.endsWith(".xml");
25+
2026
return (
21-
(filePath.toLowerCase().includes("junit") || filePath.endsWith(".xml")) &&
27+
hasSupportedName &&
2228
(content.includes("<testsuite") || content.includes("<testsuites"))
2329
);
2430
}

actions/parse-ci-reports/src/parsers/JUnitParser.test.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,14 @@ describe("JUnitParser", () => {
1515
assert.strictEqual(parser.canParse("test-results.xml", content), true);
1616
});
1717

18+
it("keeps auto-pattern path detection synchronized", () => {
19+
const filePath = "reports/junit-report.xml";
20+
const content = `<?xml version="1.0"?><testsuite name="suite"><testcase name="ok"/></testsuite>`;
21+
22+
assert.ok(parser.matchesAutoPatterns(filePath));
23+
assert.ok(parser.canParse(filePath, content));
24+
});
25+
1826
it("should parse simple JUnit XML", () => {
1927
const content = `<?xml version="1.0"?>
2028
<testsuite name="Test Suite" tests="3" failures="1" skipped="1">

actions/parse-ci-reports/src/parsers/LCOVParser.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,14 @@ import { ReportData, Coverage } from "../models/ReportData.js";
77
*/
88
export class LCOVParser extends BaseParser {
99
canParse(filePath, content) {
10+
const normalizedPath = filePath.toLowerCase();
11+
const hasSupportedName =
12+
this.matchesAutoPatterns(filePath) ||
13+
normalizedPath.includes("lcov") ||
14+
normalizedPath.endsWith(".info");
15+
1016
return (
11-
(filePath.toLowerCase().includes("lcov") || filePath.endsWith(".info")) &&
17+
hasSupportedName &&
1218
content.includes("TN:") &&
1319
(content.includes("SF:") || content.includes("DA:"))
1420
);

actions/parse-ci-reports/src/parsers/PrettierParser.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,15 @@ export class PrettierParser extends BaseParser {
2626
return true;
2727
}
2828

29-
if (filePath?.toLowerCase().includes("prettier")) {
29+
const normalizedPath = filePath.toLowerCase();
30+
const hasSupportedName =
31+
this.matchesAutoPatterns(filePath) || normalizedPath.includes("prettier");
32+
33+
if (!hasSupportedName) {
34+
return false;
35+
}
36+
37+
if (normalizedPath.includes("prettier")) {
3038
return /\[(warn|error)\]\s+.+/i.test(content);
3139
}
3240

0 commit comments

Comments
 (0)