You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							355 lines
						
					
					
						
							11 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							355 lines
						
					
					
						
							11 KiB
						
					
					
				| #!/usr/bin/env bash | |
| # | |
| # Build Architecture Guard Script | |
| #  | |
| # Author: Matthew Raymer | |
| # Date: 2025-08-22 | |
| # Purpose: Protects build-critical files by requiring BUILDING.md updates | |
| # Enhanced to protect Android build system including asset validation,  | |
| # API routing, and resource generation logic | |
| # | |
| # Usage: | |
| #   ./scripts/build-arch-guard.sh --staged     # Check staged files (pre-commit) | |
| #   ./scripts/build-arch-guard.sh --range      # Check range (pre-push) | |
| #   ./scripts/build-arch-guard.sh              # Check working directory | |
| # | |
| 
 | |
| set -euo pipefail | |
| 
 | |
| # Sensitive paths that require BUILDING.md updates when modified | |
| SENSITIVE=( | |
|   "vite.config.*"  | |
|   "scripts/**"  | |
|   "electron/**"  | |
|   "android/**"  | |
|   "ios/**" | |
|   "sw_scripts/**"  | |
|   "sw_combine.js"  | |
|   "Dockerfile"  | |
|   "docker/**" | |
|   "capacitor.config.ts" | |
|   "capacitor-assets.config.json"  # Critical for Android assets | |
|   "package.json" | |
|   "package-lock.json" | |
|   "yarn.lock" | |
|   "pnpm-lock.yaml" | |
|   "resources/**"                   # Source assets for Android | |
| ) | |
| 
 | |
| # Documentation files that must be updated alongside sensitive changes | |
| DOCS_REQUIRED=( | |
|   "BUILDING.md" | |
|   "doc/README-BUILD-GUARD.md"     # Guard documentation | |
| ) | |
| 
 | |
| # Colors for output | |
| RED='\033[0;31m' | |
| GREEN='\033[0;32m' | |
| YELLOW='\033[1;33m' | |
| BLUE='\033[0;34m' | |
| NC='\033[0m' # No Color | |
| 
 | |
| log_info() { | |
|     echo -e "${BLUE}[guard]${NC} $1" | |
| } | |
| 
 | |
| log_warn() { | |
|     echo -e "${YELLOW}[guard]${NC} $1" | |
| } | |
| 
 | |
| log_error() { | |
|     echo -e "${RED}[guard]${NC} $1" | |
| } | |
| 
 | |
| log_success() { | |
|     echo -e "${GREEN}[guard]${NC} $1" | |
| } | |
| 
 | |
| # Collect files based on mode | |
| collect_files() { | |
|     if [[ "${1:-}" == "--staged" ]]; then | |
|         # Pre-commit: check staged files | |
|         git diff --name-only --cached | |
|     elif [[ "${1:-}" == "--range" ]]; then | |
|         # Pre-push: check commits being pushed | |
|         RANGE="${2:-HEAD~1..HEAD}" | |
|         git diff --name-only "$RANGE" | |
|     else | |
|         # Default: check working directory changes | |
|         git diff --name-only HEAD | |
|     fi | |
| } | |
| 
 | |
| # Check if a file matches any sensitive pattern | |
| matches_sensitive() { | |
|     local f="$1" | |
|     for pat in "${SENSITIVE[@]}"; do | |
|         # Convert glob pattern to regex | |
|         local rx="^${pat//\./\.}$" | |
|         rx="${rx//\*\*/.*}" | |
|         rx="${rx//\*/[^/]*}" | |
|          | |
|         if [[ "$f" =~ $rx ]]; then | |
|             return 0 | |
|         fi | |
|     done | |
|     return 1 | |
| } | |
| 
 | |
| # Check if documentation was updated | |
| check_docs_updated() { | |
|     local changed_files=("$@") | |
|      | |
|     for changed_file in "${changed_files[@]}"; do | |
|         for required_doc in "${DOCS_REQUIRED[@]}"; do | |
|             if [[ "$changed_file" == "$required_doc" ]]; then | |
|                 return 0 | |
|             fi | |
|         done | |
|     done | |
|     return 1 | |
| } | |
| 
 | |
| # Check if Android build system was modified | |
| check_android_build_changes() { | |
|     local changed_files=("$@") | |
|      | |
|     for file in "${changed_files[@]}"; do | |
|         if [[ "$file" =~ ^android/ ]] || [[ "$file" =~ ^scripts/build-android\.sh$ ]]; then | |
|             return 0 | |
|         fi | |
|     done | |
|     return 1 | |
| } | |
| 
 | |
