ci: fix mermaid parse check — use mermaid.core.mjs (no Puppeteer/Chromium needed)
Some checks failed
CI / Security audit (push) Has been cancelled
Build and Push Docker Image / build (push) Has been cancelled
CI / Tests & coverage (push) Has been cancelled
Docs Check / Markdown lint (push) Has been cancelled
Docs Check / Mermaid diagram parse check (push) Has been cancelled

This commit is contained in:
2026-05-17 18:50:46 +01:00
parent 6bf8098265
commit 6cf01f5530

View File

@@ -43,67 +43,54 @@ jobs:
with: with:
node-version: "22" node-version: "22"
- name: Install mermaid-js CLI - name: Install mermaid
run: npm install -g @mermaid-js/mermaid-cli run: npm install mermaid
- name: Write Puppeteer config (no-sandbox for CI)
run: |
echo '{"args":["--no-sandbox","--disable-setuid-sandbox"]}' > /tmp/puppeteer-config.json
- name: Extract and validate Mermaid diagrams - name: Extract and validate Mermaid diagrams
run: | run: |
node - <<'EOF' cat > check-mermaid.mjs << 'SCRIPT'
const fs = require('fs'); import { readFileSync, readdirSync } from 'fs';
const path = require('path'); import { join } from 'path';
const { execSync } = require('child_process'); import mermaid from './node_modules/mermaid/dist/mermaid.core.mjs';
const os = require('os');
function findMarkdownFiles(dir) { function findMdFiles(dir) {
const results = []; const out = [];
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) { for (const e of readdirSync(dir, { withFileTypes: true })) {
const full = path.join(dir, entry.name); const full = join(dir, e.name);
if (entry.isDirectory() && entry.name !== 'node_modules' && !entry.name.startsWith('.')) { if (e.isDirectory() && e.name !== 'node_modules' && !e.name.startsWith('.'))
results.push(...findMarkdownFiles(full)); out.push(...findMdFiles(full));
} else if (entry.isFile() && entry.name.endsWith('.md')) { else if (e.isFile() && e.name.endsWith('.md'))
results.push(full); out.push(full);
}
} }
return results; return out;
} }
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'mermaid-')); let errors = 0, total = 0;
let errors = 0;
let total = 0;
for (const mdFile of findMarkdownFiles('.')) { for (const mdFile of findMdFiles('.')) {
const content = fs.readFileSync(mdFile, 'utf8'); const content = readFileSync(mdFile, 'utf8');
const blocks = [...content.matchAll(/^```mermaid\n([\s\S]*?)^```/gm)]; const blocks = [...content.matchAll(/^```mermaid\n([\s\S]*?)^```/gm)];
if (!blocks.length) continue; if (!blocks.length) continue;
console.log(`\nChecking ${mdFile} (${blocks.length} diagram(s))`); console.log(`\nChecking ${mdFile} (${blocks.length} diagram(s))`);
for (let i = 0; i < blocks.length; i++) {
blocks.forEach((match, i) => {
total++; total++;
const mmdFile = path.join(tmpDir, `diagram-${total}.mmd`); const diagram = blocks[i][1].trim();
const svgFile = path.join(tmpDir, `diagram-${total}.svg`);
fs.writeFileSync(mmdFile, match[1]);
try { try {
execSync( await mermaid.parse(diagram);
`mmdc -i "${mmdFile}" -o "${svgFile}" --puppeteerConfigFile /tmp/puppeteer-config.json`,
{ stdio: 'pipe' }
);
console.log(` [OK] diagram ${i + 1}`); console.log(` [OK] diagram ${i + 1}`);
} catch (err) { } catch (err) {
const msg = (err.stderr || err.stdout || '').toString().split('\n')[0]; const msg = String(err.message || err).split('\n')[0];
console.error(` [FAIL] diagram ${i + 1}: ${msg}`); console.error(` [FAIL] diagram ${i + 1}: ${msg}`);
console.log(`::warning file=${mdFile}::Mermaid diagram ${i + 1} failed: ${msg}`); console.log(`::warning file=${mdFile}::Mermaid diagram ${i + 1} failed: ${msg}`);
errors++; errors++;
} }
}); }
} }
console.log(`\nTotal diagrams checked: ${total}. Failures: ${errors}`); console.log(`\nTotal: ${total}. Failures: ${errors}`);
if (errors > 0) { if (errors > 0) {
console.log(`::warning::${errors} Mermaid diagram(s) failed to parse.`); console.log(`::warning::${errors} Mermaid diagram(s) failed to parse.`);
process.exit(1); process.exit(1);
} }
EOF SCRIPT
node check-mermaid.mjs