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
63 changes: 25 additions & 38 deletions .github/workflows/hooks-sync.yml
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
# Copyright 2026 ResQ Software
# SPDX-License-Identifier: Apache-2.0
#
# Validate canonical git hooks shipped from this repo:
# - shellcheck + bash-parse every hook and the installer
# - diff scripts/git-hooks/ against the embedded templates in
# resq-software/crates (crates/resq-cli/templates/git-hooks/) at master
# Validate the installer that ships canonical ResQ git hooks.
#
# The templates must be byte-identical — they are the single source of
# truth that installs into every ResQ repo.
# Canonical template content lives in resq-software/crates
# (crates/resq-cli/templates/git-hooks/). This repo no longer ships its own
# copy — install-hooks.sh prefers `resq dev install-hooks` when the binary
# is available, and falls back to fetching templates from the crates repo.
# So the only thing to validate here is the installer itself.

name: hooks-sync

on:
push:
branches: [main]
paths:
- 'scripts/git-hooks/**'
- 'scripts/install-hooks.sh'
- 'scripts/install-resq.sh'
- '.github/workflows/hooks-sync.yml'
pull_request:
paths:
- 'scripts/git-hooks/**'
- 'scripts/install-hooks.sh'
- 'scripts/install-resq.sh'
- '.github/workflows/hooks-sync.yml'
workflow_dispatch:

Expand All @@ -42,47 +42,34 @@ jobs:
run: |
shellcheck -S warning \
scripts/install-hooks.sh \
scripts/git-hooks/pre-commit \
scripts/git-hooks/commit-msg \
scripts/git-hooks/prepare-commit-msg \
scripts/git-hooks/pre-push \
scripts/git-hooks/post-checkout \
scripts/git-hooks/post-merge
scripts/install-resq.sh

- name: bash -n parse check
run: |
set -e
for f in scripts/install-hooks.sh scripts/git-hooks/pre-commit scripts/git-hooks/commit-msg scripts/git-hooks/prepare-commit-msg scripts/git-hooks/pre-push scripts/git-hooks/post-checkout scripts/git-hooks/post-merge; do
for f in scripts/install-hooks.sh scripts/install-resq.sh; do
bash -n "$f"
done

drift-check:
name: drift vs crates templates
smoke:
name: smoke — raw-fetch fallback path
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Fetch canonical templates from resq-software/crates@main
- name: Spin up a throwaway git repo and install hooks
run: |
mkdir -p /tmp/crates-templates
for h in pre-commit commit-msg prepare-commit-msg pre-push post-checkout post-merge; do
curl -fsSL \
"https://raw.githubusercontent.com/resq-software/crates/master/crates/resq-cli/templates/git-hooks/$h" \
-o "/tmp/crates-templates/$h"
done

- name: Diff against scripts/git-hooks/
run: |
rc=0
set -e
TMP="$(mktemp -d)"
cd "$TMP"
git init -q
git -c user.email=ci@example.com -c user.name=ci commit --allow-empty -q -m init
# Force the raw-fetch fallback by ensuring no `resq` on PATH.
env -i HOME="$HOME" PATH=/usr/bin:/bin \
bash "$GITHUB_WORKSPACE/scripts/install-hooks.sh" "$TMP"
ls -la "$TMP/.git-hooks/"
for h in pre-commit commit-msg prepare-commit-msg pre-push post-checkout post-merge; do
if ! diff -u "scripts/git-hooks/$h" "/tmp/crates-templates/$h"; then
echo "::error file=scripts/git-hooks/$h::drifts from resq-software/crates@master:crates/resq-cli/templates/git-hooks/$h"
rc=1
fi
test -x "$TMP/.git-hooks/$h" || { echo "missing: $h"; exit 1; }
bash -n "$TMP/.git-hooks/$h"
done
if [ "$rc" -ne 0 ]; then
echo "::error::Canonical hook templates in dev/ and crates/ must be byte-identical."
echo "::error::Sync them in both repos or retire one copy (Phase 4 of the hardening plan)."
exit 1
fi
echo "✅ All hook templates match crates/resq-cli/templates/git-hooks/"
[ "$(git -C "$TMP" config core.hooksPath)" = ".git-hooks" ]
19 changes: 14 additions & 5 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ scripts/
install-hooks.sh — Installs canonical git hooks into a repo (local or curl-piped)
install-hooks.ps1 — PowerShell mirror
install-resq.sh — Installs the `resq` CLI binary from GitHub Releases (SHA-verified)
git-hooks/ — Canonical hook shims (pre-commit, commit-msg, pre-push, …)
# Canonical hook templates are owned by resq-software/crates
# (crates/resq-cli/templates/git-hooks/). install-hooks.sh fetches them
# from there (or lets `resq dev install-hooks` scaffold offline). No copy
# lives in this repo.
lib/
log.{sh,ps1} — Colored log helpers
platform.{sh,ps1} — OS / arch detection, command_exists
Expand Down Expand Up @@ -58,10 +61,16 @@ shellcheck install.sh # Lint the bash script

