#!/usr/bin/env bash set -euo pipefail REPO_DIR="${REPO_DIR:-$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)}" ENV_FILE="${ENV_FILE:-/home/m/assistant-deploy/production-compose.env}" POSTGRES_CONTAINER="${POSTGRES_CONTAINER:-assistant-postgres-1}" if [[ ! -f "$ENV_FILE" ]]; then echo "migration runner: env file is missing" >&2 exit 1 fi set -a # The deployment env file is controlled by the production operator. Values # are used only by the local Docker/psql boundary and are never logged. . "$ENV_FILE" set +a : "${POSTGRES_SUPERUSER:?POSTGRES_SUPERUSER is required}" POSTGRES_SUPERUSER="${POSTGRES_SUPERUSER//$'\r'/}" DATABASE="${POSTGRES_DB:-assistant}" DATABASE="${DATABASE//$'\r'/}" psql_exec() { docker exec -i "$POSTGRES_CONTAINER" psql -v ON_ERROR_STOP=1 -U "$POSTGRES_SUPERUSER" -d "$DATABASE" "$@" } psql_exec -c "CREATE TABLE IF NOT EXISTS public.assistant_migration_history (migration_id TEXT PRIMARY KEY, applied_at_unix_millis BIGINT NOT NULL CHECK (applied_at_unix_millis > 0));" if [[ -n "${MIGRATION_BASELINE:-}" ]]; then if [[ ! "$MIGRATION_BASELINE" =~ ^[0-9]{3}$ ]]; then echo "migration runner: invalid MIGRATION_BASELINE" >&2 exit 1 fi now_ms="$(date +%s%3N)" for file in "$REPO_DIR"/database/migrations/[0-9][0-9][0-9]_*.sql; do migration_id="$(basename "$file" .sql)" number="${migration_id:0:3}" if (( 10#$number <= 10#$MIGRATION_BASELINE )); then psql_exec -c "INSERT INTO public.assistant_migration_history(migration_id, applied_at_unix_millis) VALUES ('$migration_id', $now_ms) ON CONFLICT (migration_id) DO NOTHING;" fi done fi for file in "$REPO_DIR"/database/migrations/[0-9][0-9][0-9]_*.sql; do [[ -f "$file" ]] || continue migration_id="$(basename "$file" .sql)" applied="$(psql_exec -At -c "SELECT 1 FROM public.assistant_migration_history WHERE migration_id='$migration_id' LIMIT 1;")" [[ "$applied" == "1" ]] && continue psql_exec < "$file" now_ms="$(date +%s%3N)" psql_exec -c "INSERT INTO public.assistant_migration_history(migration_id, applied_at_unix_millis) VALUES ('$migration_id', $now_ms);" done