Skip to content

Commit e633e59

Browse files
committed
feat: basic running of dbmate migrations from tool
1 parent f5cbb07 commit e633e59

File tree

4 files changed

+234
-2
lines changed

4 files changed

+234
-2
lines changed

flake.nix

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -524,7 +524,7 @@
524524
chmod +x $out/bin/pg-restore
525525
'';
526526
sync-exts-versions = pkgs.runCommand "sync-exts-versions" { } ''
527-
mkdir -p $out/bin
527+
mkdir -p $out/bin
528528
substitute ${./nix/tools/sync-exts-versions.sh.in} $out/bin/sync-exts-versions \
529529
--subst-var-by 'YQ' '${pkgs.yq}/bin/yq' \
530530
--subst-var-by 'JQ' '${pkgs.jq}/bin/jq' \
@@ -533,8 +533,34 @@
533533
--subst-var-by 'NIX' '${pkgs.nixVersions.nix_2_20}/bin/nix'
534534
chmod +x $out/bin/sync-exts-versions
535535
'';
536+
dbmate-tool =
537+
let
538+
migrationsDir = ./migrations/db;
539+
in
540+
pkgs.runCommand "dbmate-tool" {
541+
buildInputs = with pkgs; [
542+
overmind
543+
dbmate
544+
nix
545+
jq
546+
];
547+
nativeBuildInputs = with pkgs; [
548+
makeWrapper
549+
];
550+
} ''
551+
mkdir -p $out/bin $out/migrations
552+
cp -r ${migrationsDir}/* $out
553+
substitute ${./nix/tools/dbmate-tool.sh.in} $out/bin/dbmate-tool \
554+
--subst-var-by 'PGSQL_DEFAULT_PORT' '${pgsqlDefaultPort}' \
555+
--subst-var-by 'MIGRATIONS_DIR' $out \
556+
--subst-var-by 'PGSQL_SUPERUSER' '${pgsqlSuperuser}'
557+
chmod +x $out/bin/dbmate-tool
558+
wrapProgram $out/bin/dbmate-tool \
559+
--prefix PATH : ${pkgs.lib.makeBinPath [ pkgs.overmind pkgs.dbmate pkgs.nix pkgs.jq]}
560+
'';
536561
};
537562

563+
538564
# Create a testing harness for a PostgreSQL package. This is used for
539565
# 'nix flake check', and works with any PostgreSQL package you hand it.
540566
makeCheckHarness = pgpkg:
@@ -651,6 +677,7 @@
651677
migration-test = mkApp "migrate-tool" "migrate-postgres";
652678
sync-exts-versions = mkApp "sync-exts-versions" "sync-exts-versions";
653679
pg-restore = mkApp "pg-restore" "pg-restore";
680+
dbmate-tool = mkApp "dbmate-tool" "dbmate-tool";
654681
};
655682

656683
# 'devShells.default' lists the set of packages that are included in the
@@ -689,6 +716,7 @@
689716
basePackages.start-replica
690717
basePackages.migrate-tool
691718
basePackages.sync-exts-versions
719+
dbmate
692720
];
693721
shellHook = ''
694722
export HISTFILE=.history

migrations/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ For compatibility with hosted projects, we include [migrate.sh](migrate.sh) that
2020

2121
1. Run all `db/init-scripts` with `postgres` superuser role.
2222
2. Run all `db/migrations` with `supabase_admin` superuser role.
23-
3. Finalize role passwords with `/etc/postgres.schema.sql` if present.
23+
3. Finalize role passwords with `/etc/postgresql.schema.sql` if present.
2424

2525
Additionally, [supabase/postgres](https://github.com/supabase/postgres/blob/develop/ansible/playbook-docker.yml#L9) image contains several migration scripts to configure default extensions. These are run first by docker entrypoint and included in ami by ansible.
2626

nix/tools/dbmate-tool.sh.in

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
#!/usr/bin/env bash
2+
# shellcheck shell=bash
3+
4+
[ ! -z "$DEBUG" ] && set -x
5+
6+
# Default values
7+
PSQL_VERSION="15"
8+
MIGRATION_FILE=""
9+
PORTNO="@PGSQL_DEFAULT_PORT@"
10+
PGSQL_SUPERUSER=@PGSQL_SUPERUSER@
11+
PGPASSWORD="${PGPASSWORD:-postgres}"
12+
PGSQL_USER="postgres"
13+
FLAKE_URL="github:supabase/postgres"
14+
MIGRATIONS_DIR="@MIGRATIONS_DIR@"
15+
16+
# Cleanup function
17+
cleanup() {
18+
echo "Cleaning up..."
19+
20+
# Kill overmind processes first
21+
if [ -S "./.overmind.sock" ]; then
22+
overmind kill || true
23+
sleep 2
24+
fi
25+
26+
# Kill any remaining postgres processes
27+
echo "Killing any remaining postgres processes..."
28+
pkill -9 postgres || true
29+
pkill -9 -f "tmux.*overmind.*postgresql" || true
30+
31+
# Extra cleanup for tmux sessions
32+
tmux ls 2>/dev/null | grep 'overmind' | cut -d: -f1 | xargs -I{} tmux kill-session -t {} || true
33+
34+
# Remove socket and Procfile
35+
rm -f .overmind.sock Procfile
36+
37+
# Verify cleanup
38+
remaining=$(ps aux | grep -E "(postgres|overmind|tmux.*postgresql)" | grep -v grep || true)
39+
if [ ! -z "$remaining" ]; then
40+
echo "Warning: Some processes might still be running:"
41+
echo "$remaining"
42+
fi
43+
}
44+
45+
# Set up trap for cleanup on script exit
46+
trap cleanup EXIT
47+
48+
# Function to display help
49+
print_help() {
50+
echo "Usage: nix run .#dbmate-tool -- [options]"
51+
echo
52+
echo "Options:"
53+
echo " -v, --version [15|16|orioledb-17] Specify the PostgreSQL version to use (required defaults to --all)"
54+
echo " -p, --port PORT Specify the port number to use (default: 5435)"
55+
echo " -h, --help Show this help message"
56+
echo
57+
echo "Description:"
58+
echo " Runs 'dbmate up' against a locally running the version of database you specify. Or 'all' to run against all versions."
59+
echo " NOTE: To create a migration, you must run 'nix develop' and then 'dbmate new <migration_name>' to create a new migration file."
60+
echo
61+
echo "Examples:"
62+
echo " nix run .#dbmate-tool"
63+
echo " nix run .#dbmate-tool -- --version 15"
64+
echo " nix run .#dbmate-tool -- --version 16 --port 5433"
65+
}
66+
67+
68+
# Parse arguments
69+
while [[ "$#" -gt 0 ]]; do
70+
case "$1" in
71+
-v|--version)
72+
if [[ -n "$2" && ! "$2" =~ ^- ]]; then
73+
PSQL_VERSION="$2"
74+
shift 2
75+
else
76+
echo "Error: --version requires an argument (15, 16, or orioledb-17)"
77+
exit 1
78+
fi
79+
;;
80+
-u|--user)
81+
if [[ -n "$2" && ! "$2" =~ ^- ]]; then
82+
PGSQL_USER="$2"
83+
shift 2
84+
else
85+
echo "Error: --user requires an argument"
86+
exit 1
87+
fi
88+
;;
89+
-f|--flake-url)
90+
if [[ -n "$2" && ! "$2" =~ ^- ]]; then
91+
FLAKE_URL="$2"
92+
shift 2
93+
else
94+
echo "Error: --flake-url requires an argument"
95+
exit 1
96+
fi
97+
;;
98+
-p|--port)
99+
if [[ -n "$2" && ! "$2" =~ ^- ]]; then
100+
PORTNO="$2"
101+
shift 2
102+
else
103+
echo "Error: --port requires an argument"
104+
exit 1
105+
fi
106+
;;
107+
-h|--help)
108+
print_help
109+
exit 0
110+
;;
111+
*)
112+
echo "Unknown option: $1"
113+
print_help
114+
exit 1
115+
;;
116+
esac
117+
done
118+
119+
PSQLBIN=$(nix build --no-link "$FLAKE_URL#psql_$PSQL_VERSION/bin" --json | jq -r '.[].outputs.out + "/bin"')
120+
echo "Using PostgreSQL version $PSQL_VERSION from $PSQLBIN"
121+
# Function to wait for PostgreSQL to be ready
122+
wait_for_postgres() {
123+
local max_attempts=30 # Increased significantly
124+
local attempt=1
125+
126+
# Give overmind a moment to actually start the process
127+
sleep 2
128+
129+
while [ $attempt -le $max_attempts ]; do
130+
"${PSQLBIN}/pg_isready" -h localhost -p "$PORTNO" -U "$PGSQL_SUPERUSER" -d postgres
131+
local status=$?
132+
133+
if [ $status -eq 0 ]; then
134+
echo "PostgreSQL is ready!"
135+
return 0
136+
fi
137+
echo "Waiting for PostgreSQL to start (attempt $attempt/$max_attempts)..."
138+
sleep 2
139+
attempt=$((attempt + 1))
140+
done
141+
142+
echo "PostgreSQL failed to start after $max_attempts attempts"
143+
overmind echo postgres
144+
return 1
145+
}
146+
147+
# Create Procfile
148+
cat > Procfile << EOF
149+
postgres_${PSQL_VERSION}: exec nix run "$FLAKE_URL#start-server" "$PSQL_VERSION"
150+
EOF
151+
152+
echo "Starting PostgreSQL server with: exec nix run $FLAKE_URL#start-server $PSQL_VERSION"
153+
cat Procfile
154+
155+
# Start services with Overmind
156+
overmind start -D
157+
158+
159+
echo "Waiting for overmind socket..."
160+
max_wait=5
161+
count=0
162+
while [ $count -lt $max_wait ]; do
163+
if [ -S "./.overmind.sock" ]; then
164+
# Found the socket, give it a moment to be ready
165+
sleep 2
166+
echo "Socket file found and ready"
167+
break
168+
fi
169+
echo "Waiting for socket file (attempt $count/$max_wait)"
170+
sleep 1
171+
count=$((count + 1))
172+
done
173+
174+
175+
echo "Waiting for PostgreSQL to be ready..."
176+
177+
#Wait for PostgreSQL to be ready to accept connections
178+
if ! wait_for_postgres; then
179+
echo "Failed to connect to PostgreSQL server"
180+
exit 1
181+
fi
182+
183+
echo "PostgreSQL server is ready"
184+
185+
# Configure PostgreSQL roles and permissions
186+
if ! "${PSQLBIN}/psql" -v ON_ERROR_STOP=1 --no-password --no-psqlrc -U "$PGSQL_SUPERUSER" -p "$PORTNO" -h localhost -d postgres <<-EOSQL
187+
create role postgres superuser login password '$PGPASSWORD';
188+
alter database postgres owner to postgres;
189+
EOSQL
190+
then
191+
echo "Failed to configure PostgreSQL roles and permissions"
192+
exit 1
193+
fi
194+
#set db url to run dbmate
195+
export DATABASE_URL="postgres://$PGSQL_USER:$PGPASSWORD@localhost:$PORTNO/postgres?sslmode=disable"
196+
197+
ls -la "$MIGRATIONS_DIR"
198+
pwd
199+
dbmate --migrations-dir "$MIGRATIONS_DIR/init-scripts" up
200+
"${PSQLBIN}/psql" -v ON_ERROR_STOP=1 --no-password --no-psqlrc -U postgres -p "$PORTNO" -h localhost -c "ALTER USER supabase_admin WITH PASSWORD '$PGPASSWORD'"
201+
export DATABASE_URL="postgres://$PGSQL_SUPERUSER:$PGPASSWORD@localhost:$PORTNO/postgres?sslmode=disable"
202+
dbmate --migrations-dir "$MIGRATIONS_DIR/migrations" up
203+
echo "PostgreSQL configuration completed successfully"

psqlbin

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/nix/store/0qvxl5gpzgw6am0biba429clvfd7wrzv-postgresql-and-plugins-15.8

0 commit comments

Comments
 (0)