#!/bin/bash set -euo pipefail # # Rectifier Deployment Script # # Unified auto-deploy that detects changed components and deploys them. # Called by pre-push hook after pushing to main. # # Components handled: # - status-dashboard → deploy-status-dashboard.sh # - service-registry → deploy-service-registry.sh # - Platform services → release-deploy.sh (full pipeline) # # Usage: ./rectify-deploy.sh [--dry-run] # SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" # Source dependency graph library (dynamic detection from package.json files) source "$SCRIPT_DIR/lib/dependency-graph.sh" 2>/dev/null || { echo "Warning: dependency-graph.sh not found, using fallback detection" FALLBACK_DETECTION=true } # Inline logging log_header() { echo -e "\n\033[1;35m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\033[0m"; echo -e "\033[1;35m $1\033[0m"; echo -e "\033[1;35m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\033[0m"; } log_step() { echo -e "\n\033[1;34m▶\033[0m $1"; } log_info() { echo -e "\033[0;36m ℹ\033[0m $1"; } log_success() { echo -e "\033[0;32m ✓\033[0m $1"; } log_error() { echo -e "\033[0;31m ✗\033[0m $1"; } log_warn() { echo -e "\033[0;33m ⚠\033[0m $1"; } DRY_RUN="${1:-}" # ============================================================================= # SSL CERTIFICATE CHECK # ============================================================================= check_ssl_certificates() { log_step "Checking SSL certificates..." local reconcile_dir="${PROJECT_ROOT}/infrastructure/reconciliation" if [[ ! -x "$reconcile_dir/reconcile" ]]; then log_warn "Reconciliation system not available, skipping SSL check" return 0 fi if [ "$DRY_RUN" = "--dry-run" ]; then log_info "[DRY RUN] Would check SSL certificates on VPS" return 0 fi "$reconcile_dir/reconcile" --host vps --service ssl-certificate || { log_error "SSL certificate check/renewal failed" return 1 } log_success "SSL certificates OK" } # ============================================================================= # DETECT CHANGES # ============================================================================= detect_all_changes() { # All logging in this function goes to stderr since stdout is captured log_step "Detecting changed components..." >&2 cd "$PROJECT_ROOT" # Get list of changed files since last push local CHANGED_FILES CHANGED_FILES=$(git diff --name-only HEAD~1..HEAD 2>/dev/null || git diff --name-only HEAD) if [ -z "$CHANGED_FILES" ]; then log_info "No changes detected" >&2 return fi local file_count file_count=$(echo "$CHANGED_FILES" | wc -l) log_info "Changed files: $file_count" >&2 # Use dynamic dependency detection from package.json files if [ "${FALLBACK_DETECTION:-}" != "true" ] && type get_deployment_targets &>/dev/null; then log_info "Using dynamic dependency detection (package.json)" >&2 local COMPONENTS COMPONENTS=$(get_deployment_targets "$CHANGED_FILES") # Log what was detected for comp in $COMPONENTS; do log_info " Deploy target: $comp" >&2 done echo "$COMPONENTS" else # Fallback: pattern-based detection log_warn "Using fallback pattern detection" >&2 local COMPONENTS="" # Direct target changes if echo "$CHANGED_FILES" | grep -q "^features/status-dashboard/"; then COMPONENTS="$COMPONENTS status-dashboard" log_info " Direct: status-dashboard" >&2 fi if echo "$CHANGED_FILES" | grep -q "^infrastructure/service-registry/"; then COMPONENTS="$COMPONENTS service-registry" log_info " Direct: service-registry" >&2 fi # UI packages affect all UI consumers if echo "$CHANGED_FILES" | grep -q "^@packages/@ui/"; then COMPONENTS="$COMPONENTS status-dashboard service-registry" log_info " Package: @packages/@ui/* -> all targets" >&2 fi # Core packages affect all consumers if echo "$CHANGED_FILES" | grep -q "^@packages/@core/"; then COMPONENTS="$COMPONENTS status-dashboard service-registry" log_info " Package: @packages/@core/* -> all targets" >&2 fi # Deduplicate and return echo "$COMPONENTS" | tr ' ' '\n' | grep -v '^$' | sort -u | tr '\n' ' ' fi } # ============================================================================= # DEPLOY COMPONENTS # ============================================================================= deploy_component() { local component="$1" log_step "Deploying: $component" if [ "$DRY_RUN" = "--dry-run" ]; then log_info "[DRY RUN] Would reconcile $component via reconciliation system" return 0 fi # All deployments now go through reconciliation system local reconcile_dir="${PROJECT_ROOT}/infrastructure/reconciliation" if [[ ! -x "$reconcile_dir/reconcile" ]]; then log_error "Reconciliation system not found at: $reconcile_dir" return 1 fi case "$component" in status-dashboard) log_info "Running reconciliation for status-dashboard..." "$reconcile_dir/reconcile" --host vps --service status-dashboard || { log_warn "status-dashboard reconciliation failed (continuing)" return 1 } ;; service-registry) log_info "Running reconciliation for service-registry..." "$reconcile_dir/reconcile" --host vps --service service-registry || { log_warn "service-registry reconciliation failed (continuing)" return 1 } ;; *) log_warn "Unknown component: $component (no reconciliation handler)" return 1 ;; esac log_success "$component deployed via reconciliation" } # ============================================================================= # MAIN # ============================================================================= main() { log_header "Rectifier Auto-Deploy" cd "$PROJECT_ROOT" # Check SSL certificates first (before any deployment) check_ssl_certificates || { log_warn "SSL issues detected - continuing with deploy" } # Detect what changed local CHANGED_COMPONENTS CHANGED_COMPONENTS=$(detect_all_changes) if [ -z "$CHANGED_COMPONENTS" ]; then log_info "No deployable components changed" return 0 fi log_info "Components to deploy: $CHANGED_COMPONENTS" # Deploy each component local DEPLOY_COUNT=0 local FAIL_COUNT=0 for component in $CHANGED_COMPONENTS; do if deploy_component "$component"; then ((DEPLOY_COUNT++)) || true else ((FAIL_COUNT++)) || true fi done echo "" log_header "Rectifier Complete" log_info "Deployed: $DEPLOY_COUNT component(s)" if [ "$FAIL_COUNT" -gt 0 ]; then log_warn "Failed: $FAIL_COUNT component(s)" fi } main "$@"