182 lines
5.5 KiB
Bash
Executable File
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."
|