Skip to content

Commit 9a4fbfd

Browse files
jfrochesamrose
andauthored
feat: support multiple versions of the http extension (#1664)
* feat: support multiple versions of the http extension Build multiple versions of the http extension on different PostgreSQL versions. Add test for the extensions and their upgrade on PostgreSQL 15 and 17. * feat: http multiversion extension and pg_regress tests * chore: bump to test * tests: local mock http server for http regress tests * fix: a better way to handle http server for tests * chore: bump to release --------- Co-authored-by: Sam Rose <[email protected]>
1 parent dd54146 commit 9a4fbfd

File tree

12 files changed

+873
-41
lines changed

12 files changed

+873
-41
lines changed

ansible/vars.yml

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,38 @@
1+
---
12
supabase_internal: true
23
ebssurrogate_mode: true
34
async_mode: true
45

56
postgres_major:
67
- "15"
78
- "17"
8-
- "orioledb-17"
9+
- orioledb-17
910

1011
# Full version strings for each major version
1112
postgres_release:
12-
postgresorioledb-17: "17.5.1.029"
13-
postgres17: "17.6.1.008"
14-
postgres15: "15.14.1.008"
13+
postgresorioledb-17: 17.5.1.030-orioledb
14+
postgres17: 17.6.1.009
15+
postgres15: 15.14.1.009
1516

1617
# Non Postgres Extensions
17-
pgbouncer_release: "1.19.0"
18+
pgbouncer_release: 1.19.0
1819
pgbouncer_release_checksum: sha256:af0b05e97d0e1fd9ad45fe00ea6d2a934c63075f67f7e2ccef2ca59e3d8ce682
1920

2021
# The checksum can be found under "Assets", in the GitHub release page for each version.
2122
# The binaries used are: ubuntu-aarch64 and linux-static.
2223
# https://github.com/PostgREST/postgrest/releases
23-
postgrest_release: "13.0.5"
24+
postgrest_release: 13.0.5
2425
postgrest_arm_release_checksum: sha256:7b4eafdaf76bc43b57f603109d460a838f89f949adccd02f452ca339f9a0a0d4
2526
postgrest_x86_release_checksum: sha256:05be2bd48abee6c1691fc7c5d005023466c6989e41a4fc7d1302b8212adb88b5
2627

2728
gotrue_release: 2.179.0
2829
gotrue_release_checksum: sha1:e985fce00b2720b747e6a04420910015c4967121
2930

30-
aws_cli_release: "2.23.11"
31+
aws_cli_release: 2.23.11
3132

3233
salt_minion_version: 3007
3334

34-
golang_version: "1.22.11"
35+
golang_version: 1.22.11
3536
golang_version_checksum:
3637
arm64: sha256:0fc88d966d33896384fbde56e9a8d80a305dc17a9f48f1832e061724b1719991
3738
amd64: sha256:9ebfcab26801fa4cf0627c6439db7a4da4d3c6766142a3dd83508240e4f21031
@@ -52,10 +53,10 @@ postgres_exporter_release_checksum:
5253
arm64: sha256:29ba62d538b92d39952afe12ee2e1f4401250d678ff4b354ff2752f4321c87a0
5354
amd64: sha256:cb89fc5bf4485fb554e0d640d9684fae143a4b2d5fa443009bd29c59f9129e84
5455

55-
adminapi_release: 0.92.1
56-
adminmgr_release: 0.32.1
56+
adminapi_release: "0.92.1"
57+
adminmgr_release: "0.32.1"
5758
supabase_admin_agent_release: 1.4.38
5859
supabase_admin_agent_splay: 30
5960

60-
vector_x86_deb: "https://packages.timber.io/vector/0.48.X/vector_0.48.0-1_amd64.deb"
61-
vector_arm_deb: "https://packages.timber.io/vector/0.48.X/vector_0.48.0-1_arm64.deb"
61+
vector_x86_deb: https://packages.timber.io/vector/0.48.X/vector_0.48.0-1_amd64.deb
62+
vector_arm_deb: https://packages.timber.io/vector/0.48.X/vector_0.48.0-1_arm64.deb

nix/checks.nix

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,11 +163,43 @@
163163
which
164164
getkey-script
165165
supabase-groonga
166+
python3
167+
netcat
166168
];
167169
}
168170
''
169171
set -e
170172
173+
# Start HTTP mock server for http extension tests
174+
# Use a build-specific directory for coordination
175+
BUILD_TMP=$(mktemp -d)
176+
HTTP_MOCK_PORT_FILE="$BUILD_TMP/http-mock-port"
177+
178+
echo "Starting HTTP mock server (will find free port)..."
179+
HTTP_MOCK_PORT_FILE="$HTTP_MOCK_PORT_FILE" ${pkgs.python3}/bin/python3 ${./tests/http-mock-server.py} &
180+
HTTP_MOCK_PID=$!
181+
182+
# Clean up on exit
183+
trap "kill $HTTP_MOCK_PID 2>/dev/null || true; rm -rf '$BUILD_TMP'" EXIT
184+
185+
# Wait for server to start and write port file
186+
for i in {1..10}; do
187+
if [ -f "$HTTP_MOCK_PORT_FILE" ]; then
188+
HTTP_MOCK_PORT=$(cat "$HTTP_MOCK_PORT_FILE")
189+
echo "HTTP mock server started on port $HTTP_MOCK_PORT"
190+
break
191+
fi
192+
sleep 1
193+
done
194+
195+
if [ ! -f "$HTTP_MOCK_PORT_FILE" ]; then
196+
echo "Failed to start HTTP mock server"
197+
exit 1
198+
fi
199+
200+
# Export the port for use in SQL tests
201+
export HTTP_MOCK_PORT
202+
171203
#First we need to create a generic pg cluster for pgtap tests and run those
172204
export GRN_PLUGINS_DIR=${pkgs.supabase-groonga}/lib/groonga/plugins
173205
PGTAP_CLUSTER=$(mktemp -d)
@@ -228,6 +260,13 @@
228260
pg_ctl -D "$PGTAP_CLUSTER" stop
229261
exit 1
230262
fi
263+
264+
# Create a table to store test configuration
265+
psql -p ${pgPort} -h ${self.supabase.defaults.host} --username=supabase_admin -d testing -c "
266+
CREATE TABLE IF NOT EXISTS test_config (key TEXT PRIMARY KEY, value TEXT);
267+
INSERT INTO test_config (key, value) VALUES ('http_mock_port', '$HTTP_MOCK_PORT')
268+
ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value;
269+
"
231270
SORTED_DIR=$(mktemp -d)
232271
for t in $(printf "%s\n" ${builtins.concatStringsSep " " sortedTestList}); do
233272
psql -p ${pgPort} -h ${self.supabase.defaults.host} --username=supabase_admin -d testing -f "${./tests/sql}/$t.sql" || true
@@ -261,6 +300,13 @@
261300
exit 1
262301
fi
263302
303+
# Create a table to store test configuration for pg_regress tests
304+
psql -p ${pgPort} -h ${self.supabase.defaults.host} --no-password --username=supabase_admin -d postgres -c "
305+
CREATE TABLE IF NOT EXISTS test_config (key TEXT PRIMARY KEY, value TEXT);
306+
INSERT INTO test_config (key, value) VALUES ('http_mock_port', '$HTTP_MOCK_PORT')
307+
ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value;
308+
"
309+
264310
mkdir -p $out/regression_output
265311
if ! pg_regress \
266312
--use-existing \

