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"
0 commit comments