ci: add separate docs-check workflow for Markdown lint and Mermaid parse validation
Some checks failed
CI / Security audit (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
Build and Push Docker Image / build (push) Has been cancelled

- docs-check.yml runs on push/PR only when .md files change
- markdown-lint job: uses markdownlint-cli to check all .md files
- mermaid-parse job: extracts all mermaid blocks from .md files and
  validates each via mmdc (mermaid-js CLI) in headless Chromium
- Both jobs use continue-on-error: true so docs failures never block
  a release or fail the main CI pipeline
- .markdownlint.json disables MD013 (line length), MD033 (inline HTML),
  MD041 (first-line heading) to reduce noise on this repo
This commit is contained in:
2026-05-17 18:36:16 +01:00
parent 2cf163dfff
commit a368636ec4
2 changed files with 115 additions and 0 deletions

View File

@@ -0,0 +1,109 @@
name: Docs Check
on:
push:
branches: ["**"]
paths:
- "**.md"
- ".gitea/workflows/docs-check.yml"
pull_request:
branches: ["**"]
paths:
- "**.md"
- ".gitea/workflows/docs-check.yml"
jobs:
markdown-lint:
name: Markdown lint
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: "22"
- name: Install markdownlint-cli
run: npm install -g markdownlint-cli
- name: Lint all Markdown files
run: markdownlint "**/*.md" --ignore node_modules
mermaid-parse:
name: Mermaid diagram parse check
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: "22"
- name: Install mermaid-js CLI
run: npm install -g @mermaid-js/mermaid-cli
- 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
run: |
node - <<'EOF'
const fs = require('fs');
const path = require('path');
const { execSync } = require('child_process');
const os = require('os');
function findMarkdownFiles(dir) {
const results = [];
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
const full = path.join(dir, entry.name);
if (entry.isDirectory() && entry.name !== 'node_modules' && !entry.name.startsWith('.')) {
results.push(...findMarkdownFiles(full));
} else if (entry.isFile() && entry.name.endsWith('.md')) {
results.push(full);
}
}
return results;
}
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'mermaid-'));
let errors = 0;
let total = 0;
for (const mdFile of findMarkdownFiles('.')) {
const content = fs.readFileSync(mdFile, 'utf8');
const blocks = [...content.matchAll(/^```mermaid\n([\s\S]*?)^```/gm)];
if (!blocks.length) continue;
console.log(`\nChecking ${mdFile} (${blocks.length} diagram(s))`);
blocks.forEach((match, i) => {
total++;
const mmdFile = path.join(tmpDir, `diagram-${total}.mmd`);
const svgFile = path.join(tmpDir, `diagram-${total}.svg`);
fs.writeFileSync(mmdFile, match[1]);
try {
execSync(
`mmdc -i "${mmdFile}" -o "${svgFile}" --puppeteerConfigFile /tmp/puppeteer-config.json`,
{ stdio: 'pipe' }
);
console.log(` [OK] diagram ${i + 1}`);
} catch (err) {
const msg = (err.stderr || err.stdout || '').toString().split('\n')[0];
console.error(` [FAIL] diagram ${i + 1}: ${msg}`);
console.log(`::warning file=${mdFile}::Mermaid diagram ${i + 1} failed: ${msg}`);
errors++;
}
});
}
console.log(`\nTotal diagrams checked: ${total}. Failures: ${errors}`);
if (errors > 0) {
console.log(`::warning::${errors} Mermaid diagram(s) failed to parse.`);
process.exit(1);
}
EOF