Skip to content

Add GitHub Actions CI for pgxntool + pgxntool-test #15

@jnasbyupgrade

Description

@jnasbyupgrade

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

  1. CI triggers on push/PR to either pgxntool or pgxntool-test
  2. Branch matching: if the other repo has a matching branch name, use it; otherwise fall back to master
  3. Must work for PRs from forks (jnasbyupgrade/*)
  4. PostgreSQL version matrix using pgxn/pgxn-tools container
  5. 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:

  1. No secrets/tokens — eliminates an entire class of maintenance and failure modes
  2. PR status works naturally — results appear on the PR that triggered them
  3. Fork PRs just work — no special handling needed
  4. Simpler debugging — each CI run is self-contained
  5. 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

  • Validate PG version matrix against what pg-start actually supports
  • Add apt-get install -y rsync ruby-asciidoctor to both workflows
  • Use submodules: recursive for pgxntool-test checkout
  • Use git config --global --add safe.directory for both repo paths
  • Check out both repos as siblings: pgxntool-test/ and pgxntool/ under $GITHUB_WORKSPACE
  • After pgxntool checkout, create local branch: git checkout -B $BRANCH
  • Set PGXNBRANCH env var to bypass test infrastructure's own detection
  • Configure git user.email/user.name for test operations
  • Determine if make test or make test-all is appropriate for CI
  • Test that check-readme works correctly with fresh checkout timestamps

Open questions

  1. Should CI run make test or make test-all? (Extra tests have additional requirements)
  2. What PG versions should the matrix include? (Need to validate against pgxn/pgxn-tools)
  3. Should we add jq to the install list for future-proofing?
  4. Is there value in adding a concurrency group to cancel stale runs on rapid pushes to the same branch?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions