Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 49 additions & 56 deletions .docs/extensions.es.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,104 +4,97 @@

Cada extensión tiene dos partes:

1. **Cómo se instala**, en el [`Dockerfile`](../Dockerfile).
2. **Cómo se prueba**, en `extensions/<nombre>/test.sql`.
1. **Cómo se instala**: una línea en [`extensions/pgdg.txt`](../extensions/pgdg.txt) o unas pocas líneas en el [`Dockerfile`](../Dockerfile).
2. **Cómo se prueba**: `extensions/<nombre>/test.sql`.

No hay más código que tocar.
No hay más código que tocar. La lista completa de lo que se incluye está en [Extensiones incluidas](./included-extensions.es.md).

## Añadir una extensión

### Opción A: está empaquetada en PGDG (preferida)
Elige la primera opción que funcione, en este orden.

Busca `postgresql-<major>-<nombre>` en [apt.postgresql.org](https://apt.postgresql.org/pub/repos/apt/pool/main/). Tiene que existir para todas las versiones soportadas.
### Opción A: está empaquetada en PGDG (preferida)

Declara su versión arriba del todo en el Dockerfile. El comentario `# renovate:` le indica a Renovate el índice de PGDG, para que abra un PR cuando se empaquete una versión nueva:
Busca `postgresql-<major>-<paquete>` en [apt.postgresql.org](https://apt.postgresql.org/pub/repos/apt/pool/main/) y mira qué versiones tiene:

```dockerfile
# renovate: datasource=deb depName=postgresql-18-mi-extension registryUrl=https://apt.postgresql.org/pub/repos/apt?suite=trixie-pgdg&components=main&binaryArch=amd64
ARG MI_EXTENSION_VERSION=1.2.3
```sh
docker run --rm postgres:18 bash -c 'apt-get update -qq && apt-cache madison postgresql-18-<paquete>'
```

`suite` es la versión de Debian de la imagen base (hoy `trixie`) seguida de `-pgdg`. Puedes comprobarla con `docker run --rm postgres:18 cat /etc/os-release`.

Después, añádela fijada al `apt-get install` de la etapa final, y a los labels:
Si existe la misma versión upstream para todas las versiones mayores soportadas, añade una línea a `extensions/pgdg.txt`:

```dockerfile
ARG MI_EXTENSION_VERSION
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
"postgresql-${PG_MAJOR}-postgis-3=${POSTGIS_VERSION}+*" \
"postgresql-${PG_MAJOR}-mi-extension=${MI_EXTENSION_VERSION}*" \
&& rm -rf /var/lib/apt/lists/*
LABEL ... \
io.github.ruxwez.postgres.mi-extension.version="${MI_EXTENSION_VERSION}"
```
mi-paquete 1.2.3
```

El `*` final cubre la revisión de Debian (`1.2.3-1.pgdg13+1`). Usa `+*` cuando la versión del paquete lleve `+dfsg` o algo parecido, como pasa con PostGIS. Puedes ver las versiones disponibles con:
Si la versión cambia según la versión mayor, o el paquete no existe para alguna, añade una línea por versión mayor:

```sh
docker run --rm postgres:18 bash -c 'apt-get update -qq && apt-cache madison postgresql-18-mi-extension'
```
mi-paquete/17 2.0.1
mi-paquete/18 2.1.0
```

PGDG suele mantener varias versiones anteriores en su índice, así que la versión fijada sigue funcionando un tiempo después de que salga una nueva. Cuando una versión desaparece del índice, el build falla con `Version '…' was not found` hasta que se hace merge del PR de Renovate.

La imagen oficial base define `PG_MAJOR`.
La versión es la upstream, sin la revisión de Debian: `1.2.3` cubre `1.2.3-1.pgdg13+1`. Renovate actualiza estas líneas y las agrupa en un PR semanal.

### Opción B: compilarla desde el código fuente
### Opción B: los autores publican paquetes precompilados

Declara su versión arriba del todo en el Dockerfile, junto a las demás:
Si los autores adjuntan a sus releases un `.deb` (o un `.zip` con uno) por cada versión mayor de PostgreSQL y arquitectura, añádelo a la etapa `prebuilt`. `fetch-deb` lo descarga y se queda solo con sus archivos de PostgreSQL:

```dockerfile
# renovate: datasource=github-tags depName=owner/mi-extension
# arriba, con las demás versiones
# renovate: datasource=github-releases depName=owner/mi-extension
ARG MI_EXTENSION_VERSION=1.2.3
```

El comentario `# renovate:` justo encima del `ARG` permite que Renovate abra un PR cada vez que salga un tag nuevo. Mantén el mismo formato.

Añade una etapa encima de `build-base`. Tiene que instalar en `/out` (con `DESTDIR`):

```dockerfile
FROM build-base AS mi-extension
# en la etapa prebuilt
ARG MI_EXTENSION_VERSION
RUN git clone --depth 1 --branch "v${MI_EXTENSION_VERSION}" https://github.com/owner/mi-extension.git /src \
&& make -C /src \
&& make -C /src install DESTDIR=/out
RUN fetch-deb "https://github.com/owner/mi-extension/releases/download/v${MI_EXTENSION_VERSION}/mi-extension-pg${PG_MAJOR}-${TARGETARCH}.deb"
```

En la etapa final, cópiala y añade su versión a los labels:
### Opción C: compilarla desde el código fuente

Añade una línea a la etapa `source`. `pgxs-build` descarga un tag (o un commit) y hace `make install` en `/out`:

```dockerfile
# arriba, con las demás versiones
# renovate: datasource=github-tags depName=owner/mi-extension
ARG MI_EXTENSION_VERSION=1.2.3

# en la etapa source
ARG MI_EXTENSION_VERSION
COPY --from=mi-extension /out/ /
LABEL ... \
io.github.ruxwez.postgres.mi-extension.version="${MI_EXTENSION_VERSION}"
RUN pgxs-build https://github.com/owner/mi-extension.git "v${MI_EXTENSION_VERSION}"
```

Si el build necesita más paquetes, añádelos a `build-base`. No llegan a la imagen final.
Argumentos opcionales: un subdirectorio y después argumentos extra de `make` (`pgxs-build URL TAG subdir USE_PGXS=1`). Si la extensión no soporta las versiones mayores antiguas, pon delante `MIN_PG_MAJOR=16` para saltárselas. Si el build necesita paquetes `-dev`, añádelos al `apt-get install` de la etapa `source`; no llegan a la imagen final. Las librerías de runtime van en el `apt-get install` de la etapa final.

### Después, en ambos casos
El comentario `# renovate:` justo encima del `ARG` permite que Renovate abra un PR cada vez que salga una versión nueva. Mantén el mismo formato.

Crea `extensions/<nombre>/test.sql`. Tiene que **usar** la extensión, no solo crearla, y lanzar un error si el resultado es incorrecto:
## Escribir el test

Crea `extensions/<nombre>/test.sql`. Tiene que **usar** la extensión, no solo crearla, y fallar si el resultado es incorrecto. `assert_true(condición, mensaje)` está disponible en todas las bases de datos de test:

```sql
CREATE EXTENSION mi_extension;

DO $$
BEGIN
IF mi_funcion(1) <> 2 THEN
RAISE EXCEPTION 'mi_extension: resultado inesperado';
END IF;
END $$;
SELECT assert_true(mi_funcion(1) = 2, 'mi_extension: mi_funcion()');
```

`tests/run.sh` lo detecta automáticamente. Por último, añade la extensión a la tabla del README.
`tests/run.sh` lo detecta automáticamente. Cada test se ejecuta en una base de datos nueva, todos en el mismo servidor. Estos archivos opcionales en el mismo directorio cambian ese comportamiento:

| Archivo | Contenido | Efecto |
|---|---|---|
| `server.conf` | Líneas de `postgresql.conf`, p. ej. `shared_preload_libraries = 'mi_extension'` | Se aplican al servidor de test. Los valores de `shared_preload_libraries` de todas las extensiones se combinan. |
| `pg-versions` | Versiones mayores soportadas, p. ej. `17 18` | En las demás versiones el test sale como `SKIP` en vez de fallar. |
| `database` | Un nombre de base de datos, p. ej. `postgres` | El test se ejecuta ahí en vez de en una base de datos nueva (lo necesitan pg_cron y las extensiones que dependen de ella). |
| `isolated` | Por qué la extensión no puede compartir servidor | El test se ejecuta en un servidor propio, solo con su `server.conf`. |

Por último, añade la extensión a [Extensiones incluidas](./included-extensions.es.md) y a la tabla de categorías del README.

## Actualizar una extensión

Cambia su `ARG *_VERSION` arriba del todo en el Dockerfile. Renovate abre estos PRs por ti, tanto para los paquetes apt como para las extensiones que se compilan.
Cambia su versión en `extensions/pgdg.txt` o en su `ARG` arriba del todo en el Dockerfile. Renovate abre estos PRs por ti.

Una vez hecho el merge, el cambio solo llega a `18` y `latest`. Para llevarlo a `18-v1`, saca una release (en [Releases](./releases.es.md) se explica qué número subir).

## Añadir o quitar una versión de PostgreSQL

Edita la lista `major` en [`docker-bake.hcl`](../docker-bake.hcl). Para mover `:latest` a una versión nueva, cambia también `LATEST`. El CI construye y prueba todas las versiones de esa lista, así que si alguna extensión no está disponible para una versión, el build falla.
Edita la lista `major` en [`docker-bake.hcl`](../docker-bake.hcl). Para mover `:latest` a una versión nueva, cambia también `LATEST`. El CI construye y prueba todas las versiones de esa lista. Si alguna extensión no está disponible para una versión nueva, ponle un archivo `pg-versions` (con las líneas por versión mayor o el `MIN_PG_MAJOR` correspondientes), o espera a que lo esté.
105 changes: 49 additions & 56 deletions .docs/extensions.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,104 +4,97 @@

Every extension has two parts:

1. **How it's installed**, in the [`Dockerfile`](../Dockerfile).
2. **How it's tested**, in `extensions/<name>/test.sql`.
1. **How it's installed**: a line in [`extensions/pgdg.txt`](../extensions/pgdg.txt), or a few lines in the [`Dockerfile`](../Dockerfile).
2. **How it's tested**: `extensions/<name>/test.sql`.

There is no other code to touch.
There is no other code to touch. The full list of what's included is in [Included extensions](./included-extensions.md).

## Adding an extension

### Option A: it's packaged in PGDG (preferred)
Pick the first option that works, in this order.

Look for `postgresql-<major>-<name>` on [apt.postgresql.org](https://apt.postgresql.org/pub/repos/apt/pool/main/). It has to exist for every supported version.
### Option A: it's packaged in PGDG (preferred)

Declare its version at the top of the Dockerfile. The `# renovate:` comment points Renovate at the PGDG index, so it opens a PR when a new version is packaged:
Look for `postgresql-<major>-<package>` on [apt.postgresql.org](https://apt.postgresql.org/pub/repos/apt/pool/main/), and list the versions it has:

```dockerfile
# renovate: datasource=deb depName=postgresql-18-my-extension registryUrl=https://apt.postgresql.org/pub/repos/apt?suite=trixie-pgdg&components=main&binaryArch=amd64
ARG MY_EXTENSION_VERSION=1.2.3
```sh
docker run --rm postgres:18 bash -c 'apt-get update -qq && apt-cache madison postgresql-18-<package>'
```

`suite` is the Debian release of the base image (`trixie` today) followed by `-pgdg`. Check it with `docker run --rm postgres:18 cat /etc/os-release`.

Then add it to the `apt-get install` in the final stage, pinned, and to the labels:
If the same upstream version exists for every supported major, add one line to `extensions/pgdg.txt`:

```dockerfile
ARG MY_EXTENSION_VERSION
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
"postgresql-${PG_MAJOR}-postgis-3=${POSTGIS_VERSION}+*" \
"postgresql-${PG_MAJOR}-my-extension=${MY_EXTENSION_VERSION}*" \
&& rm -rf /var/lib/apt/lists/*
LABEL ... \
io.github.ruxwez.postgres.my-extension.version="${MY_EXTENSION_VERSION}"
```
my-package 1.2.3
```

The trailing `*` matches the Debian revision (`1.2.3-1.pgdg13+1`). Use `+*` when the package version contains `+dfsg` or similar, as PostGIS does. You can list the available versions with:
If the version differs per major, or the package doesn't exist for some of them, add one line per major instead:

```sh
docker run --rm postgres:18 bash -c 'apt-get update -qq && apt-cache madison postgresql-18-my-extension'
```
my-package/17 2.0.1
my-package/18 2.1.0
```

PGDG usually keeps a few previous versions in its index, so the pin keeps working for a while after a new release. Once a version is dropped from the index, the build fails with `Version '…' was not found` until the Renovate PR is merged.

`PG_MAJOR` is set by the official base image.
The version is the upstream one, without the Debian revision: `1.2.3` matches `1.2.3-1.pgdg13+1`. Renovate updates these lines and groups them into one weekly PR.

### Option B: build it from source
### Option B: the authors publish prebuilt packages

Declare its version at the top of the Dockerfile, next to the others:
If the authors attach a `.deb` (or a `.zip` with one) per PostgreSQL major and architecture to their releases, add it to the `prebuilt` stage. `fetch-deb` downloads it and keeps only its PostgreSQL files:

```dockerfile
# renovate: datasource=github-tags depName=owner/my-extension
# at the top, with the other versions
# renovate: datasource=github-releases depName=owner/my-extension
ARG MY_EXTENSION_VERSION=1.2.3
```

The `# renovate:` comment right above the `ARG` lets Renovate open a PR whenever a new tag is released. Keep the same format.

Add a stage on top of `build-base`. It must install into `/out` (via `DESTDIR`):

```dockerfile
FROM build-base AS my-extension
# in the prebuilt stage
ARG MY_EXTENSION_VERSION
RUN git clone --depth 1 --branch "v${MY_EXTENSION_VERSION}" https://github.com/owner/my-extension.git /src \
&& make -C /src \
&& make -C /src install DESTDIR=/out
RUN fetch-deb "https://github.com/owner/my-extension/releases/download/v${MY_EXTENSION_VERSION}/my-extension-pg${PG_MAJOR}-${TARGETARCH}.deb"
```

In the final stage, copy it over and add its version to the labels:
### Option C: build it from source

Add a line to the `source` stage. `pgxs-build` fetches a tag (or a commit) and runs `make install` into `/out`:

```dockerfile
# at the top, with the other versions
# renovate: datasource=github-tags depName=owner/my-extension
ARG MY_EXTENSION_VERSION=1.2.3

# in the source stage
ARG MY_EXTENSION_VERSION
COPY --from=my-extension /out/ /
LABEL ... \
io.github.ruxwez.postgres.my-extension.version="${MY_EXTENSION_VERSION}"
RUN pgxs-build https://github.com/owner/my-extension.git "v${MY_EXTENSION_VERSION}"
```

If the build needs extra packages, add them to `build-base`. They won't reach the final image.
Optional arguments: a subdirectory, then extra `make` arguments (`pgxs-build URL TAG subdir USE_PGXS=1`). Prefix with `MIN_PG_MAJOR=16` to skip older majors that the extension doesn't support. If the build needs `-dev` packages, add them to the `apt-get install` of the `source` stage; they don't reach the final image. Runtime libraries go in the final stage's `apt-get install`.

### Then, in both cases
The `# renovate:` comment right above the `ARG` lets Renovate open a PR whenever a new version is released. Keep the same format.

Create `extensions/<name>/test.sql`. It should **use** the extension, not only create it, and raise an error if the result is wrong:
## Writing the test

Create `extensions/<name>/test.sql`. It should **use** the extension, not only create it, and fail if the result is wrong. `assert_true(condition, message)` is available in every test database:

```sql
CREATE EXTENSION my_extension;

DO $$
BEGIN
IF my_function(1) <> 2 THEN
RAISE EXCEPTION 'my_extension: unexpected result';
END IF;
END $$;
SELECT assert_true(my_function(1) = 2, 'my_extension: my_function()');
```

`tests/run.sh` picks it up automatically. Finally, add the extension to the table in the README.
`tests/run.sh` picks it up automatically. Each test runs in a fresh database, all of them on one server. These optional files in the same directory change that:

| File | Content | Effect |
|---|---|---|
| `server.conf` | `postgresql.conf` lines, e.g. `shared_preload_libraries = 'my_extension'` | Applied to the test server. `shared_preload_libraries` values from every extension are merged. |
| `pg-versions` | Supported majors, e.g. `17 18` | On other majors the test is reported as `SKIP` instead of failing. |
| `database` | A database name, e.g. `postgres` | The test runs there instead of in a fresh database (pg_cron and the extensions that depend on it need this). |
| `isolated` | Why the extension can't share a server | The test runs on a server of its own, with only its own `server.conf`. |

Finally, add the extension to [Included extensions](./included-extensions.md) and to the category table in the README.

## Upgrading an extension

Change its `ARG *_VERSION` at the top of the Dockerfile. Renovate opens these PRs for you, for both apt packages and extensions built from source.
Change its version in `extensions/pgdg.txt` or in its `ARG` at the top of the Dockerfile. Renovate opens these PRs for you.

Once merged, the change only reaches `18` and `latest`. To ship it to `18-v1`, cut a release (see [Releases](./releases.md) to pick the version bump).

## Adding or dropping a PostgreSQL version

Edit the `major` list in [`docker-bake.hcl`](../docker-bake.hcl). To move `:latest` to a new major, change `LATEST` too. CI builds and tests every version in that list, so a version where some extension isn't available fails the build.
Edit the `major` list in [`docker-bake.hcl`](../docker-bake.hcl). To move `:latest` to a new major, change `LATEST` too. CI builds and tests every version in that list. If an extension isn't available for a new major, either give it a `pg-versions` file (and the matching per-major lines or `MIN_PG_MAJOR`), or wait until it is.
Loading
Loading