chore: bump version to 1.2.0-dev (+ automate version bumps)#341
chore: bump version to 1.2.0-dev (+ automate version bumps)#341
Conversation
The DO $$ RAISE INFO 'pg_textsearch vX.Y.Z' $$; block in the main SQL file and the matching block in the upgrade SQL produce a single INFO line that every regression test absorbs. That meant 62 expected output files needed regeneration on every release. None of the nearby extensions (pgvector, pgvectorscale, pg_search, timescaledb) emit a load banner; pg_textsearch was the outlier. The library-version mismatch RAISE EXCEPTION (the actual correctness check) stays. Version remains discoverable via SHOW pg_textsearch.library_version, \\dx pg_textsearch, and pg_extension.extversion. Also add scripts/bump-version.sh, which automates the text substitutions across the SQL files, Makefile, control file, mod.c, README, CLAUDE.md, test scripts, and msmarco benchmark check. Auto- detects dev-bump vs release mode from the version pattern. Refuses to run on a dirty tree; greps for stragglers after substituting.
Collapse the per-file substitution checklist (the script does it now) and replace with a step-driven sequence. Add a section on auditing the upgrade SQL script — that's the one piece the script can't automate, and the most likely place to ship a regression. Keep the upgrade compatibility matrix, on-disk format versions, and troubleshooting sections as-is.
Generated by scripts/bump-version.sh 1.1.0 1.2.0-dev. Renames the base SQL file 1.1.0 → 1.2.0-dev, creates the upgrade-script stub 1.1.0--1.2.0-dev.sql (library-version check only; contributors fill in feature DDL as work lands), and updates default_version, PG_MODULE_MAGIC_EXT, the Makefile DATA list, README, CLAUDE.md, test scripts, and the msmarco benchmark version check.
The check `IF lib_ver != 'X.Y.Z' THEN RAISE EXCEPTION` in sql/pg_textsearch--1.0.0--1.1.0.sql breaks upgrade chains once a newer dev version is the default. Walking 1.0.0 → 1.1.0 → 1.2.0-dev runs the 1.0.0--1.1.0.sql script with the 1.2.0-dev binary loaded, and the equality check fires. Upgrade scripts must accept any loaded library version because they may run as intermediate steps in a chain that ends at default_version, not at the version named in the upgrade filename. Drop the equality check in upgrade scripts; keep the "library is loaded" check as a sanity guard against missing shared_preload_libraries. The version-equality check stays in the main install file (which only runs on CREATE EXTENSION, not on UPDATE). Updates the script's stub template too so future bumps generate upgrade scripts with the relaxed check.
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
| 🚀 **Status**: v1.2.0-dev - Production ready. | ||
|
|
||
|  | ||
|  |
There was a problem hiding this comment.
🔴 After running scripts/bump-version.sh 1.1.0 1.2.0-dev, README.md line 21 references images/tapir_and_friends_v1.2.0-dev.png, but that file does not exist (only tapir_and_friends_v1.1.0.png is in images/). The dogfood commit in this PR therefore ships a broken image link in the rendered README on GitHub for the entire dev cycle, and the underlying script flaw will recur on every future dev bump. Fix: either skip the image-filename substitution in dev mode (treat it like the release banner, which the script intentionally leaves to the human) or add a banner reminder to the dev-mode next-steps output.
Extended reasoning...
What's wrong
The bump script unconditionally rewrites every literal occurrence of OLD to NEW inside README.md via the common_files loop in scripts/bump-version.sh:
common_files=(
pg_textsearch.control
src/mod.c
README.md
...
)
for f in "${common_files[@]}"; do
if [[ -f $f ]]; then
perl -i -pe "s/\Q$OLD\E/$NEW/g" "$f"
fi
doneIn release mode that's correct — the banner image is renamed in the same release, and the next-steps output reminds the human to rename images/tapir_and_friends_v$OLD.png to images/tapir_and_friends_v$NEW.png. In dev mode, however, no banner image is renamed (the script does not produce dev-cycle images), and the dev-mode next-steps block at lines ~197-202 only says:
Next steps (dev bump):
1. Review the generated stub $NEW_UPGRADE.
2. Open a PR titled "chore: bump version to $NEW".
There is no reminder about the dangling image reference, so the rewritten line ships unnoticed.
Step-by-step proof
ls images/in this PR's tree shows onlypageviz.jpgandtapir_and_friends_v1.1.0.png— there is notapir_and_friends_v1.2.0-dev.png.README.mdline 21 in this PR reads:.- The substitution that produced line 21 is the literal
OLD → NEWrewrite insideREADME.md(Makefile, control file, mod.c, etc. all get the same treatment). - The straggler check at the end of the script does not catch this: it greps for the literal
$OLD(1.1.0), but the rewritten path no longer contains1.1.0— it contains1.2.0-dev. The check is for old references the script missed, not for new references the script created pointing at non-existent files. - GitHub renders
README.md, so the markdown image will resolve to a 404 on github.com/timescale/pg_textsearch for the entire 1.2.0 dev cycle, until either the v1.2.0 release lands atapir_and_friends_v1.2.0-dev.pngis dropped in by hand.
Why the PR description doesn't cover it
The PR description says: "scripts/bump-version.sh reminds you of both [the banner image and the upgrade-tests matrix] in its next-steps output." That claim is true for the release branch (lines ~184-196 of the script include both reminders). It is not true for the dev branch (lines ~197-202), which mentions neither. So the human running the dev bump has no in-script signal to investigate the now-broken README link.
Impact
Cosmetic but visible: the public README on GitHub renders with a broken image until v1.2.0 ships. Not a correctness bug for the extension itself.
Suggested fix
Two reasonable options, both small:
- Skip the image-line substitution in dev mode. Replace the image reference rewrite with a targeted no-op for dev bumps so the README continues to point at the last released banner (
v1.1.0.png) until release time. This mirrors what the script already does for the actual image file (it never renames or creates one in dev mode). - Add a dev-mode next-step reminder. Append to the dev-mode
cat <<EOFblock something like: "3. Drop a banner image atimages/tapir_and_friends_v$NEW.png(the README now references it), or revert the README image-line rewrite by hand." This keeps the substitution behavior but surfaces the consequence.
Option 1 is cleaner — it keeps the dev tree internally consistent without relying on humans reading next-steps output.
| elif [[ $MODE == release ]]; then | ||
| # Find and rename the upgrade file `sql/pg_textsearch--PREV--OLD.sql`. | ||
| # Globbing here uses bash's nullglob so we can count safely. | ||
| shopt -s nullglob | ||
| upgrades=( sql/pg_textsearch--*--"$OLD".sql ) | ||
| shopt -u nullglob | ||
| if [[ ${#upgrades[@]} -ne 1 ]]; then | ||
| echo "Error: expected exactly one sql/pg_textsearch--*--$OLD.sql," \ | ||
| "found ${#upgrades[@]}." >&2 | ||
| exit 2 | ||
| fi | ||
| SRC_UPGRADE=${upgrades[0]} | ||
| DST_UPGRADE=${SRC_UPGRADE//$OLD.sql/$NEW.sql} | ||
|
|
||
| git mv "$SRC_MAIN" "$DST_MAIN" | ||
| git mv "$SRC_UPGRADE" "$DST_UPGRADE" | ||
| fi |
There was a problem hiding this comment.
🔴 Release mode of bump-version.sh skips substitutions that dev mode performs, breaking the next release. When run as ./scripts/bump-version.sh X.Y.Z-dev X.Y.Z, the elif [[ $MODE == release ]] block (lines 116–132) only does git mv on the two SQL files. It skips three things dev mode handles: (1) the perl -i -pe "s/\Q$OLD\E/$NEW/g" "$DST_MAIN" body substitution (so the renamed pg_textsearch--X.Y.Z.sql still contains IF lib_ver <> '\''X.Y.Z-dev'\'' and the version comment, causing CREATE EXTENSION to fail with library version mismatch: loaded=X.Y.Z, expected=X.Y.Z-dev once pg_textsearch.control and src/mod.c are bumped by the common_files loop); (2) the same substitution on $DST_UPGRADE (silently masked because the straggler check excludes sql/pg_textsearch--*--*.sql); and (3) the two Makefile-rewriting perl invocations (lines 109–114), which leaves DATA pointing at the now-nonexistent -dev filenames so make install fails. The dogfooded commit only exercised dev mode, so the first real release (e.g. 1.2.0-dev → 1.2.0) will hit this. Fix: move the substitutions out of the if MODE == dev block so they run unconditionally, or duplicate them into the release branch (and add Makefile to common_files).
Extended reasoning...
What the bug is
scripts/bump-version.sh has two mode branches: dev (post-release bump like 1.1.0 → 1.2.0-dev) and release (1.2.0-dev → 1.2.0). Dev mode does three things release mode skips, even though both modes need them:
| Action | Dev branch | Release branch | In common_files loop? |
|---|---|---|---|
| Rename main SQL file | line 82 | line 130 | n/a |
| Substitute body of $DST_MAIN | line 83 (perl -i -pe ...) |
missing | no |
| Rename upgrade SQL file | n/a (creates new stub) | line 131 | n/a |
| Substitute body of $DST_UPGRADE | n/a | missing | no |
| Rewrite Makefile DATA list | lines 109–114 | missing | no |
The common_files loop (lines 137–152) covers pg_textsearch.control, src/mod.c, README, CLAUDE.md, three test scripts, and the msmarco benchmark — but neither the renamed SQL files nor the Makefile.
Step-by-step proof: ./scripts/bump-version.sh 1.2.0-dev 1.2.0
Starting state (current PR):
pg_textsearch.controlsaysdefault_version = '1.2.0-dev'src/mod.csays.version = "1.2.0-dev"sql/pg_textsearch--1.2.0-dev.sqlbody containsIF lib_ver OPERATOR(pg_catalog.<>) '1.2.0-dev' THEN ... 'expected=%', ..., '1.2.0-dev'MakefileDATA containssql/pg_textsearch--1.2.0-dev.sqlandsql/pg_textsearch--1.1.0--1.2.0-dev.sql
Run ./scripts/bump-version.sh 1.2.0-dev 1.2.0:
- Mode detected as
release(line 39). git mv sql/pg_textsearch--1.2.0-dev.sql sql/pg_textsearch--1.2.0.sql(line 130). Noperlsubstitution runs on the body.git mv sql/pg_textsearch--1.1.0--1.2.0-dev.sql sql/pg_textsearch--1.1.0--1.2.0.sql(line 131). Noperlsubstitution runs on the body.common_filesloop rewritespg_textsearch.control→default_version = '1.2.0'andsrc/mod.c→.version = "1.2.0".- Makefile is never touched — neither the dev branch nor
common_filesincludes it in release mode. - Straggler check at line 160 runs
git grep -l --fixed-strings '1.2.0-dev'. The pathspec':!sql/pg_textsearch--*--*.sql'excludes the upgrade file but not the main install file or the Makefile, so warnings appear forsql/pg_textsearch--1.2.0.sqlandMakefile. The script exits 0; the warnings are easily missed.
End state:
sql/pg_textsearch--1.2.0.sqlstill has-- pg_textsearch extension version 1.2.0-devand the'1.2.0-dev'literals in the version-equality block.sql/pg_textsearch--1.1.0--1.2.0.sqlstill has-- Upgrade from 1.1.0 to 1.2.0-dev(functionally harmless, but inconsistent).MakefileDATA still referencessql/pg_textsearch--1.2.0-dev.sqlandsql/pg_textsearch--1.1.0--1.2.0-dev.sql— files that no longer exist.
What this breaks
make install fails because PGXS reads the DATA list and tries to install files that no longer exist after the renames.
If a human catches the Makefile warning and fixes it by hand but doesn't notice the SQL warning, they get a compiling extension that fails at runtime: CREATE EXTENSION pg_textsearch raises pg_textsearch library version mismatch: loaded=1.2.0, expected=1.2.0-dev because mod.c reports 1.2.0 (substituted) while the install file's version-equality check still demands 1.2.0-dev (not substituted).
Why existing safeguards don't catch it
The straggler check at line 160 partially catches this:
Makefileis not in the exclusion list, so the user sees a warning.sql/pg_textsearch--1.2.0.sqlis not matched by:!sql/pg_textsearch--*--*.sql(only one--), so this warns too.- But
sql/pg_textsearch--1.1.0--1.2.0.sqlis matched by that exclusion (two--), so its stale-- Upgrade from 1.1.0 to 1.2.0-devcomment is silently kept.
The straggler check is a soft warning; the script's exit status is 0, the next-steps output makes no mention of fixing the SQL or Makefile, and RELEASING.md (lines 31–35) tells users "This renames the SQL files and updates every version reference across the tree." The dogfood test in commit 3 exercises only dev mode, so this regression has never been caught by CI or by the PR's own integration test.
How to fix
Either (a) duplicate dev mode's substitutions into the release branch, or (b) move them out of the mode-specific block. Option (b) is cleaner:
# After the mode-specific block (renames), before common_files:
perl -i -pe "s/\Q$OLD\E/$NEW/g" "$DST_MAIN"
[[ -n ${DST_UPGRADE:-} ]] && perl -i -pe "s/\Q$OLD\E/$NEW/g" "$DST_UPGRADE"For the Makefile, the simplest fix is adding it to common_files. The dev-mode-specific Makefile substitution at line 109 (pg_textsearch--OLD.sql → pg_textsearch--NEW.sql) is exactly the literal substitution common_files already does, and the second invocation (lines 110–114) only matters for dev mode (it appends a new PREV--NEW.sql line). Adding Makefile to common_files correctly handles release mode (just renames OLD.sql → NEW.sql for both DATA entries) and is a no-op redundant write in dev mode. If preserving the dev-only append is desired, keep that single perl invocation in the dev branch and add Makefile to common_files for the renames.
Summary
Post-1.1.0 dev bump, plus tooling so future bumps are mechanical.
Three commits:
Drop CREATE EXTENSION load banner; add bump-version.sh — Remove
the
RAISE INFO 'pg_textsearch vX.Y.Z'block that fired on every`CREATE EXTENSION`. It produced one INFO line that 62 expected
outputs had to absorb, so every release regenerated 62 files for
the same one-line diff. Survey of nearby extensions (pgvector,
pgvectorscale, pg_search, timescaledb) and standard contribs
(pg_stat_statements, hstore, pg_trgm, pgcrypto, postgis) confirms
none emit a load banner; pg_textsearch was the outlier. The
library-version mismatch `RAISE EXCEPTION` (the actual
correctness check) stays. Version remains discoverable via
`SHOW pg_textsearch.library_version`, `\dx`, and
`pg_extension.extversion`.
Also adds `scripts/bump-version.sh`, which automates the text
substitutions across SQL files, Makefile DATA, control file,
mod.c, README, CLAUDE.md, test scripts, and the msmarco benchmark
version check. Auto-detects dev-bump vs release mode from the
version pattern; refuses to run on a dirty tree; reports
stragglers after substituting; prints next-steps for the human.
docs: simplify RELEASING.md around bump-version.sh — Collapse
the per-file substitution checklist (the script does it now) and
replace with a step-driven sequence. Add a section on auditing
the upgrade SQL script — the one piece the script can't automate
and the most likely place to ship a regression.
chore: bump version to 1.2.0-dev — Generated by running
`scripts/bump-version.sh 1.1.0 1.2.0-dev` (the dogfood proves
the script works). Renames the base SQL file, creates the
upgrade-script stub, updates default_version /
PG_MODULE_MAGIC_EXT / Makefile / README / CLAUDE.md / test
scripts / msmarco benchmark.
Testing
Follow-up for the next release
Replace the banner image and add 1.1.0 to the upgrade-tests matrix
when cutting v1.2.0; `scripts/bump-version.sh` reminds you of both
in its next-steps output.