| # Check if asset configuration was modified | |
| check_asset_config_changes() { | |
|     local changed_files=("$@") | |
|      | |
|     for file in "${changed_files[@]}"; do | |
|         if [[ "$file" =~ ^capacitor-assets\.config\.json$ ]] || [[ "$file" =~ ^resources/ ]]; then | |
|             return 0 | |
|         fi | |
|     done | |
|     return 1 | |
| } | |
| 
 | |
| # Enhanced validation for Android changes | |
| validate_android_changes() { | |
|     local changed_files=("$@") | |
|      | |
|     if check_android_build_changes "${changed_files[@]}"; then | |
|         log_warn "Android build system changes detected!" | |
|         echo | |
|         echo "Android build system changes require enhanced validation:" | |
|         echo "  - Test asset generation: npm run build:android --assets" | |
|         echo "  - Test API routing modes: --dev and --dev --api-ip <custom>" | |
|         echo "  - Verify resource fallback mechanisms" | |
|         echo "  - Test across development/test/production modes" | |
|         echo | |
|         echo "Please ensure BUILDING.md includes Android-specific testing procedures." | |
|         echo | |
|     fi | |
|      | |
|     if check_asset_config_changes "${changed_files[@]}"; then | |
|         log_warn "Asset configuration changes detected!" | |
|         echo | |
|         echo "Asset configuration changes require validation:" | |
|         echo "  - Test asset generation across all platforms" | |
|         echo "  - Verify resource files are properly created" | |
|         echo "  - Test asset validation scripts" | |
|         echo | |
|     fi | |
| } | |
| 
 | |
| # Feedback collection for continuous improvement | |
| collect_feedback_data() { | |
|     local mode="$1" | |
|     local sensitive_touched=("${@:2}") | |
|     local timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ") | |
|      | |
|     # Create feedback log entry | |
|     local feedback_log=".guard-feedback.log" | |
|     echo "[$timestamp] Guard execution: $mode" >> "$feedback_log" | |
|     echo "  Sensitive files: ${sensitive_touched[*]}" >> "$feedback_log" | |
|      | |
|     # Log Android-specific changes for analysis | |
|     if check_android_build_changes "${sensitive_touched[@]}"; then | |
|         echo "  Android changes detected" >> "$feedback_log" | |
|     fi | |
|      | |
|     # Log asset configuration changes for analysis | |
|     if check_asset_config_changes "${sensitive_touched[@]}"; then | |
|         echo "  Asset config changes detected" >> "$feedback_log" | |
|     fi | |
|      | |
|     echo "" >> "$feedback_log" | |
| } | |
| 
 | |
| # Enhanced error handling with Android-specific guidance | |
| handle_documentation_error() { | |
|     local sensitive_touched=("$@") | |
|      | |
|     log_error "Build-sensitive files changed but BUILDING.md was not updated!" | |
|     echo | |
|     echo "The following build-sensitive files were modified:" | |
|     for file in "${sensitive_touched[@]}"; do | |
|         echo "  - $file" | |
|     done | |
|     echo | |
|     echo "When modifying build-critical files, you must also update BUILDING.md" | |
|     echo "to document any changes to the build process." | |
|     echo | |
| 
 | |
|     # Add Android-specific guidance | |
|     if check_android_build_changes "${sensitive_touched[@]}"; then | |
|         echo "⚠️  ANDROID BUILD SYSTEM CHANGES DETECTED ⚠️" | |
|         echo "Android changes require enhanced documentation including:" | |
|         echo "  - Asset validation procedures" | |
|         echo "  - API routing configuration" | |
|         echo "  - Resource generation testing" | |
|         echo "  - Platform-specific build modes" | |
|         echo | |
|     fi | |
|      | |
|     if check_asset_config_changes "${sensitive_touched[@]}"; then | |
|         echo "🎨 ASSET CONFIGURATION CHANGES DETECTED 🎨" | |
|         echo "Asset changes require documentation including:" | |
|         echo "  - Asset generation procedures" | |
|         echo "  - Resource validation steps" | |
|         echo "  - Platform-specific asset requirements" | |
|         echo | |
|     fi | |
| 
 | |
|     echo "Please:" | |
|     echo "  1. Update BUILDING.md with relevant changes" | |
|     echo "  2. Stage the BUILDING.md changes: git add BUILDING.md" | |
|     echo "  3. Retry your commit/push" | |
|     echo | |
|     echo "💡 Feedback: If this guard is too strict or missing patterns," | |
|     echo "   please report to the development team for continuous improvement." | |
|     echo | |
|     echo "📊 Feedback Categories:" | |
|     echo "  - False positives (files flagged that shouldn't be)" | |
|     echo "  - False negatives (sensitive files not caught)" | |
|     echo "  - Missing patterns (new file types to protect)" | |
|     echo "  - Overly strict (patterns too restrictive)" | |
|     echo "  - Documentation gaps (missing guidance)" | |
|     echo "  - Testing improvements (better procedures)" | |
|     echo | |
|     echo "📝 Report feedback to: Development team with specific examples" | |
|     echo | |
| } | |
| 
 | |
