Motivation
pgxntool has no CI. Tests only run locally. We need GitHub Actions CI that triggers on commits to either repo and uses the existing branch matching rules.
Requirements
- CI triggers on push/PR to either
pgxntool or pgxntool-test
- Branch matching: if the other repo has a matching branch name, use it; otherwise fall back to
master
- Must work for PRs from forks (
jnasbyupgrade/*)
- PostgreSQL version matrix using
pgxn/pgxn-tools container
- Ideally avoid duplicate runs when both repos change on the same branch
Reference: Existing cat_tools CI
name: CI
on: [push, pull_request]
jobs:
test:
strategy:
matrix:
pg: [17, 16, 15, 14, 13, 12, 11, 10, 9.6, 9.5, 9.4, 9.3, 9.2]
name: 🐘 PostgreSQL ${{ matrix.pg }}
runs-on: ubuntu-latest
container: pgxn/pgxn-tools
steps:
- name: Start PostgreSQL ${{ matrix.pg }}
run: pg-start ${{ matrix.pg }}
- uses: actions/checkout@v4
- run: pg-build-test
Note: pgxntool-test uses make test (BATS-based), not pg-build-test.
Reference: Branch Matching Rules
From test/lib/helpers.bash (setup_pgxntool_vars):
| Situation |
Rule |
Current repo on master |
Use master for other repo |
| Current repo on feature branch, other repo HAS it |
Use feature branch |
| Current repo on feature branch, other repo LACKS it |
Fall back to master |
Proposed Design A: Reusable Workflow (3 files)
Files: pgxntool-test/.github/workflows/test.yml (reusable), pgxntool-test/.github/workflows/ci.yml, pgxntool/.github/workflows/ci.yml
Architecture:
pgxntool push → pgxntool/ci.yml → repository_dispatch → pgxntool-test/ci.yml → test.yml
pgxntool-test push → pgxntool-test/ci.yml → test.yml
fork PRs → inline test job (no dispatch possible from forks)
Pros:
- Test logic defined once in reusable
test.yml
- Concurrency groups for deduplication (same branch pair → only one run survives)
- PG version matrix defined in one place
Cons:
- Requires PAT or GitHub App token (
PGXNTOOL_DISPATCH_TOKEN) for cross-repo dispatch
repository_dispatch results appear in pgxntool-test's Actions tab, not on the pgxntool PR
- Fork PR handling requires separate inline job (duplicating test logic) or cross-repo
workflow_call pinned to @master
- Token rotation/expiration is a silent failure mode
PGXNBRANCH=HEAD approach is fragile (see adversary review)
Proposed Design B: Simple Dual-Workflow (2 files)
Files: pgxntool-test/.github/workflows/ci.yml, pgxntool/.github/workflows/ci.yml
Architecture:
pgxntool push → pgxntool/ci.yml (checks out both repos, runs make test)
pgxntool-test push → pgxntool-test/ci.yml (checks out both repos, runs make test)
Each workflow independently resolves branches via git ls-remote and runs the full test suite.
Pros:
- No cross-repo coordination, no secrets needed
- Fork PRs work naturally (public repo reads only)
- Each CI run is fully self-contained and debuggable
- Results appear on the PR that triggered them
- No PAT/token management
Cons:
- Duplicate runs when both repos change on same branch (~5 min wasted CI time)
- Test logic slightly duplicated across two workflow files (~50 lines each)
- Requires
git checkout -b after actions/checkout to create local branch for git subtree add
- Hardcodes
jnasbyupgrade as fork org in branch resolution
Adversary Review: Issues Found in Both Designs
Blockers (both designs)
| Issue |
Details |
Missing rsync |
pgxn/pgxn-tools does not include rsync. Test infrastructure uses it everywhere (foundation.bats, ensure_foundation(), build_test_repo_from_template()). Total blocker. Fix: apt-get install -y rsync |
Missing asciidoctor |
Container lacks it. Makefile's check-readme (called by test-setup) needs it. Fix: apt-get install -y asciidoctor (or ruby-asciidoctor) |
| BATS submodule |
test/bats/ is a git submodule. actions/checkout doesn't init submodules by default. Fix: submodules: recursive in checkout step |
safe.directory |
Container may run as different user than checkout owner. Git refuses to operate without safe.directory config. Fix: git config --global --add safe.directory for both repos |
Design A specific issues
| Issue |
Severity |
Details |
PGXNBRANCH=HEAD fragile |
High |
Works for local paths but has wrong semantics for remote URLs and detached HEAD states |
| PAT management |
Medium |
Token expiration silently breaks all cross-repo triggering |
| No PR status |
Medium |
Dispatch-triggered test results don't appear on pgxntool PRs |
| API rate limiting |
Low |
Unauthenticated curl to GitHub API is 60 req/hr |
Design B specific issues
| Issue |
Severity |
Details |
Detached HEAD + git checkout -b |
Medium |
Could fail if branch already exists; should use -B (force-create) |
| Hardcoded fork org |
Low |
Only checks jnasbyupgrade for matching branches; doesn't generalize to other contributors |
| Duplicate runs |
Low |
~5 min wasted CI when both repos change on same branch |
Both designs
| Issue |
Severity |
Details |
PGXNTOOL_SOURCE_DIR |
Medium |
Makefile hardcodes ../pgxntool relative path; both repos must be checked out as siblings |
Missing jq |
Low |
If any test calls assert_valid_meta_json(), needs jq in container |
| PG matrix validation |
Low |
Some older PG versions (9.2, 9.3) may not be available in current pgxn/pgxn-tools |
Recommendation
Start with Design B (Simple Dual-Workflow). Rationale:
- No secrets/tokens — eliminates an entire class of maintenance and failure modes
- PR status works naturally — results appear on the PR that triggered them
- Fork PRs just work — no special handling needed
- Simpler debugging — each CI run is self-contained
- Duplicate runs are cheap — ~5 min extra CI vs significant complexity to prevent
Design A's benefits (deduplication, single test definition) don't justify the operational overhead of PAT management and the invisible-status problem for pgxntool PRs.
Implementation checklist
Open questions
- Should CI run
make test or make test-all? (Extra tests have additional requirements)
- What PG versions should the matrix include? (Need to validate against
pgxn/pgxn-tools)
- Should we add
jq to the install list for future-proofing?
- Is there value in adding a
concurrency group to cancel stale runs on rapid pushes to the same branch?
Motivation
pgxntool has no CI. Tests only run locally. We need GitHub Actions CI that triggers on commits to either repo and uses the existing branch matching rules.
Requirements
pgxntoolorpgxntool-testmasterjnasbyupgrade/*)pgxn/pgxn-toolscontainerReference: Existing cat_tools CI
Note: pgxntool-test uses
make test(BATS-based), notpg-build-test.Reference: Branch Matching Rules
From
test/lib/helpers.bash(setup_pgxntool_vars):mastermasterfor other repomasterProposed Design A: Reusable Workflow (3 files)
Files:
pgxntool-test/.github/workflows/test.yml(reusable),pgxntool-test/.github/workflows/ci.yml,pgxntool/.github/workflows/ci.ymlArchitecture:
Pros:
test.ymlCons:
PGXNTOOL_DISPATCH_TOKEN) for cross-repo dispatchrepository_dispatchresults appear in pgxntool-test's Actions tab, not on the pgxntool PRworkflow_callpinned to@masterPGXNBRANCH=HEADapproach is fragile (see adversary review)Proposed Design B: Simple Dual-Workflow (2 files)
Files:
pgxntool-test/.github/workflows/ci.yml,pgxntool/.github/workflows/ci.ymlArchitecture:
Each workflow independently resolves branches via
git ls-remoteand runs the full test suite.Pros:
Cons:
git checkout -bafteractions/checkoutto create local branch forgit subtree addjnasbyupgradeas fork org in branch resolutionAdversary Review: Issues Found in Both Designs
Blockers (both designs)
rsyncpgxn/pgxn-toolsdoes not includersync. Test infrastructure uses it everywhere (foundation.bats,ensure_foundation(),build_test_repo_from_template()). Total blocker. Fix:apt-get install -y rsyncasciidoctorcheck-readme(called bytest-setup) needs it. Fix:apt-get install -y asciidoctor(orruby-asciidoctor)test/bats/is a git submodule.actions/checkoutdoesn't init submodules by default. Fix:submodules: recursivein checkout stepsafe.directorysafe.directoryconfig. Fix:git config --global --add safe.directoryfor both reposDesign A specific issues
PGXNBRANCH=HEADfragilecurlto GitHub API is 60 req/hrDesign B specific issues
git checkout -b-B(force-create)jnasbyupgradefor matching branches; doesn't generalize to other contributorsBoth designs
PGXNTOOL_SOURCE_DIR../pgxntoolrelative path; both repos must be checked out as siblingsjqassert_valid_meta_json(), needsjqin containerpgxn/pgxn-toolsRecommendation
Start with Design B (Simple Dual-Workflow). Rationale:
Design A's benefits (deduplication, single test definition) don't justify the operational overhead of PAT management and the invisible-status problem for pgxntool PRs.
Implementation checklist
pg-startactually supportsapt-get install -y rsync ruby-asciidoctorto both workflowssubmodules: recursivefor pgxntool-test checkoutgit config --global --add safe.directoryfor both repo pathspgxntool-test/andpgxntool/under$GITHUB_WORKSPACEgit checkout -B $BRANCHPGXNBRANCHenv var to bypass test infrastructure's own detectionmake testormake test-allis appropriate for CIcheck-readmeworks correctly with fresh checkout timestampsOpen questions
make testormake test-all? (Extra tests have additional requirements)pgxn/pgxn-tools)jqto the install list for future-proofing?concurrencygroup to cancel stale runs on rapid pushes to the same branch?