Files
cacti/tests/tools/pre-commit-check.sh
Thomas Vincent b430f5b1ec fix(tests): make hooks, CI helpers and the i18n audit fail closed (#8457)
* fix(hooks): check staged blobs and fail closed in the changelog tools

The pre-commit hooks read working-tree files while claiming to check staged content, check-changelog.py passed when its base diff failed, and fold-changelog.py deleted fragments it had not validated.

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* fix(tests): make CI helper scripts fail when they check nothing

check_all_pages.sh passed without logging in or crawling, the sink inventory accepted ripgrep errors, install_packages.sh and copyright_year.sh lost their failures, and the LDAP spec asserted before navigation finished.

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* fix(i18n): audit only changed .po entries and keep contributor badges separate

audit_po.py failed every translation PR on pre-existing errors and matched non-printf text as conversions; update-contributors.py leaked badges between aliased contributors.

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* docs(changelog): add fragment for #8457

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* test(e2e): move the pointer off the Deepness multiselect button

Deepness sets a zero body margin, so the unhovered #ms-button sits at the viewport origin and headless Chromium on Linux intermittently applies :hover to it.

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* ci: pull pinned integration database from authenticated mirror

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

---------

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
2026-10-23 08:17:12 -04:00

204 lines
5.3 KiB
Bash
Executable File

#!/bin/sh
# +-------------------------------------------------------------------------+
# | Pre-commit validation wrapper for Cacti |
# | Checks environment and dev tools before running linters. |
# +-------------------------------------------------------------------------+
set -eu
VENDOR_BIN="include/vendor/bin"
REQUIRED_PHP_MAJOR=8
MAX_PHP_MINOR=4
# ---- Environment checks (run before any tool) ----
check_php_version() {
php_ver=$(php -r 'echo PHP_MAJOR_VERSION . "." . PHP_MINOR_VERSION;' 2>/dev/null || echo "unknown")
major=$(echo "$php_ver" | cut -d. -f1)
minor=$(echo "$php_ver" | cut -d. -f2)
if [ "$major" != "$REQUIRED_PHP_MAJOR" ]; then
echo "WARNING: PHP $php_ver detected. Cacti requires PHP 8.x"
elif [ "$minor" -gt "$MAX_PHP_MINOR" ] 2>/dev/null; then
echo "WARNING: PHP $php_ver detected. Cacti targets PHP 8.1-8.4."
echo " Some type features (true|string) are not available on PHP 8.1."
echo " Consider: export PATH=\"/opt/homebrew/opt/php@8.4/bin:\${PATH}\""
fi
}
# Staged PHP files, one per line. Paths are read back with `read -r`, so
# spaces survive; quotePath=false keeps non-ASCII names unescaped.
staged_php_files() {
git -c core.quotePath=false diff --cached --name-only --diff-filter=ACMR -- '*.php'
}
check_merge_conflicts() {
staged=$(staged_php_files)
if [ -z "$staged" ]; then
return 0
fi
# Inspect the staged blob: a marker resolved only in the working tree is
# still committed.
conflicts=$(printf '%s\n' "$staged" | while IFS= read -r f; do
if git show ":$f" | grep -E -q '^(<<<<<<<|=======$|>>>>>>>)'; then
printf '%s\n' "$f"
fi
done)
if [ -n "$conflicts" ]; then
echo ""
echo "ERROR: Merge conflict markers found in staged files:"
echo "$conflicts"
echo " Resolve conflicts before committing."
echo ""
exit 1
fi
}
check_composer_lock() {
if git diff --cached --name-only | grep -q '^composer\.lock$'; then
echo ""
echo "ERROR: composer.lock is staged for commit."
echo " Cacti supports multiple PHP versions; composer.lock must not be committed."
echo " Run: git reset HEAD composer.lock"
echo ""
exit 1
fi
}
check_vendor_dev_deps() {
php tests/tools/check_vendor_policy.php
}
check_autoload_freshness() {
if [ ! -f include/vendor/autoload.php ]; then
echo "WARNING: your are missing the composer autoload. Please run composer install"
exit 1
fi
}
check_tool() {
tool="$1"
label="$2"
if [ ! -x "$VENDOR_BIN/$tool" ]; then
echo ""
echo "ERROR: $label not found at $VENDOR_BIN/$tool"
echo ""
echo " Run: composer install --ignore-platform-reqs"
echo ""
echo " Dev dependencies must be installed for pre-commit hooks."
echo " This is a one-time setup after cloning or switching branches."
echo ""
exit 1
fi
# Verify the tool can actually load (catches missing Symfony/autoload issues)
if ! "$VENDOR_BIN/$tool" --version > /dev/null 2>&1; then
echo ""
echo "ERROR: $label exists but failed to load. Autoload may be stale."
echo ""
echo " Run: composer install --ignore-platform-reqs"
echo ""
exit 1
fi
}
# ---- Lint / analysis tools ----
# Lint the staged blobs with php -l. The previous phplint branch linted the
# working tree and its guard could never be true, so it never ran.
run_lint() {
echo "Running php -l on staged files..."
staged=$(staged_php_files)
if [ -z "$staged" ]; then
echo " No staged PHP files to check."
return 0
fi
failed=$(printf '%s\n' "$staged" | while IFS= read -r f; do
if ! git show ":$f" | php -l > /dev/null 2>&1; then
printf '%s\n' "$f"
fi
done)
if [ -n "$failed" ]; then
echo "Syntax errors in staged files:"
printf '%s\n' "$failed" | while IFS= read -r f; do
printf ' %s\n' "$f"
git show ":$f" | php -l 2>&1 || true
done
exit 1
fi
echo " All staged PHP files pass syntax check."
}
run_phpcsfixer() {
check_tool "php-cs-fixer" "PHP CS Fixer"
echo "Running PHP CS Fixer (dry-run)..."
if ! composer run-script php-cs-fixer; then
echo ""
echo "TIP: To auto-fix formatting issues, run:"
echo " composer run-script php-cs-fixit"
echo ""
exit 1
fi
}
run_phpstan() {
check_tool "phpstan" "PHPStan"
echo "Running PHPStan..."
composer run-script phpstan
}
# ---- Pre-flight checks (always run) ----
run_preflight() {
check_php_version
check_merge_conflicts
check_composer_lock
check_vendor_dev_deps
check_autoload_freshness
}
# ---- Main ----
case "${1:-all}" in
lint)
run_preflight
run_lint
;;
phpcsfixer)
run_preflight
run_phpcsfixer
;;
phpstan)
run_preflight
run_phpstan
;;
all)
run_preflight
run_lint
run_phpcsfixer
run_phpstan
;;
preflight)
run_preflight
echo "Pre-flight checks passed."
;;
*)
echo "Usage: $0 {lint|phpcsfixer|phpstan|all|preflight}"
exit 1
;;
esac