From 442d4e8ae02b71abb237ece2fce6dc6cb93a9d0d Mon Sep 17 00:00:00 2001 From: Orion Kindel Date: Sun, 11 Jun 2023 16:43:53 -0500 Subject: [PATCH] feat: run migrations against running database --- .env.schema | 3 +++ docker-compose.yml | 4 ++-- schema/000_revision.sql | 8 ++++++++ scripts/build.sh | 14 ++++++-------- scripts/diff.sh | 4 ++-- scripts/env.sh | 4 +++- scripts/migrate.sh | 38 ++++++++++++++++++++++++++++++++++++++ 7 files changed, 62 insertions(+), 13 deletions(-) create mode 100644 .env.schema create mode 100644 schema/000_revision.sql mode change 100644 => 100755 scripts/migrate.sh diff --git a/.env.schema b/.env.schema new file mode 100644 index 0000000..e520b19 --- /dev/null +++ b/.env.schema @@ -0,0 +1,3 @@ +POSTGRES_USER=postgres +POSTGRES_PASSWORD=password +POSTGRES_DB=dnim diff --git a/docker-compose.yml b/docker-compose.yml index 578b231..a85ff3a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -9,7 +9,7 @@ services: volumes: - "./data/base:/var/lib/postgres/data" env_file: - - "./.env" + - "./.env.schema" head: container_name: "head" image: "postgres:15.3-bullseye" @@ -19,4 +19,4 @@ services: volumes: - "./data/head:/var/lib/postgres/data" env_file: - - "./.env" + - "./.env.schema" diff --git a/schema/000_revision.sql b/schema/000_revision.sql new file mode 100644 index 0000000..3ea3f72 --- /dev/null +++ b/schema/000_revision.sql @@ -0,0 +1,8 @@ +create table public.migration + ( from_revision text not null + , to_revision text not null + , performed_on timestamp not null default now() + , script text not null + ); + +insert into migration (from_revision, to_revision, script) values ('empty', 'empty', ''); diff --git a/scripts/build.sh b/scripts/build.sh index 4f13a01..6bfc533 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -1,6 +1,6 @@ #! /usr/bin/bash -source ./scripts/env.sh +source ./scripts/env.sh ./.env.schema rev=${1:-HEAD} @@ -25,17 +25,15 @@ switch_back_to_head() { } trap 'switch_back_to_head' EXIT -url=postgresql://$POSTGRES_USER:$POSTGRES_PASSWORD@localhost:$port/$POSTGRES_DB +url=postgresql://$POSTGRES_USER:$POSTGRES_PASSWORD@localhost:$port -psql \ - --quiet \ - $url \ - --command="drop schema public cascade; create schema public;" \ - 1>/dev/null +dropdb=$(mktemp) +echo "drop database dnim with (force); create database dnim;" > "$dropdb" +psql --quiet "$url/postgres" --file="$dropdb" 1>/dev/null ls ./schema/ | xargs -I{} \ psql \ --quiet \ - $url \ + "$url/$POSTGRES_DB" \ --file=./schema/{} \ 1>/dev/null diff --git a/scripts/diff.sh b/scripts/diff.sh index d179cbc..bf9474e 100755 --- a/scripts/diff.sh +++ b/scripts/diff.sh @@ -2,7 +2,7 @@ set -e -source ./scripts/env.sh +source ./scripts/env.sh ./.env.schema rev=${1:-} @@ -20,4 +20,4 @@ docker compose up -d ./scripts/build.sh HEAD echo "migrate from $rev => HEAD" 1>&2 -migra --unsafe $base_url $head_url +migra --unsafe $base_url $head_url || echo "migra exited with code $?. this is /probably/ fine" 1>&2 diff --git a/scripts/env.sh b/scripts/env.sh index fde2126..3212962 100755 --- a/scripts/env.sh +++ b/scripts/env.sh @@ -1,3 +1,5 @@ #! /usr/bin/bash -while read line; do export $line; done < ./.env +file=${1:-./.env} + +while read line; do export "$line"; done < "$file" diff --git a/scripts/migrate.sh b/scripts/migrate.sh old mode 100644 new mode 100755 index 3686f0f..7bc84ae --- a/scripts/migrate.sh +++ b/scripts/migrate.sh @@ -1,3 +1,41 @@ #! /usr/bin/bash +set -e +source ./scripts/env.sh ./.env + +if [[ -n $(git status --porcelain) ]]; then + echo "git working tree dirty" 1>&2; + exit 1; +fi + +head=$(git show --format=format:%h -q) + +get_dnim_database_count="copy (select count(*) from pg_database where datname = 'dnim') to stdout with null as '';" +dnim_database_count=$(psql "$POSTGRES_ROOT_CONNECTION_URL" -c "$get_dnim_database_count") + +if [[ "$dnim_database_count" = "0" ]]; then + echo "fresh database" + psql "$POSTGRES_ROOT_CONNECTION_URL" -c "create database dnim;" + ls ./schema/ | xargs -I{} psql --quiet "$POSTGRES_CONNECTION_URL" --file=./schema/{} 1>/dev/null + last_revision='empty' + script='' +else + get_last_revision="copy (select to_revision from migration order by performed_on desc limit 1) to stdout with null as '';" + last_revision=$(psql "$POSTGRES_CONNECTION_URL" -c "$get_last_revision") + script=$(./scripts/diff.sh "$last_revision") + + if [[ "$1" = "--greenlight" ]]; then + psql "$POSTGRES_CONNECTION_URL" -c "$script" + else + to_review="tmp/migrate_${last_revision}_to_${head}.sql" + echo "$script" > "$to_review" + echo "script written to $to_review" + echo "review and rerun with --greenlight to apply migration" + exit + fi +fi + +insert_migration="insert into migration (from_revision, to_revision, script) values ('$last_revision', '$head', \$migration\$$script\$migration\$);" +psql "$POSTGRES_CONNECTION_URL" -c "$insert_migration" +echo "inserted migration"