From 8c6fe725141a3e45a7c6797408d5904f08304324 Mon Sep 17 00:00:00 2001 From: Cyrus Omar Date: Mon, 27 Apr 2026 16:57:52 +0100 Subject: [PATCH 1/2] Add pre-commit hook for autoformatting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stored under scripts/git-hooks/ and installed via core.hooksPath. Hook runs `dune fmt --auto-promote` and re-stages any of the originally-staged files that the formatter touched, so commits never contain unformatted code. Files that weren't staged are left alone, even if the formatter modified them — so unrelated unstaged WIP doesn't get swept into the commit. Wired install-hooks into deps/dev so existing developers pick up the hook on their next make invocation. --- Makefile | 14 ++++++++++---- scripts/git-hooks/pre-commit | 16 ++++++++++++++++ 2 files changed, 26 insertions(+), 4 deletions(-) create mode 100755 scripts/git-hooks/pre-commit diff --git a/Makefile b/Makefile index 802a66945d..6b55fb168d 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,16 @@ HTML_DIR="$(shell pwd)/_build/default/src/web/www" SERVER="http://0.0.0.0:8000/" -.PHONY: all deps change-deps setup-instructor setup-student dev dev-helper dev-student fmt watch watch-release release release-student echo-html-dir serve serve2 repl test clean setup-zarith +.PHONY: all deps change-deps setup-instructor setup-student dev dev-helper dev-student fmt watch watch-release release release-student echo-html-dir serve serve2 repl test clean setup-zarith install-hooks all: dev +install-hooks: + @if [ "$$(git config --get core.hooksPath)" != "scripts/git-hooks" ]; then \ + git config core.hooksPath scripts/git-hooks; \ + echo "Installed git hooks (core.hooksPath -> scripts/git-hooks)."; \ + fi + # Install native BigInt runtime for zarith_stubs_js to fix WebWorker postMessage serialization. # The vendored runtime.js uses native JS BigInt (from zarith_stubs_js v0.17.0) which survives # structured clone, unlike the BigInteger.js library used in older versions. @@ -12,7 +18,7 @@ setup-zarith: @echo "Installing native BigInt zarith runtime..." @cp vendor/zarith_native_bigint_runtime.js "$$(opam var lib)/zarith_stubs_js/runtime.js" -deps: +deps: install-hooks opam repo add archive git+https://github.com/ocaml/opam-repository-archive opam update opam install ./hazel.opam.locked --deps-only --with-test --with-doc @@ -36,9 +42,9 @@ dev-helper: setup-zarith dune fmt --auto-promote || true dune build @ocaml-index @src/fmt --auto-promote src --profile dev -dev: setup-instructor dev-helper +dev: install-hooks setup-instructor dev-helper -dev-student: setup-student dev-helper +dev-student: install-hooks setup-student dev-helper fmt: dune fmt --auto-promote diff --git a/scripts/git-hooks/pre-commit b/scripts/git-hooks/pre-commit new file mode 100755 index 0000000000..0438473c7e --- /dev/null +++ b/scripts/git-hooks/pre-commit @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -u + +# Capture which files are staged for this commit. After running the formatter, +# we'll re-add these (and only these) so the commit picks up any formatting +# fixes — without sweeping in unrelated unstaged changes the developer may have. +staged=$(git diff --cached --name-only --diff-filter=ACMR) + +echo "[pre-commit] dune fmt --auto-promote" +dune fmt --auto-promote || true + +if [ -n "$staged" ]; then + while IFS= read -r f; do + [ -e "$f" ] && git add -- "$f" + done <<<"$staged" +fi From e4396c2f35ee98b521c69f0bf69c620269d87760 Mon Sep 17 00:00:00 2001 From: Cyrus Omar Date: Mon, 27 Apr 2026 17:19:05 +0100 Subject: [PATCH 2/2] Limit hook auto-install to make deps; document in README & CONTRIBUTING MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move install-hooks off make dev / dev-student — it only needs to run during initial setup. Add a Git Hooks section to CONTRIBUTING.md and a one-line pointer in README.md so contributors know what make deps is wiring up. --- CONTRIBUTING.md | 8 ++++++++ Makefile | 4 ++-- README.md | 2 ++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5fe81e87ee..bff1205e2d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -79,6 +79,14 @@ The `make dev` and `make release` commands do three things: 4. Compile the OCaml bytecode to JavaScript (`_build/default/src/hazelweb/www/hazel.js`) using `js_of_ocaml`. +## Git Hooks + +`make deps` installs a `pre-commit` hook (under `scripts/git-hooks/`) by setting `core.hooksPath`. On every commit the hook runs `dune fmt --auto-promote` and re-stages any of the *staged* files the formatter touched, so commits never contain unformatted code. + +- Files you didn't stage are left alone, even if the formatter modifies them — your unrelated unstaged WIP won't be swept into the commit. +- If you ever need to bypass the hook (e.g. to share a WIP refactor that you don't want autoformatted yet), pass `--no-verify` to `git commit`. +- If your clone predates this and the hook isn't running, run `make deps` (or `make install-hooks`) once to install it. + ## Live Building For a smoother dev experience, use `make watch` rather than `make dev` to automatically watch for file changes and rebuild immediately. You can also run `make watch-release` to continuously build the release diff --git a/Makefile b/Makefile index 6b55fb168d..3c0234a7df 100644 --- a/Makefile +++ b/Makefile @@ -42,9 +42,9 @@ dev-helper: setup-zarith dune fmt --auto-promote || true dune build @ocaml-index @src/fmt --auto-promote src --profile dev -dev: install-hooks setup-instructor dev-helper +dev: setup-instructor dev-helper -dev-student: install-hooks setup-student dev-helper +dev-student: setup-student dev-helper fmt: dune fmt --auto-promote diff --git a/README.md b/README.md index 23f8fce8e8..4360f257fe 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,8 @@ If you already have `ocaml` version 5.2.0, at least version 2.0 of `opam`, and a - `make deps` - `make dev` +`make deps` also installs a pre-commit git hook that auto-formats your staged code on every commit. See [CONTRIBUTING.md](CONTRIBUTING.md#git-hooks) for details. + ### Long Version If the above pre-requisites don't apply, please follow the step-by-step installation instructions contained in [INSTALL.md](INSTALL.md).