name: Deploy to Production on: push: branches: - main jobs: deploy: runs-on: ubuntu-latest env: COMPOSE_PROJECT_NAME: voxblog INFISICAL_TOKEN: ${{ secrets.INFISICAL_TOKEN }} INFISICAL_SITE_URL: ${{ secrets.INFISICAL_SITE_URL }} INFISICAL_CLI_IMAGE: infisical/cli:latest steps: - name: Checkout code uses: actions/checkout@v3 - name: Create placeholder .env run: touch .env - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 - name: Load secrets from Infisical shell: bash run: | set -euo pipefail if [ -z "${INFISICAL_TOKEN}" ]; then echo "INFISICAL_TOKEN is not configured" exit 1 fi CLI_IMAGE="${INFISICAL_CLI_IMAGE:-infisical/cli:latest}" docker pull "$CLI_IMAGE" >/dev/null tmp_file=$(mktemp) if [ -n "${INFISICAL_API_URL:-}" ]; then docker run --rm \ -e INFISICAL_TOKEN="$INFISICAL_TOKEN" \ ${INFISICAL_SITE_URL:+-e INFISICAL_SITE_URL="$INFISICAL_SITE_URL"} \ -e INFISICAL_API_URL="$INFISICAL_API_URL" \ "$CLI_IMAGE" export --format=dotenv > "$tmp_file" elif [ -n "${INFISICAL_SITE_URL:-}" ]; then api_url="${INFISICAL_SITE_URL%/}/api" docker run --rm \ -e INFISICAL_TOKEN="$INFISICAL_TOKEN" \ -e INFISICAL_SITE_URL="$INFISICAL_SITE_URL" \ -e INFISICAL_API_URL="$api_url" \ "$CLI_IMAGE" export --format=dotenv > "$tmp_file" else docker run --rm \ -e INFISICAL_TOKEN="$INFISICAL_TOKEN" \ "$CLI_IMAGE" export --format=dotenv > "$tmp_file" fi # Persist a runtime .env so external checks that expect the file succeed. cp "$tmp_file" .env while IFS= read -r line || [ -n "$line" ]; do if [ -z "$line" ] || [[ "$line" == \#* ]]; then continue fi key="${line%%=*}" value="${line#*=}" echo "::add-mask::$value" printf '%s=%s\n' "$key" "$value" >> "$GITHUB_ENV" done < "$tmp_file" rm -f "$tmp_file" - name: Stop existing containers run: docker-compose down || true - name: Build images run: docker-compose build --no-cache - name: Start containers run: docker-compose up -d - name: Wait for services run: sleep 15 - name: Run database migrations run: docker-compose exec -T api pnpm run drizzle:migrate || echo "Migration skipped" - name: Health check API run: | for i in {1..10}; do if curl -f http://localhost:3301/api/health; then echo "API is healthy" exit 0 fi echo "Waiting for API... ($i/10)" sleep 5 done echo "API health check failed" docker-compose logs api exit 1 - name: Health check Admin run: | if curl -f http://localhost:3300; then echo "Admin is healthy" else echo "Admin health check failed" docker-compose logs admin exit 1 fi - name: Clean up old images run: docker image prune -af --filter "until=24h" - name: Deployment summary run: | echo "✅ Deployment successful!" echo "Services:" docker-compose ps