Skip to content

chore(#111): upgrade pre-push-gate from advisory reminder to blocking check-runner#121

Merged
atlas-apex merged 2 commits into
devfrom
chore/GH-111-pre-push-gate-blocking
Apr 24, 2026
Merged

chore(#111): upgrade pre-push-gate from advisory reminder to blocking check-runner#121
atlas-apex merged 2 commits into
devfrom
chore/GH-111-pre-push-gate-blocking

Conversation

@atlas-apex

Copy link
Copy Markdown
Collaborator

Summary

Upgrades pre-push-gate.sh from an advisory reminder (prints a checklist and exits 0) to a blocking check-runner (reads a configured list of shell commands, executes them, blocks on red with exit 2).

The rule in .claude/rules/pr-workflow.md § Before git push (HARD STOP) has always said "Never push without running CI checks locally." The old hook printed a reminder, so the mechanical enforcement didn't actually match the written rule. This PR closes that asymmetry.

  • Hook now reads .pre_push.commands from project config (shared reader from [Chore] Make ticket-prefix whitelist + schema project-configurable (not hardcoded) #109) and runs each entry's run field in sequence.
  • First non-zero exit blocks the push; the failing command name + last 20 lines of output go to stderr.
  • Shipped default is an empty command list — hook stays a no-op until a fork opts in by defining its checks. (Deliberate: the framework repo itself doesn't have lint/test/build to run; each fork wires its own CI per its stack.)
  • Emergency bypass: <!-- pre-push: skip --> in the HEAD commit message. Grep-able on purpose so bypasses are auditable.
  • Fail-fast: once a command fails, subsequent commands don't run. Parallel execution is a polish-level follow-up.

Changed files:

  • .claude/hooks/pre-push-gate.sh — rewritten
  • .claude/hooks/tests/test_pre_push_gate.sh — new, 7 cases
  • .claude/project-config.defaults.json — added pre_push.commands subtree (empty by default)
  • docs/rule-audit.md — flipped "Before git push" rule from "partial" to "yes" + updated the footnote

Testing

$ bash .claude/hooks/tests/test_pre_push_gate.sh
PASS [non-git-push-silent]
PASS [empty-commands-noop]
PASS [passing-command]
PASS [failing-command-blocks]
PASS [skip-marker-bypasses]
PASS [fail-fast-on-first-red]
PASS [no-config-noop]
PASS: 7   FAIL: 0

Also dogfood: this very PR was pushed through the upgraded hook. Since the framework repo has no configured .pre_push.commands in its defaults file, the gate exits 0 silently — proving the "empty-commands-noop" path works end-to-end against the apexyard repo itself.

What a per-fork override looks like

Minimal example in a fork's .claude/project-config.json:

{
  "pre_push": {
    "commands": [
      { "name": "lint",      "run": "npm run lint" },
      { "name": "typecheck", "run": "npm run typecheck" },
      { "name": "test",      "run": "npm run test" },
      { "name": "build",     "run": "npm run build" }
    ]
  }
}

Teams on yarn, pnpm, make, cargo, go, mix and so on all configure here — the hook doesn't care about the package manager. The command runs in a sub-shell rooted at the repo top-level.

Scope — what this does NOT do

  • No change to the shipped default command set. Adopters opt in per-fork; the framework itself stays no-op. Changing the shipped default is a separate call.
  • No parallel execution. Fail-fast sequential is the v1. If fork owners report the time cost is painful, add a parallel: true flag in a follow-up.
  • No change to pre-push-gate.sh's matcher wiring in .claude/settings.json — same matcher, new behaviour.

Follow-ups

  • Parallel execution within a command group (lint + typecheck can usually run in parallel).
  • Richer command spec (e.g. run_if_exists: "package.json" to skip on repos without that file).
  • Deprecation warning on the legacy flat commit_types key in validate-commit-format.sh (noted in AgDR-0006 as a deferred item).

Glossary

Term Definition
Pre-push gate The hook that fires on Bash commands matching git push. Enforces the HARD STOP rule that local checks must pass before pushing.
Skip marker A literal token in the HEAD commit message that lets a single push through without running checks. Leaves a grep-able trace.
Fail-fast The first non-zero command aborts the whole gate. The alternative (run all, aggregate) is a follow-up.

Closes #111

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants