From 2d3b7d6edc1e59b7c69c289b7b8b3eec2e34a3a8 Mon Sep 17 00:00:00 2001 From: Gabriele Fedi Date: Wed, 18 Mar 2026 10:10:25 +0100 Subject: [PATCH 1/7] feat: support sql version in metadata Signed-off-by: Gabriele Fedi --- dagger/maintenance/image.go | 8 ++++---- dagger/maintenance/parse.go | 7 ++++++- pg-crash/metadata.hcl | 14 ++++++++++---- pgaudit/metadata.hcl | 14 ++++++++++---- pgvector/metadata.hcl | 14 ++++++++++---- postgis/metadata.hcl | 14 ++++++++++---- 6 files changed, 50 insertions(+), 21 deletions(-) diff --git a/dagger/maintenance/image.go b/dagger/maintenance/image.go index 26b633a1..7cd5b9d7 100644 --- a/dagger/maintenance/image.go +++ b/dagger/maintenance/image.go @@ -147,16 +147,16 @@ func getExtensionImageWithTimestamp(metadata *extensionMetadata, distribution st // extractExtensionVersion returns the extension version for a given distribution and pgMajor, // extracted from the extension's metadata. func extractExtensionVersion(versions versionMap, distribution string, pgMajor int) (string, error) { - packageVersion := versions[distribution][strconv.Itoa(pgMajor)] - if packageVersion == "" { + extVersion, ok := versions[distribution][strconv.Itoa(pgMajor)] + if !ok { return "", fmt.Errorf("no package version found for distribution %q and version %d", distribution, pgMajor) } re := regexp.MustCompile(`^(\d+(?:\.\d+)+)`) - matches := re.FindStringSubmatch(packageVersion) + matches := re.FindStringSubmatch(extVersion.Package) if len(matches) < 2 { - return "", fmt.Errorf("cannot extract extension version from %q", packageVersion) + return "", fmt.Errorf("cannot extract extension version from %q", extVersion.Package) } return matches[1], nil diff --git a/dagger/maintenance/parse.go b/dagger/maintenance/parse.go index ab68e200..a32ec222 100644 --- a/dagger/maintenance/parse.go +++ b/dagger/maintenance/parse.go @@ -18,7 +18,12 @@ type buildMatrix struct { MajorVersions []string } -type versionMap map[string]map[string]string +type extensionVersion struct { + Package string `hcl:"package" cty:"package"` + Sql string `hcl:"sql" cty:"sql"` +} + +type versionMap map[string]map[string]extensionVersion type extensionMetadata struct { Name string `hcl:"name" cty:"name"` diff --git a/pg-crash/metadata.hcl b/pg-crash/metadata.hcl index 30e8560c..93c42344 100644 --- a/pg-crash/metadata.hcl +++ b/pg-crash/metadata.hcl @@ -16,12 +16,18 @@ metadata = { versions = { bookworm = { - // renovate: suite=bookworm-pgdg depName=postgresql-18-pg-crash - "18" = "0.3-2.pgdg12+1" + "18" = { + // renovate: suite=bookworm-pgdg depName=postgresql-18-pg-crash + package = "0.3-2.pgdg12+1" + sql = "0.3-2" + } } trixie = { - // renovate: suite=trixie-pgdg depName=postgresql-18-pg-crash - "18" = "0.3-2.pgdg13+1" + "18" = { + // renovate: suite=trixie-pgdg depName=postgresql-18-pg-crash + package = "0.3-2.pgdg13+1" + sql = "0.3-2" + } } } } diff --git a/pgaudit/metadata.hcl b/pgaudit/metadata.hcl index 47d3bb8d..84c5e438 100644 --- a/pgaudit/metadata.hcl +++ b/pgaudit/metadata.hcl @@ -14,12 +14,18 @@ metadata = { versions = { bookworm = { - // renovate: suite=bookworm-pgdg depName=postgresql-18-pgaudit - "18" = "18.0-2.pgdg12+1" + "18" = { + // renovate: suite=bookworm-pgdg depName=postgresql-18-pgaudit + package = "18.0-2.pgdg12+1" + sql = "18.0" + } } trixie = { - // renovate: suite=trixie-pgdg depName=postgresql-18-pgaudit - "18" = "18.0-2.pgdg13+1" + "18" = { + // renovate: suite=trixie-pgdg depName=postgresql-18-pgaudit + package = "18.0-2.pgdg13+1" + sql = "18.0" + } } } } diff --git a/pgvector/metadata.hcl b/pgvector/metadata.hcl index 567efa21..92e263d5 100644 --- a/pgvector/metadata.hcl +++ b/pgvector/metadata.hcl @@ -14,12 +14,18 @@ metadata = { versions = { bookworm = { - // renovate: suite=bookworm-pgdg depName=postgresql-18-pgvector - "18" = "0.8.2-1.pgdg12+1" + "18" = { + // renovate: suite=bookworm-pgdg depName=postgresql-18-pgvector + package = "0.8.2-1.pgdg12+1" + sql = "0.8.2" + } } trixie = { - // renovate: suite=trixie-pgdg depName=postgresql-18-pgvector - "18" = "0.8.2-1.pgdg13+1" + "18" = { + // renovate: suite=trixie-pgdg depName=postgresql-18-pgvector + package = "0.8.2-1.pgdg13+1" + sql = "0.8.2" + } } } } diff --git a/postgis/metadata.hcl b/postgis/metadata.hcl index 44b28bf3..bcbdd954 100644 --- a/postgis/metadata.hcl +++ b/postgis/metadata.hcl @@ -15,12 +15,18 @@ metadata = { versions = { bookworm = { - // renovate: suite=bookworm-pgdg depName=postgresql-18-postgis-3 - "18" = "3.6.2+dfsg-1.pgdg12+1" + "18" = { + // renovate: suite=bookworm-pgdg depName=postgresql-18-postgis-3 + package = "3.6.2+dfsg-1.pgdg12+1" + sql = "3.6.2" + } } trixie = { - // renovate: suite=trixie-pgdg depName=postgresql-18-postgis-3 - "18" = "3.6.2+dfsg-1.pgdg13+1" + "18" = { + // renovate: suite=trixie-pgdg depName=postgresql-18-postgis-3 + package = "3.6.2+dfsg-1.pgdg13+1" + sql = "3.6.2" + } } } } From 9019a19ad82dee6265be7ea70d6ee23c11e8eb3d Mon Sep 17 00:00:00 2001 From: Gabriele Fedi Date: Wed, 18 Mar 2026 14:10:57 +0100 Subject: [PATCH 2/7] feat: set sql version in annotations Signed-off-by: Gabriele Fedi --- dagger/maintenance/main.go | 4 ++-- docker-bake.hcl | 9 ++++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/dagger/maintenance/main.go b/dagger/maintenance/main.go index e7be181c..012959af 100644 --- a/dagger/maintenance/main.go +++ b/dagger/maintenance/main.go @@ -179,10 +179,10 @@ func (m *Maintenance) GenerateTestingValues( targetExtensionImage) } - version := annotations["org.opencontainers.image.version"] + version := annotations["io.cloudnativepg.image.sql.version"] if version == "" { return nil, fmt.Errorf( - "extension image %s doesn't have an 'org.opencontainers.image.version' annotation", + "extension image %s doesn't have an 'io.cloudnativepg.image.sql.version' annotation", targetExtensionImage) } diff --git a/docker-bake.hcl b/docker-bake.hcl index 69987d19..5d912736 100644 --- a/docker-bake.hcl +++ b/docker-bake.hcl @@ -79,6 +79,7 @@ target "default" { "index,manifest:io.cloudnativepg.image.base.name=${getBaseImage(distro, pgVersion)}", "index,manifest:io.cloudnativepg.image.base.pgmajor=${pgVersion}", "index,manifest:io.cloudnativepg.image.base.os=${distro}", + "index,manifest:io.cloudnativepg.image.sql.version=${getExtensionSqlVersion(distro, pgVersion)}", ] labels = { "org.opencontainers.image.created" = "${now}", @@ -96,6 +97,7 @@ target "default" { "io.cloudnativepg.image.base.name" = "${getBaseImage(distro, pgVersion)}", "io.cloudnativepg.image.base.pgmajor" = "${pgVersion}", "io.cloudnativepg.image.base.os" = "${distro}", + "io.cloudnativepg.image.sql.version" = "${getExtensionSqlVersion(distro, pgVersion)}", } } @@ -106,7 +108,12 @@ function getImageName { function getExtensionPackage { params = [ distro, pgVersion ] - result = metadata.versions[distro][pgVersion] + result = metadata.versions[distro][pgVersion]["package"] +} + +function getExtensionSqlVersion { + params = [ distro, pgVersion ] + result = metadata.versions[distro][pgVersion]["sql"] } // Parse the packageVersion to extract the MM.mm.pp extension version. From a2b9b548baba9b380e162308d9e07c324a99e89e Mon Sep 17 00:00:00 2001 From: Gabriele Fedi Date: Wed, 18 Mar 2026 16:35:44 +0100 Subject: [PATCH 3/7] chore: configure renovate for sql version Signed-off-by: Gabriele Fedi --- pg-crash/metadata.hcl | 2 -- pgaudit/metadata.hcl | 2 ++ pgvector/metadata.hcl | 2 ++ postgis/metadata.hcl | 2 ++ renovate.json | 2 +- 5 files changed, 7 insertions(+), 3 deletions(-) diff --git a/pg-crash/metadata.hcl b/pg-crash/metadata.hcl index 93c42344..45d26e09 100644 --- a/pg-crash/metadata.hcl +++ b/pg-crash/metadata.hcl @@ -19,14 +19,12 @@ metadata = { "18" = { // renovate: suite=bookworm-pgdg depName=postgresql-18-pg-crash package = "0.3-2.pgdg12+1" - sql = "0.3-2" } } trixie = { "18" = { // renovate: suite=trixie-pgdg depName=postgresql-18-pg-crash package = "0.3-2.pgdg13+1" - sql = "0.3-2" } } } diff --git a/pgaudit/metadata.hcl b/pgaudit/metadata.hcl index 84c5e438..28339b11 100644 --- a/pgaudit/metadata.hcl +++ b/pgaudit/metadata.hcl @@ -17,6 +17,7 @@ metadata = { "18" = { // renovate: suite=bookworm-pgdg depName=postgresql-18-pgaudit package = "18.0-2.pgdg12+1" + // renovate: suite=bookworm-pgdg depName=postgresql-18-pgaudit extractVersion=^(?\d+\.\d+).*$ sql = "18.0" } } @@ -24,6 +25,7 @@ metadata = { "18" = { // renovate: suite=trixie-pgdg depName=postgresql-18-pgaudit package = "18.0-2.pgdg13+1" + // renovate: suite=trixie-pgdg depName=postgresql-18-pgaudit extractVersion=^(?\d+\.\d+).*$ sql = "18.0" } } diff --git a/pgvector/metadata.hcl b/pgvector/metadata.hcl index 92e263d5..d2cc60ab 100644 --- a/pgvector/metadata.hcl +++ b/pgvector/metadata.hcl @@ -17,6 +17,7 @@ metadata = { "18" = { // renovate: suite=bookworm-pgdg depName=postgresql-18-pgvector package = "0.8.2-1.pgdg12+1" + // renovate: suite=bookworm-pgdg depName=postgresql-18-pgvector extractVersion=^(?\d+\.\d+\.\d+).*$ sql = "0.8.2" } } @@ -24,6 +25,7 @@ metadata = { "18" = { // renovate: suite=trixie-pgdg depName=postgresql-18-pgvector package = "0.8.2-1.pgdg13+1" + // renovate: suite=trixie-pgdg depName=postgresql-18-pgvector extractVersion=^(?\d+\.\d+\.\d+).*$ sql = "0.8.2" } } diff --git a/postgis/metadata.hcl b/postgis/metadata.hcl index bcbdd954..951e2a98 100644 --- a/postgis/metadata.hcl +++ b/postgis/metadata.hcl @@ -18,6 +18,7 @@ metadata = { "18" = { // renovate: suite=bookworm-pgdg depName=postgresql-18-postgis-3 package = "3.6.2+dfsg-1.pgdg12+1" + // renovate: suite=bookworm-pgdg depName=postgresql-18-postgis-3 extractVersion=^(?\d+\.\d+\.\d+).*$ sql = "3.6.2" } } @@ -25,6 +26,7 @@ metadata = { "18" = { // renovate: suite=trixie-pgdg depName=postgresql-18-postgis-3 package = "3.6.2+dfsg-1.pgdg13+1" + // renovate: suite=trixie-pgdg depName=postgresql-18-postgis-3 extractVersion=^(?\d+\.\d+\.\d+).*$ sql = "3.6.2" } } diff --git a/renovate.json b/renovate.json index 57dcf1b5..d7e8a28c 100644 --- a/renovate.json +++ b/renovate.json @@ -17,7 +17,7 @@ "**/*.hcl" ], "matchStrings": [ - "\\/\\/\\s*renovate:\\s*?(suite=(?.*?))?\\s*depName=(?.*?)?\\s*\"[A-Za-z0-9_-]+\"\\s*=\\s*\"(?.*)\"" + "\\/\\/\\s*renovate:\\s*?(suite=(?.*?))?\\s*depName=(?.*?)?(?: extractVersion=(?[^\\s]+?))?\\s*(sql|package)\\s*=\\s*\"(?.*)\"" ], "registryUrlTemplate": "https://download.postgresql.org/pub/repos/apt?suite={{#if suite}}{{suite}}{{else}}stable{{/if}}&components=main&binaryArch=amd64", "datasourceTemplate": "deb" From cf77853400c9f019d907fdcc7becd7dc690ea06b Mon Sep 17 00:00:00 2001 From: Gabriele Fedi Date: Wed, 18 Mar 2026 16:46:11 +0100 Subject: [PATCH 4/7] chore: optional version annotation Signed-off-by: Gabriele Fedi --- dagger/maintenance/main.go | 2 +- dagger/maintenance/parse.go | 1 - docker-bake.hcl | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/dagger/maintenance/main.go b/dagger/maintenance/main.go index 012959af..b6497581 100644 --- a/dagger/maintenance/main.go +++ b/dagger/maintenance/main.go @@ -180,7 +180,7 @@ func (m *Maintenance) GenerateTestingValues( } version := annotations["io.cloudnativepg.image.sql.version"] - if version == "" { + if version == "" && metadata.CreateExtension { return nil, fmt.Errorf( "extension image %s doesn't have an 'io.cloudnativepg.image.sql.version' annotation", targetExtensionImage) diff --git a/dagger/maintenance/parse.go b/dagger/maintenance/parse.go index a32ec222..049f81f9 100644 --- a/dagger/maintenance/parse.go +++ b/dagger/maintenance/parse.go @@ -20,7 +20,6 @@ type buildMatrix struct { type extensionVersion struct { Package string `hcl:"package" cty:"package"` - Sql string `hcl:"sql" cty:"sql"` } type versionMap map[string]map[string]extensionVersion diff --git a/docker-bake.hcl b/docker-bake.hcl index 5d912736..76183ccf 100644 --- a/docker-bake.hcl +++ b/docker-bake.hcl @@ -113,7 +113,7 @@ function getExtensionPackage { function getExtensionSqlVersion { params = [ distro, pgVersion ] - result = metadata.versions[distro][pgVersion]["sql"] + result = lookup(metadata.versions[distro][pgVersion], "sql", "") } // Parse the packageVersion to extract the MM.mm.pp extension version. From b6573508e6a3d42dfe3f65ec31ad7ecc36851dcf Mon Sep 17 00:00:00 2001 From: Gabriele Fedi Date: Wed, 18 Mar 2026 17:07:14 +0100 Subject: [PATCH 5/7] feat: update metadata.hcl template Signed-off-by: Gabriele Fedi --- templates/metadata.hcl.tmpl | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/templates/metadata.hcl.tmpl b/templates/metadata.hcl.tmpl index deeb18b6..d7057c73 100644 --- a/templates/metadata.hcl.tmpl +++ b/templates/metadata.hcl.tmpl @@ -79,8 +79,15 @@ metadata = { {{- range $distro := .Distros}} {{ $distro }} = { {{- range $version := $.Versions}} - // renovate: suite={{ $distro }}-pgdg depName={{ replaceAll $.Package "%version%" $version }} - "{{ $version }}" = "" + "{{ $version }}" = { + // renovate: suite={{ $distro }}-pgdg depName={{ replaceAll $.Package "%version%" $version }} + package = "" + // TODO: Remove this comment after adding the sql version if extension uses CREATE EXTENSION + // TODO: Adjust the extractVersion regex pattern based on your extension's versioning scheme + // Examples: \d+\.\d+ for major.minor (e.g., "18.0"), \d+\.\d+\.\d+ for major.minor.patch (e.g., "0.8.2") + // renovate: suite={{ $distro }}-pgdg depName={{ replaceAll $.Package "%version%" $version }} extractVersion=^(?\d+\.\d+\.\d+).*$ + sql = "" + } {{- end}} } {{- end}} From c7347ea873db9af734c51a6b42eb15932fa9ba14 Mon Sep 17 00:00:00 2001 From: Gabriele Fedi Date: Wed, 18 Mar 2026 17:29:40 +0100 Subject: [PATCH 6/7] docs: updated md files Signed-off-by: Gabriele Fedi --- CONTRIBUTING_NEW_EXTENSION.md | 15 +++++++++++++++ README.md | 11 ++++++----- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/CONTRIBUTING_NEW_EXTENSION.md b/CONTRIBUTING_NEW_EXTENSION.md index e743f715..ee2823e0 100644 --- a/CONTRIBUTING_NEW_EXTENSION.md +++ b/CONTRIBUTING_NEW_EXTENSION.md @@ -76,6 +76,21 @@ remains constant, the versioning reflects the underlying Debian release: > upstream repositories and trigger update Pull Requests once your extension is > merged. +#### Package Version vs. SQL Version + +Your `metadata.hcl` file requires two version fields: + +- **`package`**: The full Debian package version (e.g., `0.8.2-1.pgdg13+1`). + This includes packaging metadata and is used to install the correct package. + +- **`sql`**: The PostgreSQL extension version as it appears in the catalog + (e.g., `0.8.2`). This is the version of the extension that will be verified + as part of the automatic testing of the resulting containers. It should + match what is defined by the `default_version` field in the control file. + +The **SQL version** is optional and only needed if your extension uses +`CREATE EXTENSION` (when `create_extension = true` in metadata). + #### Inspecting the Package Content If you want to get a list of the files contained in the package, you need to diff --git a/README.md b/README.md index fc0759f6..f11d8800 100644 --- a/README.md +++ b/README.md @@ -138,11 +138,12 @@ other tools to identify the base PostgreSQL version and OS distribution. ### CloudNativePG-Specific Labels -| Label | Description | Example | -| :--- | :--- | :--- | -| `io.cloudnativepg.image.base.name` | Base PostgreSQL container image | `ghcr.io/cloudnative-pg/postgresql:18-minimal-bookworm` | -| `io.cloudnativepg.image.base.pgmajor` | PostgreSQL major version | `18` | -| `io.cloudnativepg.image.base.os` | Operating system distribution | `bookworm` | +| Label | Description | Example | +| :--- |:---------------------------------| :--- | +| `io.cloudnativepg.image.base.name` | Base PostgreSQL container image | `ghcr.io/cloudnative-pg/postgresql:18-minimal-bookworm` | +| `io.cloudnativepg.image.base.pgmajor` | PostgreSQL major version | `18` | +| `io.cloudnativepg.image.base.os` | Operating system distribution | `bookworm` | +| `io.cloudnativepg.image.sql.version` | PostgreSQL extension SQL version | `0.8.2` | ### Standard OCI Labels From bc774ac1d6028f0b0d153fbdb4840b8575ed8e75 Mon Sep 17 00:00:00 2001 From: Gabriele Fedi Date: Wed, 18 Mar 2026 17:41:28 +0100 Subject: [PATCH 7/7] chore: improve error message for missing annotation Signed-off-by: Gabriele Fedi --- dagger/maintenance/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dagger/maintenance/main.go b/dagger/maintenance/main.go index b6497581..9c0b90fd 100644 --- a/dagger/maintenance/main.go +++ b/dagger/maintenance/main.go @@ -182,7 +182,7 @@ func (m *Maintenance) GenerateTestingValues( version := annotations["io.cloudnativepg.image.sql.version"] if version == "" && metadata.CreateExtension { return nil, fmt.Errorf( - "extension image %s doesn't have an 'io.cloudnativepg.image.sql.version' annotation", + "extension image %s doesn't have an 'io.cloudnativepg.image.sql.version' annotation or its value is empty", targetExtensionImage) }