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
13 changes: 7 additions & 6 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ https://github.com/Postgres-Extensions/pgxntool-test
Extension projects include pgxntool via git subtree:

```bash
git subtree add -P pgxntool --squash git@github.com:decibel/pgxntool.git release
git subtree add -P pgxntool --squash git@github.com:Postgres-Extensions/pgxntool.git release
pgxntool/setup.sh
```

Expand Down Expand Up @@ -151,7 +151,7 @@ project/
│ ├── deps.sql # Load extension and test dependencies
│ ├── sql/*.sql # Test SQL files
│ └── expected/*.out # Expected test outputs
└── doc/ # Optional docs (*.adoc, *.asciidoc)
└── doc/ # Optional docs (*.adoc, *.asciidoc, *.asc)
```

## Commands for Extension Developers (End Users)
Expand All @@ -160,7 +160,7 @@ These are the commands extension developers use (documented for context):

```bash
make # Build extension (generates versioned SQL, docs)
make test # Full test: testdeps → install → installcheck → show diffs
make test # Full test: testdeps → [test-build] → [install] → installcheck → safeguard checks → show diffs ([...] = when enabled; see Critical Testing Rules)
make results # Run tests and update expected output files
make html # Generate HTML from Asciidoc sources
make tag # Create git tag for current META.json version
Expand All @@ -176,9 +176,10 @@ make pgxntool-sync # Update to latest pgxntool via git subtree pull
### Critical Testing Rules

**NEVER use `make installcheck` directly**. Always use `make test` instead. The `make test` target ensures:
- Correct test dependency installation (`testdeps`, and `test-build` when enabled)
- Extension is installed before tests run (`install`)
- Correct test dependency installation (`testdeps`, and `test-build` when enabled); `testdeps`' default `pgtap` prerequisite auto-installs pgtap via `pgxn install`, a no-op when `PGXNTOOL_ENABLE_PGXN_INSTALL=no`
- Extension is filesystem-installed before tests run (`install`), unless `PGXNTOOL_ENABLE_FS_INSTALL=no`
- Test comparison via `installcheck`, with diffs shown on failure
- Safeguard checks that fail the run: the stale-expected-file check (orphaned or non-`.out` files in `test/expected/`, run after `pg_regress`), and, when `test/install` is in use, the check that every `test/install/*.sql` file sets `ON_ERROR_STOP`

Note: `make test` intentionally does *not* depend on `clean` — depending on `clean` caused problems with incremental/watch-based builds (see `base.mk`). If your tests need a clean build to pass, that's a sign of a missing dependency elsewhere, not something to fix by adding `clean` back.

Expand Down Expand Up @@ -223,7 +224,7 @@ When tests fail, examine the diff output carefully. The actual test output in `t

### Document Generation
- Auto-detects `asciidoctor` or `asciidoc`
- Generates HTML from `*.adoc` and `*.asciidoc` in `$(DOC_DIRS)`
- Generates HTML from `*.adoc`, `*.asciidoc` and `*.asc` in `$(DOC_DIRS)`
- HTML required for `make dist`, optional for `make install`
- Template-based rules via `ASCIIDOC_template`

Expand Down
46 changes: 29 additions & 17 deletions README.asc
Original file line number Diff line number Diff line change
Expand Up @@ -42,28 +42,33 @@ These are the make targets that are provided by base.mk
NOTE: all the targets normally provided by Postgres http://www.postgresql.org/docs/current/static/extend-pgxs.html[PGXS] still work. If you need to skip PGXS being included entirely (for advanced/non-standard setups), set `PGXNTOOL_NO_PGXS_INCLUDE` in your Makefile before `include pgxntool/base.mk`.

=== html
This will build any .html files that can be created. See <<_Document_Handling>>.
This will build any .html files that can be created. See <<_document_handling>>.

=== check-duplicate-docs
Warns if two `$(DOCS)` entries would install to the same filename, which would otherwise fail `make install`.

`all` depends on this, so it also runs as part of a plain `make`, `make install` and `make test`; you only need to invoke it directly to check without building anything.

=== test
Runs your extension's test suite: installs the extension and runs it through PGXS's `installcheck`, first pulling in anything you've hooked into <<_testdeps>> and, if enabled, sanity-checking your test SQL via <<_test_build>>.
Runs your extension's test suite: filesystem-installs the extension (unless `PGXNTOOL_ENABLE_FS_INSTALL=no`) and runs it through PGXS's `installcheck`, first pulling in anything you've hooked into <<_testdeps>> and, if enabled, sanity-checking your test SQL via <<_test_build>>.

`make test` also fails on two safeguard checks:

- The stale-expected-file check, run after `pg_regress` finishes: fails if `test/expected/` (or `test/build/expected/`) has a `.out` file with no matching `.sql`, or a file that isn't `.out`. See <<_pgxntool_enable_check_stale_expected>>.
- When <<_testinstall,test/install>> is in use, the `ON_ERROR_STOP` check: fails if any `test/install/*.sql` file neither includes `test/pgxntool/psql.sql` nor sets `ON_ERROR_STOP` itself. See <<_pgxntool_enable_test_install_error_stop_check>>.

`make test` runs `pg_regress` in up to two separate passes:

1. If <<_test_build,test-build>> is enabled, it runs first, in its own isolated pass over `test/build/*.sql`. If it fails, the second pass never happens — there's no point checking install/query behavior against a build that doesn't even come up cleanly.
2. The main pass follows: any <<_testinstall,test/install>> files, then your regular `test/sql/*.sql` files, together in a single `pg_regress` invocation (so state the install files create persists into the regular tests).

Within each pass, files run in alphabetical order by filename.
Within each pass, files run in byte-value (ASCII) order of their filenames.

Whether `test-build` runs is controlled by the `PGXNTOOL_ENABLE_TEST_BUILD` variable — see <<_test_build>> for what it does and how to turn it on/off.

NOTE: `test` intentionally does *not* depend on `clean` — that caused problems with incremental/watch-based builds. If your tests need a clean build to pass, that's a sign of a missing dependency elsewhere rather than something to fix by adding `clean` back.

NOTE: `test` exits non-zero (after printing `regression.diffs`) if any test fails. Previously it always exited 0 regardless of test results, silently masking failures from CI and other automation that relies on the exit code.
NOTE: `test` exits non-zero (after printing `regression.diffs`) if any test fails, so CI and other automation can rely on its exit code.

NOTE: While you can still run `make installcheck` or any other valid PGXS make target directly, it's recommended to use `make test` when using pgxntool. The `test` target ensures proper test isolation and correct dependency installation.

Expand Down Expand Up @@ -175,11 +180,10 @@ Runs setup files before the main test suite within the same `pg_regress` invocat
test/install/
├── *.sql # SQL setup files (checked in)
├── *.out # GENERATED, gitignored -- see WARNING below
├── .gitignore # Ignores pg_regress artifacts (*.out.diff)
└── schedule # GENERATED - auto-created by make
└── schedule # GENERATED, gitignored - auto-created by make
----

The `schedule` file is generated automatically and listed in `.gitignore`. Do not edit it. `*.out` is gitignored too, for the reason explained below — don't commit it.
The `schedule` file is generated automatically and listed in the top-level `.gitignore` that `setup.sh` installs. Do not edit it. `*.out` is gitignored too, for the reason explained below — don't commit it.

**Ordering:** Install files run in plain byte-value (ASCII) order of their filenames, guaranteed regardless of filesystem or locale. If one install file depends on another having already run, encode that dependency in the filenames themselves (e.g. `01_roles.sql` before `02_extension.sql`).

Expand Down Expand Up @@ -237,7 +241,7 @@ NOTE: This pattern isn't (yet) native to pgxntool — you wire up the mode selec
- https://github.com/Postgres-Extensions/pg_count_nulls/blob/9f088ac36f6345023bb5b3d20ad0e4aa6ade0d69/test/sql/extension_tests.sql[pg_count_nulls `test/sql/extension_tests.sql`] additionally demonstrates testing an extension installed into a non-default schema. It's a useful reference for that specific problem, but it also defines its assertions as plpgsql functions rather than plain pgTAP calls — a pattern that adds complexity of its own and isn't recommended as a model for U&U testing itself.

=== testdeps
This rule allows you to ensure certain actions have taken place before running tests. By default it has a single prerequisite, `pgtap`, which will attempt to install http://pgtap.org[pgtap] from PGXN. This depneds on having the pgxn client installed.
This rule allows you to ensure certain actions have taken place before running tests. By default it has a single prerequisite, `pgtap`, which installs http://pgtap.org[pgtap] from PGXN (via the pgxn client) if it isn't already filesystem-installed. `pgtap` is a no-op when `PGXNTOOL_ENABLE_PGXN_INSTALL=no`; see <<_pgxntool_enable_pgxn_install>>.

You can add any other dependencies you want by simply adding another `testdeps` rule. For example:

Expand Down Expand Up @@ -293,7 +297,7 @@ make PGXNTOOL_ENABLE_VERIFY_RESULTS=no results
----

=== tag
`make tag` will create a git tag for the current version of your extension, as determined by the META.json file (generated from `META.in.json` — see <<_pgxn_distributions_vs_extensions>>), and push it to `origin`. The reason to do this is so you can always refer to the exact code that went into a released version. For where `tag`, `dist`, and `post-tag-version-bump` fit in a full release, see link:releasing-with-pgxntool.md[releasing-with-pgxntool.md].
`make tag` will create a git tag for the current version of your extension, as determined by the META.json file (generated from `META.in.json` — see <<_pgxn_distributions_vs_extensions>>), and push it to `$(PGXN_REMOTE)` (`origin` by default; see <<_pgxn_remote>>). The reason to do this is so you can always refer to the exact code that went into a released version. For where `tag`, `dist`, and `post-tag-version-bump` fit in a full release, see link:releasing-with-pgxntool.md[releasing-with-pgxntool.md].

If a tag for the current version already exists and points at your current commit, `make tag` does nothing — this makes it safe for other targets (like `dist`) to depend on `tag` without worrying about re-running it. If the existing tag points at a *different* commit — meaning you likely forgot to bump the version — you'll get an error. If you're certain you want to over-write the tag, you can do `make forcetag`, which removes the existing tag (via `make rmtag`) and creates a new one.

Expand Down Expand Up @@ -329,12 +333,18 @@ TIP: The actual work is done by `pgxntool/pgxntool-sync.sh`, so you can run it d

TIP: `pgxntool-sync.sh` itself delegates the 3-way merge of `setup.sh`-copied files to `pgxntool/update-setup-files.sh <old-pgxntool-commit>`, which you can also run directly -- for example, to redo or debug just the merge step without pulling again. `<old-pgxntool-commit>` is the pgxntool subtree commit that was current *before* the sync you want to re-merge.

TIP: There is also a `pgxntool-sync-%` rule if you need to do more advanced things. `make pgxntool-sync-<name>` pulls from the `<repo> <ref>` defined by the `pgxntool-sync-<name>` make variable.
TIP: There is also a `pgxntool-sync-%` rule if you need to do more advanced things. `make pgxntool-sync-<name>` pulls from the `<repo> <ref>` defined by the `pgxntool-sync-<name>` make variable. Three are built in:

`pgxntool-sync-master`:: `https://github.com/Postgres-Extensions/pgxntool.git master` -- the unreleased development branch.
`pgxntool-sync-local`:: `../pgxntool release` -- the `release` branch of a sibling `../pgxntool` checkout.
`pgxntool-sync-local-master`:: `../pgxntool master` -- the `master` branch of that sibling checkout.

CAUTION: Syncing from anything other than a release can add unwanted history to your repo and make later merges harder to resolve.

=== pgxntool-version
`make pgxntool-version` prints the version of the embedded pgxntool copy, read from the first line of `pgxntool/HISTORY.asc`. That line is "STABLE" instead of a version number if this copy was synced from an unreleased commit rather than a tagged release.

TIP: The actual work is done by `pgxntool/bin/version`, so you can run it directly (`pgxntool/bin/version`) if you'd rather not go through `make`.
TIP: The actual work is done by `pgxntool/bin/version`, so you can run it directly (`pgxntool/bin/version`) if you'd rather not go through `make`. It optionally takes a `<history-file>` argument to read instead of `pgxntool/HISTORY.asc`. It exits non-zero if that file is missing, empty, or its first line is neither `STABLE` nor an `X.Y.Z` version.

=== list
`make list` prints every make target defined in your project — including ones provided by PGXS and pgxntool, not just ones you wrote — one per line. Useful for discovering what's available without reading through the Makefile.
Expand All @@ -357,12 +367,14 @@ Generates pg_tle (Trusted Language Extensions) registration SQL files for deploy

`make pgtle` generates SQL files in `pg_tle/` subdirectories organized by pg_tle version ranges. For version range details, see `pgtle_versions.md`.

Set `PGXNTOOL_PGTLE_VERSION` on the command line to limit generation to the single version range that value falls into, instead of every known range:
Set `PGXNTOOL_PGTLE_VERSION` on the command line to a range name (`1.0.0-1.4.0`, `1.4.0-1.5.0` or `1.5.0+`) to generate only that range instead of every known range:

----
make pgtle PGXNTOOL_PGTLE_VERSION=1.5.0
make pgtle PGXNTOOL_PGTLE_VERSION=1.5.0+
----

The value must be one of those range names exactly; it is not mapped from a plain pg_tle version. Any other value (e.g. `1.5.0`) is not validated and produces a bogus `pg_tle/1.5.0/` directory.

=== check-pgtle
Checks if pg_tle is installed and reports the version. This target:
- Reports the version from `pg_extension` if `CREATE EXTENSION pg_tle` has been run in the database
Expand Down Expand Up @@ -575,7 +587,7 @@ PGXNtool replaces each `$(ASCIIDOC_EXTS)` in `$(ASCIIDOC_FILES)` with `html`.
The result is appended to `ASCIIDOC_HTML` using `+=`.

=== Document Rules
If Asciidoc is found (or `$(ASCIIDOC)` is set), `html` is added as a dependency of the `all` target, which both `install` and `installcheck` depend on — so docs get built for install and test, but only if Asciidoc is available.
If Asciidoc is found (or `$(ASCIIDOC)` is set), `html` is added as a dependency of the `all` target, which `install` depends on (and `installcheck` reaches through `install` when `PGXNTOOL_ENABLE_FS_INSTALL=yes`) — so docs get built for install and test, but only if Asciidoc is available.
The `dist` rule always depends on `html` directly, regardless of whether Asciidoc was found, to ensure html files are up-to-date before creating a distribution.

The `html` rule simply depends on `$(ASCIIDOC_HTML).
Expand Down Expand Up @@ -746,15 +758,15 @@ make dist PGXN_REMOTE=upstream

=== PGXNTOOL_POST_TAG_VERSION

Default: `stable`. The placeholder value `make post-tag-version-bump` sets `default_version` to. Not valid semver, but PostgreSQL doesn't require semver for extension versions. If you override this, also update the `sql/*--stable.sql` line and its `!sql/*--*--stable.sql` negation (which keeps the `{old}--stable` update script tracked) in your `.gitignore` to match.
Default: `stable`. The placeholder value `make post-tag-version-bump` sets `default_version` to. It must be non-empty and contain only ASCII letters, digits, `.` and `-`; anything else makes `post-tag-version-bump` fail. Not valid semver, but PostgreSQL doesn't require semver for extension versions. If you override this, also update the `sql/*--stable.sql` line and its `!sql/*--*--stable.sql` negation (which keeps the `{old}--stable` update script tracked) in your `.gitignore` to match.

=== ASCIIDOC

Default: auto-detected, the first of `asciidoctor` or `asciidoc` found on `PATH`. Path to the Asciidoc processor used to build `.html` files from `$(ASCIIDOC_EXTS)` source files. Override if the processor you want isn't first on `PATH`, or isn't on `PATH` at all. See <<_document_handling>>.

=== PGXNTOOL_PGTLE_VERSION

Default: unset (generates every known pg_tle version range). Set on the command line to limit `make pgtle` to the single version range this value falls into. Not named `PGTLE_VERSION`: make auto-imports same-named environment variables, and that name collided silently with CI jobs that set a `PGTLE_VERSION` env var for an unrelated purpose (which pg_tle to test against). See <<_pgtle>>.
Default: unset (generates every known pg_tle version range). Set on the command line to a range name (`1.0.0-1.4.0`, `1.4.0-1.5.0` or `1.5.0+`, exactly) to limit `make pgtle` to that one range; any other value is passed through unvalidated and generates a bogus `pg_tle/<value>/` directory. Not named `PGTLE_VERSION`: make auto-imports same-named environment variables, and that name collided silently with CI jobs that set a `PGTLE_VERSION` env var for an unrelated purpose (which pg_tle to test against). See <<_pgtle>>.

=== PGXNTOOL_PGTLE_TARGET_VERSION

Expand Down Expand Up @@ -798,7 +810,7 @@ Default: `yes`. Enables or disables a build-time check that every `test/install/

=== PGXNTOOL_ENABLE_FS_INSTALL *

Default: `yes`. Controls whether `install` is a prerequisite of `test`/`verify-results`, and whether `installcheck` depends on `install`. Set to `no` for "existing mode" testing, where the extension under test was deployed some other way (e.g. registered via pg_tle instead of the filesystem, or installed by a binary pg_upgrade) -- with this set, `make test`/`make installcheck`/`make verify-results` run against whatever is already installed instead of filesystem-installing first.
Default: `yes`. Controls whether `install` is a prerequisite of `test`/`verify-results`, and whether `installcheck` and <<_test_build,test-build>> depend on `install`. Set to `no` for "existing mode" testing, where the extension under test was deployed some other way (e.g. registered via pg_tle instead of the filesystem, or installed by a binary pg_upgrade) -- with this set, `make test`/`make installcheck`/`make verify-results` run against whatever is already installed instead of filesystem-installing first.

=== PGXNTOOL_ENABLE_PGXN_INSTALL *

Expand Down
Loading
Loading