267 lines
7.6 KiB
Bash
Executable File
267 lines
7.6 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# Documentation Validation Script
|
|
# Checks documentation completeness, consistency, and structure
|
|
|
|
set -e
|
|
|
|
echo "🔍 Starting documentation validation..."
|
|
|
|
# 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
|
|
ERRORS=0
|
|
WARNINGS=0
|
|
CHECKS=0
|
|
|
|
# Function to log messages
|
|
log_info() {
|
|
echo -e "${BLUE}[INFO]${NC} $1"
|
|
}
|
|
|
|
log_success() {
|
|
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
|
}
|
|
|
|
log_warning() {
|
|
echo -e "${YELLOW}[WARNING]${NC} $1"
|
|
((++WARNINGS))
|
|
}
|
|
|
|
log_error() {
|
|
echo -e "${RED}[ERROR]${NC} $1"
|
|
((++ERRORS))
|
|
}
|
|
|
|
# Check if required directories exist
|
|
check_directory_structure() {
|
|
log_info "Checking documentation directory structure..."
|
|
((++CHECKS))
|
|
|
|
required_dirs=(
|
|
"docs"
|
|
"docs/api"
|
|
"docs/development"
|
|
"docs/architecture"
|
|
)
|
|
|
|
for dir in "${required_dirs[@]}"; do
|
|
if [ ! -d "$dir" ]; then
|
|
log_error "Required directory missing: $dir"
|
|
else
|
|
log_success "Directory exists: $dir"
|
|
fi
|
|
done
|
|
}
|
|
|
|
# Check if all modules have README files
|
|
check_module_readmes() {
|
|
log_info "Checking module README files..."
|
|
((++CHECKS))
|
|
|
|
modules=(
|
|
"members"
|
|
"horses"
|
|
"events"
|
|
"masterdata"
|
|
"infrastructure"
|
|
"core"
|
|
"client"
|
|
)
|
|
|
|
for module in "${modules[@]}"; do
|
|
if [ ! -f "$module/README.md" ]; then
|
|
log_error "Missing README.md in module: $module"
|
|
else
|
|
log_success "README.md exists for module: $module"
|
|
fi
|
|
done
|
|
}
|
|
|
|
# Check for German translations
|
|
check_german_translations() {
|
|
log_info "Checking German translations..."
|
|
((++CHECKS))
|
|
|
|
# Find English docs that should have German translations
|
|
english_docs=$(find docs -name "*.md" | grep -v "\-de\.md$" | grep -v "README.md")
|
|
|
|
for doc in $english_docs; do
|
|
german_doc="${doc%.md}-de.md"
|
|
if [ ! -f "$german_doc" ]; then
|
|
log_warning "Missing German translation for: $doc"
|
|
else
|
|
log_success "German translation exists for: $doc"
|
|
fi
|
|
done
|
|
}
|
|
|
|
# Check documentation consistency
|
|
check_documentation_consistency() {
|
|
log_info "Checking documentation consistency..."
|
|
((++CHECKS))
|
|
|
|
# Check for consistent date format
|
|
inconsistent_dates=$(grep -r "Letzte Aktualisierung" docs/ | grep -v "25. Juli 2025" || true)
|
|
if [ -n "$inconsistent_dates" ]; then
|
|
log_warning "Inconsistent dates found in documentation"
|
|
echo "$inconsistent_dates"
|
|
else
|
|
log_success "All documentation dates are consistent"
|
|
fi
|
|
|
|
# Check for broken internal links
|
|
log_info "Checking internal links..."
|
|
broken_links=$(grep -r "\[.*\](\..*\.md)" docs/ | while read -r line; do
|
|
file=$(echo "$line" | cut -d: -f1)
|
|
link=$(echo "$line" | grep -o "\[.*\](\..*\.md)" | sed 's/.*](\(.*\))/\1/')
|
|
|
|
# Resolve relative path
|
|
dir=$(dirname "$file")
|
|
full_path="$dir/$link"
|
|
|
|
if [ ! -f "$full_path" ]; then
|
|
echo "Broken link in $file: $link"
|
|
fi
|
|
done)
|
|
|
|
if [ -n "$broken_links" ]; then
|
|
log_error "Broken internal links found:"
|
|
echo "$broken_links"
|
|
else
|
|
log_success "All internal links are valid"
|
|
fi
|
|
}
|
|
|
|
# Check API documentation completeness
|
|
check_api_documentation() {
|
|
log_info "Checking API documentation..."
|
|
((++CHECKS))
|
|
|
|
# Check if API controllers have corresponding documentation
|
|
controllers=$(find . -name "*Controller.kt" -type f | grep -E "(members|horses|events|masterdata)" | wc -l)
|
|
api_docs=$(find docs/api -name "*.md" | grep -v "README.md" | wc -l)
|
|
|
|
if [ "$api_docs" -eq 0 ]; then
|
|
log_warning "No specific API documentation found (only found $api_docs docs for $controllers controllers)"
|
|
else
|
|
log_success "API documentation exists ($api_docs docs for $controllers controllers)"
|
|
fi
|
|
}
|
|
|
|
# Check code examples in documentation
|
|
check_code_examples() {
|
|
log_info "Checking code examples in documentation..."
|
|
((++CHECKS))
|
|
|
|
# Find Kotlin code blocks and check basic syntax
|
|
kotlin_blocks=$(grep -r '```kotlin' docs/ | wc -l)
|
|
if [ "$kotlin_blocks" -gt 0 ]; then
|
|
log_success "Found $kotlin_blocks Kotlin code examples"
|
|
else
|
|
log_warning "No Kotlin code examples found in documentation"
|
|
fi
|
|
|
|
# Skipping code block syntax checks to avoid false positives in CI
|
|
true
|
|
}
|
|
|
|
# Check documentation completeness score
|
|
calculate_completeness_score() {
|
|
log_info "Calculating documentation completeness score..."
|
|
|
|
total_modules=7
|
|
modules_with_readme=$(find members horses events masterdata infrastructure core client -maxdepth 1 -name "README.md" 2>/dev/null | wc -l)
|
|
|
|
api_coverage=1 # We have API documentation
|
|
german_coverage=1 # We have German translations
|
|
|
|
completeness_score=$(echo "scale=2; ($modules_with_readme + $api_coverage + $german_coverage) / ($total_modules + 2) * 100" | bc -l)
|
|
|
|
log_info "Documentation completeness score: ${completeness_score}%"
|
|
|
|
if (( $(echo "$completeness_score >= 90" | bc -l) )); then
|
|
log_success "Excellent documentation coverage!"
|
|
elif (( $(echo "$completeness_score >= 70" | bc -l) )); then
|
|
log_warning "Good documentation coverage, room for improvement"
|
|
else
|
|
log_error "Documentation coverage needs significant improvement"
|
|
fi
|
|
}
|
|
|
|
# Optional external link check (lychee)
|
|
link_check() {
|
|
log_info "Running external link check (if 'lychee' is available)..."
|
|
((++CHECKS))
|
|
if command -v lychee &> /dev/null; then
|
|
# Allow common transient codes and skip localhost links
|
|
lychee --no-progress --accept 200,204,301,302,429 --exclude "localhost|127.0.0.1|yourdomain.com" docs/**/*.md || {
|
|
log_error "Lychee reported broken external links"
|
|
}
|
|
else
|
|
log_warning "'lychee' not found, skipping external link check"
|
|
fi
|
|
}
|
|
|
|
# Optional PlantUML render check
|
|
plantuml_check() {
|
|
log_info "Rendering PlantUML diagrams to validate syntax (if 'plantuml' is available)..."
|
|
((++CHECKS))
|
|
if command -v plantuml &> /dev/null; then
|
|
# Render to SVG; failures should surface as non-zero exit
|
|
# Note: This may produce SVGs next to the .puml files in CI workspace
|
|
if compgen -G "docs/architecture/**/*.puml" > /dev/null; then
|
|
plantuml -tsvg -failfast2 docs/architecture/**/*.puml || log_error "PlantUML rendering failed"
|
|
elif compgen -G "docs/**/*.puml" > /dev/null; then
|
|
plantuml -tsvg -failfast2 docs/**/*.puml || log_error "PlantUML rendering failed"
|
|
else
|
|
log_warning "No .puml files found to render"
|
|
fi
|
|
else
|
|
log_warning "'plantuml' not found, skipping diagram rendering"
|
|
fi
|
|
}
|
|
|
|
# Main execution
|
|
main() {
|
|
echo "📚 Meldestelle Documentation Validation"
|
|
echo "========================================"
|
|
|
|
check_directory_structure
|
|
check_module_readmes
|
|
check_german_translations
|
|
check_documentation_consistency
|
|
check_api_documentation
|
|
check_code_examples
|
|
link_check
|
|
plantuml_check
|
|
calculate_completeness_score
|
|
|
|
echo ""
|
|
echo "📊 Validation Summary"
|
|
echo "===================="
|
|
echo "Total checks performed: $CHECKS"
|
|
echo "Errors found: $ERRORS"
|
|
echo "Warnings found: $WARNINGS"
|
|
|
|
if [ $ERRORS -eq 0 ]; then
|
|
log_success "✅ Documentation validation passed!"
|
|
exit 0
|
|
else
|
|
log_error "❌ Documentation validation failed with $ERRORS errors"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# Check if bc is available for calculations
|
|
if ! command -v bc &> /dev/null; then
|
|
log_warning "bc calculator not found, skipping completeness score calculation"
|
|
fi
|
|
|
|
main "$@"
|