#!/usr/bin/env bash set -euo pipefail DEPLOY_ENV="${1:-unknown}" COMPOSE_FILE="${COMPOSE_FILE:-docker-compose.prod.yml}" APP_ENV_FILE="${APP_ENV_FILE:-.env.production}" DEPLOY_ENV_FILE="${DEPLOY_ENV_FILE:-deploy.env}" READY_URL="${READY_URL:-http://127.0.0.1:${APP_HOST_PORT:-3000}/api/ready}" READY_ATTEMPTS="${READY_ATTEMPTS:-60}" READY_SLEEP_SECONDS="${READY_SLEEP_SECONDS:-5}" if [ -f "${APP_ENV_FILE}" ]; then set -a # Load application secrets so docker compose interpolation sees them. . "${APP_ENV_FILE}" set +a fi if [ -f "${DEPLOY_ENV_FILE}" ]; then set -a . "${DEPLOY_ENV_FILE}" set +a fi : "${APP_IMAGE:?APP_IMAGE must be set}" : "${MIGRATOR_IMAGE:?MIGRATOR_IMAGE must be set}" : "${POSTGRES_PASSWORD:?POSTGRES_PASSWORD must be set}" echo "Deploy environment: ${DEPLOY_ENV}" echo "Compose file: ${COMPOSE_FILE}" echo "App env file: ${APP_ENV_FILE}" echo "App image: ${APP_IMAGE}" echo "Migrator image: ${MIGRATOR_IMAGE}" DOCKER_REGISTRY="${DOCKER_REGISTRY:-ghcr.io}" if [ -n "${GHCR_USERNAME:-}" ] && [ -n "${GHCR_TOKEN:-}" ]; then printf '%s\n' "${GHCR_TOKEN}" | docker login "${DOCKER_REGISTRY}" -u "${GHCR_USERNAME}" --password-stdin fi docker compose -f "${COMPOSE_FILE}" config -q docker compose -f "${COMPOSE_FILE}" pull app migrator docker compose -f "${COMPOSE_FILE}" up -d postgres redis docker compose -f "${COMPOSE_FILE}" run --rm migrator docker compose -f "${COMPOSE_FILE}" up -d app for attempt in $(seq 1 "${READY_ATTEMPTS}"); do if curl -fsS "${READY_URL}" >/dev/null 2>&1; then echo "Application ready after attempt ${attempt}" docker compose -f "${COMPOSE_FILE}" ps exit 0 fi sleep "${READY_SLEEP_SECONDS}" done echo "Deployment failed readiness check: ${READY_URL}" >&2 docker compose -f "${COMPOSE_FILE}" ps >&2 docker compose -f "${COMPOSE_FILE}" logs --tail 200 app >&2 exit 1