From b0180e5368bbd722d4177bc94c218f435b8440b5 Mon Sep 17 00:00:00 2001 From: Aryan Jasala Date: Fri, 6 Nov 2026 05:03:03 +0530 Subject: [PATCH 1/3] feat: add a ci-result check and stop repeating check names wp-ci.yml gains a ci-result job, shown as " / CI result": one stable check to require in branch protection. It needs every other job, runs even when they fail or are skipped, and fails if any of them failed or was cancelled, so a skipped job still counts as passing but a broken one does not. The leaves' job names no longer repeat the caller's: the test-php matrix job is "Test PHP " or "Test PHP , WP ", and the build, artifact-gate, detect-changes and lint-php jobs drop their duplicated prefixes. No known caller requires a wp-ci check by name today; ci-result is the one to require from now on. --- .github/workflows/ci-build-artifact-gate.yml | 2 +- .github/workflows/ci-build.yml | 2 +- .github/workflows/ci-detect-changes.yml | 2 +- .github/workflows/ci-lint-php.yml | 2 +- .github/workflows/wp-ci.yml | 42 +++++++++++++++++++- README.md | 10 +++++ 6 files changed, 55 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci-build-artifact-gate.yml b/.github/workflows/ci-build-artifact-gate.yml index d648994..ff75af0 100644 --- a/.github/workflows/ci-build-artifact-gate.yml +++ b/.github/workflows/ci-build-artifact-gate.yml @@ -21,7 +21,7 @@ permissions: jobs: build-artifact-gate: - name: Block committed build artifacts + name: Check gated paths runs-on: ${{ fromJSON(inputs.runs-on) }} steps: - name: Checkout repository diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml index ae2f855..f83ad0a 100644 --- a/.github/workflows/ci-build.yml +++ b/.github/workflows/ci-build.yml @@ -59,7 +59,7 @@ permissions: jobs: build: - name: Build + name: Production build runs-on: ${{ fromJSON(inputs.runs-on) }} defaults: run: diff --git a/.github/workflows/ci-detect-changes.yml b/.github/workflows/ci-detect-changes.yml index 5585c56..3c57efe 100644 --- a/.github/workflows/ci-detect-changes.yml +++ b/.github/workflows/ci-detect-changes.yml @@ -70,7 +70,7 @@ permissions: jobs: detect: - name: Detect changes + name: Bucket changed files runs-on: ${{ fromJSON(inputs.runs-on) }} outputs: # css/js/php come from the scope step; total/ignored/gha stay repo-wide on detect. diff --git a/.github/workflows/ci-lint-php.yml b/.github/workflows/ci-lint-php.yml index 31201cf..048b5f8 100644 --- a/.github/workflows/ci-lint-php.yml +++ b/.github/workflows/ci-lint-php.yml @@ -51,7 +51,7 @@ permissions: jobs: lint-php: - name: Lint PHP + name: ${{ inputs.enable-phpstan && 'PHPCS + PHPStan' || 'PHPCS' }} runs-on: ${{ fromJSON(inputs.runs-on) }} defaults: run: diff --git a/.github/workflows/wp-ci.yml b/.github/workflows/wp-ci.yml index def8020..de00d25 100644 --- a/.github/workflows/wp-ci.yml +++ b/.github/workflows/wp-ci.yml @@ -323,7 +323,8 @@ jobs: working-dir: ${{ needs.validate-inputs.outputs.working-dir }} test-php: - name: Test PHP + # Named explicitly: GitHub's default suffix for this matrix renders as "(8.3, )". + name: Test PHP ${{ matrix.php }}${{ matrix.wp != '' && format(', WP {0}', matrix.wp) || '' }} needs: [validate-inputs, detect-changes] if: >- (needs.detect-changes.outputs.php-count > 0 || needs.detect-changes.outputs.gha-count > 0) @@ -421,3 +422,42 @@ jobs: runs-on: ${{ inputs.runs-on }} gated-paths: ${{ inputs.gated-paths }} working-dir: ${{ needs.validate-inputs.outputs.working-dir }} + + # The one check to require in branch protection: " / CI result". The other check + # names and their count change with project-type, skip, what changed and the PHP matrix, and a + # skipped required check counts as passing. Runs on always(), so a failed, cancelled or + # never-started job fails it, while a job skipped by its own gate does not. + ci-result: + name: CI result + needs: + - validate-inputs + - detect-changes + - lint-css + - lint-js + - lint-php + - test-js + - test-php + - build + - build-artifact + - a11y + - artifact-gate + if: always() + runs-on: ${{ fromJSON(inputs.runs-on) }} + steps: + - name: Check every job's result + shell: bash + env: + NEEDS: ${{ toJSON(needs) }} + run: | + set -euo pipefail + { + echo "| Job | Result |" + echo "|---|---|" + jq -r 'to_entries[] | "| `\(.key)` | \(.value.result) |"' <<< "$NEEDS" + } >> "$GITHUB_STEP_SUMMARY" + bad="$(jq -r 'to_entries[] | select(.value.result != "success" and .value.result != "skipped") | "\(.key) (\(.value.result))"' <<< "$NEEDS")" + if [ -n "$bad" ]; then + echo "::error::CI did not pass: $(printf '%s' "$bad" | paste -sd ',' - | sed 's/,/, /g')." + exit 1 + fi + echo "Every job passed or was skipped by its own gate." diff --git a/README.md b/README.md index 2817217..4843836 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,16 @@ Node comes from `.nvmrc` in `working-dir`, then the repository root, falling bac `node-version` to override it. `wp-ci.yml` also forwards `php-version`, the Composer settings and a `*-command` input per job, each falling back to that job's default when left empty. +### Branch protection + +Require one check per `wp-ci.yml` call: ` / CI result`, for example +`CI / CI result`, or `plugins/acme-blocks / CI result` for each unit of the matrix in +[`examples/wp-ci.yml`](examples/wp-ci.yml). It fails when any job failed, was cancelled or never +started, and passes when every job passed or was skipped by its own gate. Don't require the other +checks: which of them run, and their names, change with `project-type`, `skip`, the PHP matrix and +what a pull request touched, and a required check that never reports leaves the pull request +waiting forever. + ## Workflows Each workflow declares its inputs, secrets and outputs in its own `workflow_call` block, and GitHub From 37a6a6b6a86d67e069b9e4958c4cf02067655e14 Mon Sep 17 00:00:00 2001 From: Aryan Jasala Date: Fri, 6 Nov 2026 05:52:17 +0530 Subject: [PATCH 2/3] docs: list the renamed checks and the rule for renaming them AGENTS.md now matches what this change does: a renamed job name is feat when a code search finds no caller requiring the old check, with that evidence in the PR body, and feat! otherwise. The README lists each old and new check name, and says that a calling job with its own if: reports no CI result when it is skipped. --- AGENTS.md | 2 +- README.md | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index 5576e20..5fe6e14 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -129,6 +129,6 @@ Use `bash -eo pipefail -c`, never bare `bash -c`: `-e` is not inherited, so a ba ## PR instructions - GitHub flow: branch off `main`, PR back into `main`. A release is a tag on `main` that release-please cuts. Name branches `/` (`fix/runs-on-input`). Never commit to `main` directly. -- [Conventional Commits](https://www.conventionalcommits.org/) for the PR title, typed by what changes for callers: `fix:` or `feat:` for any change to a reusable workflow, and `feat!:` for anything a caller has to change for (a removed, renamed or newly required input, a new `permissions:` entry, a renamed job `name:`). `docs:` and `chore:` (e.g. `chore(self-check): ...`) are only for this repo's own files and don't cut a release. `ci:` isn't accepted here: nearly everything in this repo is CI, so the title check makes the choice explicit. Example: `feat(lint-css): Add lint-css workflow`. +- [Conventional Commits](https://www.conventionalcommits.org/) for the PR title, typed by what changes for callers: `fix:` or `feat:` for any change to a reusable workflow, and `feat!:` for anything a caller has to change for (a removed, renamed or newly required input, a new `permissions:` entry). A renamed job `name:` changes a check name callers may require: it is `feat:` when a code search finds no caller requiring the old name, with that evidence in the PR body and the old and new names in the README's "Renamed checks" list, and `feat!:` otherwise. `docs:` and `chore:` (e.g. `chore(self-check): ...`) are only for this repo's own files and don't cut a release. `ci:` isn't accepted here: nearly everything in this repo is CI, so the title check makes the choice explicit. Example: `feat(lint-css): Add lint-css workflow`. - Ensure the Code quality commands pass, the caller example is updated alongside the workflow, and the PR title says what changed for a consumer — see `CONTRIBUTING.md` for the full checklist. - Ask first before removing or renaming an input, adding a deploy target, or granting a job `contents: write` it does not already need. diff --git a/README.md b/README.md index 5433740..5270f46 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,25 @@ checks: which of them run, and their names, change with `project-type`, `skip`, what a pull request touched, and a required check that never reports leaves the pull request waiting forever. +`CI result` only exists when the calling job runs. A calling job with its own `if:` that skips +reports no `CI result`, so a repository that gates the call needs its own always-running aggregate +job, or should not require `CI result`. + +#### Renamed checks + +Check names come from job names, so a rename changes what a ruleset must require. Since v1.2.0: + +| Workflow | Old check name | New check name | +|---|---|---| +| `ci-lint-php.yml` | `Lint PHP` | `PHPCS`, or `PHPCS + PHPStan` with `enable-phpstan` | +| `ci-build.yml` | `Build` | `Production build` | +| `ci-detect-changes.yml` | `Detect changes` | `Bucket changed files` | +| `ci-build-artifact-gate.yml` | `Block committed build artifacts` | `Check gated paths` | +| `wp-ci.yml` (`test-php` matrix) | `Test PHP`, the same for every leg | `Test PHP `, or `Test PHP , WP ` | + +Called through `wp-ci.yml`, each appears after the `wp-ci.yml` job, for example +`CI / Lint PHP / PHPCS`; called directly, after the caller's job, for example `lint / PHPCS`. + ## Workflows Each workflow declares its inputs, secrets and outputs in its own `workflow_call` block, and GitHub From c67a496b479091c08c57a12d0def55eaa3a23197 Mon Sep 17 00:00:00 2001 From: Aryan Jasala Date: Fri, 6 Nov 2026 05:52:40 +0530 Subject: [PATCH 3/3] docs: give the old test-php check name as GitHub's default matrix name --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5270f46..58b9689 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ Check names come from job names, so a rename changes what a ruleset must require | `ci-build.yml` | `Build` | `Production build` | | `ci-detect-changes.yml` | `Detect changes` | `Bucket changed files` | | `ci-build-artifact-gate.yml` | `Block committed build artifacts` | `Check gated paths` | -| `wp-ci.yml` (`test-php` matrix) | `Test PHP`, the same for every leg | `Test PHP `, or `Test PHP , WP ` | +| `wp-ci.yml` (`test-php` matrix) | `Test PHP (, )`, GitHub's default, e.g. `Test PHP (8.3, )` | `Test PHP `, or `Test PHP , WP ` | Called through `wp-ci.yml`, each appears after the `wp-ci.yml` job, for example `CI / Lint PHP / PHPCS`; called directly, after the caller's job, for example `lint / PHPCS`.