Add update+upgrade (U&U) test infrastructure (stack 2/3) #13
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| push: | |
| branches: | |
| - master | |
| pull_request: | |
| env: | |
| PGUSER: postgres | |
| jobs: | |
| # Style linter (https://github.com/Postgres-Extensions/linter, vendored at | |
| # .vendor/linter -- lint.mk is the thin local hand-off, see its comment). | |
| # No `needs:` on anything: this is the cheapest possible check (no | |
| # database, no container beyond a plain checkout, seconds to run), so it | |
| # should never be waiting in a queue behind -- or racing for a runner slot | |
| # against -- the PG matrix below. It's gated behind nothing and everything | |
| # else of any real weight is gated behind it (see the `test` job's needs). | |
| # Deliberately checked out WITHOUT submodules -- `make lint` is the same | |
| # command a developer runs locally, and lint.mk self-initializes the | |
| # submodule on first use. Using the exact same entry point here is what | |
| # actually proves that self-init works, rather than papering over it with | |
| # a submodules: true checkout. | |
| lint: | |
| name: 🧹 SQL Lint | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Check out the repo | |
| uses: actions/checkout@v4 | |
| - name: Lint SQL | |
| run: make lint | |
| # Cheap gate that lets the test matrix below skip itself on commits that | |
| # touch only docs. Runs on every push/pull_request unconditionally (no | |
| # paths-ignore on the workflow itself) -- a workflow-level paths-ignore | |
| # would skip this job too on a docs-only push, and the required | |
| # all-checks-passed check would then never report and get stuck Pending in | |
| # branch protection. | |
| # | |
| # Also derives the supported-PostgreSQL-major list the test job's matrix | |
| # consumes, from a single pair of constants below, so adding or dropping a | |
| # major is a one-line edit here instead of touching the matrix directly. | |
| changes: | |
| name: 🔍 Detect changes & derive PG matrix | |
| runs-on: ubuntu-latest | |
| outputs: | |
| docs_only: ${{ steps.diff.outputs.docs_only }} | |
| supported_pg: ${{ steps.pg.outputs.supported_pg }} | |
| steps: | |
| - name: Check out the repo | |
| uses: actions/checkout@v4 | |
| with: | |
| # Full history needed so BASE and HEAD below are both reachable | |
| # for `git diff`. | |
| fetch-depth: 0 | |
| - name: Compute per-push changed files | |
| id: diff | |
| run: | | |
| # Fail-safe FIRST, before anything else runs: any early exit below | |
| # (an unusable BASE/HEAD, a failed git diff) leaves this in place, | |
| # so the test matrix only ever gets skipped after actually proving | |
| # the push is docs-only. | |
| echo "docs_only=false" >> "$GITHUB_OUTPUT" | |
| if [ "${{ github.event_name }}" = "pull_request" ]; then | |
| BASE="${{ github.event.pull_request.base.sha }}" | |
| HEAD="${{ github.event.pull_request.head.sha }}" | |
| else | |
| BASE="${{ github.event.before }}" | |
| HEAD="${{ github.event.after }}" | |
| fi | |
| echo "base=$BASE" | |
| echo "head=$HEAD" | |
| # A missing HEAD, or an all-zeros BASE (a new branch's first push, | |
| # where GitHub reports no prior commit), means no real diff can be | |
| # computed -- leave the fail-safe in place. | |
| if [ -z "$HEAD" ] || [ -z "$BASE" ] || [[ "$BASE" =~ ^0+$ ]]; then | |
| exit 0 | |
| fi | |
| CHANGED=$(git diff --name-only "$BASE" "$HEAD") || exit 0 | |
| [ -z "$CHANGED" ] && exit 0 | |
| DOCS_ONLY=true | |
| while IFS= read -r f; do | |
| if ! [[ "$f" =~ \.(md|asc)$ ]]; then | |
| DOCS_ONLY=false | |
| break | |
| fi | |
| done <<< "$CHANGED" | |
| echo "changed files:" | |
| echo "$CHANGED" | |
| echo "docs_only=$DOCS_ONLY" >> "$GITHUB_OUTPUT" | |
| - name: Derive the supported-PostgreSQL-major list | |
| id: pg | |
| run: | | |
| # SINGLE SOURCE OF TRUTH for the supported PostgreSQL majors. To | |
| # add or drop a major, edit only the two constants below; the test | |
| # job's matrix derives its version list from them. Do NOT hardcode | |
| # a supported major directly in a job matrix. | |
| # | |
| # NEWEST -- highest PostgreSQL major tested. | |
| # CURRENT_FLOOR -- oldest major supported. object_reference | |
| # requires cat_tools at both build and runtime, | |
| # and cat_tools's own current release declares | |
| # PostgreSQL 12 as its build floor, so | |
| # object_reference can't usefully claim support | |
| # for anything older either. | |
| NEWEST=18 | |
| CURRENT_FLOOR=12 | |
| supported=$(seq "$NEWEST" -1 "$CURRENT_FLOOR") | |
| # Emit a JSON array for the test job's matrix to consume via | |
| # fromJSON. | |
| json=$(printf '%s\n' $supported | paste -sd, - | sed 's/^/[/; s/$/]/') | |
| echo "supported_pg=$json" >> "$GITHUB_OUTPUT" | |
| test: | |
| # Gated behind lint too, not just changes: lint is nearly free to run, | |
| # so a baseline that's already broken by a style violation shouldn't | |
| # also tie up runner slots on the much heavier PG matrix below. | |
| # success() must be written explicitly -- GitHub only assumes success() | |
| # as a job's default when the job has no if: at all. | |
| needs: [changes, lint] | |
| if: success() && needs.changes.outputs.docs_only != 'true' | |
| strategy: | |
| matrix: | |
| # Supported majors, from the single source in the changes job. | |
| pg: ${{ fromJSON(needs.changes.outputs.supported_pg) }} | |
| name: 🐘 PostgreSQL ${{ matrix.pg }} | |
| runs-on: ubuntu-latest | |
| container: pgxn/pgxn-tools | |
| steps: | |
| - name: Start PostgreSQL ${{ matrix.pg }} | |
| run: pg-start ${{ matrix.pg }} | |
| - name: Check out the repo | |
| uses: actions/checkout@v4 | |
| - name: Test on PostgreSQL ${{ matrix.pg }} | |
| run: make test | |
| # A single stable check name for use as a required status check in branch | |
| # protection rules. Matrix jobs produce check names like "🐘 PostgreSQL 14" | |
| # which would all need to be listed individually and updated whenever the | |
| # matrix changes. This job passes if all others passed or were skipped | |
| # (e.g. test, on a docs-only push), and fails if any failed or were | |
| # cancelled. | |
| all-checks-passed: | |
| needs: [changes, lint, test] | |
| if: always() | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Check all jobs passed or were skipped | |
| run: | | |
| if [[ "${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }}" == "true" ]]; then | |
| echo "One or more jobs failed or were cancelled" | |
| exit 1 | |
| fi |