#!/usr/bin/env bash # scripts/quality/run-all.sh # # Run every local quality gate in sequence. Each gate is independent; # a failure does not stop the rest (we collect failures and report at # the end). Use this before tagging a release or before showing the # repo to an external reviewer. # # Wall-time budget on a typical dev laptop (M-series Mac): # license-headers.sh ~1 s # check-markdown-links.py ~2 s # sanitizers.sh ~3 min # coverage.sh ~2 min # clang-tidy.sh ~2 min (depends on header count) # multi-compiler.sh ~5 min (per compiler) # reproducible-build.sh ~6 min # cgal-version-matrix.sh ~5 min per CGAL version # ───────────────────────────── # TOTAL ~25–40 min # # Usage: # bash scripts/quality/run-all.sh # everything # bash scripts/quality/run-all.sh --fast # skip the slow gates # (cgal-matrix, multi-compiler, # coverage, reproducible) # # Exit code: number of failed gates (so 0 = green). set -uo pipefail ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" cd "$ROOT" || exit 2 FAST=0 [ "${1:-}" = "--fast" ] && FAST=1 GATES_FAST=( "License headers | bash scripts/quality/license-headers.sh" "CGAL conventions | python3 scripts/quality/cgal-conventions.py" "clang-format drift | bash scripts/quality/clang-format.sh" "cmake-format/-lint | bash scripts/quality/cmake-format.sh" "codespell | bash scripts/quality/codespell.sh" "shellcheck | bash scripts/quality/shellcheck.sh" "cppcheck | bash scripts/quality/cppcheck.sh" "Markdown links | python3 scripts/check-markdown-links.py" "Sanitizers | bash scripts/quality/sanitizers.sh" "clang-tidy | bash scripts/quality/clang-tidy.sh" ) GATES_SLOW=( "Coverage | bash scripts/quality/coverage.sh" "Multi-compiler | bash scripts/quality/multi-compiler.sh" "Reproducible build | bash scripts/quality/reproducible-build.sh" "CGAL version matrix | bash scripts/quality/cgal-version-matrix.sh" ) if [ "$FAST" -eq 1 ]; then GATES=("${GATES_FAST[@]}") else GATES=("${GATES_FAST[@]}" "${GATES_SLOW[@]}") fi LOG_DIR="build-quality-logs" mkdir -p "$LOG_DIR" echo "============================================================" echo " conformallab++ local quality gates" echo " mode: $([ $FAST -eq 1 ] && echo 'FAST (4 gates)' || echo "FULL (${#GATES[@]} gates)")" echo " logs: $LOG_DIR/" echo "============================================================" results="" failed=0 skipped=0 i=0 for entry in "${GATES[@]}"; do i=$((i + 1)) name="${entry%%|*}" name="${name%%[[:space:]]*([[:space:]])}" # trim trailing space cmd="${entry##*|}" cmd="${cmd##[[:space:]]}" # Slug-safe filename slug=$(echo "$name" | tr ' /[:upper:]' '_-[:lower:]' | tr -cd 'a-z0-9_-') log="$LOG_DIR/$slug.log" echo echo "──── [$i/${#GATES[@]}] $name ────" eval "$cmd" >"$log" 2>&1 rc=$? # Exit code 2 from any of our gate scripts = "tool not installed". # Treat as SKIP rather than FAIL so a partial dev environment can # still run the rest of the sweep. if [ "$rc" -eq 2 ] && head -3 "$log" | grep -qE "FAIL:.*not (in PATH|installed|found)"; then echo " SKIP (tool not installed — see $log)" results="${results} SKIP $name (missing tool) " skipped=$((skipped + 1)) elif [ "$rc" -eq 0 ]; then echo " OK ($log)" results="${results} PASS $name " else echo " FAIL (rc=$rc) — see $log" echo " last 20 lines:" tail -20 "$log" | sed 's/^/ /' results="${results} FAIL $name ($log) " failed=$((failed + 1)) fi done echo echo "============================================================" echo " Summary" echo "============================================================" printf "%s" "$results" echo echo " passed: $((${#GATES[@]} - failed - skipped)) / ${#GATES[@]}" echo " skipped: $skipped (tool not installed; gate is local-only)" echo " failed: $failed" exit $failed