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
86 changes: 77 additions & 9 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,81 @@ on:
push:
branches:
- master
paths-ignore:
- '**.md'
- '**.asc'
pull_request:
paths-ignore:
- '**.md'
- '**.asc'
env:
PGUSER: postgres
jobs:
# Cheap gate that lets the heavy jobs below skip themselves on commits
# that touch only docs. This must run on every push/pull_request (no
# paths-ignore on the workflow itself), otherwise the required
# all-checks-passed check would never report on doc-only pushes and get
# stuck Pending in branch protection.
changes:
name: 🔍 Detect docs-only changes
runs-on: ubuntu-latest
outputs:
docs_only: ${{ steps.diff.outputs.docs_only }}
steps:
- name: Check out the repo
uses: actions/checkout@v6
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: |
if [ "${{ github.event_name }}" = "pull_request" ] && \
[ "${{ github.event.action }}" = "synchronize" ] && \
[ -n "${{ github.event.before }}" ]; then
# A push to an already-open PR: before/after give the true
# per-push diff, same as for a branch push.
BASE="${{ github.event.before }}"
HEAD="${{ github.event.after }}"
elif [ "${{ github.event_name }}" = "pull_request" ]; then
# First run for this PR (opened/reopened/etc, or synchronize
# without a usable before): fall back to the whole base...head
# diff.
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"

# Fail-safe: a missing HEAD, or an all-zeros BASE (e.g. a new
# branch's first push, where GitHub reports no prior commit),
# means we can't compute a real diff. Run the full matrix rather
# than risk skipping tests.
if [ -z "$HEAD" ] || [ -z "$BASE" ] || [[ "$BASE" =~ ^0+$ ]]; then
echo "docs_only=false" >> "$GITHUB_OUTPUT"
exit 0
fi

CHANGED=$(git diff --name-only "$BASE" "$HEAD" || echo __DIFF_FAILED__)

DOCS_ONLY=true
if [ "$CHANGED" = "__DIFF_FAILED__" ] || [ -z "$CHANGED" ]; then
DOCS_ONLY=false
else
while IFS= read -r f; do
if ! [[ "$f" =~ \.(md|asc)$ ]]; then
DOCS_ONLY=false
break
fi
done <<< "$CHANGED"
fi

echo "changed files:"
echo "$CHANGED"
echo "docs_only=$DOCS_ONLY" >> "$GITHUB_OUTPUT"

test:
needs: [changes]
if: needs.changes.outputs.docs_only != 'true'
strategy:
matrix:
pg: [18, 17, 16, 15, 14, 13, 12, 11, 10]
Expand All @@ -31,6 +95,8 @@ jobs:
run: make test

pg-upgrade-test:
needs: [changes]
if: needs.changes.outputs.docs_only != 'true'
strategy:
matrix:
include:
Expand Down Expand Up @@ -117,6 +183,8 @@ jobs:
# we cannot pg_upgrade from a cluster that has them installed.

extension-update-test:
needs: [changes]
if: needs.changes.outputs.docs_only != 'true'
strategy:
matrix:
# Restricted to PG10 only because the pre-0.2.2 install scripts use
Expand Down Expand Up @@ -181,10 +249,10 @@ jobs:
# 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.
# on a docs-only push with paths-ignore), and fails if any failed or were
# cancelled.
# the heavy jobs gated off by the `changes` job on a docs-only push), and
# fails if any failed or were cancelled.
all-checks-passed:
needs: [test, pg-upgrade-test, extension-update-test]
needs: [changes, test, pg-upgrade-test, extension-update-test]
if: always()
runs-on: ubuntu-latest
steps:
Expand Down
16 changes: 15 additions & 1 deletion .github/workflows/claude-code-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@ jobs:
claude-review:
# Trusted fork only, and skip drafts (don't spend API/CI on unfinished PRs).
# To add more trusted owners, extend the head-owner check.
#
# SECURITY-CRITICAL: this owner check is the ONLY thing that makes
# `allow-unsafe-pr-checkout: true` below acceptable. Without it, this
# pull_request_target job would check out and let Claude act on
# arbitrary fork code while holding base-repo secrets/token — a "pwn
# request". Do not remove or loosen this condition (e.g. drop the
# owner check, or allow non-owner forks) without re-evaluating the
# fork-checkout step's safety.
if: >-
github.event.pull_request.draft == false &&
github.event.pull_request.head.repo.owner.login == 'jnasbyupgrade'
Expand Down Expand Up @@ -78,12 +86,18 @@ jobs:
if: steps.gate.outputs.decision == 'run'
# Intentionally tracks the major-version tag (not a pinned SHA) so
# upstream fixes are picked up automatically.
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
repository: ${{ github.event.pull_request.head.repo.full_name }}
ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 1
persist-credentials: false
# Unsafe by default (actions/checkout refuses fork-PR checkouts
# under pull_request_target/workflow_run). Only OK here because
# the job is gated to the project owner's forks — see the `if:`
# on the `claude-review` job above; that check is what makes
# this safe.
allow-unsafe-pr-checkout: true

- name: Run Claude Code Review
if: steps.gate.outputs.decision == 'run'
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/claude.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
- name: Checkout repository
# Intentionally tracks the major-version tag (not a pinned SHA) so
# upstream fixes are picked up automatically.
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
fetch-depth: 1
persist-credentials: false
Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

After **every** push, monitor GitHub CI in a background subagent until all jobs pass or a failure is confirmed. Use `gh pr checks <pr> --watch` when the branch has an open PR; otherwise (a branch with no PR yet, or a push to `master`) use `gh run watch` for the pushed commit. Investigate and fix failures immediately rather than leaving them for the user to notice.

(`paths-ignore` in `.github/workflows/ci.yml` skips CI only when the *entire* change set is docs-only — e.g. a docs-only push to `master`, or a PR whose whole diff is `**.md`/`**.asc`. A docs-only commit on a PR that also touches code still triggers CI on the full PR diff. When unsure, check `gh run list` for the pushed commit and monitor whatever run appears; if none does, there is nothing to watch.)
(`.github/workflows/ci.yml`'s `changes` job computes the actual per-push changed file set and exposes `docs_only`; the heavy `test`, `pg-upgrade-test`, and `extension-update-test` jobs skip when `needs.changes.outputs.docs_only == 'true'` — i.e. every changed file in that push matches `**.md`/`**.asc`. Unlike the old workflow-level `paths-ignore`, this is evaluated per push/commit, not over the whole PR diff, so a doc-only commit on a PR that also touches code still gets the skip, and the workflow (including the required `all-checks-passed` check) always triggers and reports rather than being skipped outright by GitHub. When unsure, check `gh run list` for the pushed commit and monitor whatever run appears; if none does, there is nothing to watch.)

## Build/test system (pgxntool)

Expand Down
Loading