perf: optimize pre-push hook from ~12min to ~30s

- Add --no-clean to cargo llvm-cov for incremental builds (~5s vs ~8min)
- Skip Rust checks when no src-tauri/ files changed
- Merge redundant frontend test + coverage into single coverage step
- Reorder: fast lints (fmt, clippy) before slow coverage for quick feedback
- Add timing output and LAPUTA_FULL_COVERAGE=1 escape hatch

Expected: frontend-only push ~1 min, frontend+Rust ~2-3 min
This commit is contained in:
lucaronin
2026-02-27 15:53:05 +01:00
parent e5f3746e8e
commit d202268ed3
2 changed files with 77 additions and 25 deletions

View File

@@ -2,49 +2,96 @@
# Pre-push: full CI checks run locally before any push.
# This replaces remote CI for normal task pushes.
# DO NOT skip with --no-verify (Claude Code is configured to never do this).
#
# ── Optimizations (Feb 2026) ─────────────────────────────────────────────
#
# 1. --no-clean on cargo llvm-cov: reuses previous instrumented build
# artifacts for incremental compilation. Reduces Rust coverage from
# ~8 min (full recompile) to ~30-60s (incremental rebuild).
#
# 2. Change detection: skips Rust checks entirely when no files under
# src-tauri/ changed. Saves ~1-2 min on frontend-only pushes.
#
# 3. Merged redundant test runs: frontend coverage (step 2) already runs
# all tests, so the separate test step was removed.
#
# 4. Fast-fail ordering: within Rust checks, fast lints (fmt ~2s, clippy
# ~15s) run before slow coverage (~30-60s) for quicker feedback.
#
# 5. Force full coverage: set LAPUTA_FULL_COVERAGE=1 to run cargo llvm-cov
# without --no-clean (clean rebuild, accurate baseline).
#
# Expected times (warm cache, incremental):
# Frontend only: ~1 min
# Frontend+Rust: ~2-3 min
# Full coverage: ~9-10 min (with LAPUTA_FULL_COVERAGE=1)
# ─────────────────────────────────────────────────────────────────────────
set -e
START_TIME=$(date +%s)
echo ""
echo "🚀 Pre-push checks (replaces CI — do not skip)"
echo "================================================"
# ── 0. Build check ────────────────────────────────────────────────────────
# ── Detect what changed ─────────────────────────────────────────────────
PUSH_TARGET=$(git rev-parse @{push} 2>/dev/null || echo "")
RUST_CHANGED=true
if [ -n "$PUSH_TARGET" ]; then
CHANGED=$(git diff --name-only "$PUSH_TARGET"..HEAD)
if ! echo "$CHANGED" | grep -qE '^(src-tauri/|Cargo)'; then
RUST_CHANGED=false
fi
fi
# ── 0. TypeScript + Vite build ──────────────────────────────────────────
echo ""
echo "📦 [0/5] TypeScript + Vite build..."
echo "📦 [0/4] TypeScript + Vite build..."
pnpm exec tsc --noEmit
pnpm build
echo " ✅ Build OK"
# ── 1. Frontend tests ─────────────────────────────────────────────────────
# ── 1. Frontend coverage (≥70%) — includes all unit tests ───────────────
echo ""
echo "🧪 [1/5] Frontend tests..."
pnpm test --run --silent
echo " ✅ Frontend tests OK"
# ── 2. Frontend coverage (≥70%) ───────────────────────────────────────────
echo ""
echo "📊 [2/5] Frontend coverage (≥70%)..."
echo "📊 [1/4] Frontend tests + coverage (≥70%)..."
pnpm test:coverage --silent
echo " ✅ Frontend coverage OK"
# ── 3. Rust tests + coverage (≥85% lines) ────────────────────────────────
# ── 2. Rust lint (clippy + fmt) — fast, run before coverage ─────────────
echo ""
echo "🦀 [3/5] Rust tests + coverage (≥85% lines)..."
cargo llvm-cov \
--manifest-path src-tauri/Cargo.toml \
--fail-under-lines 85
echo " ✅ Rust coverage OK"
if [ "$RUST_CHANGED" = true ]; then
echo "🔧 [2/4] Clippy + rustfmt..."
cargo clippy --manifest-path=src-tauri/Cargo.toml -- -D warnings
cargo fmt --manifest-path=src-tauri/Cargo.toml -- --check
echo " ✅ Rust lint OK"
else
echo "⏭️ [2/4] Rust lint — skipped (no src-tauri/ changes)"
fi
# ── 4. Clippy + rustfmt ───────────────────────────────────────────────────
# ── 3. Rust coverage (≥85% lines) ──────────────────────────────────────
echo ""
echo "🔧 [4/5] Clippy + rustfmt..."
cargo clippy --manifest-path=src-tauri/Cargo.toml -- -D warnings
cargo fmt --manifest-path=src-tauri/Cargo.toml -- --check
echo " ✅ Rust lint OK"
if [ "$RUST_CHANGED" = true ]; then
LLVM_COV_FLAGS="--no-clean"
if [ "${LAPUTA_FULL_COVERAGE:-0}" = "1" ]; then
LLVM_COV_FLAGS=""
echo "🦀 [3/4] Rust coverage — FULL (LAPUTA_FULL_COVERAGE=1)..."
else
echo "🦀 [3/4] Rust coverage (≥85%, incremental)..."
fi
# shellcheck disable=SC2086
cargo llvm-cov \
--manifest-path src-tauri/Cargo.toml \
$LLVM_COV_FLAGS \
--fail-under-lines 85
echo " ✅ Rust coverage OK"
else
echo "⏭️ [3/4] Rust coverage — skipped (no src-tauri/ changes)"
fi
# ── 5. CodeScene code health gate (≥9.2) ────────────────────────────────
# ── 4. CodeScene code health gate (≥9.2) ────────────────────────────────
echo ""
echo "🏥 [5/5] CodeScene code health gate (≥9.2)..."
echo "🏥 [4/4] CodeScene code health gate (≥9.2)..."
if [ -z "$CODESCENE_PAT" ] || [ -z "$CODESCENE_PROJECT_ID" ]; then
echo " ⚠️ CODESCENE_PAT or CODESCENE_PROJECT_ID not set — skipping"
else
@@ -65,7 +112,12 @@ print(f' ✅ Code Health {score:.2f} ≥ {threshold}')
"
fi
END_TIME=$(date +%s)
ELAPSED=$((END_TIME - START_TIME))
MINUTES=$((ELAPSED / 60))
SECONDS=$((ELAPSED % 60))
echo ""
echo "================================================"
echo "✅ All checks passed — pushing"
echo "✅ All checks passed — pushing (${MINUTES}m ${SECONDS}s)"
echo ""

View File

@@ -9,7 +9,7 @@ pnpm lint && npx tsc --noEmit # lint + types
pnpm test # unit tests
pnpm test:coverage # frontend ≥70% coverage
cargo test # Rust tests
cargo llvm-cov --manifest-path src-tauri/Cargo.toml --fail-under-lines 85
cargo llvm-cov --manifest-path src-tauri/Cargo.toml --no-clean --fail-under-lines 85
pre_commit_code_health_safeguard # CodeScene ≥9.2 — if it fails, fix structurally (see below)
```