Contents
Releasing cat_tools
cat_tools builds on pgxntool (https://github.com/Postgres-Extensions/pgxntool);
the release machinery (make tag, make dist) lives in pgxntool/base.mk. These
steps cut a new release.
1. Safety check: verify committed version files haven’t drifted
Before anything else, confirm every committed versioned install script still matches what that version actually shipped.
- [ ] For each committed versioned install script —
sql/cat_tools--<version>.sql.in(0.2.0 onward) orsql/cat_tools--<version>.sql(the historical pre-0.2.0 files0.1.0/0.1.3/0.1.4/0.1.5, which have no.sql.insource and are tracked directly; see CLAUDE.md “SQL file conventions”) — find its last-touching commit:git log -1 --format='%H %ad' -- sql/cat_tools--<version>.sql.in(or.sql). - [ ] Confirm that commit is no later than when that version was actually tagged.
cat_tools tags every release, unprefixed (e.g.
0.2.2,0.2.3— see step 6’smake tag), so compare directly:git log -1 --format='%H %ad' <version>. (No tags exist before0.2.2—0.1.x,0.2.0, and0.2.1predate cat_tools' tagging convention — so this direct comparison is only available from0.2.2onward.) - [ ] A version file touched by a commit LATER than its own release’s tag is a red
flag — it likely means
default_versionincat_tools.controlwas left pointing at that real (non-stable) version after release, and a later source edit tosql/cat_tools.sql.insilently regenerated — and corrupted — the committed file viasql.mk’s current-version rule ($(EXTENSION__CURRENT_VERSION__FILES:.sql=.sql.in): sql/cat_tools.sql.in cat_tools.control, whichcps the base source over it). Investigate before proceeding. - [ ] Known exception, not necessarily a corruption: a version file whose last-touching commit is much later than its version’s real release can also mean the file was legitimately backfilled or reformatted after the fact (e.g. once new build tooling started requiring something that wasn’t tracked before). A late touch-date alone isn’t suspicious — only worry about a file whose content actually differs from what shipped.
2. Pre-release checks
- [ ] Open issues/PRs for this release reviewed, merged or deferred.
- [ ] CI green on all supported PostgreSQL versions (the
all-checks-passedjob on master). - [ ] Locally:
make verify-resultspasses. It depends on$(TEST_DEPS)directly, not ontestitself (deliberately — seebase.mk’s own comment on why:test’s early exit on a regression would otherwise abort the chain before verify-results got to inspect and report the diff), so it still runs the suite first, then gates on the results with a stricter pgtap-aware check.make testitself also returns non-zero on a regression as of pgxntool 2.3.0, butverify-resultsremains the stricter, documented gate.
3. Decide the version and what to track
- [ ] Pick the new version (semantic versioning).
- [ ] Minor change? Consider NOT committing the generated versioned install script.
If this release makes only fairly minor changes (unlikely to cross a PostgreSQL
supported-version boundary), decide whether to omit the generated
sql/cat_tools--<version>.sql.in— it has little update-test-coverage value and omitting it keeps the repo smaller (it is regenerated fromsql/cat_tools.sql.inat build time). The update script (sql/cat_tools--<prev>--<version>.sql.in) is ALWAYS committed. See CLAUDE.md “SQL file conventions”.
4. Update version + changelog
⚠️ CRITICAL — you are temporarily leaving the
stablepseudo-version. Master’sdefault_versionnormally sits at thestablepseudo-version so that source edits regeneratecat_tools--stable.sqland never a frozen released file. Stamping a real version here points the generated current-version file atcat_tools--<version>. The moment this release is merged you MUST flipdefault_versionback tostableon master (step 7). If you forget, the next source edit on master will regenerate — and corrupt — the just-released version’s install file.
sql/cat_tools--<version>.sql.inmust ALWAYS be tracked — that’s the entire point, keeping a real history of the extension across releases.stableis the ONE exception (its.sql.inis gitignored, not tracked) for the ONE reason thatstableitself is never actually released, so there’s no history to keep.
- [ ] Bump
default_versionincat_tools.control(bumped by hand). - [ ] Bump the version in
META.in.json— the source of truth isprovides.cat_tools.version(also update the top-levelversion);META.json,control.mk, andmeta.mk(which feedsPGXNVERSION) regenerate viamake. - [ ] Advance
release_statusinMETA.in.jsonas appropriate (unstable → testing → stable). - [ ] Add/finish the update script
sql/cat_tools--<prev>--<version>.sql.in; confirmALTER EXTENSION cat_tools UPDATEfrom the previous version reaches the new one, on multiple PG majors. - [ ] Stamp
HISTORY.asc: the topSTABLEsection accumulates user-facing changes as PRs land; at release, rename that header to the new version number.
5. Verify
- [ ]
make verify-resultsgreen (it runstestfirst, then gates on the results). - [ ] From a clean checkout (or
git archiveof the tag):make && make installregenerates and installs cleanly andCREATE EXTENSION cat_tools;reports the new version — confirms a PGXN consumer can build from the tracked sources alone. (This mirrors whatmake distships, since it archives the tag: committed files only, so any omitted generated install script is regenerated on the consumer’s side.)
6. Tag and distribute
⚠️ Pass
PGXN_REMOTE=<remote>to every target below if your clone’soriginis a personal fork (as it typically is for a maintainer working from a fork, with the canonical repo configured under some other remote name — checkgit remote -vrather than assuming it’s calledupstream). Without it,tag/rmtag/forcetag/distpush tooriginby default — silently tagging the fork instead ofPostgres-Extensions/cat_tools. This is exactly what happened when the 0.2.3 release tag was first cut and had to be re-pointed by hand; pgxntool 2.2.0 addedPGXN_REMOTEspecifically to fix this (https://github.com/Postgres-Extensions/pgxntool/issues/53).
- [ ] Commit the release changes; working tree must be clean —
make tagaborts with “Untracked changes!” on a dirty tree. - [ ]
make tag— creates a git tag named exactly the version, UNPREFIXED (e.g.0.2.3, matching the existing0.2.2tag; novprefix), taken fromPGXNVERSION, and pushes it to$(PGXN_REMOTE)(defaultorigin). It is idempotent when the tag already points at HEAD, and errors if the tag exists on a different commit. To move an existing tag usemake forcetag(=make rmtagthenmake tag);make rmtagdeletes the tag locally and on$(PGXN_REMOTE). - [ ]
make dist— depends ontag(and builds the HTML docs), thengit archives the tag into../cat_tools-<version>.zip(parent directory). Because it archives the tag, only committed files are included. If a.gitattributesexists it must be committed, ordistaborts (git archive only honorsexport-ignorefor committed files).make forcedist=forcetag+dist. - [ ] Upload the
../cat_tools-<version>.zipto PGXN (manual).
7. Return master to stable (CRITICAL — do not skip)
- [ ] As soon as the release is merged, flip
default_versionback to thestablepseudo-version on master (cat_tools.control+META.in.json), open a new topSTABLEsection inHISTORY.asc, and re-seed a freshsql/cat_tools--<this-release>--stable.sql.inupdate script for the next cycle. Leaving master stamped at the real version means the next source edit regenerates and corrupts the released version’s install file. The just-releasedsql/cat_tools--<version>.sql.instays tracked, permanently — nothing to clean up or remove there; see step 4’s note above.
The persistent
stablepseudo-version (a permanent version literally namedstable, with a livesql/cat_tools--<last-release>--stable.sql.inupdate script that every source fix targets) decouples fixes from version bumps. The machinery is built intosql.mk; it lands immediately after the 0.2.3 release, so 0.2.3 itself is the last release cut before the scheme exists — steps 4/7 above describe the flow from the next release onward.
Notes and caveats
- 0.2.3 catalog-view repair /
pg_upgradecaveat. Databases updated from 0.2.0/0.2.1 hold broken catalog views that fail binarypg_upgradeto PostgreSQL 12+ until the extension is updated to 0.2.3 (the update rebuilds them, dropping and recreating the publicpg_class_v/column/pg_class()objects withoutCASCADE). Surface this in the release notes when people may cross the PG 11 → 12+ boundary. See README.asc “Updating the extension” and https://github.com/Postgres-Extensions/cat_tools/pull/42.