mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-06 10:59:59 +00:00
make lint runs install-lint once and then dispatches its fifteen targets in parallel. scripts/lint/mermaid.sh provisioned chrome-headless-shell inside that parallel phase with `npx puppeteer browsers install --install-deps`, whose `apt-get satisfy` carries no lock timeout. In a fresh stack container another target held the apt lock, the shared libraries stayed missing, the script only warned, and all 289 Markdown files then failed on libnspr4.so (#795). utils/install/lint/mermaid_cli.py now provisions the browser right after mmdc, inside the serial install-lint step, as root with --install-deps and as a user without it, because puppeteer refuses to install libraries without root. A failed install deletes the chrome-headless-shell cache folder and retries once under a 900 second timeout per attempt; a cut-off download otherwise leaves a folder without its executable, and puppeteer refuses every later install of that build. The install-lint stamp counts as fresh only while the browser executable exists, so a recreated container provisions it again. mermaid.sh no longer calls apt-get or npx. It renders one minimal diagram first and, when that fails, exits with mmdc's output instead of reporting every Markdown file. Verified: tests/unit/python/scripts/lint/test_mermaid.py stubs mmdc, npx and apt-get. With a browser that cannot load libnspr4.so the script exits 1 with that line, before any Markdown file renders, and mmdc is the only tool it calls. Against main's mermaid.sh the same test fails: it calls apt-get and npx and reports the files one by one. The installer and stamp cases pass, shellcheck is clean. Not verified: a full make lint in a recreated stack container. The race reproduced in one of two runs in the issue. feature/store-i18n changed the provisioning in mermaid.sh with2f5f52bd1aanddc67bce5f0(timeout, deleting a cut-off browser). Both behaviours moved into mermaid_cli.py here, so its merge takes this version of mermaid.sh. Closes #795 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
79 lines
2.5 KiB
Bash
Executable File
79 lines
2.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# shellcheck shell=bash
|
|
#
|
|
# Validate every Mermaid diagram in the repository's Markdown by rendering it
|
|
# with @mermaid-js/mermaid-cli (mmdc). A diagram GitHub cannot render (syntax
|
|
# error, reserved-word node id, ...) makes mmdc exit nonzero, failing the lint.
|
|
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
|
REPO_ROOT="$(cd -- "${SCRIPT_DIR}/../.." && pwd)"
|
|
|
|
cd "${REPO_ROOT}"
|
|
|
|
# shellcheck source=scripts/meta/env/load.sh
|
|
source scripts/meta/env/load.sh
|
|
|
|
if ! command -v mmdc >/dev/null 2>&1; then
|
|
echo "mmdc (@mermaid-js/mermaid-cli) not installed. Run 'make install-lint' first." >&2
|
|
exit 127
|
|
fi
|
|
|
|
workdir="$(mktemp -d)"
|
|
trap 'rm -rf "${workdir}"' EXIT
|
|
|
|
puppeteer_cfg="${workdir}/puppeteer-config.json"
|
|
printf '%s\n' '{"args":["--no-sandbox","--disable-gpu"]}' >"${puppeteer_cfg}"
|
|
|
|
mapfile -t md_files < <(grep -rlF --include='*.md' '```mermaid' . 2>/dev/null | sort || true)
|
|
|
|
if [[ ${#md_files[@]} -eq 0 ]]; then
|
|
echo "No Markdown files contain a mermaid block; nothing to render."
|
|
exit 0
|
|
fi
|
|
|
|
printf '%s\n' 'flowchart LR' ' a --> b' >"${workdir}/preflight.mmd"
|
|
if ! mmdc --puppeteerConfigFile "${puppeteer_cfg}" -i "${workdir}/preflight.mmd" \
|
|
-o "${workdir}/preflight.svg" >"${workdir}/preflight.log" 2>&1; then
|
|
printf "mmdc cannot render a minimal diagram, so none of the %d Markdown file(s) was checked. 'make install-lint-force' provisions its browser:\n" \
|
|
"${#md_files[@]}" >&2
|
|
sed 's/^/ /' "${workdir}/preflight.log" >&2
|
|
exit 1
|
|
fi
|
|
|
|
: "${INFINITO_WORKER_CPU:?INFINITO_WORKER_CPU must be set (provided by default.env via the env loader)}"
|
|
jobs="${INFINITO_WORKER_CPU}"
|
|
|
|
# shellcheck disable=SC2329,SC2317 # invoked indirectly through xargs + bash -c
|
|
render_one() {
|
|
local md="$1"
|
|
local slug
|
|
slug="$(printf '%s' "${md}" | tr '/.' '__')"
|
|
if ! mmdc --puppeteerConfigFile "${puppeteer_cfg}" -i "${md}" \
|
|
-o "${workdir}/${slug}.out.md" >"${workdir}/${slug}.log" 2>&1; then
|
|
printf '%s\n' "${md}" >"${workdir}/${slug}.fail"
|
|
fi
|
|
}
|
|
export -f render_one
|
|
export workdir puppeteer_cfg
|
|
|
|
# shellcheck disable=SC2016 # the single-quoted body expands inside the child bash
|
|
printf '%s\n' "${md_files[@]}" |
|
|
xargs -P "${jobs}" -I {} bash -c 'render_one "$1"' _ {}
|
|
|
|
status=0
|
|
for fail in "${workdir}"/*.fail; do
|
|
[[ -e "${fail}" ]] || continue
|
|
status=1
|
|
md="$(cat "${fail}")"
|
|
printf '❌ %s\n' "${md}"
|
|
sed 's/^/ /' "${fail%.fail}.log"
|
|
done
|
|
|
|
if [[ "${status}" -eq 0 ]]; then
|
|
printf '✅ %d Markdown file(s) with mermaid render cleanly.\n' "${#md_files[@]}"
|
|
fi
|
|
|
|
exit "${status}"
|