#!/bin/bash # Content Consistency Validation Script # Validates that content structure is consistent and server can process all content # set -e removed - handle errors explicitly to avoid early exits on warnings # Configuration CONTENT_DIR="${SITE_CONTENT_PATH:-site/content}" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # Counters TOTAL_CHECKS=0 PASSED_CHECKS=0 FAILED_CHECKS=0 # Function to print colored output print_status() { local status=$1 local message=$2 case $status in "PASS") echo -e "${GREEN}✅ PASS${NC}: $message" ((PASSED_CHECKS++)) ;; "FAIL") echo -e "${RED}❌ FAIL${NC}: $message" ((FAILED_CHECKS++)) ;; "WARN") echo -e "${YELLOW}⚠️ WARN${NC}: $message" ;; "INFO") echo -e "${BLUE}ℹ️ INFO${NC}: $message" ;; esac ((TOTAL_CHECKS++)) } # Function to check if directory exists and is not empty check_directory() { local dir=$1 local description=$2 if [ ! -d "$dir" ]; then print_status "FAIL" "$description directory missing: $dir" return 1 fi local file_count file_count=$(ls -A "$dir" 2>/dev/null | wc -l) if [ "$file_count" -eq 0 ]; then print_status "WARN" "$description directory is empty: $dir" return 0 # Return 0 for warnings to not exit with set -e fi print_status "PASS" "$description directory exists and has content: $dir" return 0 } # Function to validate markdown files validate_markdown_files() { local base_dir=$1 local content_type=$2 print_status "INFO" "Validating $content_type markdown files in $base_dir" local md_count=0 local invalid_count=0 while IFS= read -r -d '' file; do ((md_count++)) # Check if file has frontmatter if ! head -n1 "$file" | grep -q "^---$"; then print_status "FAIL" "Missing frontmatter in: ${file#$PROJECT_ROOT/}" ((invalid_count++)) continue fi # Check if file has closing frontmatter if ! sed -n '2,$p' "$file" | grep -q "^---$"; then print_status "FAIL" "Invalid frontmatter (no closing ---) in: ${file#$PROJECT_ROOT/}" ((invalid_count++)) continue fi # Check for required frontmatter fields local frontmatter=$(sed -n '/^---$/,/^---$/p' "$file") if ! echo "$frontmatter" | grep -q "^title:"; then print_status "FAIL" "Missing 'title' field in: ${file#$PROJECT_ROOT/}" ((invalid_count++)) fi if ! echo "$frontmatter" | grep -q "^slug:"; then print_status "FAIL" "Missing 'slug' field in: ${file#$PROJECT_ROOT/}" ((invalid_count++)) fi done < <(find "$base_dir" -name "*.md" -type f -print0) if [ $md_count -eq 0 ]; then print_status "WARN" "No markdown files found in $base_dir" else if [ $invalid_count -eq 0 ]; then print_status "PASS" "All $md_count $content_type markdown files are valid" else print_status "FAIL" "$invalid_count of $md_count $content_type markdown files have issues" fi fi } # Function to validate content structure validate_content_structure() { print_status "INFO" "=== Content Structure Validation ===" # Check main content directory check_directory "$CONTENT_DIR" "Main content" # Check content-kinds.toml exists local content_kinds_file="$CONTENT_DIR/content-kinds.toml" if [ ! -f "$content_kinds_file" ]; then print_status "FAIL" "content-kinds.toml missing: $content_kinds_file" return 1 fi print_status "PASS" "content-kinds.toml exists" # Check routes configuration if [ -f "$CONTENT_DIR/routes.toml" ]; then print_status "PASS" "routes.toml exists" elif [ -d "$CONTENT_DIR/routes/" ]; then print_status "PASS" "routes/ directory exists" else print_status "FAIL" "No routes configuration found (routes.toml or routes/ directory)" fi # Validate each enabled content type while IFS= read -r content_type; do local content_dir="$CONTENT_DIR/$content_type" if check_directory "$content_dir" "Content type '$content_type'"; then # Check for language directories local lang_count=0 for lang_dir in "$content_dir"/*/; do if [ -d "$lang_dir" ]; then local lang=$(basename "$lang_dir") check_directory "$lang_dir" "Language '$lang' in '$content_type'" validate_markdown_files "$lang_dir" "$content_type/$lang" ((lang_count++)) fi done if [ $lang_count -eq 0 ]; then print_status "WARN" "No language directories found in $content_type" fi fi done < <(get_enabled_content_types) } # Function to get enabled content types from content-kinds.toml get_enabled_content_types() { local content_kinds_file="$CONTENT_DIR/content-kinds.toml" if [ ! -f "$content_kinds_file" ]; then echo "blog" echo "recipes" return fi # Simplified parsing - look for directory entries that aren't commented out grep -E '^\s*directory\s*=' "$content_kinds_file" | \ sed 's/.*directory\s*=\s*"\([^"]*\)".*/\1/' | \ while read -r dir; do if [ -d "$CONTENT_DIR/$dir" ]; then echo "$dir" fi done } # Function to check server can process content validate_server_processing() { print_status "INFO" "=== Server Content Processing Validation ===" # Check if server binary exists if [ ! -f "$PROJECT_ROOT/target/debug/server" ] && [ ! -f "$PROJECT_ROOT/target/release/server" ]; then print_status "WARN" "Server binary not found - run 'cargo build --features content-static' first" return fi print_status "PASS" "Server binary is available for content processing" } # Function to validate i18n structure validate_i18n_structure() { print_status "INFO" "=== Internationalization Structure Validation ===" local locales_dir="$CONTENT_DIR/locales" if check_directory "$locales_dir" "Locales"; then # Check for language directories in locales for lang_dir in "$locales_dir"/*/; do if [ -d "$lang_dir" ]; then local lang=$(basename "$lang_dir") check_directory "$lang_dir" "Locale '$lang'" # Check for common.ftl if [ -f "$lang_dir/common.ftl" ]; then print_status "PASS" "common.ftl exists for language '$lang'" else print_status "WARN" "common.ftl missing for language '$lang'" fi fi done fi # Check menus local menus_dir="$CONTENT_DIR/menus" if check_directory "$menus_dir" "Menus"; then for menu_file in "$menus_dir"/*.toml; do if [ -f "$menu_file" ]; then local lang=$(basename "$menu_file" .toml) print_status "PASS" "Menu configuration exists for language '$lang'" fi done fi } # Function to remove deprecated files/directories cleanup_deprecated() { print_status "INFO" "=== Cleanup Deprecated Build Outputs ===" # The /public directory is now deprecated since server processes content dynamically if [ -d "$PROJECT_ROOT/public" ]; then local item_count=$(find "$PROJECT_ROOT/public" -type f | wc -l) if [ "$item_count" -gt 5 ]; then # Allow for a few static files print_status "WARN" "Found $item_count files in /public - consider removing pre-built HTML" print_status "INFO" "Server now processes content dynamically from /content" else print_status "PASS" "/public directory has minimal static files" fi fi } # Main validation function main() { echo "🔍 Content Consistency Validation" echo "==================================" echo "Content directory: $CONTENT_DIR" echo "Project root: $PROJECT_ROOT" echo "" validate_content_structure echo "" validate_i18n_structure echo "" validate_server_processing echo "" cleanup_deprecated echo "" # Summary echo "🏁 Validation Summary" echo "====================" echo "Total checks: $TOTAL_CHECKS" echo "Passed: $PASSED_CHECKS" echo "Failed: $FAILED_CHECKS" if [ $FAILED_CHECKS -eq 0 ]; then print_status "PASS" "All content validation checks passed!" echo "" echo "✅ Content structure is consistent and ready for server processing" echo "🚀 You can run: cargo run --features content-static" exit 0 else echo "" echo "❌ Content validation found $FAILED_CHECKS issues" echo "🔧 Please fix the issues above before building" exit 1 fi } # Run main function main "$@"