Skip to content

Commit c4bc979

Browse files
justin808claude
andcommitted
Add smart pre-commit hooks to prevent CI failures
Features: - Checks all files changed in current branch vs master (not just staged files) - Runs RuboCop on Ruby files with auto-fix suggestions - Runs Prettier on JS/TS/JSON/MD files with auto-fix suggestions - Validates trailing newlines on all changed files - Fast execution - only checks files modified in the branch - Provides helpful error messages and fix commands - Includes install script for easy team setup Benefits: - Prevents CI failures from linting issues - Catches problems before they reach remote - Only processes relevant files for speed - Shows exactly what files are being checked - Gives actionable fix commands Usage: - Run ./bin/install-git-hooks to set up - Hook runs automatically before each commit - Use git commit --no-verify to bypass if needed 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent 349dca2 commit c4bc979

File tree

2 files changed

+132
-1
lines changed

2 files changed

+132
-1
lines changed

bin/install-git-hooks

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
#!/bin/bash
2+
# Install Git hooks for React on Rails development
3+
# This script sets up pre-commit hooks to prevent CI failures
4+
5+
set -e
6+
7+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
8+
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
9+
HOOKS_DIR="$REPO_ROOT/.git/hooks"
10+
11+
echo "🪝 Installing Git hooks for React on Rails..."
12+
13+
# Ensure hooks directory exists
14+
mkdir -p "$HOOKS_DIR"
15+
16+
# Install pre-commit hook
17+
cat > "$HOOKS_DIR/pre-commit" << 'EOF'
18+
#!/bin/sh
19+
# Pre-commit hook to run linting and formatting on all branch changes vs master
20+
# This prevents CI failures by catching issues early on all modified files
21+
22+
set -e
23+
24+
echo "🔍 Running pre-commit checks on branch changes..."
25+
26+
# Find the merge base with master to get all files changed in this branch
27+
MERGE_BASE=$(git merge-base HEAD origin/master 2>/dev/null || git merge-base HEAD master 2>/dev/null || echo "master")
28+
29+
# Get all files changed in this branch (both staged and unstaged)
30+
BRANCH_FILES=$(git diff --name-only "$MERGE_BASE"...HEAD 2>/dev/null || true)
31+
UNSTAGED_FILES=$(git diff --name-only 2>/dev/null || true)
32+
33+
# Combine and deduplicate files, filter out invalid entries
34+
ALL_CHANGED_FILES=$(echo -e "$BRANCH_FILES\n$UNSTAGED_FILES" | sort -u | grep -v '^$' | grep -v '^-' || true)
35+
36+
if [ -z "$ALL_CHANGED_FILES" ]; then
37+
echo "ℹ️ No changed files to check in this branch"
38+
exit 0
39+
fi
40+
41+
echo "📝 Files changed in this branch vs master:"
42+
echo "$ALL_CHANGED_FILES" | sed 's/^/ - /'
43+
44+
# Track if any checks fail
45+
CHECKS_FAILED=0
46+
47+
# Check Ruby files with RuboCop
48+
RUBY_FILES=$(echo "$ALL_CHANGED_FILES" | grep -E '\.(rb|rake)$' | grep -v '^$' || true)
49+
if [ -n "$RUBY_FILES" ]; then
50+
echo ""
51+
echo "🔍 Checking Ruby files with RuboCop..."
52+
RUBY_FILES_LIST=$(echo "$RUBY_FILES" | tr '\n' ' ')
53+
if ! bundle exec rubocop $RUBY_FILES_LIST; then
54+
echo "❌ RuboCop check failed!"
55+
echo "💡 Auto-fix: bundle exec rubocop $RUBY_FILES_LIST --auto-correct"
56+
CHECKS_FAILED=1
57+
else
58+
echo "✅ RuboCop checks passed for Ruby files"
59+
fi
60+
fi
61+
62+
# Check JS/TS/JSON/MD files with Prettier
63+
PRETTIER_FILES=$(echo "$ALL_CHANGED_FILES" | grep -E '\.(js|jsx|ts|tsx|json|md|yml|yaml)$' | grep -v '^$' || true)
64+
if [ -n "$PRETTIER_FILES" ]; then
65+
echo ""
66+
echo "🔍 Checking formatting with Prettier..."
67+
PRETTIER_FILES_LIST=$(echo "$PRETTIER_FILES" | tr '\n' ' ')
68+
if ! yarn run prettier --check $PRETTIER_FILES_LIST 2>/dev/null; then
69+
echo "❌ Prettier check failed!"
70+
echo "💡 Auto-fix: yarn run prettier --write $PRETTIER_FILES_LIST"
71+
CHECKS_FAILED=1
72+
else
73+
echo "✅ Prettier checks passed for JS/TS/MD files"
74+
fi
75+
fi
76+
77+
# Check for missing trailing newlines in tracked files
78+
echo ""
79+
echo "🔍 Checking for trailing newlines..."
80+
NEWLINE_ISSUES=""
81+
for file in $ALL_CHANGED_FILES; do
82+
if [ -f "$file" ] && [ -s "$file" ]; then
83+
if ! tail -c 1 "$file" | grep -q '^$'; then
84+
echo "❌ Missing trailing newline: $file"
85+
NEWLINE_ISSUES="$NEWLINE_ISSUES $file"
86+
CHECKS_FAILED=1
87+
fi
88+
fi
89+
done
90+
91+
if [ -z "$NEWLINE_ISSUES" ]; then
92+
echo "✅ All files have proper trailing newlines"
93+
fi
94+
95+
# Summary
96+
echo ""
97+
if [ $CHECKS_FAILED -eq 0 ]; then
98+
echo "✅ All pre-commit checks passed!"
99+
echo "📊 Checked $(echo "$ALL_CHANGED_FILES" | wc -l | tr -d ' ') files changed in this branch"
100+
exit 0
101+
else
102+
echo "❌ Pre-commit checks failed!"
103+
echo "🛠️ Please fix the issues above and try committing again."
104+
echo ""
105+
echo "🚀 Quick fixes:"
106+
if [ -n "$RUBY_FILES" ]; then
107+
echo " Ruby: bundle exec rubocop $(echo "$RUBY_FILES" | tr '\n' ' ') --auto-correct"
108+
fi
109+
if [ -n "$PRETTIER_FILES" ]; then
110+
echo " Format: yarn run prettier --write $(echo "$PRETTIER_FILES" | tr '\n' ' ')"
111+
fi
112+
if [ -n "$NEWLINE_ISSUES" ]; then
113+
echo " Newlines: Add trailing newline to:$NEWLINE_ISSUES"
114+
fi
115+
echo ""
116+
echo "📊 Failed on $(echo "$ALL_CHANGED_FILES" | wc -l | tr -d ' ') files changed in this branch"
117+
exit 1
118+
fi
119+
EOF
120+
121+
# Make hook executable
122+
chmod +x "$HOOKS_DIR/pre-commit"
123+
124+
echo "✅ Pre-commit hook installed successfully!"
125+
echo ""
126+
echo "🚀 The hook will now run automatically before each commit and check:"
127+
echo " - RuboCop for Ruby files changed in your branch"
128+
echo " - Prettier for JS/TS/JSON/MD files changed in your branch"
129+
echo " - Trailing newlines for all changed files"
130+
echo ""
131+
echo "💡 To skip the hook temporarily: git commit --no-verify"
132+
echo "🔧 To uninstall: rm $HOOKS_DIR/pre-commit"

test-file.md

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)