dev1/deploy_all.sh
Josh a736e1d4d1
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
CORS ALLOWED ORIGINS fix/alignment.
2025-09-02 14:21:47 +00:00

157 lines
7.0 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
set -euo pipefail
# ───────────────────────── config ─────────────────────────
ENV="${1:-${ENV:-dev}}"
case "$ENV" in dev|staging|prod) ;; *) echo "❌ Unknown ENV='$ENV'"; exit 1 ;; esac
PROJECT="aptivaai-${ENV}"
REG="us-central1-docker.pkg.dev/${PROJECT}/aptiva-repo"
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
MIRROR_TO_STAGING="${MIRROR_TO_STAGING:-false}" # default off (set via Woodpecker var)
MIRROR_TO_PROD="${MIRROR_TO_PROD:-false}" # default off
PROMOTE_PROD="${PROMOTE_PROD:-false}" # default off
echo "🔧 Deploying environment: $ENV (GCP: $PROJECT)"
SECRETS=(
ENV_NAME PROJECT CORS_ALLOWED_ORIGINS
TOKEN_MAX_AGE_MS COOKIE_SECURE COOKIE_SAMESITE ACCESS_COOKIE_NAME
SERVER1_PORT SERVER2_PORT SERVER3_PORT
JWT_SECRET OPENAI_API_KEY ONET_USERNAME ONET_PASSWORD
STRIPE_SECRET_KEY STRIPE_PUBLISHABLE_KEY STRIPE_WH_SECRET
STRIPE_PRICE_PREMIUM_MONTH STRIPE_PRICE_PREMIUM_YEAR
STRIPE_PRICE_PRO_MONTH STRIPE_PRICE_PRO_YEAR
DB_HOST DB_NAME DB_PORT DB_USER DB_PASSWORD
DB_SSL_CERT DB_SSL_KEY DB_SSL_CA
SUPPORT_SENDGRID_API_KEY EMAIL_INDEX_SECRET APTIVA_API_BASE
TWILIO_ACCOUNT_SID TWILIO_AUTH_TOKEN TWILIO_MESSAGING_SERVICE_SID
GOOGLE_MAPS_API_KEY
KMS_KEY_NAME DEK_PATH
)
cd "$ROOT"
# ───────────── pull runtime secrets (BEFORE build) ─────────────
echo "🔐 Pulling secrets from Secret Manager"
for S in "${SECRETS[@]}"; do
export "$S"="$(gcloud secrets versions access latest --secret="${S}_${ENV}" --project="$PROJECT")"
done
export FROM_SECRETS_MANAGER=true
# React needs the prefixed var at BUILD time
export REACT_APP_GOOGLE_MAPS_API_KEY="$GOOGLE_MAPS_API_KEY"
export REACT_APP_ENV_NAME="$ENV_NAME"
# ───────────────────────── node + npm ci cache ─────────────────────────
echo "🛠 Building front-end bundle (skips when unchanged)"
export npm_config_cache="${HOME}/.npm" # persist npm cache
export CI=false # dont treat warnings as errors
NODE_VER="$(node -v 2>/dev/null || echo 'none')"
if [[ ! -f .last-node || "$(cat .last-node 2>/dev/null || echo)" != "$NODE_VER" ]]; then
echo "♻️ Node changed → cleaning node_modules (was '$(cat .last-node 2>/dev/null || echo none)', now '${NODE_VER}')"
rm -rf node_modules .build.hash
fi
echo "$NODE_VER" > .last-node
if [[ ! -f package-lock.json ]]; then
echo "⚠️ package-lock.json missing; running npm ci"
npm ci --silent --no-audit --no-fund
else
LOCK_HASH="$(sha1sum package-lock.json | awk '{print $1}')"
if [[ -d node_modules && -f .last-lock && "$(cat .last-lock)" == "$LOCK_HASH" ]]; then
echo "📦 node_modules up-to-date; skipping npm ci"
else
echo "📦 installing deps…"
npm ci --silent --no-audit --no-fund
echo "$LOCK_HASH" > .last-lock
echo "$LOCK_HASH" > .lock.hash # legacy compat
fi
fi
# ───────────────────────── npm run build cache ─────────────────────────
SRC_HASH="$(find src public -type f -print0 2>/dev/null | sort -z | xargs -0 sha1sum | sha1sum | awk '{print $1}')"
PKG_HASH="$(sha1sum package.json package-lock.json 2>/dev/null | sha1sum | awk '{print $1}')"
BUILD_ENV_HASH="$(printf '%s' "${REACT_APP_GOOGLE_MAPS_API_KEY}-${REACT_APP_API_URL:-}" | sha1sum | awk '{print $1}')"
COMBINED_HASH="${SRC_HASH}-${PKG_HASH}-${BUILD_ENV_HASH}"
if [[ -f .build.hash && "$(cat .build.hash)" == "$COMBINED_HASH" && -d build ]]; then
echo "🏗 static bundle up-to-date; skipping npm run build"
else
echo "🏗 Building static bundle…"
GENERATE_SOURCEMAP=false NODE_OPTIONS="--max-old-space-size=4096" npm run build
echo "$COMBINED_HASH" > .build.hash
fi
# ───────────────────── build & push images (SEQUENTIAL) ─────────────────────
export DOCKER_BUILDKIT=1
export COMPOSE_DOCKER_CLI_BUILD=1
export BUILDKIT_PROGRESS=plain # stable progress output
TAG="$(git rev-parse --short HEAD)-$(date -u +%Y%m%d%H%M)"
echo "🔨 Building & pushing containers (tag = ${TAG})"
build_and_push () {
local svc="$1"
echo "🧱 Building ${svc}"
docker build --progress=plain -f "Dockerfile.${svc}" -t "${REG}/${svc}:${TAG}" .
echo "⏫ Pushing ${svc}"
docker push "${REG}/${svc}:${TAG}"
}
SERVICES=(server1 server2 server3 nginx)
# Build & push to DEV registry first (source of truth)
for svc in "${SERVICES[@]}"; do
build_and_push "$svc"
done
# ───────────────────── optional: mirror to staging/prod ─────────────────────
# Staging mirror
if [[ "$MIRROR_TO_STAGING" == "true" ]]; then
echo "🔁 Mirroring images to STAGING registry (tag=${TAG})"
DST_REG_STG="us-central1-docker.pkg.dev/aptivaai-staging/aptiva-repo"
for svc in "${SERVICES[@]}"; do
docker tag "${REG}/${svc}:${TAG}" "${DST_REG_STG}/${svc}:${TAG}"
docker push "${DST_REG_STG}/${svc}:${TAG}"
done
printf "%s" "${TAG}" | gcloud secrets versions add IMG_TAG --data-file=- --project="aptivaai-staging" >/dev/null
echo "🏷 IMG_TAG published to aptivaai-staging"
else
echo "⏭ Skipping staging mirror (MIRROR_TO_STAGING=$MIRROR_TO_STAGING)"
fi
# Prod mirror (dual-key: MIRROR_TO_PROD && PROMOTE_PROD)
if [[ "$MIRROR_TO_PROD" == "true" && "$PROMOTE_PROD" == "true" ]]; then
echo "🔁 Mirroring images to PROD registry (tag=${TAG})"
DST_REG_PROD="us-central1-docker.pkg.dev/aptivaai-prod/aptiva-repo"
for svc in "${SERVICES[@]}"; do
docker tag "${REG}/${svc}:${TAG}" "${DST_REG_PROD}/${svc}:${TAG}"
docker push "${DST_REG_PROD}/${svc}:${TAG}"
done
printf "%s" "${TAG}" | gcloud secrets versions add IMG_TAG --data-file=- --project="aptivaai-prod" >/dev/null
echo "🏷 IMG_TAG published to aptivaai-prod"
else
echo "⏭ Skipping prod mirror (MIRROR_TO_PROD=$MIRROR_TO_PROD, PROMOTE_PROD=$PROMOTE_PROD)"
fi
# ───────────────────── write IMG_TAG locally ─────────────────────
export IMG_TAG="${TAG}"
echo "🔖 Using IMG_TAG=${IMG_TAG}"
# ───────────────────── publish IMG_TAG to Secret Manager ─────────────────────
printf "%s" "${TAG}" | gcloud secrets versions add IMG_TAG --data-file=- --project="$PROJECT" >/dev/null
echo "📦 IMG_TAG pushed to Secret Manager"
# ───────────────────── docker compose up ─────────────────────
preserve=IMG_TAG,FROM_SECRETS_MANAGER,REACT_APP_API_URL,REACT_APP_GOOGLE_MAPS_API_KEY,$(IFS=,; echo "${SECRETS[*]}")
echo "🚀 docker compose up -d (env: $preserve)"
sudo --preserve-env="$preserve" docker compose up -d --force-recreate \
2> >(grep -v 'WARN \[0000\]')
echo "✅ Deployment finished"