commit 59f24388a40d6237895a74b0dd57f81b100153bd Author: Angel Hudgins Date: Fri Jan 16 18:22:32 2026 +0100 Initial commit: working check-history script with verbose mode - Fixed critical bug with pnpm build/check error handling - Added verbose mode (-v/--verbose) with debug logging - Added .env file copying from main repo to worktrees - Added proper error handling with || true for debug statements diff --git a/check-history.sh b/check-history.sh new file mode 100755 index 0000000..77990b7 --- /dev/null +++ b/check-history.sh @@ -0,0 +1,256 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Usage: +# check-history.sh [--verbose] +# Example: +# check-history.sh 2 4 # checks commits 2,3,4,5 +# check-history.sh 5 1 # checks only commit 5 +# check-history.sh 1 1 --verbose # verbose mode + +VERBOSE=0 +if [ $# -lt 2 ] || [ $# -gt 3 ]; then + echo "Usage: $0 [--verbose|-v]" + exit 1 +fi + +if [ $# -eq 3 ] && { [ "$3" = "--verbose" ] || [ "$3" = "-v" ]; }; then + VERBOSE=1 +fi + +# Debug logging helper +debug() { + if [ "$VERBOSE" -eq 1 ]; then + echo "[DEBUG] $*" >&2 + fi +} + +# Convert user-friendly 1-indexed "Nth from HEAD" into 0-indexed offset +START_OFFSET="$(( $1 - 1 ))" +COUNT="$2" +REPO_ROOT="$(git rev-parse --show-toplevel)" +TMP_BASE="/tmp/check-history-$$" +WORKTREES_DIR="$TMP_BASE/worktrees" +LOGS_DIR="$TMP_BASE/logs" +PNPM_STORE="$HOME/.cache/check-history/pnpm-store" + +debug "REPO_ROOT: $REPO_ROOT" +debug "TMP_BASE: $TMP_BASE" +debug "PNPM_STORE: $PNPM_STORE" + +mkdir -p "$WORKTREES_DIR" "$LOGS_DIR" "$PNPM_STORE" + +echo "Checking commits from offset $1 (HEAD~$START_OFFSET) for $COUNT commits…" +echo + +# Build list of commits as if by `git rebase -i HEAD~N` (HEAD=0 newest) as if by `git rebase -i HEAD~N` +# HEAD = index 0, parent = index 1, etc. +mapfile -t HEAD_TO_OLD <&2 + exit 1 +fi + +# Compute slice from BEGIN_INDEX to START_INDEX inclusive +COMMITS=("${ALL_COMMITS[@]:$BEGIN_INDEX:$COUNT}") +debug "Selected commits:" +for c in "${COMMITS[@]}"; do + debug " $c" +done +# ----------------------------- +# Frontend builder +# ----------------------------- +build_frontend() { + ( + [ "$VERBOSE" -eq 1 ] && echo "[BUILD_DEBUG] Entering rfc-edge-frontend directory" || true + cd rfc-edge-frontend || { + echo "❌ Failed to cd into rfc-edge-frontend" + return 1 + } + [ "$VERBOSE" -eq 1 ] && echo "[BUILD_DEBUG] cd succeeded, PWD=$PWD" || true + + export PNPM_HOME="$PWD/.pnpm_home" + export PNPM_STORE_PATH="$PNPM_STORE" + export PNPM_HARD_LINKS=false + + # Copy .env file from main repo if it exists and isn't present in worktree + if [ ! -f .env ] && [ -f "$REPO_ROOT/rfc-edge-frontend/.env" ]; then + [ "$VERBOSE" -eq 1 ] && echo "[BUILD_DEBUG] Copying .env file from main repo" || true + cp "$REPO_ROOT/rfc-edge-frontend/.env" .env + elif [ -f .env ]; then + [ "$VERBOSE" -eq 1 ] && echo "[BUILD_DEBUG] .env file already exists in worktree" || true + else + [ "$VERBOSE" -eq 1 ] && echo "[BUILD_DEBUG] No .env file found in main repo" || true + fi + + [ "$VERBOSE" -eq 1 ] && echo "[BUILD_DEBUG] Environment variables set:" || true + [ "$VERBOSE" -eq 1 ] && echo "[BUILD_DEBUG] PNPM_HOME=$PNPM_HOME" || true + [ "$VERBOSE" -eq 1 ] && echo "[BUILD_DEBUG] PNPM_STORE_PATH=$PNPM_STORE_PATH" || true + + mkdir -p "$PNPM_HOME" "$PNPM_STORE_PATH" + [ "$VERBOSE" -eq 1 ] && echo "[BUILD_DEBUG] Created pnpm directories" || true + + [ "$VERBOSE" -eq 1 ] && echo "[BUILD_DEBUG] Running pnpm install..." || true + if [ "$VERBOSE" -eq 1 ]; then + pnpm install --frozen-lockfile /dev/null 2>&1 + fi || { + echo "❌ pnpm install failed" + return 1 + } + [ "$VERBOSE" -eq 1 ] && echo "[BUILD_DEBUG] pnpm install succeeded" || true + + [ "$VERBOSE" -eq 1 ] && echo "[BUILD_DEBUG] Running pnpm build..." || true + if [ "$VERBOSE" -eq 1 ]; then + pnpm build /dev/null 2>&1 + fi || { + echo "❌ pnpm build failed" + return 1 + } + [ "$VERBOSE" -eq 1 ] && echo "[BUILD_DEBUG] pnpm build succeeded" || true + + [ "$VERBOSE" -eq 1 ] && echo "[BUILD_DEBUG] Running pnpm check..." || true + if [ "$VERBOSE" -eq 1 ]; then + pnpm check /dev/null 2>&1 + fi || { + echo "❌ pnpm check failed" + return 1 + } + [ "$VERBOSE" -eq 1 ] && echo "[BUILD_DEBUG] pnpm check succeeded" || true + ) +} + +# ----------------------------- +# Ctrl-C cleanup +# ----------------------------- +cleanup() { + echo " +Caught interrupt, cleaning worktrees…" >&2 + git worktree prune >/dev/null 2>&1 || true + rm -rf "$TMP_BASE" >/dev/null 2>&1 || true + exit 130 +} +trap cleanup INT + +# ----------------------------- +# Commit checker +# ----------------------------- +check_commit() { + local commit="$1" + local worktree="$2" + local log="$3" + + [ "$VERBOSE" -eq 1 ] && debug "check_commit() called for $commit" || true + [ "$VERBOSE" -eq 1 ] && debug " worktree: $worktree" || true + [ "$VERBOSE" -eq 1 ] && debug " log: $log" || true + + ( + set -euo pipefail + echo "===== COMMIT $commit =====" + + [ "$VERBOSE" -eq 1 ] && echo "[CHECK_DEBUG] Adding worktree at $worktree" || true + git worktree add --force --detach "$worktree" "$commit" >/dev/null + [ "$VERBOSE" -eq 1 ] && echo "[CHECK_DEBUG] Worktree created, changing directory" || true + cd "$worktree" + [ "$VERBOSE" -eq 1 ] && echo "[CHECK_DEBUG] In worktree, PWD=$PWD" || true + + if [ -d rfc-edge-frontend ]; then + [ "$VERBOSE" -eq 1 ] && echo "[CHECK_DEBUG] Found rfc-edge-frontend directory" || true + echo "→ Building frontend…" + if ! build_frontend; then + echo "❌ Frontend build failed" + exit 1 + fi + [ "$VERBOSE" -eq 1 ] && echo "[CHECK_DEBUG] Frontend build completed successfully" || true + else + [ "$VERBOSE" -eq 1 ] && echo "[CHECK_DEBUG] No rfc-edge-frontend directory found, skipping frontend build" || true + fi + + echo "→ Running cargo check…" + [ "$VERBOSE" -eq 1 ] && echo "[CHECK_DEBUG] Starting cargo check" || true + if ! cargo check --quiet; then + echo "❌ Cargo check failed" + exit 1 + fi + [ "$VERBOSE" -eq 1 ] && echo "[CHECK_DEBUG] Cargo check completed successfully" || true + + echo "✓ OK" + ) >"$log" 2>&1 + + return $? +} + +# ----------------------------- +# Sequential execution +# ----------------------------- +FAIL=0 +i=1 +TOTAL=${#COMMITS[@]} +for commit in "${COMMITS[@]}"; do + worktree="$WORKTREES_DIR/$commit" + log="$LOGS_DIR/$commit.log" + + debug "===== Processing commit $i/$TOTAL =====" + debug "Commit: $commit" + debug "Worktree: $worktree" + debug "Log file: $log" + + echo "[ $i / $TOTAL ] Checking $commit…" + if ! check_commit "$commit" "$worktree" "$log"; then + echo "❌ FAILED at commit $commit" + sed 's/^/ /' "$log" + FAIL=1 + break + fi + debug "Commit $commit passed" + sed 's/^/ /' "$log" + + debug "Removing worktree at $worktree" + git worktree remove --force "$worktree" >/dev/null 2>&1 + + ((i++)) + echo +done + +# ----------------------------- +# Final output +# ----------------------------- +if [ "$FAIL" -eq 1 ]; then + echo "❌ Stopped early due to failure." + debug "Cleaning up: removing $TMP_BASE" +else + echo "🎉 All commits passed!" + debug "All commits verified successfully" + debug "Cleaning up: removing $TMP_BASE" +fi +rm -rf "$TMP_BASE" >/dev/null 2>&1 +debug "Cleanup complete" +