Skip to content

Commit 169b3cf

Browse files
bitnerclaude
andcommitted
CI: build Debian packages + GHCR Docker image; add Makefile shim
Expand release.yml (on v* tags, with workflow_dispatch dry-run) to produce: - debian: .deb packages for PostgreSQL 16/17/18, built in a debian:bookworm container (glibc-compatible with PGDG Debian and the postgres:18 image) via cargo pgrx package + packaging/build-deb.sh (dpkg-deb, no fpm). cargo-pgrx is set up with a hand-written ~/.pgrx/config.toml so no initdb runs as root. - docker: ghcr.io/<owner>/pg_table_range image (:18 / :vX.Y.Z / :latest) from the official postgres:18 image + postgresql-18-postgis-3 + the pg18 .deb, enabling postgis and pg_table_range in the default DB on first init. - github-release: attaches the .deb files to the GitHub Release. - pgxn: validate META.json, bundle, upload (now gated to tags). Add a thin Makefile wrapping cargo-pgrx (auto-detects PG major from PG_CONFIG, writes a minimal pgrx config.toml so no cargo pgrx init is needed) so make install / pgxn install work. README install section reworked around the three routes (Docker, .deb, source/make). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent b040e1d commit 169b3cf

6 files changed

Lines changed: 323 additions & 35 deletions

File tree

.github/workflows/release.yml

Lines changed: 155 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,173 @@
1-
name: Release to PGXN
1+
name: Release
22

3-
# Publishes a release to the PostgreSQL Extension Network (https://pgxn.org) when a
4-
# version tag is pushed. Requires two repository secrets, from a PGXN Manager account
5-
# (https://manager.pgxn.org): PGXN_USERNAME and PGXN_PASSWORD.
3+
# Builds release artifacts and publishes them when a version tag (v*) is pushed:
4+
# * debian - .deb packages for PostgreSQL 16/17/18 (Debian bookworm / PGDG)
5+
# * docker - ghcr.io image: PostgreSQL 18 + PostGIS + pg_table_range
6+
# * github-release - attaches the .deb files to the GitHub Release (tags only)
7+
# * pgxn - bundles the source and uploads it to https://pgxn.org (tags only)
68
#
7-
# To cut a release:
8-
# 1. Bump "version" in Cargo.toml and META.json (keep them identical).
9-
# 2. Commit, then tag: git tag v0.1.0 && git push origin v0.1.0
10-
# The tag (without its leading "v") must match the META.json version.
9+
# workflow_dispatch runs the build jobs as a dry run (no pushes / publishes), so packaging
10+
# can be validated without cutting a release.
11+
#
12+
# Secrets required for the tagged release:
13+
# PGXN_USERNAME / PGXN_PASSWORD - a PGXN Manager account (https://manager.pgxn.org)
14+
# The Docker push uses the built-in GITHUB_TOKEN (no extra secret needed).
1115

1216
on:
1317
push:
1418
tags:
1519
- "v*"
20+
workflow_dispatch:
21+
22+
env:
23+
PGRX_VERSION: "0.18.1"
1624

