#!/usr/bin/env bash # # Build Architecture Guard Script # # Author: Matthew Raymer # Date: 2025-08-20 # Purpose: Protects build-critical files by requiring BUILDING.md updates # # 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" "package.json" "package-lock.json" "yarn.lock" "pnpm-lock.yaml" ) # Documentation files that must be updated alongside sensitive changes DOCS_REQUIRED=("BUILDING.md") # 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 } # Main guard logic main() { local mode="${1:-}" local arg="${2:-}" log_info "Running Build Architecture Guard..." # Collect changed files mapfile -t changed_files < <(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 # 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 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 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 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 echo "Examples:" echo " $0 --staged # Pre-commit check" echo " $0 --range origin/main..HEAD # Pre-push check" echo " $0 # Working directory check" exit 0 fi main "$@"