Skip to content

Commit 2ee1ac8

Browse files
jfrocheyvan-sraka
andauthored
feat: support multiple versions of the pg_tap extension (#1678)
* feat: support multiple versions of the pg_tap extension Build multiple versions of the pg_tap extension on different PostgreSQL versions. Add test for the extensions and their upgrade on PostgreSQL 15 and 17. * feat: use default nixos extension test And run pg_regress tests for pgtap as part of the unified extension tests * chore: nix fmt * fix(pgtap): define ext variable before sed command Define the ext variable to point to the correct shared library path before using it in the sed command that sets module_pathname in the PostgreSQL extension control file. * fix(pgtap): use platform-specific extension suffix for shared library detection Check for src/pgtap${postgresql.dlSuffix} instead of hardcoded src/pgtap.so to properly detect the shared library on all platforms (e.g., .dylib on macOS). * fix(pgtap): add guards for empty versions and conditional module_pathname - Add assertion guard to fail clearly when no supported versions exist for the current PostgreSQL version, preventing lib.last on empty list - Gate module_pathname rewrite on shared library existence: only set module_pathname when the shared library exists, remove the line entirely for SQL-only versions to prevent CREATE EXTENSION failures --------- Co-authored-by: Yvan Sraka <yvan@sraka.xyz>
1 parent 833a9e7 commit 2ee1ac8

6 files changed

Lines changed: 162 additions & 36 deletions

File tree

nix/ext/pgtap.nix

Lines changed: 118 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -6,41 +6,129 @@
66
perl,
77
perlPackages,
88
which,
9+
buildEnv,
10+
fetchpatch2,
911
}:
10-
11-
stdenv.mkDerivation rec {
12+
let
1213
pname = "pgtap";
13-
name = pname;
14-
version = "1.2.0";
1514

16-
src = fetchFromGitHub {
17-
owner = "theory";
18-
repo = "pgtap";
19-
rev = "v${version}";
20-
hash = "sha256-lb0PRffwo6J5a6Hqw1ggvn0cW7gPZ02OEcLPi9ineI8=";
21-
};
15+
# Load version configuration from external file
16+
allVersions = (builtins.fromJSON (builtins.readFile ./versions.json)).${pname};
17+
18+
# Filter versions compatible with current PostgreSQL version
19+
supportedVersions = lib.filterAttrs (
20+
_: value: builtins.elem (lib.versions.major postgresql.version) value.postgresql
21+
) allVersions;
22+
23+
# Derived version information
24+
versions = lib.naturalSort (lib.attrNames supportedVersions);
25+
latestVersion =
26+
assert lib.assertMsg (
27+
versions != [ ]
28+
) "pgtap: no supported versions for PostgreSQL ${lib.versions.major postgresql.version}";
29+
lib.last versions;
30+
numberOfVersions = builtins.length versions;
31+
packages = builtins.attrValues (
32+
lib.mapAttrs (name: value: build name value.hash) supportedVersions
33+
);
34+
repoOwner = "theory";
35+
36+
# Build function for individual versions
37+
build =
38+
version: hash:
39+
stdenv.mkDerivation rec {
40+
inherit pname version;
41+
42+
src = fetchFromGitHub {
43+
owner = repoOwner;
44+
repo = pname;
45+
rev = "v${version}";
46+
inherit hash;
47+
};
48+
49+
nativeBuildInputs = [
50+
postgresql
51+
perl
52+
perlPackages.TAPParserSourceHandlerpgTAP
53+
which
54+
];
55+
56+
patches = lib.optionals (version == "1.3.3") [
57+
# Fix error in upgrade script from 1.2.0 to 1.3.3
58+
(fetchpatch2 {
59+
name = "pgtap-fix-upgrade-from-1.2.0-to-1.3.3.patch";
60+
url = "https://github.com/${repoOwner}/${pname}/pull/338.diff?full_index=1";
61+
hash = "sha256-AVRQyqCGoc0gcoMRWBJKMmUBjadGtWg7rvHmTq5rRpw=";
62+
})
63+
];
64+
65+
installPhase = ''
66+
runHook preInstall
67+
68+
mkdir -p $out/{lib,share/postgresql/extension}
69+
70+
# Create version-specific control file
71+
if [[ -f src/pgtap${postgresql.dlSuffix} ]]; then
72+
# For versions with shared library, set module_pathname
73+
ext="$out/lib/${pname}-${version}${postgresql.dlSuffix}"
74+
sed -e "/^default_version =/d" \
75+
-e "s|^module_pathname = .*|module_pathname = '$ext'|" \
76+
${pname}.control > $out/share/postgresql/extension/${pname}--${version}.control
77+
else
78+
# For SQL-only versions, remove module_pathname line entirely
79+
sed -e "/^default_version =/d" \
80+
-e "/^module_pathname =/d" \
81+
${pname}.control > $out/share/postgresql/extension/${pname}--${version}.control
82+
fi
83+
84+
# Copy SQL file to install the specific version
85+
cp sql/${pname}--${version}.sql $out/share/postgresql/extension
86+
87+
if [[ -f src/pgtap${postgresql.dlSuffix} ]]; then
88+
# Install the shared library with version suffix
89+
install -Dm755 src/pgtap${postgresql.dlSuffix} $out/lib/${pname}-${version}${postgresql.dlSuffix}
90+
fi
91+
92+
# For the latest version, create default control file and symlink and copy SQL upgrade scripts
93+
if [[ "${version}" == "${latestVersion}" ]]; then
94+
{
95+
echo "default_version = '${version}'"
96+
cat $out/share/postgresql/extension/${pname}--${version}.control
97+
} > $out/share/postgresql/extension/${pname}.control
98+
cp sql/${pname}--*--*.sql $out/share/postgresql/extension
99+
elif [[ "${version}" == "1.3.1" ]]; then
100+
# 1.3.1 is the first and only version with a C extension
101+
ln -sfn ${pname}-${version}${postgresql.dlSuffix} $out/lib/${pname}${postgresql.dlSuffix}
102+
fi
103+
'';
104+
105+
meta = with lib; {
106+
description = "A unit testing framework for PostgreSQL";
107+
longDescription = ''
108+
pgTAP is a unit testing framework for PostgreSQL written in PL/pgSQL and PL/SQL.
109+
It includes a comprehensive collection of TAP-emitting assertion functions,
110+
as well as the ability to integrate with other TAP-emitting test frameworks.
111+
It can also be used in the xUnit testing style.
112+
'';
113+
homepage = "https://pgtap.org";
114+
inherit (postgresql.meta) platforms;
115+
license = licenses.mit;
116+
};
117+
};
118+
in
119+
buildEnv {
120+
name = pname;
121+
paths = packages;
22122

23-
nativeBuildInputs = [
24-
postgresql
25-
perl
26-
perlPackages.TAPParserSourceHandlerpgTAP
27-
which
123+
pathsToLink = [
124+
"/lib"
125+
"/share/postgresql/extension"
28126
];
29127

30-
installPhase = ''
31-
install -D {sql/pgtap--${version}.sql,pgtap.control} -t $out/share/postgresql/extension
32-
'';
33-
34-
meta = with lib; {
35-
description = "A unit testing framework for PostgreSQL";
36-
longDescription = ''
37-
pgTAP is a unit testing framework for PostgreSQL written in PL/pgSQL and PL/SQL.
38-
It includes a comprehensive collection of TAP-emitting assertion functions,
39-
as well as the ability to integrate with other TAP-emitting test frameworks.
40-
It can also be used in the xUnit testing style.
41-
'';
42-
homepage = "https://pgtap.org";
43-
inherit (postgresql.meta) platforms;
44-
license = licenses.mit;
128+
passthru = {
129+
inherit versions numberOfVersions;
130+
pname = "${pname}-all";
131+
version =
132+
"multi-" + lib.concatStringsSep "-" (map (v: lib.replaceStrings [ "." ] [ "-" ] v) versions);
45133
};
46134
}

nix/ext/tests/default.nix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,7 @@ builtins.listToAttrs (
368368
"pg_stat_monitor"
369369
"pg_tle"
370370
"pgaudit"
371+
"pgtap"
371372
"postgis"
372373
"vector"
373374
"wal2json"

nix/ext/versions.json

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -786,6 +786,28 @@
786786
"hash": "sha256-STJVvvrLVLe1JevNu6u6EftzAWv+X+J8lu66su7Or2s="
787787
}
788788
},
789+
"pgtap": {
790+
"1.2.0": {
791+
"postgresql": [
792+
"15"
793+
],
794+
"hash": "sha256-lb0PRffwo6J5a6Hqw1ggvn0cW7gPZ02OEcLPi9ineI8="
795+
},
796+
"1.3.1": {
797+
"postgresql": [
798+
"15",
799+
"17"
800+
],
801+
"hash": "sha256-HOgCb1CCfsfbMbMMWuzFJ4B8CfVm9b0sI2zBY3/kqyI="
802+
},
803+
"1.3.3": {
804+
"postgresql": [
805+
"15",
806+
"17"
807+
],
808+
"hash": "sha256-YgvfLGF7pLVcCKD66NnWAydDxtoYHH1DpLiYTEKHJ0E="
809+
}
810+
},
789811
"pg_tle": {
790812
"1.0.1": {
791813
"postgresql": [

0 commit comments

Comments
 (0)