1725
jobs:
18-
release:
19-
name: Bundle and release on PGXN
26+
debian:
27+
name: Debian package (PostgreSQL ${{ matrix.pg }})
28+
runs-on: ubuntu-latest
29+
container: debian:bookworm
30+
strategy:
31+
fail-fast: false
32+
matrix:
33+
pg: ["16", "17", "18"]
34+
steps:
35+
- name: Install build dependencies and PGDG PostgreSQL ${{ matrix.pg }}
36+
run: |
37+
set -eux
38+
apt-get update
39+
apt-get install -y --no-install-recommends \
40+
ca-certificates curl gnupg git build-essential pkg-config \
41+
clang libclang-dev libreadline-dev zlib1g-dev flex bison
42+
curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc \
43+
| gpg --dearmor -o /usr/share/keyrings/pgdg.gpg
44+
echo "deb [signed-by=/usr/share/keyrings/pgdg.gpg] https://apt.postgresql.org/pub/repos/apt bookworm-pgdg main" \
45+
> /etc/apt/sources.list.d/pgdg.list
46+
apt-get update
47+
apt-get install -y --no-install-recommends \
48+
"postgresql-${{ matrix.pg }}" "postgresql-server-dev-${{ matrix.pg }}"
49+
50+
- uses: actions/checkout@v4
51+
52+
- name: Install Rust (toolchain from rust-toolchain.toml)
53+
run: |
54+
curl --proto '=https' --tlsv1.2 -fsSL https://sh.rustup.rs | sh -s -- -y --default-toolchain none
55+
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
56+
57+
- name: Cache cargo
58+
uses: actions/cache@v4
59+
with:
60+
path: |
61+
~/.cargo/registry
62+
~/.cargo/git
63+
~/.cargo/bin
64+
key: deb-cargo-${{ env.PGRX_VERSION }}-${{ hashFiles('Cargo.lock') }}
65+
66+
- name: Install cargo-pgrx
67+
run: |
68+
rustup show
69+
cargo install cargo-pgrx --version "=${{ env.PGRX_VERSION }}" --locked
70+
71+
- name: Build the extension for PostgreSQL ${{ matrix.pg }}
72+
run: |
73+
# cargo-pgrx needs a config.toml that knows this PostgreSQL; write a minimal one
74+
# (no `cargo pgrx init`, which would run initdb and fail as root in this container).
75+
mkdir -p ~/.pgrx
76+
printf '[configs]\npg%s = "%s"\n' "${{ matrix.pg }}" \
77+
"/usr/lib/postgresql/${{ matrix.pg }}/bin/pg_config" > ~/.pgrx/config.toml
78+
cargo pgrx package --no-default-features --features "pg${{ matrix.pg }}" \
79+
--pg-config "/usr/lib/postgresql/${{ matrix.pg }}/bin/pg_config"
80+
81+
- name: Build .deb
82+
run: bash packaging/build-deb.sh "${{ matrix.pg }}"
83+
84+
- name: Upload .deb artifact
85+
uses: actions/upload-artifact@v4
86+
with:
87+
name: deb-pg${{ matrix.pg }}
88+
path: target/deb/*.deb
89+
if-no-files-found: error
90+
91+
docker:
92+
name: Docker image (ghcr.io)
93+
needs: debian
94+
runs-on: ubuntu-latest
95+
permissions:
96+
contents: read
97+
packages: write
98+
steps:
99+
- uses: actions/checkout@v4
100+
101+
- name: Download the PostgreSQL 18 .deb
102+
uses: actions/download-artifact@v4
103+
with:
104+
name: deb-pg18
105+
path: docker-deb
106+
107+
- name: Compute image tags
108+
id: meta
109+
run: |
110+
repo="ghcr.io/${GITHUB_REPOSITORY_OWNER,,}/pg_table_range"
111+
tags="${repo}:18"
112+
push=false
113+
if [ "${GITHUB_REF_TYPE}" = "tag" ]; then
114+
tags="${tags},${repo}:${GITHUB_REF_NAME},${repo}:latest"
115+
push=true
116+
fi
117+
echo "tags=${tags}" >> "$GITHUB_OUTPUT"
118+
echo "push=${push}" >> "$GITHUB_OUTPUT"
119+
120+
- name: Set up Buildx
121+
uses: docker/setup-buildx-action@v3
122+
123+
- name: Log in to GHCR
124+
if: steps.meta.outputs.push == 'true'
125+
uses: docker/login-action@v3
126+
with:
127+
registry: ghcr.io
128+
username: ${{ github.actor }}
129+
password: ${{ secrets.GITHUB_TOKEN }}
130+
131+
- name: Build and push image
132+
uses: docker/build-push-action@v6
133+
with:
134+
context: .
135+
file: packaging/Dockerfile
136+
push: ${{ steps.meta.outputs.push }}
137+
tags: ${{ steps.meta.outputs.tags }}
138+
139+
github-release:
140+
name: GitHub Release
141+
needs: debian
142+
if: github.ref_type == 'tag'
143+
runs-on: ubuntu-latest
144+
permissions:
145+
contents: write
146+
steps:
147+
- name: Download all .deb artifacts
148+
uses: actions/download-artifact@v4
149+
with:
150+
pattern: deb-pg*
151+
path: debs
152+
merge-multiple: true
153+
154+
- name: Create / update the GitHub Release
155+
uses: softprops/action-gh-release@v2
156+
with:
157+
files: debs/*.deb
158+
generate_release_notes: true
159+
160+
pgxn:
161+
name: Release on PGXN
162+
needs: debian
163+
if: github.ref_type == 'tag'
20164
runs-on: ubuntu-latest
21165
container: pgxn/pgxn-tools
22166
env:
23167
PGXN_USERNAME: ${{ secrets.PGXN_USERNAME }}
24168
PGXN_PASSWORD: ${{ secrets.PGXN_PASSWORD }}
25169
steps:
26-
- name: Check out the release tag
27-
uses: actions/checkout@v4
170+
- uses: actions/checkout@v4
28171

29172
- name: Verify META.json version matches the tag
30173
run: |

Makefile

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Thin wrapper so `make` / `make install` build this pgrx (Rust) extension via cargo-pgrx,
2+
# for compatibility with PGXS-style tooling (e.g. `pgxn install`). This is NOT a real PGXS
3+
# build — it shells out to cargo-pgrx, which must be installed:
4+
#
5+
# cargo install cargo-pgrx --version 0.18.1 --locked
6+
#
7+
# Usage:
8+
# make # build for the PostgreSQL PG_CONFIG finds
9+
# make install # install into that PostgreSQL (often sudo)
10+
# make PG_CONFIG=/usr/lib/postgresql/18/bin/pg_config install
11+
#
12+
# The PostgreSQL major version is detected from PG_CONFIG and mapped to the matching pgrx
13+
# feature (pg16/pg17/pg18).
14+
15+
PG_CONFIG ?= pg_config
16+
PG_MAJOR := $(shell $(PG_CONFIG) --version | sed -E 's/[^0-9]*([0-9]+).*/\1/')
17+
CARGO ?= cargo
18+
PGRX_HOME ?= $(HOME)/.pgrx
19+
PGRX_ARGS := --no-default-features --features pg$(PG_MAJOR) --pg-config $(PG_CONFIG)
20+
21+
.PHONY: all build install clean pgrx-config
22+
23+
all: build
24+
25+
build: pgrx-config
26+
$(CARGO) pgrx package $(PGRX_ARGS)
27+
28+
install: pgrx-config
29+
$(CARGO) pgrx install --release $(PGRX_ARGS)
30+
31+
clean:
32+
$(CARGO) clean
33+
34+
# cargo-pgrx needs a config.toml that knows this PostgreSQL. Write a minimal one if absent
35+
# (avoids `cargo pgrx init`, which would run initdb to create a throwaway dev cluster). If
36+
# you already manage ~/.pgrx, register this server yourself: cargo pgrx init --pg$(PG_MAJOR) $(PG_CONFIG)
37+
pgrx-config:
38+
@mkdir -p "$(PGRX_HOME)"
39+
@if [ ! -f "$(PGRX_HOME)/config.toml" ]; then \
40+
printf '[configs]\npg%s = "%s"\n' "$(PG_MAJOR)" "$$(command -v $(PG_CONFIG))" > "$(PGRX_HOME)/config.toml"; \
41+
echo "wrote $(PGRX_HOME)/config.toml for PostgreSQL $(PG_MAJOR)"; \
42+
fi

