Eventbuzz_Web/deploy.sh

182 lines
5.5 KiB
Bash
Executable File

#!/usr/bin/env bash
#
# EventBuzz production deploy
#
# Usage:
# ./deploy.sh # backend + dashboard + visitor website + public web
# ./deploy.sh backend
# ./deploy.sh frontend
# ./deploy.sh website
# ./deploy.sh web
# ./deploy.sh all
#
# Requirements: ssh, rsync, npm, aws CLI (profile stratawiztech)
#
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SSH_KEY="${SSH_KEY:-$HOME/Documents/Keys/ravimac}"
SSH_HOST="${SSH_HOST:-root@168.144.70.247}"
BACKEND_REMOTE="${BACKEND_REMOTE:-/var/www/backend}"
AWS_PROFILE="${AWS_PROFILE:-stratawiztech}"
FRONTEND_DIR="$ROOT/frontend"
EVENTBUZZ_DIR="$ROOT/eventbuzz"
WEB_DIR="$ROOT/web"
BACKEND_DIR="$ROOT/backend"
S3_CONSOLE="s3://eventbuzzlive/console/"
S3_WEBSITE="s3://eventbuzzlive/website/"
S3_WEB="s3://eventbuzzlive/web/"
# CloudFront distributions (console dashboard + visitor website + public web)
CF_CONSOLE="${CF_CONSOLE:-E1QQM75X0JF0IU}"
CF_WEBSITE="${CF_WEBSITE:-E3ORUQT7269RIM}"
CF_WEB="${CF_WEB:-ETZS6Z42DG7I6}"
log() { printf '\n\033[1;36m==>\033[0m %s\n' "$*"; }
die() { printf '\033[1;31merror:\033[0m %s\n' "$*" >&2; exit 1; }
ssh_cmd() {
ssh -i "$SSH_KEY" -o StrictHostKeyChecking=accept-new "$SSH_HOST" "$@"
}
rsync_ssh() {
rsync -avz -e "ssh -i $SSH_KEY -o StrictHostKeyChecking=accept-new" "$@"
}
invalidate_cloudfront() {
local distribution_id="$1"
local label="$2"
log "CloudFront invalidation ($label) → $distribution_id /*"
aws cloudfront create-invalidation \
--distribution-id "$distribution_id" \
--paths "/*" \
--profile "$AWS_PROFILE" \
--output text \
--query 'Invalidation.Id'
}
# Ensure dashboard / visitor builds use production API URLs (not localhost).
apply_production_env() {
log "Applying production env for dashboard (frontend/.env.production)"
if [[ ! -f "$FRONTEND_DIR/.env.production" ]]; then
die "Missing $FRONTEND_DIR/.env.production — create it with production VITE_* URLs."
fi
# If a local .env exists, show what we're overriding for clarity
if [[ -f "$FRONTEND_DIR/.env" ]]; then
grep -E '^VITE_API_URL=' "$FRONTEND_DIR/.env.production" || true
fi
log "Applying production env for visitor site (eventbuzz/.env.production)"
if [[ ! -f "$EVENTBUZZ_DIR/.env.production" ]]; then
die "Missing $EVENTBUZZ_DIR/.env.production — create it with production VITE_* URLs."
fi
grep -E '^VITE_API_BASE_URL=' "$EVENTBUZZ_DIR/.env.production" || true
log "Applying production env for public web (web/.env.production)"
if [[ ! -f "$WEB_DIR/.env.production" ]]; then
die "Missing $WEB_DIR/.env.production — create it with production VITE_* URLs."
fi
grep -E '^VITE_(API_BASE_URL|PUBLIC_WEB_BASE)=' "$WEB_DIR/.env.production" || true
}
deploy_backend() {
log "Deploying backend → $SSH_HOST:$BACKEND_REMOTE/"
[[ -d "$BACKEND_DIR/src" ]] || die "Backend src folder not found at $BACKEND_DIR/src"
[[ -f "$BACKEND_DIR/package.json" ]] || die "Backend package.json not found"
[[ -f "$SSH_KEY" ]] || die "SSH key not found: $SSH_KEY"
rsync_ssh --delete \
"$BACKEND_DIR/src/" \
"$SSH_HOST:$BACKEND_REMOTE/src/"
log "Syncing package.json + package-lock.json"
rsync_ssh \
"$BACKEND_DIR/package.json" \
"$BACKEND_DIR/package-lock.json" \
"$SSH_HOST:$BACKEND_REMOTE/"
log "Installing dependencies + reloading API on server (pm2)"
ssh_cmd "cd '$BACKEND_REMOTE' && npm ci --omit=dev && (pm2 reload all || pm2 restart all || echo 'pm2 reload skipped — run manually on server')"
}
deploy_frontend() {
log "Building dashboard (console) for production"
apply_production_env
cd "$FRONTEND_DIR"
npm run build
log "Uploading dashboard dist → $S3_CONSOLE"
aws s3 rm "$S3_CONSOLE" --recursive --profile "$AWS_PROFILE"
aws s3 sync "$FRONTEND_DIR/dist" "$S3_CONSOLE" --profile "$AWS_PROFILE"
invalidate_cloudfront "$CF_CONSOLE" "console"
log "Dashboard deploy complete"
}
deploy_website() {
log "Building visitor website for production"
apply_production_env
cd "$EVENTBUZZ_DIR"
npm run build
log "Uploading visitor site dist → $S3_WEBSITE"
aws s3 rm "$S3_WEBSITE" --recursive --profile "$AWS_PROFILE"
aws s3 sync "$EVENTBUZZ_DIR/dist" "$S3_WEBSITE" --profile "$AWS_PROFILE"
invalidate_cloudfront "$CF_WEBSITE" "website"
log "Visitor website deploy complete"
}
deploy_web() {
log "Building public web app for production"
apply_production_env
cd "$WEB_DIR"
npm run build
log "Uploading public web dist → $S3_WEB"
aws s3 rm "$S3_WEB" --recursive --profile "$AWS_PROFILE"
aws s3 sync "$WEB_DIR/dist" "$S3_WEB" --profile "$AWS_PROFILE"
invalidate_cloudfront "$CF_WEB" "web"
log "Public web deploy complete"
}
usage() {
cat <<EOF
Usage: $(basename "$0") [backend|frontend|website|web|all]
backend rsync backend/src + package files, npm ci on server, pm2 reload
frontend production build + S3 sync to $S3_CONSOLE + CF invalidation
website production build + S3 sync to $S3_WEBSITE + CF invalidation
web production build + S3 sync to $S3_WEB + CF invalidation
all run all four (default)
Environment overrides:
SSH_KEY, SSH_HOST, BACKEND_REMOTE, AWS_PROFILE, CF_CONSOLE, CF_WEBSITE, CF_WEB
EOF
}
TARGET="${1:-all}"
case "$TARGET" in
backend) deploy_backend ;;
frontend) deploy_frontend ;;
website) deploy_website ;;
web) deploy_web ;;
all)
deploy_backend
deploy_frontend
deploy_website
deploy_web
;;
-h|--help|help) usage ;;
*) die "Unknown target: $TARGET (use backend|frontend|website|web|all)" ;;
esac
log "Done."