## Git hooks

Canonical hooks live in `scripts/git-hooks/` and are installed into any ResQ
repo by `scripts/install-hooks.sh` (or `.ps1`). The hooks are thin shims that
delegate heavy lifting to the `resq` CLI binary from
[`resq-software/crates`](https://github.com/resq-software/crates):
Canonical hook templates live in
[`resq-software/crates`](https://github.com/resq-software/crates/tree/master/crates/resq-cli/templates/git-hooks)
and are installed into any ResQ repo by `scripts/install-hooks.sh` (or
`.ps1`). When the `resq` binary is on PATH, the installer calls
`resq dev install-hooks` which scaffolds from the embedded templates —
offline, no network round-trip. Without `resq`, it falls back to fetching
the templates from the crates repo via raw.githubusercontent.com.

The hooks are thin shims that delegate heavy lifting back to the `resq`
binary:

- `pre-commit` → `resq pre-commit` (copyright, secrets, audit, polyglot format)
- `commit-msg` → Conventional Commits + fixup/WIP guard on main/master
Expand Down
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,12 @@ Everything is pinned via Nix flakes. No "works on my machine" issues.

## ✅ Quality gates — canonical git hooks

Six hook shims live in [`scripts/git-hooks/`](scripts/git-hooks/) and ship with `install-hooks.sh`. They delegate logic to the [`resq`](https://github.com/resq-software/crates) binary so updates roll out via a `cargo install --git` (or `install-resq.sh`) instead of by editing every repo.
Six hook shims live in [`resq-software/crates`](https://github.com/resq-software/crates/tree/master/crates/resq-cli/templates/git-hooks) — embedded in the `resq` binary *and* served at a stable raw URL. `install-hooks.sh` picks the best path automatically:

1. **`resq` on PATH** → calls `resq dev install-hooks`, which scaffolds the 6 canonical hooks from the templates embedded in the binary. Offline, versioned with the installed `resq`.
2. **No `resq`** → falls back to `curl` from `resq-software/crates/master/.../templates/git-hooks/`.

The hooks delegate logic back to the `resq` binary (`resq pre-commit`, etc.), so updates roll out via `cargo install --git` (or `install-resq.sh`) without editing every repo.

| Hook | What it gates |
|---|---|
Expand All @@ -249,7 +254,7 @@ resq dev scaffold-local-hook --kind auto # detects rust/python/node/dotnet/cp

`resq hooks doctor` reports drift, `resq hooks update` re-syncs from the embedded canonical, `resq hooks status` prints a one-line shell-friendly summary.

The same content lives in three places (`scripts/git-hooks/` here, `crates/resq-cli/templates/git-hooks/` in the `resq` binary, `crates/.git-hooks/` in the crates repo). All three are kept byte-identical by `hooks-sync.yml` workflows in both `dev/` and `crates/`. Bats + Rust integration tests cover the hook behavior end-to-end.
The canonical content lives in exactly one place: [`crates/resq-cli/templates/git-hooks/`](https://github.com/resq-software/crates/tree/master/crates/resq-cli/templates/git-hooks). The crates repo's own `.git-hooks/` (for dog-fooding) is kept identical via `hooks-sync.yml`. The `dev/` repo used to ship a third copy and was retired in Phase 4 — `install-hooks.sh` now fetches from the crates source (or lets `resq dev install-hooks` do it offline). Bats + Rust integration tests cover the hook behavior end-to-end.

## 📄 License

Expand Down
53 changes: 0 additions & 53 deletions scripts/git-hooks/README.md

This file was deleted.

46 changes: 0 additions & 46 deletions scripts/git-hooks/commit-msg

This file was deleted.

30 changes: 0 additions & 30 deletions scripts/git-hooks/post-checkout

This file was deleted.

24 changes: 0 additions & 24 deletions scripts/git-hooks/post-merge

This file was deleted.

42 changes: 0 additions & 42 deletions scripts/git-hooks/pre-commit

This file was deleted.

Loading
Loading