README.md

Lines changed: 52 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -31,32 +31,52 @@ without it.
3131
3232
## Installation
3333
34-
This is a [pgrx](https://github.com/pgcentralfoundation/pgrx) (Rust) extension, so it is
35-
built and installed with `cargo pgrx` rather than a PGXS `make`. You need a Rust toolchain
36-
and `cargo-pgrx` matching the pgrx version this release pins (currently **0.18.1**):
34+
This is a [pgrx](https://github.com/pgcentralfoundation/pgrx) (Rust) extension. Supported:
35+
PostgreSQL **16, 17, 18**. Pick whichever route fits; after installing, run
36+
`CREATE EXTENSION pg_table_range;` in each database that should use it.
37+
38+
### Docker (PostgreSQL 18 + PostGIS, batteries included)
3739
3840
```sh
39-
cargo install cargo-pgrx --version 0.18.1 --locked
41+
docker run -e POSTGRES_PASSWORD=secret ghcr.io/bitner/pg_table_range:18
42+
```
43+
44+
The image extends the official `postgres:18` with PostGIS and pg_table_range, and enables
45+
both extensions in the default database on first start. Tags: `:18`, `:vX.Y.Z`, `:latest`.
46+
47+
### Debian / Ubuntu package (no Rust toolchain needed)
4048

41-
# In a checkout of the source (from git or a PGXN download), install into the PostgreSQL
42-
# that `pg_config` points at. Match the feature flag to your server's major version:
43-
cargo pgrx install --release # PostgreSQL 18 (default)
44-
cargo pgrx install --release --no-default-features --features pg17 # PostgreSQL 17
45-
cargo pgrx install --release --no-default-features --features pg16 # PostgreSQL 16
49+
Prebuilt `.deb`s for PostgreSQL 16/17/18 (Debian **bookworm**, for the
50+
[apt.postgresql.org / PGDG](https://wiki.postgresql.org/wiki/Apt) packages) are attached to
51+
each [GitHub release](https://github.com/bitner/pg_table_range/releases):
52+
53+
```sh
54+
sudo apt install ./postgresql-18-pg-table-range_<version>-1_amd64.deb
4655
```
4756

48-
Use `--pg-config /path/to/pg_config` to target a specific PostgreSQL install. Then, in
49-
each database that should use it:
57+
### From source with cargo-pgrx
5058

51-
```sql
52-
CREATE EXTENSION pg_table_range;
59+
Requires a Rust toolchain and `cargo-pgrx` matching the pinned pgrx version (**0.18.1**).
60+
The bundled `Makefile` wraps cargo-pgrx (it writes a minimal pgrx `config.toml` for you, so
61+
no `cargo pgrx init`/`initdb` is needed):
62+
63+
```sh
64+
cargo install cargo-pgrx --version 0.18.1 --locked
65+
make install PG_CONFIG=/usr/lib/postgresql/18/bin/pg_config # major auto-detected from pg_config
5366
```
5467

55-
Supported: PostgreSQL 16, 17, and 18.
68+
Or drive cargo-pgrx directly — register your PostgreSQL once, then install (use
69+
`--no-default-features --features pg16|pg17` for those majors):
5670

57-
The distribution is also published on [PGXN](https://pgxn.org/dist/pg_table_range/). Note
58-
that `pgxn install` (which expects a PGXS Makefile) does **not** apply here; use
59-
`pgxn download pg_table_range`, unzip, and run `cargo pgrx install` as above.
71+
```sh
72+
cargo pgrx init --pg18 /usr/lib/postgresql/18/bin/pg_config
73+
cargo pgrx install --release
74+
```
75+
76+
The distribution is also on [PGXN](https://pgxn.org/dist/pg_table_range/): `pgxn download
77+
pg_table_range`, unzip, then `make install` (or the cargo-pgrx commands above). `pgxn
78+
install` runs the bundled `Makefile`, so it works too — but still needs cargo-pgrx present,
79+
since this is a Rust extension rather than a C/PGXS one.
6080

6181
## Quick Start
6282

@@ -316,12 +336,21 @@ range-type tests, which exercise the same code path.
316336

317337
## Releasing (maintainers)
318338

319-
The distribution is published to [PGXN](https://pgxn.org). Releases are automated by
320-
`.github/workflows/release.yml`, which runs on any `v*` tag and uses the
321-
[`pgxn/pgxn-tools`](https://github.com/pgxn/pgxn-tools) image to validate `META.json`,
322-
bundle the source, and upload it. One-time setup: add two repository secrets,
323-
`PGXN_USERNAME` and `PGXN_PASSWORD`, from a [PGXN Manager](https://manager.pgxn.org)
324-
account.
339+
`.github/workflows/release.yml` runs on any `v*` tag and produces everything:
340+
341+
| Job | Output |
342+
|-----|--------|
343+
| `debian` | `.deb` packages for PostgreSQL 16/17/18 (Debian bookworm / PGDG), built in a `debian:bookworm` container with `packaging/build-deb.sh` |
344+
| `docker` | `ghcr.io/<owner>/pg_table_range:18`, `:vX.Y.Z`, `:latest` (PostgreSQL 18 + PostGIS + the extension) |
345+
| `github-release` | attaches the `.deb`s to the GitHub Release |
346+
| `pgxn` | validates `META.json`, bundles the source, and uploads it to [PGXN](https://pgxn.org) |
347+
348+
`workflow_dispatch` runs `debian` + `docker` as a **dry run** (no pushes), to validate
349+
packaging without cutting a release.
350+
351+
One-time setup: add two repository secrets, `PGXN_USERNAME` and `PGXN_PASSWORD`, from a
352+
[PGXN Manager](https://manager.pgxn.org) account. (The Docker push uses the built-in
353+
`GITHUB_TOKEN`; ensure the repo allows GitHub Actions to publish packages.)
325354

326355
To cut a release:
327356

packaging/Dockerfile

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# PostgreSQL 18 with PostGIS and pg_table_range, built on the official postgres image.
2+
#
3+
# The pg18 .deb (built for Debian bookworm, so it is glibc-compatible with this base) is
4+
# expected in ./docker-deb — CI downloads it from the Debian-package build job. To build
5+
# locally: cargo pgrx package --features pg18 --pg-config <pgdg-18> && packaging/build-deb.sh 18
6+
# && mkdir -p docker-deb && cp target/deb/postgresql-18-*.deb docker-deb/
7+
# && docker build -f packaging/Dockerfile -t pg_table_range:18 .
8+
FROM postgres:18-bookworm
9+
10+
COPY docker-deb/*.deb /tmp/
11+
COPY packaging/initdb-extensions.sh /docker-entrypoint-initdb.d/10-extensions.sh
12+
13+
RUN set -eux; \
14+
apt-get update; \
15+
apt-get install -y --no-install-recommends postgresql-18-postgis-3; \
16+
apt-get install -y --no-install-recommends /tmp/postgresql-18-pg-table-range_*.deb; \
17+
rm -rf /var/lib/apt/lists/* /tmp/*.deb
18+
19+
LABEL org.opencontainers.image.source="https://github.com/bitner/pg_table_range" \
20+
org.opencontainers.image.description="PostgreSQL 18 + PostGIS + pg_table_range" \
21+
org.opencontainers.image.licenses="MIT"

packaging/build-deb.sh

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#!/usr/bin/env bash
2+
# Build a PGDG-style Debian package from a `cargo pgrx package` tree.
3+
#
4+
# packaging/build-deb.sh <pg_major> # e.g. packaging/build-deb.sh 18
5+
#
6+
# Expects `cargo pgrx package --features pg<major> --pg-config <pgdg pg_config>` to have
7+
# already produced target/release/pg_table_range-pg<major>/usr/... . Emits
8+
# target/deb/postgresql-<major>-pg-table-range_<version>-1_<arch>.deb, which installs the
9+
# .so and control/SQL files into the apt.postgresql.org (PGDG) PostgreSQL of that major.
10+
set -euo pipefail
11+
12+
MAJ="${1:?usage: build-deb.sh <pg_major>}"
13+
VER="$(sed -n 's/^version *= *"\([^"]*\)".*/\1/p' Cargo.toml | head -1)"
14+
ARCH="$(dpkg --print-architecture)"
15+
TREE="target/release/pg_table_range-pg${MAJ}"
16+
PKGDIR="target/deb/postgresql-${MAJ}-pg-table-range"
17+
DEB="target/deb/postgresql-${MAJ}-pg-table-range_${VER}-1_${ARCH}.deb"
18+
19+
[ -d "$TREE/usr" ] || { echo "missing $TREE/usr — run 'cargo pgrx package' first" >&2; exit 1; }
20+
21+
rm -rf "$PKGDIR"
22+
mkdir -p "$PKGDIR/DEBIAN"
23+
cp -r "$TREE/usr" "$PKGDIR/"
24+
25+
cat > "$PKGDIR/DEBIAN/control" <<EOF
26+
Package: postgresql-${MAJ}-pg-table-range
27+
Version: ${VER}-1
28+
Architecture: ${ARCH}
29+
Maintainer: David Bitner <bitner@dbspatial.com>
30+
Depends: postgresql-${MAJ}
31+
Section: database
32+
Priority: optional
33+
Homepage: https://github.com/bitner/pg_table_range
34+
Description: Planning-time partition pruning by per-partition data ranges
35+
Prunes partitions at planning time from a compact per-partition summary of
36+
each column's data (btree min/max, or a covering extent for range types and
37+
PostGIS geometry), including non-key columns. Built with pgrx for
38+
PostgreSQL ${MAJ}.
39+
EOF
40+
41+
mkdir -p target/deb
42+
dpkg-deb --build --root-owner-group "$PKGDIR" "$DEB"
43+
echo "built $DEB"

0 commit comments

Comments
 (0)