website-htmx-rustelo-code/scripts/sh/content/validate-content-consistency.sh

293 lines
9.2 KiB
Bash
Raw Normal View History

2026-07-10 03:44:13 +01:00
#!/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 "$@"