Skip to content

Commit c0a0905

Browse files
authored
dbmate migration running and testing tool (#1316)
* feat: basic running of dbmate migrations from tool * feat: a nix flake app tool to run dbmate migrations and produce schema.slq files * feat: test against schema.sql per mjr vrs + tool to generate * chore: pin at development branch version of tool * docs: update docs with usage info * fix: tmp use this working branch for flakeurl * chore: cleanup of test and dbmage migration tool * chore: build this version * chore: extra-conf * chore: reinstall true * chore: test no longer needs self-hosted runner, can use ephemeral * chore: correct format of runner * chore: not longer need sudo * chore: trying to get the action to use our cache * chore: conf 2nd invocation * chore: rm var * chore: nl * chore: cleanup and remove unnecessary changes * fix: make sure to run sql for pg-stat-extensions and pg-bouncer
1 parent 1bc4749 commit c0a0905

File tree

6 files changed

+369
-92
lines changed

6 files changed

+369
-92
lines changed

.github/workflows/test.yml

Lines changed: 17 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ jobs:
1717
uses: actions/checkout@v4
1818

1919
- uses: DeterminateSystems/nix-installer-action@main
20+
with:
21+
extra-conf: |
22+
substituters = https://cache.nixos.org https://nix-postgres-artifacts.s3.amazonaws.com
23+
trusted-public-keys = nix-postgres-artifacts:dGZlQOvKcNEjvT7QEAJbcV6b6uk7VF/hWMjhYleiaLI=% cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=
2024
2125
- name: Set PostgreSQL versions
2226
id: set-versions
@@ -30,19 +34,24 @@ jobs:
3034
matrix:
3135
postgres_version: ${{ fromJson(needs.prepare.outputs.postgres_versions) }}
3236
include:
33-
- runner: [self-hosted, X64]
37+
- runner: ubuntu-22.04
3438
arch: amd64
35-
- runner: arm-runner
39+
- runner: ubuntu-22.04
3640
arch: arm64
3741
runs-on: ${{ matrix.runner }}
3842
timeout-minutes: 180
3943
env:
4044
POSTGRES_PORT: 5478
4145
POSTGRES_PASSWORD: password
4246
steps:
43-
- uses: actions/checkout@v3
47+
- uses: actions/checkout@v4
4448

4549
- uses: DeterminateSystems/nix-installer-action@main
50+
with:
51+
extra-conf: |
52+
substituters = https://cache.nixos.org https://nix-postgres-artifacts.s3.amazonaws.com
53+
trusted-public-keys = nix-postgres-artifacts:dGZlQOvKcNEjvT7QEAJbcV6b6uk7VF/hWMjhYleiaLI=% cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=
54+
4655
4756
- name: Set PostgreSQL version environment variable
4857
run: echo "POSTGRES_MAJOR_VERSION=${{ matrix.postgres_version }}" >> $GITHUB_ENV
@@ -54,7 +63,7 @@ jobs:
5463
5564
- name: Generate common-nix.vars.pkr.hcl
5665
run: |
57-
PG_VERSION=$(sudo nix run nixpkgs#yq -- '.postgres_release["postgres'${{ matrix.postgres_version }}'"]' ansible/vars.yml)
66+
PG_VERSION=$(nix run nixpkgs#yq -- '.postgres_release["postgres'${{ matrix.postgres_version }}'"]' ansible/vars.yml)
5867
PG_VERSION=$(echo $PG_VERSION | tr -d '"') # Remove any surrounding quotes
5968
echo 'postgres-version = "'$PG_VERSION'"' > common-nix.vars.pkr.hcl
6069
# Ensure there's a newline at the end of the file
@@ -67,96 +76,16 @@ jobs:
6776
- name: Generate args
6877
id: args
6978
run: |
70-
ARGS=$(sudo nix run nixpkgs#yq -- 'to_entries | map(select(.value|type == "!!str")) | map(.key + "=" + .value) | join("\n")' ansible/vars.yml)
79+
ARGS=$(nix run nixpkgs#yq -- 'to_entries | map(select(.value|type == "!!str")) | map(.key + "=" + .value) | join("\n")' ansible/vars.yml)
7180
echo "result<<EOF" >> $GITHUB_OUTPUT
7281
echo "$ARGS" >> $GITHUB_OUTPUT
7382
echo "EOF" >> $GITHUB_OUTPUT
7483
75-
- run: docker context create builders
76-
- uses: docker/setup-buildx-action@v3
77-
with:
78-
endpoint: builders
79-
- uses: docker/build-push-action@v5
80-
with:
81-
load: true
82-
context: .
83-
file: Dockerfile-${{ env.PGMAJOR }}
84-
target: production
85-
build-args: |
86-
${{ steps.args.outputs.result }}
87-
tags: supabase/postgres:${{ steps.settings.outputs.postgres-version }},supabase_postgres
88-
cache-from: |
89-
type=gha,scope=${{ github.ref_name }}-${{ steps.settings.outputs.postgres-version }}-${{ matrix.arch }}
90-
type=gha,scope=${{ github.base_ref }}-${{ steps.settings.outputs.postgres-version }}-${{ matrix.arch }}
91-
cache-to: type=gha,mode=max,scope=${{ github.ref_name }}-${{ steps.settings.outputs.postgres-version }}-${{ matrix.arch }}
92-
93-
- name: Start Postgres
94-
run: |
95-
docker run --rm --pull=never \
96-
-e POSTGRES_PASSWORD=${{ env.POSTGRES_PASSWORD }} \
97-
-p ${{ env.POSTGRES_PORT }}:5432 \
98-
--name supabase_postgres \
99-
-d supabase/postgres:${{ steps.settings.outputs.postgres-version }}
100-
101-
- name: Install psql
102-
run: |
103-
sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
104-
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
105-
sudo apt update
106-
sudo apt install -y --no-install-recommends postgresql-client-${{ env.PGMAJOR }}
107-
108-
- name: Install pg_prove
109-
run: sudo cpan -T TAP::Parser::SourceHandler::pgTAP
110-
env:
111-
SHELL: /bin/bash
112-
113-
- name: Wait for healthy database
114-
run: |
115-
count=0
116-
until [ "$(docker inspect -f '{{.State.Health.Status}}' "$container")" == "healthy" ]; do
117-
exit=$?
118-
count=$((count + 1))
119-
if [ $count -ge "$retries" ]; then
120-
echo "Retry $count/$retries exited $exit, no more retries left."
121-
docker stop -t 2 "$container"
122-
return $exit
123-
fi
124-
sleep 1;
125-
done;
126-
echo "$container container is healthy"
127-
env:
128-
retries: 20
129-
container: supabase_postgres
130-
131-
- name: Run tests
132-
run: pg_prove migrations/tests/test.sql
133-
env:
134-
PGHOST: localhost
135-
PGPORT: ${{ env.POSTGRES_PORT }}
136-
PGDATABASE: postgres
137-
PGUSER: supabase_admin
138-
PGPASSWORD: ${{ env.POSTGRES_PASSWORD }}
139-
140-
- name: Check migrations are idempotent
141-
run: |
142-
for sql in ./migrations/db/migrations/*.sql; do
143-
echo "$0: running $sql"
144-
psql -v ON_ERROR_STOP=1 --no-password --no-psqlrc -f "$sql"
145-
done
146-
env:
147-
PGHOST: localhost
148-
PGPORT: ${{ env.POSTGRES_PORT }}
149-
PGDATABASE: postgres
150-
PGUSER: supabase_admin
151-
PGPASSWORD: ${{ env.POSTGRES_PASSWORD }}
152-
153-
- name: Update Dockerfile.dbmate version
154-
run: |
155-
sed -i 's/%VERSION%/${{ env.PGMAJOR }}/g' migrations/Dockerfile.dbmate
156-
84+
#TODO PR Convert to develop branch flakeurl
15785
- name: verify schema.sql is committed
15886
run: |
159-
docker compose -f migrations/docker-compose.yaml up db dbmate --abort-on-container-exit
87+
GIT_SHA=${{github.sha}}
88+
nix run github:supabase/postgres/${GIT_SHA}#dbmate-tool -- --version ${{ env.PGMAJOR }}
16089
if ! git diff --exit-code --quiet migrations/schema-${{ env.PGMAJOR }}.sql; then
16190
echo "Detected changes in schema.sql:"
16291
git diff migrations/schema-${{ env.PGMAJOR }}.sql

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,5 @@ result*
2222
#IDE
2323
.idea/
2424
.vscode/
25+
26+
db

flake.nix

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -530,7 +530,7 @@
530530
chmod +x $out/bin/pg-restore
531531
'';
532532
sync-exts-versions = pkgs.runCommand "sync-exts-versions" { } ''
533-
mkdir -p $out/bin
533+
mkdir -p $out/bin
534534
substitute ${./nix/tools/sync-exts-versions.sh.in} $out/bin/sync-exts-versions \
535535
--subst-var-by 'YQ' '${pkgs.yq}/bin/yq' \
536536
--subst-var-by 'JQ' '${pkgs.jq}/bin/jq' \
@@ -539,8 +539,42 @@
539539
--subst-var-by 'NIX' '${pkgs.nixVersions.nix_2_20}/bin/nix'
540540
chmod +x $out/bin/sync-exts-versions
541541
'';
542+
dbmate-tool =
543+
let
544+
migrationsDir = ./migrations/db;
545+
ansibleVars = ./ansible/vars.yml;
546+
pgbouncerAuthSchemaSql = ./ansible/files/pgbouncer_config/pgbouncer_auth_schema.sql;
547+
statExtensionSql = ./ansible/files/stat_extension.sql;
548+
in
549+
pkgs.runCommand "dbmate-tool" {
550+
buildInputs = with pkgs; [
551+
overmind
552+
dbmate
553+
nix
554+
jq
555+
yq
556+
];
557+
nativeBuildInputs = with pkgs; [
558+
makeWrapper
559+
];
560+
} ''
561+
mkdir -p $out/bin $out/migrations
562+
cp -r ${migrationsDir}/* $out
563+
substitute ${./nix/tools/dbmate-tool.sh.in} $out/bin/dbmate-tool \
564+
--subst-var-by 'PGSQL_DEFAULT_PORT' '${pgsqlDefaultPort}' \
565+
--subst-var-by 'MIGRATIONS_DIR' $out \
566+
--subst-var-by 'PGSQL_SUPERUSER' '${pgsqlSuperuser}' \
567+
--subst-var-by 'ANSIBLE_VARS' ${ansibleVars} \
568+
--subst-var-by 'CURRENT_SYSTEM' '${system}' \
569+
--subst-var-by 'PGBOUNCER_AUTH_SCHEMA_SQL' '${pgbouncerAuthSchemaSql}' \
570+
--subst-var-by 'STAT_EXTENSION_SQL' '${statExtensionSql}'
571+
chmod +x $out/bin/dbmate-tool
572+
wrapProgram $out/bin/dbmate-tool \
573+
--prefix PATH : ${pkgs.lib.makeBinPath [ pkgs.overmind pkgs.dbmate pkgs.nix pkgs.jq pkgs.yq ]}
574+
'';
542575
};
543576

577+
544578
# Create a testing harness for a PostgreSQL package. This is used for
545579
# 'nix flake check', and works with any PostgreSQL package you hand it.
546580
makeCheckHarness = pgpkg:
@@ -654,9 +688,11 @@
654688
start-server = mkApp "start-server" "start-postgres-server";
655689
start-client = mkApp "start-client" "start-postgres-client";
656690
start-replica = mkApp "start-replica" "start-postgres-replica";
657-
migration-test = mkApp "migrate-tool" "migrate-postgres";
691+
migrate-postgres = mkApp "migrate-tool" "migrate-postgres";
658692
sync-exts-versions = mkApp "sync-exts-versions" "sync-exts-versions";
659693
pg-restore = mkApp "pg-restore" "pg-restore";
694+
dbmate-tool = mkApp "dbmate-tool" "dbmate-tool";
695+
migration-unit-tests = mkApp "migration-unit-tests" "migration-unit-tests";
660696
};
661697

662698
# 'devShells.default' lists the set of packages that are included in the
@@ -695,6 +731,7 @@
695731
basePackages.start-replica
696732
basePackages.migrate-tool
697733
basePackages.sync-exts-versions
734+
dbmate
698735
];
699736
shellHook = ''
700737
export HISTFILE=.history

migrations/README.md

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,36 @@
1+
# Usage
2+
3+
from the root of the `supabase/postgres` project, you can run the following commands:
4+
5+
6+
```shell
7+
Usage: nix run .#dbmate-tool -- [options]
8+
9+
Options:
10+
-v, --version [15|16|orioledb-17|all] Specify the PostgreSQL version to use (required defaults to --version all)
11+
-p, --port PORT Specify the port number to use (default: 5435)
12+
-h, --help Show this help message
13+
14+
Description:
15+
Runs 'dbmate up' against a locally running the version of database you specify. Or 'all' to run against all versions.
16+
NOTE: To create a migration, you must run 'nix develop' and then 'dbmate new <migration_name>' to create a new migration file.
17+
18+
Examples:
19+
nix run .#dbmate-tool
20+
nix run .#dbmate-tool -- --version 15
21+
nix run .#dbmate-tool -- --version 16 --port 5433
22+
23+
```
24+
25+
This can also be run from a github "flake url" for example:
26+
27+
```shell
28+
nix run github:supabase/postgres#dbmate-tool -- --version 15
29+
30+
or
31+
32+
nix run github:supabase/postgres/mybranch#dbmate-tool -- --version 15
33+
```
134
# supabase/migrations
235

336
`supabase/migrations` is a consolidation of SQL migrations from:
@@ -9,6 +42,8 @@
942

1043
aiming to provide a single source of truth for migrations on the platform that can be depended upon by those components. For more information on goals see [the RFC](https://www.notion.so/supabase/Centralize-SQL-Migrations-cd3847ae027d4f2bba9defb2cc82f69a)
1144

45+
46+
1247
## How it was Created
1348

1449
Migrations were pulled (in order) from:
@@ -20,10 +55,12 @@ For compatibility with hosted projects, we include [migrate.sh](migrate.sh) that
2055

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

2560
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.
2661

62+
63+
2764
## Guidelines
2865

2966
- Migrations are append only. Never edit existing migrations once they are on master.

0 commit comments

Comments
 (0)