From 5c65b5666b0b5844e4af6535b372d6ab2776b890 Mon Sep 17 00:00:00 2001 From: Wojtek Majewski Date: Wed, 19 Nov 2025 06:15:34 +0100 Subject: [PATCH] improve git hooks --- .envrc.local.example | 6 ++++ .lefthook/pre-push/prevent-push-to-main.sh | 29 +++++++++++------- LOCAL_DEV.md | 18 +++++++++++ lefthook.yml | 35 ++++++++++++++++++++++ 4 files changed, 77 insertions(+), 11 deletions(-) create mode 100644 .envrc.local.example create mode 100644 LOCAL_DEV.md diff --git a/.envrc.local.example b/.envrc.local.example new file mode 100644 index 000000000..67e87d890 --- /dev/null +++ b/.envrc.local.example @@ -0,0 +1,6 @@ +# Local environment variables (copy to .envrc.local and customize) + +# Path to Claude symlink script (runs on git checkout) +# Claude skills are in pgflow-dev/claude private repo +# See LOCAL_DEV.md for details +# export CLAUDE_SYMLINK_SCRIPT="/path/to/your/claude/symlink.sh" diff --git a/.lefthook/pre-push/prevent-push-to-main.sh b/.lefthook/pre-push/prevent-push-to-main.sh index 781884b0e..61c3bf8dc 100755 --- a/.lefthook/pre-push/prevent-push-to-main.sh +++ b/.lefthook/pre-push/prevent-push-to-main.sh @@ -1,7 +1,8 @@ #!/bin/bash +set -e # Check current branch -branch=$(git rev-parse --abbrev-ref HEAD) +branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null) if [ "$branch" = "main" ]; then echo "ERROR: Direct pushes from main branch are not allowed!" exit 1 @@ -9,15 +10,21 @@ fi # Check destination branch (handles: git push origin feature:main) # Git hook receives: per line -# Note: Using timeout because lefthook's script execution may keep stdin open -while read -r -t 0.5 local_ref local_sha remote_ref remote_sha || [ -n "$local_ref" ]; do - [ -z "$remote_ref" ] && break - remote_branch=$(echo "$remote_ref" | sed 's#^refs/heads/##') - if [ "$remote_branch" = "main" ]; then - echo "ERROR: Pushing to remote main branch is not allowed!" - echo "Attempted: $local_ref -> $remote_ref" - exit 1 - fi -done +# Only read if stdin is available (not a tty) +if [ ! -t 0 ]; then + while IFS=' ' read -r local_ref local_sha remote_ref remote_sha; do + # Skip empty lines + [ -z "$remote_ref" ] && continue + + # Extract branch name from ref + remote_branch="${remote_ref#refs/heads/}" + + if [ "$remote_branch" = "main" ]; then + echo "ERROR: Pushing to remote main branch is not allowed!" + echo "Attempted: $local_ref -> $remote_ref" + exit 1 + fi + done +fi exit 0 diff --git a/LOCAL_DEV.md b/LOCAL_DEV.md new file mode 100644 index 000000000..55ee34855 --- /dev/null +++ b/LOCAL_DEV.md @@ -0,0 +1,18 @@ +# Local Development Setup + +This document contains setup instructions specific to local development environments. + +> **Note**: This is a starting point and will be expanded with more comprehensive setup instructions in the future. + +## Claude Symlink Hook + +Claude Code skills and configuration are stored in a separate private repository (`pgflow-dev/claude`). If you have access to this repository and need the `.claude/` directory to be symlinked on branch changes, configure the following: + +1. Add to your `.envrc.local`: + ```bash + export CLAUDE_SYMLINK_SCRIPT="/path/to/your/claude/symlink.sh" + ``` + +2. Run `direnv allow` to reload the environment + +The `post-checkout` hook in `lefthook.yml` will automatically run this script whenever you switch branches. diff --git a/lefthook.yml b/lefthook.yml index d56e13bad..74bfe5393 100644 --- a/lefthook.yml +++ b/lefthook.yml @@ -21,7 +21,42 @@ pre-commit: run: | ./scripts/validate-json-files.sh +post-checkout: + commands: + 'pnpm-install-on-deps-change': + run: | + # Only run if pnpm is available + if ! command -v pnpm &> /dev/null; then + echo "\033[33mWarning: pnpm not available, skipping dependency installation.\033[0m" + exit 0 + fi + + # Only run for branch checkouts (not file checkouts) + if [ "{3}" = "1" ]; then + # Always install if node_modules doesn't exist (new worktree case) + if [ ! -d "node_modules" ]; then + echo "📦 node_modules not found, running pnpm install --frozen-lockfile..." + pnpm install --frozen-lockfile + # Otherwise, only install if dependencies changed + elif git diff --name-only {1} {2} | grep -qE '^(package\.json|pnpm-lock\.yaml|pnpm-workspace\.yaml)$'; then + echo "📦 Dependencies changed, running pnpm install --frozen-lockfile..." + pnpm install --frozen-lockfile + fi + fi + 'claude-symlink': + run: | + if [ -n "$CLAUDE_SYMLINK_SCRIPT" ] && [ -f "$CLAUDE_SYMLINK_SCRIPT" ]; then + "$CLAUDE_SYMLINK_SCRIPT" "$PWD" + elif [ -z "$CLAUDE_SYMLINK_SCRIPT" ]; then + echo "\033[33mWarning: CLAUDE_SYMLINK_SCRIPT not set. See LOCAL_DEV.md for setup instructions.\033[0m" + fi + pre-push: + commands: + 'nx-affected-checks': + run: pnpm nx affected --target=lint,build --base=origin/main --head=HEAD scripts: 'prevent-push-to-main.sh': runner: bash + skip_output: + - meta