diff --git a/HISTORY.asc b/HISTORY.asc index 3d588c0..0eeac17 100644 --- a/HISTORY.asc +++ b/HISTORY.asc @@ -1,3 +1,39 @@ +STABLE +------ +== Breaking changes + +=== `make results` refuses on more kinds of broken pgTAP output +In `pgtap` mode, `make results` now also refuses when a `test/results/*.out` +file holding TAP output has no plan line (`1..N`), more than one plan line, +a plan line between test lines, a test count that differs from the plan, or +a `Bail out!` line. A test that died before finishing (a `no_plan()` test +that never reached `finish()`, or a `plan(N)` test cut short without pgTAP's +own mismatch line) used to look like a pass. Files without any TAP line are +still checked only through `regression.diffs`. See #106. + +=== `make test` fails on broken pgTAP output, even when blessed +Under the default `pgtap` mode of `PGXNTOOL_VERIFY_RESULTS_MODE`, `make test` +now runs `verify-tap.sh --skip-non-tap` on `test/results/*.out` and fails +when a file holding TAP output has a `not ok` (without `# TODO`), a missing +or duplicate plan line, a test count that differs from the plan, or a +`Bail out!` line -- even if that output was blessed into its expected file, +so it no longer shows up in `regression.diffs`. `regression.diffs` is still +printed, and both failures are reported. `PGXNTOOL_VERIFY_RESULTS_MODE = +diffs` turns the check off, though it also switches `make results` to +`diffs` mode. + +== New features + +=== Add `verify-tap.sh`, a standalone TAP output checker +`pgxntool/verify-tap.sh [--skip-non-tap] [FILE|-]...` fails if a TAP stream +shows a failed run: a `not ok` without `# TODO`, `Bail out!`, pgTAP's "Looks +like you planned" line, a missing or duplicate plan line, or a test count that +differs from the plan. It reads stdin by default, judges each file argument +as its own stream, and exits 0, 1 (a stream failed) or 2 (usage error or +unreadable file); see README. `--skip-non-tap` skips input holding no TAP +lines instead of failing it. `make test` and `make results` use it in +`pgtap` mode. + 2.4.0 ----- == Breaking changes diff --git a/README.asc b/README.asc index 92f132d..93905d5 100644 --- a/README.asc +++ b/README.asc @@ -52,8 +52,9 @@ Warns if two `$(DOCS)` entries would install to the same filename, which would o === test 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: +`make test` also fails on these safeguard checks: +- In `pgtap` mode (the default; see <<_verify_results_safeguard>>), the TAP check: fails if <<_verify_tap,`verify-tap.sh`>> rejects any `test/results/*.out` file holding TAP output, even when that output matches its expected file. Files with no TAP output are skipped, and `test/install` output is never checked. This runs alongside the `regression.diffs` check, and both are always reported. - 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>>. @@ -68,7 +69,7 @@ Whether `test-build` runs is controlled by the `PGXNTOOL_ENABLE_TEST_BUILD` vari 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, so CI and other automation can rely on its exit code. +NOTE: `test` exits non-zero (after printing `regression.diffs` and any TAP check failures) 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. @@ -272,10 +273,11 @@ IMPORTANT: *`make results` requires manual verification first*. The correct work Never run `make results` without first verifying the test changes are correct. The `results` target copies files from `test/results/` to `test/expected/`, so running it blindly will make incorrect output become the new expected behavior. ==== verify-results safeguard -By default, `make results` will refuse to run if your tests are failing, so you can't accidentally promote incorrect output into the new expected results. Which failures it looks for is controlled by `PGXNTOOL_VERIFY_RESULTS_MODE`, which must be one of these two values (case-insensitive; anything else is a hard `make` error): +By default, `make results` will refuse to run if your tests are failing, so you can't accidentally promote incorrect output into the new expected results. Which failures it looks for is controlled by `PGXNTOOL_VERIFY_RESULTS_MODE`, which also decides whether `make test` runs its TAP check (see <<_test>>). It must be one of these two values (case-insensitive; anything else is a hard `make` error): -`pgtap` (the default):: Scans `test/results/*.out` for pgTAP `not ok` lines (ignoring `# TODO` items) and plan-count mismatches, then also checks `test/regression.diffs` for any output mismatch pgTAP itself wouldn't catch. A test that has no expected output file yet is the one exception: it always shows up in `regression.diffs` (pgxntool creates an empty expected file for it, because `pg_regress` aborts on a missing one), so `make results` is allowed to create its first expected output — provided its own pgTAP output is clean and free of SQL errors. If a new test legitimately needs output containing a SQL error blessed, use `PGXNTOOL_ENABLE_VERIFY_RESULTS=no` for that one run. -`diffs`:: Only checks whether `test/regression.diffs` exists, so it can't create a new test's first expected output; use `pgtap` mode, or `PGXNTOOL_ENABLE_VERIFY_RESULTS=no` for that one run. +`pgtap` (the default):: Runs <<_verify_tap,`verify-tap.sh --skip-non-tap`>> on every `test/results/*.out` file, so a `not ok` (ignoring `# TODO` items), a `Bail out!`, or a missing, duplicate or misplaced plan line or a test count that differs from the plan all block; then also checks `test/regression.diffs` for any output mismatch pgTAP itself wouldn't catch. A test that has no expected output file yet is the one exception: it always shows up in `regression.diffs` (pgxntool creates an empty expected file for it, because `pg_regress` aborts on a missing one), so `make results` is allowed to create its first expected output — provided its own pgTAP output is clean and free of SQL errors. If a new test legitimately needs output containing a SQL error blessed, use `PGXNTOOL_ENABLE_VERIFY_RESULTS=no` for that one run. +`make test` runs the same `verify-tap.sh` check, so a TAP failure fails `make test` even after it has been blessed into an expected file. +`diffs`:: Only checks whether `test/regression.diffs` exists, and `make test` skips its TAP check. It can't create a new test's first expected output; use `pgtap` mode, or `PGXNTOOL_ENABLE_VERIFY_RESULTS=no` for that one run. If tests are failing, `make results` prints an explanation of what failed and exits without touching `test/expected/`; fix the failures, then re-run `make results`. @@ -424,6 +426,33 @@ $(MAKE) --no-print-directory -C ../deps/cat_tools print-pgtle >> pgtle-all.sql WARNING: Always pass `--no-print-directory` when invoking `print-pgtle` recursively from another Makefile's recipe (as above). GNU Make auto-prints `Entering directory`/`Leaving directory` announcements to stdout for recursive invocations, which silently corrupts a redirected combined SQL file with garbage lines. `--no-print-directory` suppresses them. +[[_verify_tap]] +== verify-tap.sh +`pgxntool/verify-tap.sh` checks TAP output (such as pgTAP's) and fails if it shows a failed test run. It doesn't need `make` or a database, so you can run it on any TAP output, including outside of pgxntool; `make test` and `make results` use it in `pgtap` mode (see <<_verify_results_safeguard>>). + +---- +pgxntool/verify-tap.sh [--skip-non-tap] [FILE|-]... +---- + +With no arguments, or for a `-` argument, it reads stdin; otherwise each `FILE` is judged as its own TAP stream: + +---- +psql -XtA -f my_test.sql | pgxntool/verify-tap.sh +pgxntool/verify-tap.sh test/results/*.out +---- + +Only unindented lines count, so subtest output is ignored. A stream passes only if: + +* no `not ok` line lacks `# TODO` +* there is no `Bail out!` line +* there is no pgTAP `# Looks like you planned` line +* there is exactly one plan line (`1..N`), before every test line (`plan(N)`) or after every one (`no_plan()` plus `finish()`) +* the number of test lines (`ok N`/`not ok N`) equals `N`; `1..0` with no tests passes + +Input with no plan line and no test lines fails, since it means nothing ran. With `--skip-non-tap`, such input (plain SQL output, say) is skipped silently instead, which lets you pass a mix of TAP and non-TAP files. Each problem is reported on stderr, naming its source (`stdin` or the file's path). + +Exit status is 0 if every input passes, 1 if any input fails, and 2 on a usage error or an unreadable file (in which case nothing is checked). + == Version-Specific SQL Files PGXNtool automatically generates version-specific SQL files from your base SQL file. These files follow the pattern `sql/{extension}--{version}.sql` and are used by PostgreSQL's extension system to install specific versions of your extension. @@ -786,15 +815,15 @@ Default: `$(TESTDIR)`. Directory `pg_regress` writes actual test output to -- `$ === PGXNTOOL_VERIFY_RESULTS_MODE -Default: `pgtap`. Controls how the <<_verify_results_safeguard,verify-results safeguard>> decides whether tests are failing. Must be `pgtap` or `diffs` (case-insensitive) when given explicitly; any other value, including an empty one, is a hard `make` error. +Default: `pgtap`. Controls how the <<_verify_results_safeguard,verify-results safeguard>> decides whether tests are failing, and whether <<_test,`make test`>> runs its TAP check. Must be `pgtap` or `diffs` (case-insensitive) when given explicitly; any other value, including an empty one, is a hard `make` error. ==== pgtap -Scans `test/results/*.out` for pgTap `not ok` lines and plan mismatches, falling back to checking `regression.diffs` too — except for a test that has no expected output yet, whose first expected file `make results` is allowed to create. Use this mode when your test suite uses pgTap. +Runs <<_verify_tap,`verify-tap.sh --skip-non-tap`>> on each `test/results/*.out` file, falling back to checking `regression.diffs` too — except for a test that has no expected output yet, whose first expected file `make results` is allowed to create. `make test` runs the same `verify-tap.sh` check alongside its `regression.diffs` check, so blessed TAP failures still fail it. Use this mode when your test suite uses pgTap. ==== diffs -Checks only for `regression.diffs`, matching classic pg_regress behavior. Use this mode when your tests use plain SQL expected-output comparison only. +Checks only for `regression.diffs`, matching classic pg_regress behavior; `make test` doesn't run `verify-tap.sh`. Use this mode when your tests use plain SQL expected-output comparison only. === PGXNTOOL_ENABLE_TEST_BUILD * diff --git a/README.html b/README.html index 10a92d7..5bc1850 100644 --- a/README.html +++ b/README.html @@ -470,60 +470,61 @@

