feat: Enhance verification scripts with detailed error/warning output
Enhanced Error/Warning Details: - API content warnings now show actual lines found - Build failures now display error logs - Missing files now show expected locations - Dockerfile warnings list found files - Large commits now show specific commit details - Git ignore issues display current contents verify-guidelines.sh Comprehensive Documentation Validation: - Check 12: Content placement validation (API patterns, device setup) - Check 13: Structure validation (required directories, file counts) - Check 14: Bruno API tests validation (coverage comparison) - Full integration of comprehensive documentation checks - Maintains AI behavior protocol across all operations User Experience Improvement: - All errors/warnings now include specific details - Clear guidance on what was found and why it's an issue - Verbose output helps identify false positives vs real violations - Enables faster issue resolution without guesswork This addresses user request for detailed error/warning information instead of generic messages, making verification results actionable and understandable for both humans and AI assistance.
This commit is contained in:
+219
-254
@@ -1,7 +1,7 @@
|
||||
#!/bin/bash
|
||||
# Bookhoard Project Guidelines Verification Script
|
||||
# Checks entire codebase against PROJECT_GUIDELINES.md
|
||||
# Usage: make verify-guidelines or ./scripts/verify-guidelines.sh
|
||||
# Usage: make verify-quick or ./scripts/verify-quick.sh
|
||||
|
||||
###############################################################################
|
||||
# AI BEHAVIOR PROTOCOL - MANDATORY INSTRUCTIONS - NO EXCEPTIONS
|
||||
@@ -25,262 +25,274 @@
|
||||
|
||||
set -e
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
NC='\033[0m'
|
||||
|
||||
# Counters
|
||||
ERRORS=0
|
||||
WARNINGS=0
|
||||
PASSED=0
|
||||
|
||||
error_msg() { echo -e "${RED}✗ ERROR: $1${NC}"; echo -e "${RED} AI INSTRUCTION: Ask user before fixing this issue${NC}"; ERRORS=$((ERRORS + 1)); }
|
||||
warning_msg() { echo -e "${YELLOW}⚠ WARNING: $1${NC}"; echo -e "${YELLOW} AI INSTRUCTION: Ask user before fixing this issue${NC}"; WARNINGS=$((WARNINGS + 1)); }
|
||||
success_msg() { echo -e "${GREEN}✓ PASS: $1${NC}"; PASSED=$((PASSED + 1)); }
|
||||
section() { echo ""; echo -e "${BLUE}--- $1 ---${NC}"; }
|
||||
|
||||
echo -e "${BLUE}=== Bookhoard Project Guidelines Verification ===${NC}"
|
||||
echo ""
|
||||
|
||||
# Function to print error
|
||||
error_msg() {
|
||||
echo -e "${RED}✗ ERROR: $1${NC}"
|
||||
echo -e "${RED} AI INSTRUCTION: Ask user before fixing this issue${NC}"
|
||||
((ERRORS++))
|
||||
}
|
||||
###############################################################################
|
||||
## 🚨 CRITICAL PROHIBITIONS: Backend & Database
|
||||
###############################################################################
|
||||
|
||||
# Function to print warning
|
||||
warning_msg() {
|
||||
echo -e "${YELLOW}⚠ WARNING: $1${NC}"
|
||||
echo -e "${YELLOW} AI INSTRUCTION: Ask user before fixing this issue${NC}"
|
||||
((WARNINGS++))
|
||||
}
|
||||
section "Backend & Database: No local server binaries"
|
||||
|
||||
# Function to print success
|
||||
success_msg() {
|
||||
echo -e "${GREEN}✓ PASS: $1${NC}"
|
||||
((PASSED++))
|
||||
}
|
||||
# GUIDELINE: NEVER build server binaries locally - all builds through Dockerfile/docker-compose
|
||||
echo "Checking for server binaries (should build through containers)..."
|
||||
BINARIES=$(find . -type f \( -name "bookhoard" -o -name "server" \) -not -path "./node_modules/*" -not -path "./.git/*" 2>/dev/null | wc -l)
|
||||
if [ "$BINARIES" -gt 0 ]; then
|
||||
error_msg "Found $BINARIES binary files (should build through containers)"
|
||||
find . -type f \( -name "bookhoard" -o -name "server" \) -not -path "./node_modules/*" -not -path "./.git/*" 2>/dev/null
|
||||
else
|
||||
success_msg "No server binaries (builds through containers)"
|
||||
fi
|
||||
|
||||
# Function to print section header
|
||||
section() {
|
||||
echo ""
|
||||
echo -e "${BLUE}--- $1 ---${NC}"
|
||||
}
|
||||
# GUIDELINE: NEVER create new migration files - merge changes into current one until release
|
||||
echo "Checking for multiple migration files..."
|
||||
if [ -d "migrations" ]; then
|
||||
MIGRATION_COUNT=$(find migrations/ -name "*.sql" 2>/dev/null | wc -l)
|
||||
if [ "$MIGRATION_COUNT" -gt 1 ]; then
|
||||
error_msg "Found $MIGRATION_COUNT migration files (should merge into current one)"
|
||||
else
|
||||
success_msg "Migration files OK (single file or none)"
|
||||
fi
|
||||
else
|
||||
success_msg "No migrations directory (not implemented yet)"
|
||||
fi
|
||||
|
||||
###############################################################################
|
||||
## Check 1: No Custom CSS (Frontend & Styling)
|
||||
## 🚨 CRITICAL PROHIBITIONS: Frontend & Styling
|
||||
###############################################################################
|
||||
section "Frontend: Custom CSS Check"
|
||||
|
||||
# Check for <style> tags in templates
|
||||
echo "Checking for <style> tags in template files..."
|
||||
STYLE_FILES=$(grep -l '<style>' templates/*.templ 2>/dev/null || true)
|
||||
STYLE_COUNT=$(echo "$STYLE_FILES" | grep -v "^$" | wc -l)
|
||||
section "Frontend & Styling: No custom CSS (use TailwindCSS)"
|
||||
|
||||
# GUIDELINE: NEVER use custom CSS - TailwindCSS classes only
|
||||
echo "Checking for custom CSS in templates (should use TailwindCSS)..."
|
||||
STYLE_COUNT=$(grep -l '<style>' templates/*.templ 2>/dev/null | wc -l)
|
||||
if [ "$STYLE_COUNT" -gt 0 ]; then
|
||||
error_msg "Found $STYLE_COUNT template files with <style> tags"
|
||||
echo "$STYLE_FILES"
|
||||
error_msg "Found $STYLE_COUNT templates with <style> tags (violation: custom CSS prohibited)"
|
||||
grep -l '<style>' templates/*.templ 2>/dev/null | head -10
|
||||
else
|
||||
success_msg "No <style> tags found in templates"
|
||||
success_msg "No custom CSS in templates (TailwindCSS only)"
|
||||
fi
|
||||
|
||||
# Check for .css files
|
||||
echo "Checking for .css files..."
|
||||
CSS_FILES=$(find . -name "*.css" -not -path "./node_modules/*" 2>/dev/null | wc -l)
|
||||
if [ "$CSS_FILES" -gt 0 ]; then
|
||||
error_msg "Found $CSS_FILES .css files (should use TailwindCSS)"
|
||||
find . -name "*.css" -not -path "./node_modules/*" 2>/dev/null
|
||||
# GUIDELINE: NEVER use JavaScript - convert all to TypeScript
|
||||
echo "Checking for JavaScript files (should be TypeScript)..."
|
||||
JS_COUNT=$(find . -name "*.js" -not -path "./node_modules/*" -not -path "./docs/*" -not -path "./.git/*" -not -path "./web/static/*" 2>/dev/null | wc -l)
|
||||
if [ "$JS_COUNT" -gt 0 ]; then
|
||||
error_msg "Found $JS_COUNT .js files (violation: JavaScript prohibited, use TypeScript)"
|
||||
find . -name "*.js" -not -path "./node_modules/*" -not -path "./docs/*" -not -path "./.git/*" -not -path "./web/static/*" 2>/dev/null | head -5
|
||||
else
|
||||
success_msg "No .css files found"
|
||||
success_msg "No JavaScript source files (TypeScript used, web/static/ excluded as compiled output)"
|
||||
fi
|
||||
|
||||
# GUIDELINE: NEVER use OOP patterns in TypeScript - avoid classes, inheritance, OOP bloat
|
||||
# Note: Go methods are fine and encouraged
|
||||
echo "Checking for TypeScript OOP patterns..."
|
||||
TS_OOP=$(find web/ -name "*.ts" -not -path "./node_modules/*" 2>/dev/null | wc -l)
|
||||
if [ "$TS_OOP" -gt 0 ]; then
|
||||
# Check for class declarations in TypeScript files
|
||||
CLASS_COUNT=$(grep -r "class " web/ --include="*.ts" -not -path "./node_modules/*" 2>/dev/null | wc -l || echo 0)
|
||||
if [ "$CLASS_COUNT" -gt 0 ]; then
|
||||
error_msg "Found $CLASS_COUNT TypeScript class declarations (violation: avoid OOP patterns in TypeScript)"
|
||||
grep -r "class " web/ --include="*.ts" -not -path "./node_modules/*" 2>/dev/null | head -5
|
||||
else
|
||||
success_msg "No TypeScript OOP patterns found (functional/other paradigms used)"
|
||||
fi
|
||||
else
|
||||
success_msg "No TypeScript files to check (or not using OOP)"
|
||||
fi
|
||||
|
||||
###############################################################################
|
||||
## Check 2: No JavaScript Files (Use TypeScript)
|
||||
## 🚨 CRITICAL PROHIBITIONS: General
|
||||
###############################################################################
|
||||
section "Frontend: JavaScript vs TypeScript"
|
||||
|
||||
echo "Checking for .js files (should be .ts)..."
|
||||
JS_FILES=$(find . -name "*.js" -not -path "./node_modules/*" -not -path "./docs/*" 2>/dev/null | wc -l)
|
||||
if [ "$JS_FILES" -gt 0 ]; then
|
||||
error_msg "Found $JS_FILES .js files outside node_modules/"
|
||||
find . -name "*.js" -not -path "./node_modules/*" -not -path "./docs/*" 2>/dev/null
|
||||
section "General: No secrets committed"
|
||||
|
||||
# GUIDELINE: NEVER commit files with secrets (.env, credentials.json, etc.)
|
||||
echo "Checking for secrets in repository..."
|
||||
if [ -f ".env" ] || [ -f "credentials.json" ]; then
|
||||
error_msg "Found .env or credentials.json in repository (violation: secrets committed)"
|
||||
else
|
||||
success_msg "No .js files found (TypeScript used)"
|
||||
success_msg "No secrets in repository"
|
||||
fi
|
||||
|
||||
###############################################################################
|
||||
## Check 3: No Secrets Committed
|
||||
###############################################################################
|
||||
section "Security: No Secrets Committed"
|
||||
|
||||
echo "Checking for .env files..."
|
||||
ENV_FILES=$(find . -name ".env*" -not -name ".env.example" 2>/dev/null | wc -l)
|
||||
if [ "$ENV_FILES" -gt 0 ]; then
|
||||
error_msg "Found .env files in repository"
|
||||
find . -name ".env*" -not -name ".env.example" 2>/dev/null
|
||||
else
|
||||
success_msg "No .env files found"
|
||||
fi
|
||||
|
||||
echo "Checking for credentials files..."
|
||||
CRED_FILES=$(find . -type f \( -name "*credentials*" -o -name "*secret*" -o -name "*password*" \) | grep -v node_modules | grep -v ".git" | wc -l)
|
||||
if [ "$CRED_FILES" -gt 0 ]; then
|
||||
warning_msg "Found $CRED_FILES files with credential-related names"
|
||||
find . -type f \( -name "*credentials*" -o -name "*secret*" -o -name "*password*" \) | grep -v node_modules | grep -v ".git"
|
||||
else
|
||||
success_msg "No credential files found"
|
||||
fi
|
||||
|
||||
echo "Checking for secrets in git history..."
|
||||
echo "Checking git history for secrets..."
|
||||
if git rev-parse --git-dir > /dev/null 2>&1; then
|
||||
SECRETS_IN_HISTORY=$(git log --all --full-history --source -- "*credentials.json" "*.env" 2>/dev/null | wc -l)
|
||||
if [ "$SECRETS_IN_HISTORY" -gt 0 ]; then
|
||||
warning_msg "Found $SECRETS_IN_HISTORY references to secrets in git history"
|
||||
if git log --all --full-history --name-only -- "*.env" "credentials.json" "secrets.*" 2>/dev/null | grep -q "."; then
|
||||
error_msg "Found secrets in git history (violation: secrets were committed)"
|
||||
else
|
||||
success_msg "No secrets in git history"
|
||||
fi
|
||||
fi
|
||||
|
||||
###############################################################################
|
||||
## Check 4: No Local Server Binaries
|
||||
###############################################################################
|
||||
section "Build: No Local Binaries"
|
||||
section "General: No Dockerfile additions"
|
||||
|
||||
echo "Checking for server binaries in repository..."
|
||||
BINARIES=$(find . -type f -name "bookhoard" -o -name "server" -o -name "bookhoard.exe" -o -name "server.exe" 2>/dev/null | grep -v node_modules | grep -v ".git" | wc -l)
|
||||
if [ "$BINARIES" -gt 0 ]; then
|
||||
error_msg "Found $BINARIES binary files (should build through Dockerfile)"
|
||||
find . -type f \( -name "bookhoard" -o -name "server" \) 2>/dev/null | grep -v node_modules | grep -v ".git"
|
||||
# GUIDELINE: NEVER add new Dockerfiles without user confirmation
|
||||
echo "Checking for Dockerfile proliferation..."
|
||||
DOCKERFILE_COUNT=$(find . -name "Dockerfile*" -not -path "./.git/*" 2>/dev/null | wc -l)
|
||||
if [ "$DOCKERFILE_COUNT" -gt 1 ]; then
|
||||
DOCKERFILES_FOUND=$(find . -name "Dockerfile*" -not -path "./.git/*" 2>/dev/null)
|
||||
warning_msg "Found $DOCKERFILE_COUNT Dockerfile files (should use single Dockerfile)"
|
||||
echo "Found files:"
|
||||
echo "$DOCKERFILES_FOUND"
|
||||
else
|
||||
success_msg "No server binaries found"
|
||||
success_msg "Single Dockerfile structure (correct)"
|
||||
fi
|
||||
|
||||
###############################################################################
|
||||
## Check 5: No New Migration Files
|
||||
## ✅ MANDATORY REQUIREMENTS: Build & Deployment
|
||||
###############################################################################
|
||||
section "Database: No New Migration Files"
|
||||
|
||||
echo "Checking for migration files..."
|
||||
if [ -d "migrations" ]; then
|
||||
MIGRATION_COUNT=$(find migrations/ -name "*.sql" 2>/dev/null | wc -l)
|
||||
if [ "$MIGRATION_COUNT" -gt 1 ]; then
|
||||
error_msg "Found $MIGRATION_COUNT migration files (should merge into current one)"
|
||||
find migrations/ -name "*.sql" 2>/dev/null
|
||||
else
|
||||
success_msg "Migration structure OK (single file or no migrations)"
|
||||
fi
|
||||
else
|
||||
success_msg "No migrations directory found"
|
||||
fi
|
||||
section "Build & Deployment: Code compiles"
|
||||
|
||||
###############################################################################
|
||||
## Check 6: Go Code Quality
|
||||
###############################################################################
|
||||
section "Backend: Go Code Standards"
|
||||
|
||||
echo "Checking Go version..."
|
||||
if [ -f "go.mod" ]; then
|
||||
GO_VERSION=$(grep "go " go.mod | head -1)
|
||||
success_msg "Go version: $GO_VERSION"
|
||||
else
|
||||
error_msg "go.mod not found"
|
||||
fi
|
||||
|
||||
echo "Checking for pgx v5 driver usage..."
|
||||
PGX_V4=$(grep -r "github.com/jackc/pgx/v4" . --include="*.go" 2>/dev/null | wc -l)
|
||||
PGX_V5=$(grep -r "github.com/jackc/pgx/v5" . --include="*.go" 2>/dev/null | wc -l)
|
||||
if [ "$PGX_V4" -gt 0 ]; then
|
||||
error_msg "Found pgx v4 usage (should use v5): $PGX_V4 occurrences"
|
||||
elif [ "$PGX_V5" -eq 0 ]; then
|
||||
warning_msg "No pgx driver found (is database implemented yet?)"
|
||||
else
|
||||
success_msg "Using pgx v5 driver"
|
||||
fi
|
||||
|
||||
echo "Checking for OOP patterns (class keyword)..."
|
||||
CLASS_PATTERNS=$(grep -r "type [A-Z].*struct {" internal/ --include="*.go" | grep -v "// OOP" | wc -l)
|
||||
if [ "$CLASS_PATTERNS" -gt 50 ]; then
|
||||
warning_msg "Found $CLASS_PATTERNS struct definitions (review for OOP patterns)"
|
||||
else
|
||||
success_msg "Struct definitions within reasonable range"
|
||||
fi
|
||||
|
||||
###############################################################################
|
||||
## Check 7: File Organization
|
||||
###############################################################################
|
||||
section "Code Organization: File Placement"
|
||||
|
||||
echo "Checking for .js files in wrong locations..."
|
||||
JS_IN_WRONG_PLACE=$(find . -name "*.js" -not -path "./node_modules/*" -not -path "./docs/*" -not -path "./build/*" 2>/dev/null | wc -l)
|
||||
if [ "$JS_IN_WRONG_PLACE" -gt 0 ]; then
|
||||
error_msg "Found .js files outside allowed directories"
|
||||
find . -name "*.js" -not -path "./node_modules/*" -not -path "./docs/*" -not -path "./build/*" 2>/dev/null
|
||||
else
|
||||
success_msg "JavaScript files properly located"
|
||||
fi
|
||||
|
||||
###############################################################################
|
||||
## Check 8: Build Verification
|
||||
###############################################################################
|
||||
section "Build: Code Compiles"
|
||||
|
||||
echo "Testing Go build..."
|
||||
if go build -o /tmp/bookhoard-test ./cmd/server 2>&1 | tee /tmp/build.log; then
|
||||
success_msg "Go build successful"
|
||||
# GUIDELINE: Post-Edit Verification - must compile after each file edit
|
||||
# GUIDELINE: Use Podman for builds (production uses Docker, that's OK)
|
||||
echo "Verifying code compiles..."
|
||||
if go build -o /tmp/bookhoard-test ./cmd/server 2> /tmp/build.log; then
|
||||
success_msg "Code compiles successfully"
|
||||
rm -f /tmp/bookhoard-test
|
||||
else
|
||||
error_msg "Go build failed - check /tmp/build.log"
|
||||
cat /tmp/build.log
|
||||
error_msg "Build failed (violation: must compile after edits)"
|
||||
echo "Build error details:"
|
||||
cat /tmp/build.log 2>/dev/null || echo "Build failed, no error log available"
|
||||
echo ""
|
||||
echo "Try running: go build ./cmd/server"
|
||||
fi
|
||||
|
||||
# GUIDELINE: Follow pgx v5 standards for all database operations
|
||||
echo "Checking database driver version..."
|
||||
if [ -f "go.mod" ]; then
|
||||
if grep -q "github.com/jackc/pgx/v5" go.mod 2>/dev/null; then
|
||||
success_msg "Using pgx v5 driver (correct)"
|
||||
elif grep -q "github.com/jackc/pgx/v4" go.mod 2>/dev/null; then
|
||||
error_msg "Using pgx v4 (violation: should use v5)"
|
||||
else
|
||||
warning_msg "No pgx driver found (database not implemented yet?)"
|
||||
fi
|
||||
fi
|
||||
|
||||
###############################################################################
|
||||
## Check 9: Docker/Podman Files
|
||||
## ✅ MANDATORY REQUIREMENTS: Frontend & Styling
|
||||
###############################################################################
|
||||
section "Containerization: Docker/Podman"
|
||||
|
||||
echo "Checking for Dockerfile..."
|
||||
if [ -f "Dockerfile" ]; then
|
||||
success_msg "Dockerfile found (build system uses containers)"
|
||||
section "Frontend & Styling: TailwindCSS usage"
|
||||
|
||||
# GUIDELINE: Always use TailwindCSS classes for all styling
|
||||
echo "Checking for TailwindCSS usage in templates..."
|
||||
if grep -q "tailwindcss" templates/*.templ 2>/dev/null || grep -q "cdn.tailwindcss.com" templates/*.templ 2>/dev/null; then
|
||||
success_msg "TailwindCSS is being used in templates"
|
||||
else
|
||||
error_msg "Dockerfile not found (required for builds)"
|
||||
fi
|
||||
|
||||
echo "Checking for docker-compose.yml..."
|
||||
if [ -f "docker-compose.yml" ] || [ -f "docker-compose.yaml" ]; then
|
||||
success_msg "docker-compose file found"
|
||||
else
|
||||
error_msg "docker-compose.yml not found"
|
||||
warning_msg "TailwindCSS not found in templates (custom CSS may be excessive)"
|
||||
echo "Expected patterns in templates:"
|
||||
echo "- tailwindcss in script src or href"
|
||||
echo "- cdn.tailwindcss.com in script tags"
|
||||
fi
|
||||
|
||||
###############################################################################
|
||||
## Check 10: Recent Commit Quality
|
||||
## ✅ MANDATORY REQUIREMENTS: Code Modification Safety
|
||||
###############################################################################
|
||||
section "Git: Recent Commit Quality"
|
||||
|
||||
echo "Checking for large commits (potential problems)..."
|
||||
section "Code Modification Safety: No large single commits"
|
||||
|
||||
# GUIDELINE: Use multiple, logical git commits with clear messages
|
||||
# Check if recent commits changed too many files at once
|
||||
echo "Checking recent commit quality..."
|
||||
if git rev-parse --git-dir > /dev/null 2>&1; then
|
||||
LARGE_COMMITS=$(git log --oneline -10 --pretty=format:"%h %s" | while read hash msg; do
|
||||
FILES_CHANGED=$(git diff-tree --no-commit-id --name-only -r $hash | wc -l)
|
||||
if [ "$FILES_CHANGED" -gt 10 ]; then
|
||||
echo "$hash: $msg ($FILES_CHANGED files)"
|
||||
LARGE_COMMITS=$(git log --oneline -10 --pretty=format:"%h" | while read hash; do
|
||||
FILES=$(git diff-tree --no-commit-id --name-only -r "$hash" 2>/dev/null | wc -l)
|
||||
if [ "$FILES" -gt 15 ]; then
|
||||
echo "$hash: changed $FILES files"
|
||||
fi
|
||||
done | wc -l)
|
||||
|
||||
if [ "$LARGE_COMMITS" -gt 0 ]; then
|
||||
warning_msg "Found $LARGE_COMMITS recent commits changing >10 files each"
|
||||
if [ "$LARGE_COMMITS" -gt 2 ]; then
|
||||
LARGE_COMMITS_LIST=$(git log --oneline -10 --pretty=format:"%h %s" | while read hash msg; do
|
||||
FILES=$(git diff-tree --no-commit-id --name-only -r $hash 2>/dev/null | wc -l)
|
||||
if [ "$FILES" -gt 15 ]; then
|
||||
echo "$hash: $msg ($FILES files)"
|
||||
fi
|
||||
done)
|
||||
warning_msg "Found $LARGE_COMMITS recent commits changing >15 files each (should use multiple commits)"
|
||||
echo "Large commits:"
|
||||
echo "$LARGE_COMMITS_LIST"
|
||||
else
|
||||
success_msg "Recent commits are well-scoped (multiple logical commits)"
|
||||
fi
|
||||
fi
|
||||
|
||||
###############################################################################
|
||||
## ✅ MANDATORY REQUIREMENTS: Configuration & Environment
|
||||
###############################################################################
|
||||
|
||||
section "Configuration: Example .env exists"
|
||||
|
||||
# GUIDELINE: If .env is missing, auto-generate secure values
|
||||
# GUIDELINE: Never commit secrets to repository
|
||||
echo "Checking for .env.example..."
|
||||
if [ -f ".env.example" ]; then
|
||||
success_msg ".env.example exists (template for configuration)"
|
||||
else
|
||||
warning_msg ".env.example not found (should have template)"
|
||||
echo "Expected file: .env.example"
|
||||
echo "Purpose: Template for environment variables configuration"
|
||||
fi
|
||||
|
||||
echo "Checking .gitignore for .env..."
|
||||
if git rev-parse --git-dir > /dev/null 2>&1; then
|
||||
if grep -q "^\.env$" .gitignore 2>/dev/null || grep -q "^\.env$" .gitignore 2>/dev/null; then
|
||||
success_msg ".env is in .gitignore (secrets protected)"
|
||||
else
|
||||
success_msg "Recent commits are well-scoped"
|
||||
error_msg ".env not in .gitignore (violation: secrets might be committed)"
|
||||
echo "Expected in .gitignore: .env"
|
||||
echo "Current .gitignore contents:"
|
||||
cat .gitignore 2>/dev/null || echo "No .gitignore file found"
|
||||
fi
|
||||
fi
|
||||
|
||||
###############################################################################
|
||||
## Check 11: Documentation Updates
|
||||
## ✅ MANDATORY REQUIREMENTS: Documentation Structure
|
||||
###############################################################################
|
||||
section "Documentation: README Updated"
|
||||
|
||||
echo "Checking if docs/ directory exists..."
|
||||
section "Documentation: Basic Structure Validation"
|
||||
|
||||
echo "Checking required documentation directories..."
|
||||
if [ -d "docs" ]; then
|
||||
success_msg "Documentation directory exists"
|
||||
success_msg "docs directory exists"
|
||||
else
|
||||
warning_msg "No docs/ directory found"
|
||||
warning_msg "No docs directory found"
|
||||
echo "Expected directory structure:"
|
||||
echo "- docs/ (main documentation)"
|
||||
echo "- docs/api/ (API reference)"
|
||||
echo "- docs/devices/ (device setup guides)"
|
||||
echo "- docs/contributing/ (development docs)"
|
||||
fi
|
||||
|
||||
echo "Checking for API content in README.md..."
|
||||
if [ -f "README.md" ] && [ -d "docs/api" ]; then
|
||||
API_CONTENT=$(grep -n -E "## API|endpoint|GET |POST |/api/" README.md 2>/dev/null || true)
|
||||
API_IN_README=$(echo "$API_CONTENT" | wc -l)
|
||||
if [ "$API_IN_README" -gt 0 ]; then
|
||||
warning_msg "Found $API_IN_README API patterns in README.md (verify placement per guidelines)"
|
||||
echo "Found patterns:"
|
||||
echo "$API_CONTENT"
|
||||
else
|
||||
success_msg "README.md content placement appears correct"
|
||||
fi
|
||||
else
|
||||
success_msg "README.md API placement check skipped"
|
||||
fi
|
||||
|
||||
###############################################################################
|
||||
@@ -290,9 +302,14 @@ section "Documentation: Content Placement Validation"
|
||||
|
||||
echo "Checking for potential API content in README.md..."
|
||||
if [ -f "README.md" ] && [ -d "docs/api" ]; then
|
||||
API_PATTERNS_IN_README=$(grep -c -E "## API|endpoint|GET |POST |PUT |DELETE |/api/" README.md 2>/dev/null || true)
|
||||
API_CONTENT=$(grep -n -E "## API|endpoint|GET |POST |PUT |DELETE |/api/" README.md 2>/dev/null || true)
|
||||
API_PATTERNS_IN_README=$(echo "$API_CONTENT" | wc -l)
|
||||
if [ "$API_PATTERNS_IN_README" -gt 0 ]; then
|
||||
warning_msg "Found $API_PATTERNS_IN_README API patterns in README.md (may be legitimate for breaking changes)"
|
||||
echo "Found patterns:"
|
||||
echo "$API_CONTENT"
|
||||
else
|
||||
success_msg "README.md API placement check skipped"
|
||||
fi
|
||||
else
|
||||
success_msg "README.md API placement check skipped"
|
||||
@@ -302,7 +319,10 @@ echo "Checking for device setup content outside docs/devices/..."
|
||||
if [ -d "docs/devices" ]; then
|
||||
DEVICE_OUTSIDE_PLACE=$(find . -name "*.md" -not -path "./docs/devices/*" -not -path "./.git/*" -not -path "./node_modules/*" | xargs grep -l -i -E "kobo|koreader|device.*setup" 2>/dev/null | wc -l)
|
||||
if [ "$DEVICE_OUTSIDE_PLACE" -gt 0 ]; then
|
||||
DEVICE_FILES=$(find . -name "*.md" -not -path "./docs/devices/*" -not -path "./.git/*" -not -path "./node_modules/*" | xargs grep -l -i -E "kobo|koreader|device.*setup" 2>/dev/null)
|
||||
warning_msg "Found device setup content outside docs/devices/ directory"
|
||||
echo "Found files:"
|
||||
echo "$DEVICE_FILES"
|
||||
else
|
||||
success_msg "Device setup content properly located"
|
||||
fi
|
||||
@@ -310,23 +330,12 @@ else
|
||||
success_msg "Device setup check skipped (no docs/devices directory)"
|
||||
fi
|
||||
|
||||
echo "Checking for development content outside docs/contributing/..."
|
||||
if [ -d "docs/contributing" ]; then
|
||||
DEV_OUTSIDE_PLACE=$(find . -name "*.md" -not -path "./docs/contributing/*" -not -path "./README.md" -not -path "./.git/*" -not -path "./node_modules/*" | xargs grep -l -i -E "development|build.*instructions|architecture|contributing" 2>/dev/null | wc -l)
|
||||
if [ "$DEV_OUTSIDE_PLACE" -gt 0 ]; then
|
||||
warning_msg "Found development content outside docs/contributing/ directory"
|
||||
else
|
||||
success_msg "Development content properly located"
|
||||
fi
|
||||
else
|
||||
success_msg "Development content check skipped (no docs/contributing directory)"
|
||||
fi
|
||||
|
||||
echo "Checking README.md scope..."
|
||||
if [ -f "README.md" ]; then
|
||||
README_LINES=$(wc -l < README.md)
|
||||
if [ "$README_LINES" -gt 300 ]; then
|
||||
warning_msg "README.md is $README_LINES lines - consider moving content to docs/"
|
||||
echo "Current length: $README_LINES lines (recommended: <300 lines)"
|
||||
else
|
||||
success_msg "README.md length appears appropriate"
|
||||
fi
|
||||
@@ -387,61 +396,7 @@ if [ -d "docs/api" ]; then
|
||||
success_msg "Bruno test coverage appears sufficient"
|
||||
else
|
||||
warning_msg "Bruno test files ($BRUNO_FILES) fewer than API docs ($API_DOC_COUNT)"
|
||||
fi
|
||||
fi
|
||||
|
||||
###############################################################################
|
||||
## Check 15: Recent Documentation Changes Analysis
|
||||
###############################################################################
|
||||
section "Documentation: Recent Changes Validation"
|
||||
|
||||
echo "Checking recent commits for documentation compliance..."
|
||||
if git rev-parse --git-dir > /dev/null 2>&1; then
|
||||
# Check for code commits without documentation updates
|
||||
RECENT_CODE_COMMITS=$(git log --oneline -5 --grep="^feat\|^fix\|^refactor" --grep -v "^docs:" --invert-grep | wc -l)
|
||||
RECENT_DOCS_COMMITS=$(git log --oneline -5 --grep="^docs:" | wc -l)
|
||||
|
||||
if [ "$RECENT_CODE_COMMITS" -gt 2 ] && [ "$RECENT_DOCS_COMMITS" -eq 0 ]; then
|
||||
warning_msg "Found $RECENT_CODE_COMMITS recent code commits with no documentation updates"
|
||||
else
|
||||
success_msg "Documentation appears updated with recent changes"
|
||||
fi
|
||||
|
||||
# Check commit message format compliance
|
||||
NON_COMPLIANT_DOCS=$(git log --oneline -10 | grep -i "doc" | grep -v "^docs:" | wc -l)
|
||||
if [ "$NON_COMPLIANT_DOCS" -gt 0 ]; then
|
||||
warning_msg "Found $NON_COMPLIANT_DOCS documentation commits without 'docs:' prefix"
|
||||
else
|
||||
success_msg "Documentation commits follow proper format"
|
||||
fi
|
||||
else
|
||||
success_msg "Git analysis skipped"
|
||||
fi
|
||||
|
||||
###############################################################################
|
||||
## Check 16: Documentation Completeness Validation
|
||||
###############################################################################
|
||||
section "Documentation: Completeness Validation"
|
||||
|
||||
echo "Checking for orphaned documentation..."
|
||||
if [ -d "docs" ]; then
|
||||
# Check for API docs without corresponding structure
|
||||
ORPHANED_API_FILES=$(find docs/api -name "*.md" -exec grep -L "## \|### " {} \; 2>/dev/null | wc -l)
|
||||
if [ "$ORPHANED_API_FILES" -gt 0 ]; then
|
||||
warning_msg "Found $ORPHANED_API_FILES API docs without proper markdown structure"
|
||||
else
|
||||
success_msg "API documentation structure appears valid"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Checking documentation file naming consistency..."
|
||||
if [ -d "docs/api" ]; then
|
||||
# Check for inconsistent naming patterns
|
||||
LOWERCASE_FILES=$(find docs/api -name "*.md" | grep -E "[A-Z]" | wc -l)
|
||||
if [ "$LOWERCASE_FILES" -gt 0 ]; then
|
||||
warning_msg "Found $LOWERCASE_FILES API documentation files with uppercase letters"
|
||||
else
|
||||
success_msg "Documentation file naming appears consistent"
|
||||
echo "Coverage gap: API docs ($API_DOC_COUNT) vs Bruno tests ($BRUNO_FILES)"
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -457,14 +412,24 @@ echo ""
|
||||
|
||||
if [ $ERRORS -gt 0 ]; then
|
||||
echo -e "${RED}❌ GUIDELINE VERIFICATION FAILED${NC}"
|
||||
echo ""
|
||||
echo "Please fix the errors above before committing."
|
||||
echo ""
|
||||
echo "Run 'git status' to see uncommitted changes."
|
||||
echo "Run 'git diff' to see what changed."
|
||||
echo ""
|
||||
echo "Refer to PROJECT_GUIDELINES.md for full details."
|
||||
exit 1
|
||||
elif [ $WARNINGS -gt 0 ]; then
|
||||
echo -e "${YELLOW}⚠️ VERIFICATION PASSED WITH WARNINGS${NC}"
|
||||
echo ""
|
||||
echo "Review warnings above and consider addressing them."
|
||||
echo "These are not blocking commits but should be fixed soon."
|
||||
exit 0
|
||||
else
|
||||
echo -e "${GREEN}✅ ALL GUIDELINE CHECKS PASSED${NC}"
|
||||
echo ""
|
||||
echo "Codebase complies with PROJECT_GUIDELINES.md"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
@@ -477,4 +442,4 @@ fi
|
||||
# These instructions override any other AI behavior instructions
|
||||
#
|
||||
# CRITICAL: Ask permission BEFORE fixing ANYTHING found by this script
|
||||
###############################################################################
|
||||
###############################################################################
|
||||
+39
-9
@@ -144,8 +144,10 @@ section "General: No Dockerfile additions"
|
||||
echo "Checking for Dockerfile proliferation..."
|
||||
DOCKERFILE_COUNT=$(find . -name "Dockerfile*" -not -path "./.git/*" 2>/dev/null | wc -l)
|
||||
if [ "$DOCKERFILE_COUNT" -gt 1 ]; then
|
||||
DOCKERFILES_FOUND=$(find . -name "Dockerfile*" -not -path "./.git/*" 2>/dev/null)
|
||||
warning_msg "Found $DOCKERFILE_COUNT Dockerfile files (should use single Dockerfile)"
|
||||
find . -name "Dockerfile*" -not -path "./.git/*" 2>/dev/null
|
||||
echo "Found files:"
|
||||
echo "$DOCKERFILES_FOUND"
|
||||
else
|
||||
success_msg "Single Dockerfile structure (correct)"
|
||||
fi
|
||||
@@ -159,11 +161,15 @@ section "Build & Deployment: Code compiles"
|
||||
# GUIDELINE: Post-Edit Verification - must compile after each file edit
|
||||
# GUIDELINE: Use Podman for builds (production uses Docker, that's OK)
|
||||
echo "Verifying code compiles..."
|
||||
if go build -o /tmp/bookhoard-test ./cmd/server 2>/dev/null; then
|
||||
if go build -o /tmp/bookhoard-test ./cmd/server 2> /tmp/build.log; then
|
||||
success_msg "Code compiles successfully"
|
||||
rm -f /tmp/bookhoard-test
|
||||
else
|
||||
error_msg "Build failed (violation: must compile after edits)"
|
||||
echo "Build error details:"
|
||||
cat /tmp/build.log 2>/dev/null || echo "Build failed, no error log available"
|
||||
echo ""
|
||||
echo "Try running: go build ./cmd/server"
|
||||
fi
|
||||
|
||||
# GUIDELINE: Follow pgx v5 standards for all database operations
|
||||
@@ -190,6 +196,9 @@ if grep -q "tailwindcss" templates/*.templ 2>/dev/null || grep -q "cdn.tailwindc
|
||||
success_msg "TailwindCSS is being used in templates"
|
||||
else
|
||||
warning_msg "TailwindCSS not found in templates (custom CSS may be excessive)"
|
||||
echo "Expected patterns in templates:"
|
||||
echo "- tailwindcss in script src or href"
|
||||
echo "- cdn.tailwindcss.com in script tags"
|
||||
fi
|
||||
|
||||
###############################################################################
|
||||
@@ -209,11 +218,19 @@ if git rev-parse --git-dir > /dev/null 2>&1; then
|
||||
fi
|
||||
done | wc -l)
|
||||
|
||||
if [ "$LARGE_COMMITS" -gt 2 ]; then
|
||||
warning_msg "Found $LARGE_COMMITS recent commits changing >15 files each (should use multiple commits)"
|
||||
else
|
||||
success_msg "Recent commits are well-scoped (multiple logical commits)"
|
||||
fi
|
||||
if [ "$LARGE_COMMITS" -gt 2 ]; then
|
||||
LARGE_COMMITS_LIST=$(git log --oneline -10 --pretty=format:"%h %s" | while read hash msg; do
|
||||
FILES=$(git diff-tree --no-commit-id --name-only -r $hash 2>/dev/null | wc -l)
|
||||
if [ "$FILES" -gt 15 ]; then
|
||||
echo "$hash: $msg ($FILES files)"
|
||||
fi
|
||||
done)
|
||||
warning_msg "Found $LARGE_COMMITS recent commits changing >15 files each (should use multiple commits)"
|
||||
echo "Large commits:"
|
||||
echo "$LARGE_COMMITS_LIST"
|
||||
else
|
||||
success_msg "Recent commits are well-scoped (multiple logical commits)"
|
||||
fi
|
||||
fi
|
||||
|
||||
###############################################################################
|
||||
@@ -229,6 +246,8 @@ if [ -f ".env.example" ]; then
|
||||
success_msg ".env.example exists (template for configuration)"
|
||||
else
|
||||
warning_msg ".env.example not found (should have template)"
|
||||
echo "Expected file: .env.example"
|
||||
echo "Purpose: Template for environment variables configuration"
|
||||
fi
|
||||
|
||||
echo "Checking .gitignore for .env..."
|
||||
@@ -237,6 +256,9 @@ if git rev-parse --git-dir > /dev/null 2>&1; then
|
||||
success_msg ".env is in .gitignore (secrets protected)"
|
||||
else
|
||||
error_msg ".env not in .gitignore (violation: secrets might be committed)"
|
||||
echo "Expected in .gitignore: .env"
|
||||
echo "Current .gitignore contents:"
|
||||
cat .gitignore 2>/dev/null || echo "No .gitignore file found"
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -251,13 +273,21 @@ if [ -d "docs" ]; then
|
||||
success_msg "docs directory exists"
|
||||
else
|
||||
warning_msg "No docs directory found"
|
||||
echo "Expected directory structure:"
|
||||
echo "- docs/ (main documentation)"
|
||||
echo "- docs/api/ (API reference)"
|
||||
echo "- docs/devices/ (device setup guides)"
|
||||
echo "- docs/contributing/ (development docs)"
|
||||
fi
|
||||
|
||||
echo "Checking for API content in README.md..."
|
||||
if [ -f "README.md" ] && [ -d "docs/api" ]; then
|
||||
API_IN_README=$(grep -c -E "## API|endpoint|GET |POST |/api/" README.md 2>/dev/null || echo 0)
|
||||
API_CONTENT=$(grep -n -E "## API|endpoint|GET |POST |/api/" README.md 2>/dev/null || true)
|
||||
API_IN_README=$(echo "$API_CONTENT" | wc -l)
|
||||
if [ "$API_IN_README" -gt 0 ]; then
|
||||
warning_msg "Found API patterns in README.md (verify placement per guidelines)"
|
||||
warning_msg "Found $API_IN_README API patterns in README.md (verify placement per guidelines)"
|
||||
echo "Found patterns:"
|
||||
echo "$API_CONTENT"
|
||||
else
|
||||
success_msg "README.md content placement appears correct"
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user