|
|
#!/usr/bin/env bash |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
set -euo pipefail |
|
|
|
|
|
echo "🔍 Running pre-commit checks for PiFlash..." |
|
|
|
|
|
|
|
|
RED='\033[0;31m' |
|
|
GREEN='\033[0;32m' |
|
|
YELLOW='\033[1;33m' |
|
|
BLUE='\033[0;34m' |
|
|
NC='\033[0m' |
|
|
|
|
|
|
|
|
print_status() { |
|
|
echo -e "${BLUE}[PiFlash]${NC} $1" |
|
|
} |
|
|
|
|
|
print_success() { |
|
|
echo -e "${GREEN}✅${NC} $1" |
|
|
} |
|
|
|
|
|
print_warning() { |
|
|
echo -e "${YELLOW}⚠️${NC} $1" |
|
|
} |
|
|
|
|
|
print_error() { |
|
|
echo -e "${RED}❌${NC} $1" |
|
|
} |
|
|
|
|
|
|
|
|
if ! git rev-parse --git-dir > /dev/null 2>&1; then |
|
|
print_error "Not in a git repository" |
|
|
exit 1 |
|
|
fi |
|
|
|
|
|
|
|
|
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM) |
|
|
|
|
|
if [ -z "$STAGED_FILES" ]; then |
|
|
print_warning "No staged files found" |
|
|
exit 0 |
|
|
fi |
|
|
|
|
|
print_status "Staged files: $(echo $STAGED_FILES | wc -w)" |
|
|
|
|
|
|
|
|
print_status "Validating HTML files..." |
|
|
HTML_FILES=$(echo "$STAGED_FILES" | grep -E '\.(html|htm)$' || true) |
|
|
if [ -n "$HTML_FILES" ]; then |
|
|
for file in $HTML_FILES; do |
|
|
if [ -f "$file" ]; then |
|
|
|
|
|
if ! grep -q "<!DOCTYPE html>" "$file"; then |
|
|
print_error "Missing DOCTYPE in $file" |
|
|
exit 1 |
|
|
fi |
|
|
|
|
|
|
|
|
if ! grep -q "<html" "$file" || ! grep -q "</html>" "$file"; then |
|
|
print_error "Invalid HTML structure in $file" |
|
|
exit 1 |
|
|
fi |
|
|
|
|
|
print_success "HTML validation passed for $file" |
|
|
fi |
|
|
done |
|
|
else |
|
|
print_status "No HTML files to validate" |
|
|
fi |
|
|
|
|
|
|
|
|
print_status "Validating CSS files..." |
|
|
CSS_FILES=$(echo "$STAGED_FILES" | grep -E '\.(css|scss|sass)$' || true) |
|
|
if [ -n "$CSS_FILES" ]; then |
|
|
for file in $CSS_FILES; do |
|
|
if [ -f "$file" ]; then |
|
|
|
|
|
if ! node -e " |
|
|
const fs = require('fs'); |
|
|
const css = fs.readFileSync('$file', 'utf8'); |
|
|
const openBraces = (css.match(/\{/g) || []).length; |
|
|
const closeBraces = (css.match(/\}/g) || []).length; |
|
|
if (openBraces !== closeBraces) { |
|
|
console.error('Mismatched braces in CSS'); |
|
|
process.exit(1); |
|
|
} |
|
|
" 2>/dev/null; then |
|
|
print_error "CSS syntax error in $file" |
|
|
exit 1 |
|
|
fi |
|
|
|
|
|
print_success "CSS validation passed for $file" |
|
|
fi |
|
|
done |
|
|
else |
|
|
print_status "No CSS files to validate" |
|
|
fi |
|
|
|
|
|
|
|
|
print_status "Validating JavaScript files..." |
|
|
JS_FILES=$(echo "$STAGED_FILES" | grep -E '\.(js|jsx|ts|tsx)$' || true) |
|
|
if [ -n "$JS_FILES" ]; then |
|
|
for file in $JS_FILES; do |
|
|
if [ -f "$file" ]; then |
|
|
|
|
|
if ! node -c "$file" 2>/dev/null; then |
|
|
print_error "JavaScript syntax error in $file" |
|
|
exit 1 |
|
|
fi |
|
|
|
|
|
|
|
|
if grep -q "console\.log" "$file"; then |
|
|
print_warning "console.log found in $file - consider removing for production" |
|
|
fi |
|
|
|
|
|
|
|
|
if grep -qi "TODO\|FIXME\|HACK" "$file"; then |
|
|
print_warning "TODO/FIXME/HACK comments found in $file" |
|
|
fi |
|
|
|
|
|
print_success "JavaScript validation passed for $file" |
|
|
fi |
|
|
done |
|
|
else |
|
|
print_status "No JavaScript files to validate" |
|
|
fi |
|
|
|
|
|
|
|
|
print_status "Validating JSON files..." |
|
|
JSON_FILES=$(echo "$STAGED_FILES" | grep -E '\.(json)$' || true) |
|
|
if [ -n "$JSON_FILES" ]; then |
|
|
for file in $JSON_FILES; do |
|
|
if [ -f "$file" ]; then |
|
|
if ! node -e "JSON.parse(require('fs').readFileSync('$file', 'utf8'))" 2>/dev/null; then |
|
|
print_error "Invalid JSON in $file" |
|
|
exit 1 |
|
|
fi |
|
|
|
|
|
print_success "JSON validation passed for $file" |
|
|
fi |
|
|
done |
|
|
else |
|
|
print_status "No JSON files to validate" |
|
|
fi |
|
|
|
|
|
|
|
|
print_status "Checking file sizes..." |
|
|
for file in $STAGED_FILES; do |
|
|
if [ -f "$file" ]; then |
|
|
file_size=$(stat -f%z "$file" 2>/dev/null || stat -c%s "$file" 2>/dev/null || echo 0) |
|
|
max_size=1048576 |
|
|
|
|
|
if [ "$file_size" -gt "$max_size" ]; then |
|
|
print_error "File $file is too large ($(($file_size / 1024))KB > 1MB)" |
|
|
exit 1 |
|
|
fi |
|
|
fi |
|
|
done |
|
|
print_success "File size check passed" |
|
|
|
|
|
|
|
|
print_status "Checking line endings..." |
|
|
for file in $STAGED_FILES; do |
|
|
if [ -f "$file" ]; then |
|
|
|
|
|
if file "$file" | grep -q "CRLF"; then |
|
|
print_warning "CRLF line endings found in $file - consider using LF" |
|
|
fi |
|
|
fi |
|
|
done |
|
|
print_success "Line ending check completed" |
|
|
|
|
|
|
|
|
print_status "Checking for trailing whitespace..." |
|
|
WHITESPACE_FILES="" |
|
|
for file in $STAGED_FILES; do |
|
|
if [ -f "$file" ]; then |
|
|
if grep -q '[[:space:]]$' "$file"; then |
|
|
WHITESPACE_FILES="$WHITESPACE_FILES $file" |
|
|
fi |
|
|
fi |
|
|
done |
|
|
|
|
|
if [ -n "$WHITESPACE_FILES" ]; then |
|
|
print_warning "Trailing whitespace found in:$WHITESPACE_FILES" |
|
|
print_status "Attempting to fix trailing whitespace..." |
|
|
|
|
|
for file in $WHITESPACE_FILES; do |
|
|
|
|
|
sed -i 's/[[:space:]]*$//' "$file" |
|
|
git add "$file" |
|
|
done |
|
|
|
|
|
print_success "Trailing whitespace fixed and re-staged" |
|
|
fi |
|
|
|
|
|
|
|
|
if [ -n "${1:-}" ]; then |
|
|
COMMIT_MSG_FILE="$1" |
|
|
if [ -f "$COMMIT_MSG_FILE" ]; then |
|
|
commit_msg=$(head -n1 "$COMMIT_MSG_FILE") |
|
|
|
|
|
|
|
|
if [ ${#commit_msg} -gt 72 ]; then |
|
|
print_warning "Commit message is longer than 72 characters" |
|
|
fi |
|
|
|
|
|
|
|
|
if echo "$commit_msg" | grep -qE '^(feat|fix|docs|style|refactor|test|chore)(\(.+\))?: .+'; then |
|
|
print_success "Conventional commit format detected" |
|
|
else |
|
|
print_warning "Consider using conventional commit format (feat:, fix:, docs:, etc.)" |
|
|
fi |
|
|
fi |
|
|
fi |
|
|
|
|
|
|
|
|
print_status "Scanning for sensitive data..." |
|
|
SENSITIVE_PATTERNS=( |
|
|
"password\s*=\s*['\"][^'\"]*['\"]" |
|
|
"api[_-]?key\s*=\s*['\"][^'\"]*['\"]" |
|
|
"secret\s*=\s*['\"][^'\"]*['\"]" |
|
|
"token\s*=\s*['\"][^'\"]*['\"]" |
|
|
"private[_-]?key" |
|
|
) |
|
|
|
|
|
for file in $STAGED_FILES; do |
|
|
if [ -f "$file" ]; then |
|
|
for pattern in "${SENSITIVE_PATTERNS[@]}"; do |
|
|
if grep -iE "$pattern" "$file" >/dev/null 2>&1; then |
|
|
print_error "Potential sensitive data found in $file: $pattern" |
|
|
print_error "Please review and remove sensitive information before committing" |
|
|
exit 1 |
|
|
fi |
|
|
done |
|
|
fi |
|
|
done |
|
|
print_success "Security scan completed" |
|
|
|
|
|
|
|
|
print_success "All pre-commit checks passed!" |
|
|
print_status "Ready to commit $(echo $STAGED_FILES | wc -w) files" |
|
|
|
|
|
exit 0 |
|
|
|