PGXNtool

  • 4.20. print-pgtle
  • -
  • 5. Version-Specific SQL Files +
  • 5. verify-tap.sh
  • +
  • 6. Version-Specific SQL Files
  • -
  • 6. Document Handling +
  • 7. Document Handling
  • -
  • 7. pg_tle Support +
  • 8. pg_tle Support
  • -
  • 8. Configuration Variables +
  • 9. Configuration Variables
  • -
  • 9. General PostgreSQL Notes
  • -
  • 10. Copyright
  • +
  • 10. General PostgreSQL Notes
  • +
  • 11. Copyright
  • @@ -633,11 +634,14 @@

    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:

    +

    make test also fails on these safeguard checks:

    -test exits non-zero (after printing regression.diffs) if any test fails, so CI and other automation can rely on its exit code. +test exits non-zero (after printing regression.diffs and any TAP check failures) if any test fails, so CI and other automation can rely on its exit code. @@ -1082,17 +1086,18 @@

    4.7.1. verify-results safeguard

    -

    By default, make results will refuse to run if your tests are failing, so you can’t accidentally promote incorrect output into the new expected results. Which failures it looks for is controlled by PGXNTOOL_VERIFY_RESULTS_MODE, which must be one of these two values (case-insensitive; anything else is a hard make error):

    +

    By default, make results will refuse to run if your tests are failing, so you can’t accidentally promote incorrect output into the new expected results. Which failures it looks for is controlled by PGXNTOOL_VERIFY_RESULTS_MODE, which also decides whether make test runs its TAP check (see test). It must be one of these two values (case-insensitive; anything else is a hard make error):

    pgtap (the default)
    -

    Scans test/results/*.out for pgTAP not ok lines (ignoring # TODO items) and plan-count mismatches, then also checks test/regression.diffs for any output mismatch pgTAP itself wouldn’t catch. A test that has no expected output file yet is the one exception: it always shows up in regression.diffs (pgxntool creates an empty expected file for it, because pg_regress aborts on a missing one), so make results is allowed to create its first expected output — provided its own pgTAP output is clean and free of SQL errors. If a new test legitimately needs output containing a SQL error blessed, use PGXNTOOL_ENABLE_VERIFY_RESULTS=no for that one run.

    +

    Runs verify-tap.sh --skip-non-tap on every test/results/*.out file, so a not ok (ignoring # TODO items), a Bail out!, or a missing, duplicate or misplaced plan line or a test count that differs from the plan all block; then also checks test/regression.diffs for any output mismatch pgTAP itself wouldn’t catch. A test that has no expected output file yet is the one exception: it always shows up in regression.diffs (pgxntool creates an empty expected file for it, because pg_regress aborts on a missing one), so make results is allowed to create its first expected output — provided its own pgTAP output is clean and free of SQL errors. If a new test legitimately needs output containing a SQL error blessed, use PGXNTOOL_ENABLE_VERIFY_RESULTS=no for that one run. +make test runs the same verify-tap.sh check, so a TAP failure fails make test even after it has been blessed into an expected file.

    diffs
    -

    Only checks whether test/regression.diffs exists, so it can’t create a new test’s first expected output; use pgtap mode, or PGXNTOOL_ENABLE_VERIFY_RESULTS=no for that one run.

    +

    Only checks whether test/regression.diffs exists, and make test skips its TAP check. It can’t create a new test’s first expected output; use pgtap mode, or PGXNTOOL_ENABLE_VERIFY_RESULTS=no for that one run.

    @@ -1456,13 +1461,63 @@

    -

    5. Version-Specific SQL Files

    +

    5. verify-tap.sh

    +
    +
    +

    pgxntool/verify-tap.sh checks TAP output (such as pgTAP’s) and fails if it shows a failed test run. It doesn’t need make or a database, so you can run it on any TAP output, including outside of pgxntool; make test and make results use it in pgtap mode (see verify-results safeguard).

    +
    +
    +
    +
    pgxntool/verify-tap.sh [--skip-non-tap] [FILE|-]...
    +
    +
    +
    +

    With no arguments, or for a - argument, it reads stdin; otherwise each FILE is judged as its own TAP stream:

    +
    +
    +
    +
    psql -XtA -f my_test.sql | pgxntool/verify-tap.sh
    +pgxntool/verify-tap.sh test/results/*.out
    +
    +
    +
    +

    Only unindented lines count, so subtest output is ignored. A stream passes only if:

    +
    +
    +
      +
    • +

      no not ok line lacks # TODO

      +
    • +
    • +

      there is no Bail out! line

      +
    • +
    • +

      there is no pgTAP # Looks like you planned line

      +
    • +
    • +

      there is exactly one plan line (1..N), before every test line (plan(N)) or after every one (no_plan() plus finish())

      +
    • +
    • +

      the number of test lines (ok N/not ok N) equals N; 1..0 with no tests passes

      +
    • +
    +
    +
    +

    Input with no plan line and no test lines fails, since it means nothing ran. With --skip-non-tap, such input (plain SQL output, say) is skipped silently instead, which lets you pass a mix of TAP and non-TAP files. Each problem is reported on stderr, naming its source (stdin or the file’s path).

    +
    +
    +

    Exit status is 0 if every input passes, 1 if any input fails, and 2 on a usage error or an unreadable file (in which case nothing is checked).

    +
    +
    +
    +
    +

    6. Version-Specific SQL Files

    PGXNtool automatically generates version-specific SQL files from your base SQL file. These files follow the pattern sql/{extension}--{version}.sql and are used by PostgreSQL’s extension system to install specific versions of your extension.

    -

    5.1. PGXN Distributions vs. Extensions

    +

    6.1. PGXN Distributions vs. Extensions

    PGXN distinguishes two things it’s easy to conflate: a distribution and an extension. Per the PGXN meta spec, a distribution is "a collection of extensions, source code, utilities, tests, and/or documents that are distributed together" — the thing you release and upload to PGXN, identified by the top-level name/version in META.json (generated from META.in.json — you edit the latter, never META.json directly). An extension is the individual thing installed via CREATE EXTENSION, described by its own .control file. A single distribution routinely provides more than one extension — META.in.json’s `provides map lists each one; the pgTAP distribution, for example, provides both the pgtap and schematap extensions from one release.

    @@ -1484,7 +1539,7 @@

    -

    5.2. How Version Files Are Generated

    +

    6.2. How Version Files Are Generated

    When you run make (or make all), PGXNtool:

    @@ -1514,7 +1569,7 @@

    -

    5.3. What Controls the Version Number

    +

    6.3. What Controls the Version Number

    The version number comes from each extension’s own .control file → default_version, not from META.json. PostgreSQL itself uses default_version to pick which versioned SQL file to load, so control.mk.sh parses the .control file(s) directly to keep the generated filename in sync with what PostgreSQL will actually use. META.in.json has its own, separate provides.{extension}.version for that same extension (see PGXN Distributions vs. Extensions above) — pgxntool never reads it when generating SQL files, and nothing keeps it in sync with the .control file’s default_version.

    @@ -1527,7 +1582,7 @@

    -

    5.4. Committing Version Files

    +

    6.4. Committing Version Files

    Version-specific SQL files are treated as permanent files that should be committed to your repository by default. This makes it much easier to test updates to extensions, as you can see exactly what SQL was included in each version.

    @@ -1544,7 +1599,7 @@

    -

    5.4.1. Why Commit Them: Update Testing

    +

    6.4.1. Why Commit Them: Update Testing

    The primary value of committing a version’s install script is update testing: with the file in place, you can install that exact version (CREATE EXTENSION ext VERSION 'x.y.z'), run ALTER EXTENSION ext UPDATE, and verify the update path actually works. In principle you would only ever need the very first committed version’s install script — every later version is reachable by chaining upgrade scripts from it. See test/install for how to wire this into your test suite.

    @@ -1553,13 +1608,13 @@

    -

    5.4.2. When It’s OK to Skip a Version

    +

    6.4.2. When It’s OK to Skip a Version

    For a minor version change that doesn’t meaningfully alter the extension (e.g. a small bug fix), it’s unlikely to straddle a PostgreSQL supported-version boundary, so there’s much less test-coverage value in committing that specific version’s generated install script. For large extensions, deliberately not committing some of these individual version files is worth doing to keep repository size down — the base sql/{extension}.sql still fully captures the change in git history, and the install script itself is trivially regenerated from that base file at build time.

    -

    5.4.3. Don’t .gitignore a Skipped Version — rm It Once

    +

    6.4.3. Don’t .gitignore a Skipped Version — rm It Once

    When you decide not to track a particular version’s generated install script, do not add a .gitignore entry for it.

    @@ -1571,7 +1626,7 @@

    -

    5.4.4. Never Hand-Edit a Version File That’s No Longer Current

    +

    6.4.4. Never Hand-Edit a Version File That’s No Longer Current

    control.mk.sh generates a Make rule along these lines for the current version’s file:

    @@ -1605,7 +1660,7 @@

    -

    5.5. Alternative: Ignoring All Version Files

    +

    6.5. Alternative: Ignoring All Version Files

    @@ -1645,13 +1700,13 @@

    -

    5.6. Distribution Inclusion

    +

    6.6. Distribution Inclusion

    Version-specific files are included in distributions created by make dist only if they are committed to git. Since make dist uses git archive, only tracked files are included in the distribution archive.

    -

    5.7. Multiple Versions

    +

    6.7. Multiple Versions

    If you need to support multiple versions of your extension:

    @@ -1676,9 +1731,9 @@

    -

    5.8. Gotchas

    +

    6.8. Gotchas

    -

    5.8.1. Generated SQL Files Can Be Missed on a Clean Build

    +

    6.8.1. Generated SQL Files Can Be Missed on a Clean Build

    DATA (the PGXS variable controlling what make install actually installs) is seeded by pgxntool with $(wildcard sql/--.sql), so PGXS installs whatever version-specific and upgrade files exist under sql/ when DATA is evaluated.

    @@ -1706,7 +1761,7 @@

    -

    6. Document Handling

    +

    7. Document Handling

    PGXNtool supports generation and installation of document files. There are several variables and rules that control this behavior.

    @@ -1717,7 +1772,7 @@

    -

    6.1. Document Variables

    +

    7.1. Document Variables

    DOC_DIRS
    @@ -1764,7 +1819,7 @@

    <

    -

    6.2. Document Rules

    +

    7.2. Document Rules

    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.

    @@ -1808,7 +1863,7 @@

    -

    6.3. The DOCS variable

    +

    7.3. The DOCS variable

    This variable has special meaning to PGXS. See the Postgres documentation for full details.

    @@ -1836,7 +1891,7 @@

    -

    7. pg_tle Support

    +

    8. pg_tle Support

    pgxntool can generate pg_tle (Trusted Language Extensions) registration SQL for deploying PostgreSQL extensions in managed environments like AWS RDS and Aurora where filesystem access is not available.

    @@ -1845,7 +1900,7 @@

    For make targets, see: pgtle, check-pgtle, run-pgtle, print-pgtle.

    -

    7.1. What is pg_tle?

    +

    8.1. What is pg_tle?

    pg_tle is an AWS open-source framework that enables developers to create and deploy PostgreSQL extensions without filesystem access. Traditional PostgreSQL extensions require .control and .sql files on the filesystem, which isn’t possible in managed services like RDS and Aurora.

    @@ -1857,7 +1912,7 @@

    -

    7.2. Quick Start

    +

    8.2. Quick Start

    Generate pg_tle registration SQL for your extension:

    @@ -1871,7 +1926,7 @@

    -

    7.3. Version Groupings

    +

    8.3. Version Groupings

    pgxntool creates different sets of files for different pg_tle versions to handle backward-incompatible API changes. Each version boundary represents a change to pg_tle’s API functions that we use.

    @@ -1880,7 +1935,7 @@

    @@ -1919,9 +1974,9 @@

    <
    -

    7.5. Advanced Usage

    +

    8.5. Advanced Usage

    -

    7.5.1. Multi-Extension Projects

    +

    8.5.1. Multi-Extension Projects

    If your project has multiple extensions (multiple .control files), make pgtle generates files for all of them:

    @@ -1941,7 +1996,7 @@

    -

    7.5.2. Direct pgtle.sh Invocation

    +

    8.5.2. Direct pgtle.sh Invocation

    pgtle, check-pgtle, and run-pgtle are thin make wrappers around pgtle.sh. For more targeted operations you can run it directly:

    @@ -1964,7 +2019,7 @@

    -

    7.6. How It Works

    +

    8.6. How It Works

    make pgtle does the following:

    @@ -1992,9 +2047,9 @@

    -

    7.7. Troubleshooting

    +

    8.7. Troubleshooting

    -

    7.7.1. "No versioned SQL files found"

    +

    8.7.1. "No versioned SQL files found"

    Problem: The script can’t find sql/{ext}--{version}.sql files.

    @@ -2003,7 +2058,7 @@

    -

    7.7.2. "Control file not found"

    +

    8.7.2. "Control file not found"

    Problem: The script can’t find {ext}.control in the current directory.

    @@ -2012,7 +2067,7 @@

    -

    7.7.3. "SQL file contains reserved pg_tle delimiter"

    +

    8.7.3. "SQL file contains reserved pg_tle delimiter"

    Problem: Your SQL files contain the string $pgtle_wrap_delimiter$ (extremely unlikely).

    @@ -2021,7 +2076,7 @@

    -

    7.7.4. Extension uses C code

    +

    8.7.4. Extension uses C code

    Problem: Your control file has module_pathname, indicating C code.

    @@ -2045,7 +2100,7 @@

    -

    8. Configuration Variables

    +

    9. Configuration Variables

    This is the comprehensive list of make variables you can override to customize pgxntool’s behavior, either in your Makefile (before include pgxntool/base.mk) or on the make command line. Several of these are also covered in more detail in the sections above; this section exists so there’s one place that lists all of them.

    @@ -2063,7 +2118,7 @@

    -

    8.1. PGXN_REMOTE

    +

    9.1. PGXN_REMOTE

    Default: origin. The git remote used by tag, rmtag, forcetag, and dist (which depends on tag). If your origin is a personal fork rather than the canonical repository — for example, if you develop on a fork and only push release tags to the canonical repo — set this so tagging and pushing target the right remote:

    @@ -2074,103 +2129,103 @@

    -

    8.2. PGXNTOOL_POST_TAG_VERSION

    +

    9.2. PGXNTOOL_POST_TAG_VERSION

    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.

    -

    8.3. ASCIIDOC

    +

    9.3. 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.

    -

    8.4. PGXNTOOL_PGTLE_VERSION

    +

    9.4. PGXNTOOL_PGTLE_VERSION

    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 rejected with an error. 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.

    -

    8.5. PGXNTOOL_PGTLE_TARGET_VERSION

    +

    9.5. PGXNTOOL_PGTLE_TARGET_VERSION

    Default: unset (falls back to the installed pg_tle version). Set on the command line to an actual pg_tle version (e.g. 1.5.2, not a range) to select which pg_tle/ directory make print-pgtle reads from, without needing a database connection. Distinct from PGXNTOOL_PGTLE_VERSION, which holds a range and controls generation rather than selection. See print-pgtle.

    -

    8.6. PG_CONFIG

    +

    9.6. PG_CONFIG

    Default: pg_config. Path to the pg_config binary used to detect the PostgreSQL version and locate PGXS. Override when the right pg_config isn’t the one on PATH, such as when testing against a specific PostgreSQL install.

    -

    8.7. TESTDIR

    +

    9.7. TESTDIR

    Default: test. Root directory for test input files: $(TESTDIR)/sql/, $(TESTDIR)/expected/, $(TESTDIR)/build/, $(TESTDIR)/install/. Overriding this on its own is unusual; it mainly exists so TESTOUT has a sensible default.

    -

    8.8. TESTOUT

    +

    9.8. TESTOUT

    Default: $(TESTDIR). Directory pg_regress writes actual test output to — $(TESTOUT)/results/, $(TESTOUT)/regression.diffs, etc. — via --outputdir in REGRESS_OPTS. Kept separate from TESTDIR so generated output can be pointed somewhere other than the directory holding your checked-in sql/expected files, if you want that separation.

    -

    8.9. PGXNTOOL_VERIFY_RESULTS_MODE

    +

    9.9. PGXNTOOL_VERIFY_RESULTS_MODE

    -

    Default: pgtap. Controls how the verify-results safeguard decides whether tests are failing. Must be pgtap or diffs (case-insensitive) when given explicitly; any other value, including an empty one, is a hard make error.

    +

    Default: pgtap. Controls how the verify-results safeguard decides whether tests are failing, and whether make test runs its TAP check. Must be pgtap or diffs (case-insensitive) when given explicitly; any other value, including an empty one, is a hard make error.

    -

    8.9.1. pgtap

    +

    9.9.1. pgtap

    -

    Scans test/results/*.out for pgTap not ok lines and plan mismatches, falling back to checking regression.diffs too — except for a test that has no expected output yet, whose first expected file make results is allowed to create. Use this mode when your test suite uses pgTap.

    +

    Runs verify-tap.sh --skip-non-tap on each test/results/*.out file, falling back to checking regression.diffs too — except for a test that has no expected output yet, whose first expected file make results is allowed to create. make test runs the same verify-tap.sh check alongside its regression.diffs check, so blessed TAP failures still fail it. Use this mode when your test suite uses pgTap.

    -

    8.9.2. diffs

    +

    9.9.2. diffs

    -

    Checks only for regression.diffs, matching classic pg_regress behavior. Use this mode when your tests use plain SQL expected-output comparison only.

    +

    Checks only for regression.diffs, matching classic pg_regress behavior; make test doesn’t run verify-tap.sh. Use this mode when your tests use plain SQL expected-output comparison only.

    -

    8.10. PGXNTOOL_ENABLE_TEST_BUILD *

    +

    9.10. PGXNTOOL_ENABLE_TEST_BUILD *

    Default: auto-detected — yes if test/build/*.sql files exist, no otherwise. Enables or disables the test-build pre-flight SQL check. Set explicitly to yes if you want an error when test/build/ unexpectedly has no SQL files (catches accidental deletion of its contents), or to no to disable the check even when files are present.

    -

    8.11. PGXNTOOL_ENABLE_TEST_INSTALL *

    +

    9.11. PGXNTOOL_ENABLE_TEST_INSTALL *

    Default: auto-detected — yes if test/install/*.sql files exist, no otherwise. Enables or disables the test/install schedule-based setup feature. Same explicit-override semantics as PGXNTOOL_ENABLE_TEST_BUILD.

    -

    8.12. PGXNTOOL_ENABLE_TEST_INSTALL_ERROR_STOP_CHECK *

    +

    9.12. PGXNTOOL_ENABLE_TEST_INSTALL_ERROR_STOP_CHECK *

    Default: yes. Enables or disables a build-time check that every test/install/*.sql file either includes test/pgxntool/psql.sql (which sets ON_ERROR_STOP) or has its own \set ON_ERROR_STOP or \unset ON_ERROR_STOP command; a file that sets ON_ERROR_STOP itself, to any value, is assumed to know what it’s doing — see test/install for why this is the only thing that makes a hard error in one of those files actually fail the build. Set to no to disable the check.

    -

    8.13. PGXNTOOL_ENABLE_FS_INSTALL *

    +

    9.13. PGXNTOOL_ENABLE_FS_INSTALL *

    Default: yes. Controls whether install is a prerequisite of test/verify-results, and whether installcheck and 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.

    -

    8.14. PGXNTOOL_ENABLE_PGXN_INSTALL *

    +

    9.14. PGXNTOOL_ENABLE_PGXN_INSTALL *

    Default: follows PGXNTOOL_ENABLE_FS_INSTALL (so it’s off automatically whenever filesystem install is off), but can be set independently. Controls whether installcheck auto-installs the pgtap dependency via pgxn install pgtap --sudo when it isn’t already filesystem-installed. Set to no to make this a complete no-op, e.g. when pgtap is already provided some other way and you don’t want a sudo pgxn install invoked as a side effect of testing.

    -

    8.15. PGXNTOOL_ENABLE_VERIFY_RESULTS *

    +

    9.15. PGXNTOOL_ENABLE_VERIFY_RESULTS *

    Default: yes. Enables or disables the verify-results safeguard that blocks make results when tests are failing. Setting it to empty on the command line (make PGXNTOOL_ENABLE_VERIFY_RESULTS= results) also disables it.

    -

    8.16. PGXNTOOL_ENABLE_CHECK_STALE_EXPECTED *

    +

    9.16. PGXNTOOL_ENABLE_CHECK_STALE_EXPECTED *

    Default: yes. Enables or disables the _check-stale-expected safeguard, which fails make test if test/expected/ (or test/build/expected/) contains a .out file with no corresponding .sql file — catching a stale file left behind after a test was renamed or removed. Set to no to make the check a complete no-op (it’s dropped from TEST_DEPS entirely).

    @@ -2179,13 +2234,13 @@

    -

    8.17. PGXNTOOL_CHECK_EXPECTED_FILE_TYPES *

    +

    9.17. PGXNTOOL_CHECK_EXPECTED_FILE_TYPES *

    Default: yes. Sub-check of _check-stale-expected, independent of PGXNTOOL_ENABLE_CHECK_STALE_EXPECTED: fails (with a distinct error message and exit code from the orphaned-.out check) if test/expected/ (or test/build/expected/) contains any file that isn’t *.out. Set to no to disable just this sub-check while leaving the orphaned-.out check active.

    -

    8.18. PGXNTOOL_NO_PGXS_INCLUDE

    +

    9.18. PGXNTOOL_NO_PGXS_INCLUDE

    Default: unset (PGXS is included normally). Skips including PGXS ($(PGXS)) entirely. This is only for advanced scenarios where you need to manage the PGXS include yourself; most projects should never set this.

    @@ -2193,7 +2248,7 @@

    -

    9. General PostgreSQL Notes

    +

    10. General PostgreSQL Notes

    POSTGRES-NOTES.asc collects guidance about PostgreSQL itself @@ -2204,7 +2259,7 @@

    - +

    Copyright (c) 2026 Jim Nasby <Jim.Nasby@gmail.com>

    @@ -2217,7 +2272,7 @@