diff --git a/.github/workflows/CLAUDE.md b/.github/workflows/CLAUDE.md index 48c749c..1d5a6f0 100644 --- a/.github/workflows/CLAUDE.md +++ b/.github/workflows/CLAUDE.md @@ -21,6 +21,16 @@ When a maintainer applies the `commit-with-no-tests` label (and no paired test P exists), the `test` job runs tests directly in pgxntool CI against pgxntool-test/master. This is the rare exception, not the norm. +## Doc-only bypass + +`check-test-pr` checks this first, before the paired-test-PR lookup or the +`commit-with-no-tests` label: if every changed file in the PR is pure +documentation (`*.md`, `*.asc`, `*.adoc`, `*.asciidoc`, anywhere including +under `.claude/`, but never under `.github/` — workflow definitions carry +real behavioral weight regardless of extension), it skips both the paired +branch requirement and the `test` job entirely. `claude-code-review.yml` is +a separate workflow gated by its own `if:` and always still runs. + ## Cross-repo reusable workflow — tradeoffs and constraints The `test` job calls a reusable workflow from pgxntool-test: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9e3ce90..ba0fe56 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -48,6 +48,48 @@ jobs: // (YAML expressions can't reference JS constants). const NO_TEST_LABEL = 'commit-with-no-tests'; + // DOC-ONLY BYPASS: skip both the paired-test-PR requirement and + // the actual Postgres test run when every changed file is pure + // documentation. This is independent of, and takes priority + // over, everything below — a doc-only PR needs neither a paired + // branch nor the NO_TEST_LABEL override. + // + // Files under .github/ are never doc-only even if their + // extension matches (they're workflow definitions with real + // behavioral weight, some running with pull_request_target + // privileges). Everything else — including .claude/*.md prompt + // and command docs, which carry no execution weight themselves + // — counts. + // + // This does NOT skip claude-review: that's a separate workflow + // gated by its own `if:`, unaffected by this check's outputs. + const DOC_EXTENSIONS = /\.(md|asc|adoc|asciidoc)$/i; + const changedFiles = await github.paginate(github.rest.pulls.listFiles, { + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: prNumber, + per_page: 100 + }); + // Check both filename and previous_filename: a rename like + // src/foo.sql -> docs/foo.md must not read as doc-only just + // because the new name matches — the old path is a real change. + const changedPaths = changedFiles.flatMap(f => + f.previous_filename ? [f.filename, f.previous_filename] : [f.filename] + ); + const isDocOnly = changedPaths.length > 0 && changedPaths.every(p => + DOC_EXTENSIONS.test(p) && !p.startsWith('.github/') + ); + if (isDocOnly) { + core.info( + `All ${changedFiles.length} changed file(s) are documentation-only ` + + `(matched ${DOC_EXTENSIONS}, none under .github/); skipping the ` + + `paired-test-PR requirement and the Postgres test matrix.` + ); + core.setOutput('run_tests', 'false'); + core.setOutput('test_ref', ''); + return; + } + // master-to-master PRs have no paired test PR by convention. // Run tests against pgxntool-test/master directly. //