nix/ext/pgsql-http.nix

Lines changed: 94 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,109 @@
11
{
2+
pkgs,
23
lib,
34
stdenv,
45
fetchFromGitHub,
5-
curl,
66
postgresql,
7+
curl,
78
}:
9+
let
10+
pname = "http";
811

9-
stdenv.mkDerivation rec {
10-
pname = "pgsql-http";
11-
version = "1.6.1";
12+
# Load version configuration from external file
13+
allVersions = (builtins.fromJSON (builtins.readFile ./versions.json)).${pname};
1214

13-
buildInputs = [
14-
curl
15-
postgresql
16-
];
15+
# Filter versions compatible with current PostgreSQL version
16+
supportedVersions = lib.filterAttrs (
17+
_: value: builtins.elem (lib.versions.major postgresql.version) value.postgresql
18+
) allVersions;
1719

18-
src = fetchFromGitHub {
19-
owner = "pramsey";
20-
repo = pname;
21-
rev = "refs/tags/v${version}";
22-
hash = "sha256-C8eqi0q1dnshUAZjIsZFwa5FTYc7vmATF3vv2CReWPM=";
23-
};
20+
# Derived version information
21+
versions = lib.naturalSort (lib.attrNames supportedVersions);
22+
latestVersion = lib.last versions;
23+
numberOfVersions = builtins.length versions;
24+
packages = builtins.attrValues (
25+
lib.mapAttrs (name: value: build name value.hash) supportedVersions
26+
);
27+
28+
# Build function for individual versions
29+
build =
30+
version: hash:
31+
stdenv.mkDerivation rec {
32+
inherit pname version;
33+
34+
buildInputs = [
35+
curl
36+
postgresql
37+
];
38+
39+
src = fetchFromGitHub {
40+
owner = "pramsey";
41+
repo = "pgsql-http";
42+
rev = "refs/tags/v${version}";
43+
inherit hash;
44+
};
45+
46+
installPhase = ''
47+
runHook preInstall
2448
25-
installPhase = ''
26-
mkdir -p $out/{lib,share/postgresql/extension}
49+
mkdir -p $out/{lib,share/postgresql/extension}
50+
51+
# Install versioned library
52+
install -Dm755 ${pname}${postgresql.dlSuffix} $out/lib/${pname}--${version}${postgresql.dlSuffix}
53+
54+
cp ${pname}--${version}.sql $out/share/postgresql/extension/${pname}--${version}.sql
55+
56+
# Create versioned control file with modified module path
57+
sed -e "/^default_version =/d" \
58+
-e "s|^module_pathname = .*|module_pathname = '\$libdir/${pname}'|" \
59+
${pname}.control > $out/share/postgresql/extension/${pname}--${version}.control
60+
61+
# For the latest version, create default control file and symlink and copy SQL upgrade scripts
62+
if [[ "${version}" == "${latestVersion}" ]]; then
63+
{
64+
echo "default_version = '${version}'"
65+
cat $out/share/postgresql/extension/${pname}--${version}.control
66+
} > $out/share/postgresql/extension/${pname}.control
67+
ln -sfn ${pname}--${latestVersion}${postgresql.dlSuffix} $out/lib/${pname}${postgresql.dlSuffix}
68+
cp *.sql $out/share/postgresql/extension
69+
fi
70+
71+
runHook postInstall
72+
'';
73+
74+
meta = with lib; {
75+
description = "HTTP client for Postgres";
76+
homepage = "https://github.com/pramsey/${pname}";
77+
inherit (postgresql.meta) platforms;
78+
license = licenses.postgresql;
79+
};
80+
};
81+
in
82+
pkgs.buildEnv {
83+
name = pname;
84+
paths = packages;
85+
86+
pathsToLink = [
87+
"/lib"
88+
"/share/postgresql/extension"
89+
];
90+
postBuild = ''
91+
# Verify all expected library files are present
92+
expectedFiles=${toString (numberOfVersions + 1)}
93+
actualFiles=$(ls -A $out/lib/${pname}*${postgresql.dlSuffix} | wc -l)
2794
28-
cp *${postgresql.dlSuffix} $out/lib
29-
cp *.sql $out/share/postgresql/extension
30-
cp *.control $out/share/postgresql/extension
95+
if [[ "$actualFiles" != "$expectedFiles" ]]; then
96+
echo "Error: Expected $expectedFiles library files, found $actualFiles"
97+
echo "Files found:"
98+
ls -la $out/lib/${pname}*${postgresql.dlSuffix} || true
99+
exit 1
100+
fi
31101
'';
32102

33-
meta = with lib; {
34-
description = "HTTP client for Postgres";
35-
homepage = "https://github.com/pramsey/${pname}";
36-
platforms = postgresql.meta.platforms;
37-
license = licenses.postgresql;
103+
passthru = {
104+
inherit versions numberOfVersions;
105+
pname = "${pname}-all";
106+
version =
107+
"multi-" + lib.concatStringsSep "-" (map (v: lib.replaceStrings [ "." ] [ "-" ] v) versions);
38108
};
39109
}

0 commit comments

Comments
 (0)