271 lines
7.2 KiB
Bash
Executable File
271 lines
7.2 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# Documentation Validation Script
|
|
# Checks for documentation violations and ensures SSOT is maintained
|
|
|
|
set -e
|
|
|
|
# Colors for output
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
NC='\033[0m' # No Color
|
|
|
|
# Track errors
|
|
ERRORS=0
|
|
WARNINGS=0
|
|
|
|
# Function to print error
|
|
error() {
|
|
echo -e "${RED}❌ ERROR:${NC} $1"
|
|
ERRORS=$((ERRORS + 1))
|
|
}
|
|
|
|
# Function to print warning
|
|
warning() {
|
|
echo -e "${YELLOW}⚠️ WARNING:${NC} $1"
|
|
WARNINGS=$((WARNINGS + 1))
|
|
}
|
|
|
|
# Function to print success
|
|
success() {
|
|
echo -e "${GREEN}✅${NC} $1"
|
|
}
|
|
|
|
echo "🔍 Checking documentation compliance..."
|
|
echo ""
|
|
|
|
# Get script directory and project root
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
cd "$PROJECT_ROOT"
|
|
|
|
# Check 1: No new .md files outside docs/ without approval
|
|
echo "📋 Check 1: Markdown files outside docs/ directory"
|
|
|
|
APPROVED_DIR=".docs-approval"
|
|
ALLOWED_PATHS=(
|
|
"README.md"
|
|
"docs/"
|
|
"conductor/"
|
|
"supabase/migrations/"
|
|
)
|
|
|
|
# Find all .md files
|
|
MD_FILES=$(find . -name "*.md" -type f -not -path "*/node_modules/*" -not -path "*/.git/*" | sort)
|
|
|
|
VIOLATIONS=0
|
|
for file in $MD_FILES; do
|
|
# Remove leading ./
|
|
file="${file#./}"
|
|
|
|
# Check if file is in allowed path
|
|
ALLOWED=false
|
|
for allowed_path in "${ALLOWED_PATHS[@]}"; do
|
|
if [[ "$file" == "$allowed_path"* ]] || [[ "$file" == "$allowed_path" ]]; then
|
|
ALLOWED=true
|
|
break
|
|
fi
|
|
done
|
|
|
|
if [ "$ALLOWED" = false ]; then
|
|
# Check if there's an approval file
|
|
filename=$(basename "$file")
|
|
approval_file="$APPROVED_DIR/${filename}.approved"
|
|
|
|
if [ ! -f "$approval_file" ]; then
|
|
error "Markdown file outside docs/: $file (no approval file found)"
|
|
VIOLATIONS=$((VIOLATIONS + 1))
|
|
else
|
|
success "Markdown file outside docs/ has approval: $file"
|
|
fi
|
|
fi
|
|
done
|
|
|
|
if [ $VIOLATIONS -eq 0 ]; then
|
|
success "All markdown files are in allowed locations or have approval"
|
|
fi
|
|
|
|
echo ""
|
|
|
|
# Check 2: SSOT.md exists and is up to date
|
|
echo "📋 Check 2: SSOT.md exists and is valid"
|
|
|
|
SSOT_FILE="docs/SSOT.md"
|
|
if [ ! -f "$SSOT_FILE" ]; then
|
|
error "SSOT.md not found at $SSOT_FILE"
|
|
else
|
|
success "SSOT.md exists"
|
|
|
|
# Check if SSOT has required sections
|
|
REQUIRED_SECTIONS=(
|
|
"Overview"
|
|
"Architecture"
|
|
"Local Development Setup"
|
|
"Environment Configuration"
|
|
"Database & Supabase"
|
|
"Deployment"
|
|
"Troubleshooting"
|
|
"Operations"
|
|
)
|
|
|
|
for section in "${REQUIRED_SECTIONS[@]}"; do
|
|
if ! grep -q "$section" "$SSOT_FILE"; then
|
|
warning "SSOT.md missing section: $section"
|
|
fi
|
|
done
|
|
fi
|
|
|
|
echo ""
|
|
|
|
# Check 3: SSOT.md updated when key files change
|
|
echo "📋 Check 3: SSOT.md updated when key files change"
|
|
|
|
KEY_FILES=(
|
|
"package.json"
|
|
"docker-compose.yml"
|
|
"prisma/schema.prisma"
|
|
)
|
|
|
|
# If in CI, check if key files changed
|
|
if [ -n "$CI" ] && [ -n "$GITHUB_BASE_REF" ]; then
|
|
for key_file in "${KEY_FILES[@]}"; do
|
|
if [ -f "$key_file" ]; then
|
|
# Check if file changed in this PR/branch
|
|
if git diff --name-only "$GITHUB_BASE_REF"..HEAD | grep -q "$key_file"; then
|
|
# Check if SSOT was also updated
|
|
if ! git diff --name-only "$GITHUB_BASE_REF"..HEAD | grep -q "$SSOT_FILE"; then
|
|
warning "$key_file changed but SSOT.md not updated. Please update SSOT.md to reflect changes."
|
|
else
|
|
success "$key_file changed and SSOT.md updated"
|
|
fi
|
|
fi
|
|
fi
|
|
done
|
|
else
|
|
# Not in CI, just check if files exist
|
|
for key_file in "${KEY_FILES[@]}"; do
|
|
if [ -f "$key_file" ]; then
|
|
success "Key file exists: $key_file"
|
|
fi
|
|
done
|
|
fi
|
|
|
|
echo ""
|
|
|
|
# Check 4: No duplicate setup instruction blocks
|
|
echo "📋 Check 4: Duplicate setup instruction blocks"
|
|
|
|
# Look for common setup instruction patterns
|
|
SETUP_PATTERNS=(
|
|
"npm install"
|
|
"npm run dev"
|
|
"cp .env"
|
|
"prisma generate"
|
|
"prisma migrate"
|
|
)
|
|
|
|
DUPLICATES=0
|
|
for pattern in "${SETUP_PATTERNS[@]}"; do
|
|
# Count occurrences in all .md files
|
|
COUNT=$(grep -r "$pattern" docs/*.md 2>/dev/null | wc -l | tr -d ' ')
|
|
if [ "$COUNT" -gt 3 ]; then
|
|
warning "Possible duplicate setup instructions for '$pattern' (found $COUNT occurrences)"
|
|
DUPLICATES=$((DUPLICATES + 1))
|
|
fi
|
|
done
|
|
|
|
if [ $DUPLICATES -eq 0 ]; then
|
|
success "No obvious duplicate setup instruction blocks found"
|
|
fi
|
|
|
|
echo ""
|
|
|
|
# Check 5: DOCS_INDEX.md exists and links to SSOT
|
|
echo "📋 Check 5: DOCS_INDEX.md exists and links to SSOT"
|
|
|
|
INDEX_FILE="docs/DOCS_INDEX.md"
|
|
if [ ! -f "$INDEX_FILE" ]; then
|
|
error "DOCS_INDEX.md not found"
|
|
else
|
|
success "DOCS_INDEX.md exists"
|
|
|
|
# Check if it links to SSOT
|
|
if ! grep -q "SSOT.md" "$INDEX_FILE"; then
|
|
error "DOCS_INDEX.md does not link to SSOT.md"
|
|
else
|
|
success "DOCS_INDEX.md links to SSOT.md"
|
|
fi
|
|
fi
|
|
|
|
echo ""
|
|
|
|
# Check 6: README.md points to documentation
|
|
echo "📋 Check 6: README.md points to documentation"
|
|
|
|
README_FILE="README.md"
|
|
if [ ! -f "$README_FILE" ]; then
|
|
warning "README.md not found"
|
|
else
|
|
# Check if README links to docs
|
|
if ! grep -qi "docs/" "$README_FILE" && ! grep -qi "DOCS_INDEX" "$README_FILE" && ! grep -qi "SSOT" "$README_FILE"; then
|
|
warning "README.md may not link to documentation. Ensure it points to docs/DOCS_INDEX.md or docs/SSOT.md"
|
|
else
|
|
success "README.md appears to link to documentation"
|
|
fi
|
|
fi
|
|
|
|
echo ""
|
|
|
|
# Check 7: Validate markdown links (basic check)
|
|
echo "📋 Check 7: Basic markdown link validation"
|
|
|
|
# Check for broken internal links (files that don't exist)
|
|
LINK_VIOLATIONS=0
|
|
for file in docs/*.md; do
|
|
if [ -f "$file" ]; then
|
|
# Extract markdown links
|
|
links=$(grep -oE '\[.*\]\([^)]+\)' "$file" | sed 's/.*(\(.*\))/\1/' | grep -v '^http' | grep -v '^#' | grep -v '^mailto:')
|
|
|
|
for link in $links; do
|
|
# Remove anchor if present
|
|
file_path="${link%%#*}"
|
|
|
|
# Skip empty or special links
|
|
if [ -z "$file_path" ] || [[ "$file_path" == "http"* ]]; then
|
|
continue
|
|
fi
|
|
|
|
# Check if linked file exists
|
|
if [ ! -f "$file_path" ] && [ ! -f "docs/$file_path" ]; then
|
|
warning "Possible broken link in $file: $link"
|
|
LINK_VIOLATIONS=$((LINK_VIOLATIONS + 1))
|
|
fi
|
|
done
|
|
fi
|
|
done
|
|
|
|
if [ $LINK_VIOLATIONS -eq 0 ]; then
|
|
success "No obvious broken internal links found"
|
|
fi
|
|
|
|
echo ""
|
|
|
|
# Summary
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
echo "📊 Summary"
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
|
|
if [ $ERRORS -eq 0 ] && [ $WARNINGS -eq 0 ]; then
|
|
echo -e "${GREEN}✅ All checks passed!${NC}"
|
|
exit 0
|
|
elif [ $ERRORS -eq 0 ]; then
|
|
echo -e "${YELLOW}⚠️ $WARNINGS warning(s) found (non-blocking)${NC}"
|
|
exit 0
|
|
else
|
|
echo -e "${RED}❌ $ERRORS error(s) and $WARNINGS warning(s) found${NC}"
|
|
echo ""
|
|
echo "Please fix the errors before merging."
|
|
exit 1
|
|
fi
|