#!/usr/bin/env bash set -Eeuo pipefail ts() { date +"%Y-%m-%d %H:%M:%S"; } log() { echo "[$(ts)] [INFO] $*"; } warn(){ echo "[$(ts)] [WARN] $*" >&2; } err() { echo "[$(ts)] [ERROR] $*" >&2; } die() { err "$*"; exit 1; } trap 'err "Migration failed. Showing last 200 log lines:"; docker logs --tail=200 mssql2025 2>/dev/null || true' ERR cd "$(dirname "$0")/.." [[ -f .env ]] || die "Missing .env. Create it first: cp .env.example .env" set -a # shellcheck disable=SC1091 source .env set +a [[ -n "${MSSQL_SA_PASSWORD:-}" ]] || die "MSSQL_SA_PASSWORD is empty in .env" if ! docker ps --format '{{.Names}}' | grep -qx 'mssql2025'; then die "Container mssql2025 is not running. Start it first: ./scripts/start.sh" fi health="$(docker inspect -f '{{.State.Health.Status}}' mssql2025 2>/dev/null || true)" [[ "$health" == "healthy" ]] || die "Container is not healthy (health=$health). Run ./scripts/start.sh" # Bootstrap: ensure DevDb + migration table exists bootstrap_sql=$( cat <<'SQL' IF DB_ID('DevDb') IS NULL BEGIN CREATE DATABASE DevDb; END GO USE DevDb; GO IF OBJECT_ID('dbo.__SchemaMigrations','U') IS NULL BEGIN CREATE TABLE dbo.__SchemaMigrations( Id int IDENTITY(1,1) NOT NULL PRIMARY KEY, Filename nvarchar(260) NOT NULL UNIQUE, AppliedAt datetime2 NOT NULL CONSTRAINT DF___SchemaMigrations_AppliedAt DEFAULT (sysutcdatetime()) ); END GO SQL ) log "Ensuring DevDb + dbo.__SchemaMigrations exist..." docker exec -i mssql2025 /opt/mssql-tools18/bin/sqlcmd \ -S localhost -U sa -P "$MSSQL_SA_PASSWORD" \ -b -Q "$bootstrap_sql" < /dev/null shopt -s nullglob files=(db/migrations/*.sql) if (( ${#files[@]} == 0 )); then warn "No db/migrations/*.sql files found. Nothing to do." exit 0 fi log "Applying migrations (forward-only, each file once)." for f in "${files[@]}"; do bn="$(basename "$f")" log "-> migration candidate: $bn" check_sql="SET NOCOUNT ON; USE DevDb; SELECT COUNT(1) FROM dbo.__SchemaMigrations WHERE Filename = N'$bn';" applied="$(docker exec -i mssql2025 /opt/mssql-tools18/bin/sqlcmd \ -S localhost -U sa -P "$MSSQL_SA_PASSWORD" -h -1 -W -Q "$check_sql" < /dev/null \ | tr -d '\r' | tail -n 1 | xargs || true)" if [[ "${applied:-0}" != "0" ]]; then log " (skip) already applied" continue fi log " (apply) running /migrations/$bn" docker exec -i mssql2025 /opt/mssql-tools18/bin/sqlcmd \ -S localhost -U sa -P "$MSSQL_SA_PASSWORD" \ -b -i "/migrations/$bn" < /dev/null record_sql="USE DevDb; INSERT INTO dbo.__SchemaMigrations(Filename) VALUES (N'$bn');" docker exec -i mssql2025 /opt/mssql-tools18/bin/sqlcmd \ -S localhost -U sa -P "$MSSQL_SA_PASSWORD" \ -b -Q "$record_sql" < /dev/null log " applied ✅" done log "Migrations completed ✅"