Skip to content

Commit d43c9f6

Browse files
TMHSDigitalclaude
andcommitted
ci: require the test suite and check the squash PR title for VERSION bumps
The pytest job ("Run drift_check tests") is now a required status check in the main protection ruleset, so a PR with failing tests for the fleet-wide checker cannot merge. version-bump-check also evaluates the PR title, which becomes the commit subject on squash merge, and re-runs on title edits. A "feat:" titled PR built from chore commits now needs a VERSION bump (or [skip version]). Docs list the 8 required checks. Closes #119 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: TMHSDigital <154358121+TMHSDigital@users.noreply.github.com>
1 parent f9106e8 commit d43c9f6

4 files changed

Lines changed: 26 additions & 9 deletions

File tree

‎.github/workflows/README.md‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ Current rules:
6464
| Force pushes | Blocked (`non_fast_forward` rule) |
6565
| Branch deletion | Blocked (`deletion` rule) |
6666

67-
Required status checks (a PR cannot merge until all 7 pass):
67+
Required status checks (a PR cannot merge until all 8 pass):
6868

6969
- `Validate registry.json`
7070
- `Validate docs site`
@@ -73,6 +73,7 @@ Required status checks (a PR cannot merge until all 7 pass):
7373
- `Public-repo safety scan`
7474
- `feat/fix commits require VERSION bump`
7575
- `CodeQL`
76+
- `Run drift_check tests` (the full pytest suite)
7677

7778
Post-merge guard (not in required-contexts): `release.yml`'s `Check VERSION vs latest tag` job runs on every push to `main` and fails the release if `VERSION` is behind the latest tag. It is intentionally excluded from the PR-required list because it cannot run on a PR (`release.yml` only triggers on push), and including it would permanently block every PR.
7879

‎.github/workflows/validate.yml‎

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ name: Validate
33
on:
44
pull_request:
55
branches: [main]
6+
# edited: re-check when the PR title changes (version-bump-check).
7+
types: [opened, synchronize, reopened, edited]
68
push:
79
branches: [main]
810

@@ -270,6 +272,9 @@ jobs:
270272
env:
271273
BASE_SHA: ${{ github.event.pull_request.base.sha }}
272274
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
275+
# Squash merges use the PR title as the commit subject on main,
276+
# so the title is checked like a commit (DTD#119).
277+
PR_TITLE: ${{ github.event.pull_request.title }}
273278
run: |
274279
set -euo pipefail
275280
@@ -281,12 +286,21 @@ jobs:
281286
# record separator (\x1e Record Separator) was already safe.
282287
COMMITS="$(git log "${BASE_SHA}..${HEAD_SHA}" --pretty=format:'%H%x1f%s%x1f%b%x1e')"
283288
284-
if [ -z "$COMMITS" ]; then
289+
NEEDS_BUMP="false"
290+
if echo "$PR_TITLE" | grep -qF '[skip version]'; then
291+
echo "skip | PR title | $PR_TITLE (opted out with [skip version])"
292+
elif echo "$PR_TITLE" | grep -qiE '^(feat|fix)(\([^)]*\))?!?:'; then
293+
echo "need | PR title | $PR_TITLE"
294+
NEEDS_BUMP="true"
295+
else
296+
echo "ok | PR title | $PR_TITLE"
297+
fi
298+
299+
if [ -z "$COMMITS" ] && [ "$NEEDS_BUMP" = "false" ]; then
285300
echo "No new commits to check."
286301
exit 0
287302
fi
288303
289-
NEEDS_BUMP="false"
290304
while IFS= read -r -d $'\x1e' record; do
291305
[ -z "$record" ] && continue
292306
SHA="$(echo "$record" | awk -F $'\x1f' '{print $1}')"

‎CLAUDE.md‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ gh pr checks <number> --watch
118118
gh pr merge <number> --squash --delete-branch
119119
```
120120

121-
A PR cannot be merged until all 7 required status checks pass: `Validate registry.json`, `Validate docs site`, `Validate scaffold`, `Registry sync check`, `Public-repo safety scan`, `feat/fix commits require VERSION bump`, `CodeQL`. Required approvals are 0 (solo maintainer). `release.yml`'s `Check VERSION vs latest tag` is a post-merge guard, not a PR gate.
121+
A PR cannot be merged until all 8 required status checks pass: `Validate registry.json`, `Validate docs site`, `Validate scaffold`, `Registry sync check`, `Public-repo safety scan`, `feat/fix commits require VERSION bump`, `CodeQL`, `Run drift_check tests`. Required approvals are 0 (solo maintainer). `release.yml`'s `Check VERSION vs latest tag` is a post-merge guard, not a PR gate.
122122

123123
### Prerequisites
124124

@@ -151,7 +151,8 @@ Open `docs/index.html` in a browser. The script falls back to embedded registry
151151
- Scaffold dry-run test (generates repo, verifies key files exist, scans for leaked business email)
152152
- `sync-check` job: runs `python scripts/sync_from_registry.py --check` and fails on drift
153153
- `safety-scan` job: blocks leaked business emails, drive-letter paths, unsafe DOM sinks (`innerHTML`/`eval` in `docs/`), and committed credential files
154-
- `version-bump-check` job (PR only): requires a `VERSION` bump when the PR contains any `feat:` or `fix:` commit; opt out per commit with `[skip version]`
154+
- `version-bump-check` job (PR only): requires a `VERSION` bump when the PR title or any commit is `feat:` or `fix:` (the title matters because squash merges use it as the commit subject); opt out with `[skip version]`
155+
- `test-drift-check` job: runs the full pytest suite (required check `Run drift_check tests`)
155156

156157
### Release workflow
157158

‎CONTRIBUTING.md‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ Where `$TOOLS_ROOT` is the parent directory containing your checkouts of each to
254254

255255
- Required approvals: 0 (solo-maintainer repo).
256256
- Merge method: squash merge only; merge commits and rebase merges are blocked.
257-
- All 7 required status checks listed under [CI checks](#ci-checks) must pass before merge is allowed.
257+
- All 8 required status checks listed under [CI checks](#ci-checks) must pass before merge is allowed.
258258

259259
### Branch naming
260260

@@ -307,15 +307,16 @@ Before submitting a PR, verify:
307307

308308
### CI checks
309309

310-
All PRs must pass these 7 required status checks (enforced by the `main protection` ruleset, not just advisory):
310+
All PRs must pass these 8 required status checks (enforced by the `main protection` ruleset, not just advisory):
311311

312312
- `Validate registry.json` - JSON schema and required fields
313-
- `Validate docs site` - `docs/index.html`, `style.css`, `script.js` exist
313+
- `Validate docs site` - `docs/index.html` exists
314314
- `Validate scaffold` - Python syntax and scaffold dry-run
315315
- `Registry sync check` - `scripts/sync_from_registry.py --check` exits 0
316316
- `Public-repo safety scan` - no leaked emails, drive paths, unsafe DOM sinks, or committed secrets
317-
- `feat/fix commits require VERSION bump` - enforces the rule in the Versioning section
317+
- `feat/fix commits require VERSION bump` - enforces the rule in the Versioning section, checking the PR title (the squash commit subject) as well as each commit
318318
- `CodeQL` - security scan on Python code
319+
- `Run drift_check tests` - the full pytest suite under `tests/`
319320

320321
`release.yml`'s `Check VERSION vs latest tag` runs on every push to `main` and will fail the release if `VERSION` is behind the latest tag. It is a post-merge guard, not a PR gate, so it is not in the required-contexts list.
321322

0 commit comments

Comments
 (0)