From 17d5514c3bdfafc17fe65a0f9a6c24cfda964ff1 Mon Sep 17 00:00:00 2001 From: Christopher Albert Date: Wed, 21 Oct 2026 17:14:34 +0200 Subject: [PATCH] Share optional staged Fortran checks with the colleague installer --- scripts/setup/git-hooks.sh | 29 +++++++++----- scripts/setup/pre-commit | 81 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+), 10 deletions(-) create mode 100755 scripts/setup/pre-commit diff --git a/scripts/setup/git-hooks.sh b/scripts/setup/git-hooks.sh index e47f535..7aa6b9f 100755 --- a/scripts/setup/git-hooks.sh +++ b/scripts/setup/git-hooks.sh @@ -2,7 +2,7 @@ # Optional global hygiene hook. Missing tools leave the current configuration alone. set -euo pipefail warn() { printf 'Warning: %s; repository hygiene hook installation skipped.\n' "$*" >&2; } -for tool in git python3 curl gitleaks install mktemp; do +for tool in git python3 curl install mktemp; do if ! command -v "$tool" >/dev/null 2>&1; then warn "missing $tool (install it and rerun scripts/setup/git-hooks.sh)" exit 0 @@ -10,7 +10,7 @@ for tool in git python3 curl gitleaks install mktemp; do done revision=04da3fc73d9ead713b93700de7bbf54049b5ac3e checker_sha256=849afd7097350fde0af1863c258bad09a6b75d9a378266001798335232046e59 -hook_sha256=76f3740318ac4bc4769bbaa9ebcb3b8197ae2701980e309009967d241dde669e +hook_sha256=7d5cd9daa40ffca2b7526657f0f4aa169c125d65e448007a8dfa840894ba8eee dest="$HOME/.local/share/git-hooks" if [[ "${1:-}" == --dry-run ]]; then printf 'Would install global repository hygiene %s at %s\n' "$revision" "$dest" @@ -18,12 +18,13 @@ if [[ "${1:-}" == --dry-run ]]; then fi tmp="$(mktemp -d)" trap 'rm -rf "$tmp"' EXIT -for file in repo_hygiene.py pre-commit; do - if ! curl -fsSL "https://raw.githubusercontent.com/itpplasma/.github/$revision/scripts/$file" -o "$tmp/$file"; then - warn "cannot download $file" - exit 0 - fi -done +if ! curl -fsSL --connect-timeout 5 --max-time 20 \ + "https://raw.githubusercontent.com/itpplasma/.github/$revision/scripts/repo_hygiene.py" -o "$tmp/repo_hygiene.py"; then + warn 'cannot download the pinned checker' + exit 0 +fi +# The public canonical hook is shared with the private prompts installer. +install -m 755 "$(dirname "${BASH_SOURCE[0]}")/pre-commit" "$tmp/pre-commit" python3 - "$tmp" "$checker_sha256" "$hook_sha256" <<'VERIFY' import hashlib, pathlib, sys root = pathlib.Path(sys.argv[1]) @@ -32,8 +33,16 @@ for name, digest in zip(('repo_hygiene.py', 'pre-commit'), sys.argv[2:]): raise SystemExit('SHA256 mismatch: ' + name) VERIFY mkdir -p "$dest/bin" -if [[ ! "$(command -v gitleaks)" -ef "$dest/bin/gitleaks" ]]; then - install -m 755 "$(command -v gitleaks)" "$dest/bin/gitleaks" +if command -v gitleaks >/dev/null 2>&1; then + if [[ ! "$(command -v gitleaks)" -ef "$dest/bin/gitleaks" ]]; then + install -m 755 "$(command -v gitleaks)" "$dest/bin/gitleaks" + fi +else + echo 'gitleaks not found: secret checks will warn and skip until it is installed.' >&2 +fi +if curl -fsSL --connect-timeout 1 --max-time 2 \ + https://api.github.com/repos/lazy-fortran/fo/releases/latest -o "$tmp/fo-latest.json"; then + install -m 644 "$tmp/fo-latest.json" "$dest/fo-latest.json" fi install -m 644 "$tmp/repo_hygiene.py" "$dest/repo_hygiene.py" install -m 755 "$tmp/pre-commit" "$dest/pre-commit" diff --git a/scripts/setup/pre-commit b/scripts/setup/pre-commit new file mode 100755 index 0000000..faaa478 --- /dev/null +++ b/scripts/setup/pre-commit @@ -0,0 +1,81 @@ +#!/usr/bin/env bash +# One shared optional hook, also used by itpplasma/code's colleague installer. +set -euo pipefail +hook_dir="$(cd "$(dirname "$0")" && pwd)" +export PATH="$hook_dir/bin:$HOME/.local/bin:$PATH" + +# The pinned checker does size/type checks before invoking gitleaks. Catch only +# its missing executable; all deterministic hygiene failures still block. +if command -v python3 >/dev/null && [[ -f "$hook_dir/repo_hygiene.py" ]]; then + python3 - "$hook_dir/repo_hygiene.py" <<'PY' +import importlib.util, os, subprocess, sys +spec = importlib.util.spec_from_file_location('repo_hygiene', sys.argv[1]) +checker = importlib.util.module_from_spec(spec) +spec.loader.exec_module(checker) +try: + os.chdir(checker.git('rev-parse', '--show-toplevel').decode().strip()) + status = checker.check(True, None, 'HEAD', None) +except FileNotFoundError as exc: + if exc.filename != 'gitleaks': + raise + print('gitleaks not found: secret checks skipped; install: https://github.com/gitleaks/gitleaks', file=sys.stderr) + status = 0 +except (OSError, ValueError, subprocess.CalledProcessError) as exc: + print('repo-hygiene: ' + str(exc), file=sys.stderr) + status = 2 +sys.exit(status) +PY +else + echo 'hygiene checker not found: checks skipped; rerun install-git-hooks.sh' >&2 +fi + +# Detect the project from the index, so an unstaged manifest cannot enable or +# suppress checks. Filename filters include fixed/free form and uppercase forms. +fortran=false +if git cat-file -e :fpm.toml 2>/dev/null; then + fortran=true +elif git cat-file -e :CMakeLists.txt 2>/dev/null; then + if [[ -n "$(git ls-files --cached -- '*.f' '*.F' '*.for' '*.FOR' '*.f90' '*.F90' '*.f95' '*.F95' '*.f03' '*.F03' '*.f08' '*.F08')" ]]; then + fortran=true + fi +fi +if $fortran; then + if ! command -v fo >/dev/null; then + echo 'fo not found: build/test pre-commit checks skipped; install: https://github.com/lazy-fortran/fo' >&2 + elif ! fo hook --help 2>/dev/null | grep -q 'fo hook pre-commit'; then + echo 'fo hook unavailable: build/test pre-commit checks skipped; update: https://github.com/lazy-fortran/fo' >&2 + else + # Release metadata is refreshed by the direct installer, never by a hook. + # Expired/missing/offline metadata produces no hint and never vetoes Git. + if command -v python3 >/dev/null; then + fo --version | python3 -c ' +import json, pathlib, re, sys, time +try: + cache = pathlib.Path(sys.argv[1]) + if time.time() - cache.stat().st_mtime <= 86400: + latest = json.loads(cache.read_text())["tag_name"] + current = sys.stdin.read() + version = lambda text: tuple(map(int, re.search(r"(\d+)\.(\d+)\.(\d+)", text).groups())) + if version(current) < version(latest): + print("fo update available (" + latest + "): https://github.com/lazy-fortran/fo", file=sys.stderr) +except (OSError, ValueError, KeyError, AttributeError): + pass +' "$hook_dir/fo-latest.json" || true + fi + fo hook pre-commit + fi +fi + +common_dir="$(git rev-parse --git-common-dir)" +native_hook="$common_dir/hooks/pre-commit" +if [[ -x "$native_hook" && ! "$native_hook" -ef "$0" ]]; then + exec "$native_hook" "$@" +fi +if [[ -f .pre-commit-config.yaml ]]; then + if command -v prek >/dev/null; then + exec prek run --hook-stage pre-commit + elif command -v pre-commit >/dev/null; then + exec pre-commit run --hook-stage pre-commit + fi + echo 'pre-commit/prek not found: repository hook checks skipped; install: https://pre-commit.com' >&2 +fi