| # Main guard logic | |
| main() { | |
|     local mode="${1:-}" | |
|     local arg="${2:-}" | |
|      | |
|     log_info "Running Build Architecture Guard..." | |
|      | |
|     # Collect changed files | |
|     changed_files=() | |
|     while IFS= read -r line; do | |
|         [[ -n "$line" ]] && changed_files+=("$line") | |
|     done < <(collect_files "$mode" "$arg") | |
|      | |
|     if [[ ${#changed_files[@]} -eq 0 ]]; then | |
|         log_info "No files changed, guard check passed" | |
|         exit 0 | |
|     fi | |
|      | |
|     log_info "Checking ${#changed_files[@]} changed files..." | |
|      | |
|     # Find sensitive files that were touched | |
|     sensitive_touched=() | |
|     for file in "${changed_files[@]}"; do | |
|         if matches_sensitive "$file"; then | |
|             sensitive_touched+=("$file") | |
|         fi | |
|     done | |
|      | |
|     # If no sensitive files were touched, allow the change | |
|     if [[ ${#sensitive_touched[@]} -eq 0 ]]; then | |
|         log_success "No build-sensitive files changed, guard check passed" | |
|         exit 0 | |
|     fi | |
|      | |
|     # Sensitive files were touched, log them | |
|     log_warn "Build-sensitive paths changed:" | |
|     for file in "${sensitive_touched[@]}"; do | |
|         echo "  - $file" | |
|     done | |
|      | |
|     # Enhanced validation for Android changes | |
|     validate_android_changes "${changed_files[@]}" | |
|      | |
|     # Collect feedback data for continuous improvement | |
|     collect_feedback_data "$mode" "${sensitive_touched[@]}" | |
|      | |
|     # Check if required documentation was updated | |
|     if check_docs_updated "${changed_files[@]}"; then | |
|         log_success "BUILDING.md updated alongside build changes, guard check passed" | |
|         exit 0 | |
|     else | |
|         # Enhanced error handling with Android-specific guidance | |
|         handle_documentation_error "${sensitive_touched[@]}" | |
|         exit 2 | |
|     fi | |
| } | |
| 
 | |
| # Handle help flag | |
| if [[ "${1:-}" =~ ^(-h|--help)$ ]]; then | |
|     echo "Build Architecture Guard Script" | |
|     echo | |
|     echo "Usage:" | |
|     echo "  $0 [--staged|--range [RANGE]]" | |
|     echo | |
|     echo "Options:" | |
|     echo "  --staged          Check staged files (for pre-commit hook)" | |
|     echo "  --range [RANGE]   Check git range (for pre-push hook)" | |
|     echo "                    Default range: HEAD~1..HEAD" | |
|     echo "  (no args)         Check working directory changes" | |
|     echo "  --feedback        Show feedback analysis (for maintainers)" | |
|     echo | |
|     echo "Examples:" | |
|     echo "  $0 --staged                    # Pre-commit check" | |
|     echo "  $0 --range origin/main..HEAD   # Pre-push check" | |
|     echo "  $0                             # Working directory check" | |
|     echo "  $0 --feedback                  # Analyze guard effectiveness" | |
|     exit 0 | |
| fi | |
| 
 | |
| # Handle feedback analysis | |
| if [[ "${1:-}" == "--feedback" ]]; then | |
|     if [[ -f ".guard-feedback.log" ]]; then | |
|         echo "Build Architecture Guard Feedback Analysis" | |
|         echo "==========================================" | |
|         echo | |
|         echo "Recent guard executions:" | |
|         echo | |
|         tail -20 ".guard-feedback.log" | while IFS= read -r line; do | |
|             if [[ "$line" =~ ^\[ ]]; then | |
|                 echo "📅 $line" | |
|             elif [[ "$line" =~ ^\s*Sensitive\ files: ]]; then | |
|                 echo "🔍 $line" | |
|             elif [[ "$line" =~ ^\s*Android\ changes ]]; then | |
|                 echo "🤖 $line" | |
|             elif [[ "$line" =~ ^\s*Asset\ config ]]; then | |
|                 echo "🎨 $line" | |
|             elif [[ "$line" =~ ^\s*$ ]]; then | |
|                 echo "" | |
|             else | |
|                 echo "  $line" | |
|             fi | |
|         done | |
|         echo | |
|         echo "💡 Use this data to improve guard patterns and documentation" | |
|         echo "📊 Total executions: $(grep -c "Guard execution" .guard-feedback.log 2>/dev/null || echo "0")" | |
|     else | |
|         echo "No feedback data available yet. Run the guard to collect data." | |
|     fi | |
|     exit 0 | |
| fi | |
| 
 | |
| main "$@"
 | |
| 
 |