#!/usr/bin/env bash set +x set -Eeuo pipefail umask 077 # The only active Pre-Production env source. Never source the checkout's .env. ENV_FILE='/home/kai/.config/metalcircle/preprod.env' DEPLOYMENT_STARTED=0 on_error() { local status=$? if [[ "$DEPLOYMENT_STARTED" == 0 ]]; then printf 'Deployment aborted. Running container unchanged.\n' >&2 else printf 'Deployment verification failed after the container update. Manual investigation required.\n' >&2 fi exit "$status" } trap on_error ERR CHECK_ONLY=0 if [[ "${1:-}" == '--check' && "$#" == 1 ]]; then CHECK_ONLY=1 elif [[ "$#" != 0 ]]; then printf 'Usage: ./scripts/deploy-preprod.sh [--check]\n' >&2 exit 1 fi SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)" REPO_ROOT="$(cd -- "${SCRIPT_DIR}/.." && pwd -P)" cd -- "$REPO_ROOT" if ! TOP_LEVEL="$(git rev-parse --show-toplevel 2>/dev/null)" || [[ "$(cd -- "$TOP_LEVEL" && pwd -P)" != "$REPO_ROOT" ]]; then printf 'FEHLER: %s liegt nicht in einem Git-Repository-Checkout.\n' "$REPO_ROOT" >&2 exit 1 fi BRANCH="$(git branch --show-current)" if [[ "$BRANCH" != "main" ]]; then printf 'FEHLER: Deployment ist nur von Branch main erlaubt (aktuell: %s).\n' "${BRANCH:-unbekannt}" >&2 exit 1 fi WORKTREE_STATUS="$(git status --porcelain --untracked-files=all)" if [[ -n "$WORKTREE_STATUS" ]]; then printf 'FEHLER: Working Tree ist nicht sauber. Änderungen zuerst committen oder entfernen.\n' >&2 exit 1 fi if [[ "$CHECK_ONLY" == 0 ]]; then printf 'Aktualisiere main mit Fast-Forward ...\n' git pull --ff-only origin main fi host_check() { python3 "$SCRIPT_DIR/preprod_config.py" --env-file "$ENV_FILE" "$@" } compose() { # Executes sudo docker compose --env-file "$ENV_FILE" -f compose.yml -f compose.preprod.yml. # The helper clears ambient overrides and suppresses secret-bearing raw diagnostics. host_check compose "$@" } run_preflight() { "$@" python push_preflight.py \ --expected-service-account metalcircle-push-preprod@metalcircle-30d9b.iam.gserviceaccount.com "$@" python gitea_preflight.py } printf 'Prüfe externe Environment-Datei und Host-Secret ...\n' host_check check CONFIG_FINGERPRINT="$(host_check fingerprint)" printf 'Prüfe Pre-Production-Compose-Konfiguration ...\n' compose config --quiet printf 'Baue Web-Image ...\n' compose build web printf 'Prüfe Firebase und Gitea im temporären Container ...\n' run_preflight compose run --rm --no-deps -T web if [[ "$(host_check fingerprint)" != "$CONFIG_FINGERPRINT" ]]; then printf 'ERROR: Environment or Firebase secret changed during deployment. Start again.\n' >&2 false fi if [[ "$CHECK_ONLY" == 1 ]]; then printf 'PASS: Pre-Production preflights completed; running container unchanged.\n' exit 0 fi printf 'Sichere geprüfte Environment-Datei außerhalb des Checkouts ...\n' host_check backup printf 'Aktualisiere ausschließlich den Webcontainer ...\n' DEPLOYMENT_STARTED=1 compose up -d --no-deps web printf 'Prüfe Firebase und Gitea im laufenden Webcontainer ...\n' run_preflight compose exec -T web printf '\nCompose-Status:\n' compose ps --format json printf '\nWeb-Logs der letzten 2 Minuten (maximal 100 Zeilen, sicher gefiltert):\n' compose logs --since=2m --tail=100 --no-color web printf '\nDeployter Git-Commit:\n' git log -1 --format='%h %s'