1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
|
#!/bin/sh
# Format the Python being committed, so what lands in git is already formatted.
# Imports sorted, then laid out -- both by ruff (ruff.toml pins the version).
#
# Install with `git config core.hooksPath .githooks`. Hooks are not versioned
# by git, so a hook in a repo has to be a file somebody opts into -- there is
# no way to ship one that runs on clone, and a repo that could would be a repo
# that runs code on clone.
#
# Skip a commit with `git commit --no-verify` when you mean to.
set -e
py_files=$(git diff --cached --name-only --diff-filter=ACMR | grep -E '\.py$' || true)
[ -n "$py_files" ] || exit 0
# Where ruff is. The repo-local venv first, before $PATH: ruff.toml pins a
# version, and a system ruff of the wrong one would refuse the commit while
# the venv sitting right there has the version it asked for. Off the toplevel,
# so this works from a subdirectory.
root=$(git rev-parse --show-toplevel)
if [ -x "$root/.venv/bin/ruff" ]; then
ruff="$root/.venv/bin/ruff"
else
ruff=$(command -v ruff 2>/dev/null || true)
fi
if [ -z "$ruff" ]; then
echo "pre-commit: ruff is not installed, and this commit touches Python." >&2
echo " uv sync --extra dev (a venv in .venv, version pinned)" >&2
echo " ...or commit with --no-verify if you know what you are doing." >&2
exit 1
fi
# A file with unstaged changes is the one case where formatting in place is
# dangerous: the formatter rewrites the *working tree*, and re-staging
# afterwards would commit work that was deliberately left out of the index.
# So say so and stop, rather than quietly widening a commit somebody built
# with `git add -p`.
partial=""
for f in $py_files; do
if ! git diff --quiet -- "$f"; then partial="$partial $f"; fi
done
if [ -n "$partial" ]; then
echo "pre-commit: these files are only partly staged, so formatting them" >&2
echo " in place would add work you left out of the commit:" >&2
for f in $partial; do echo " $f" >&2; done
echo " stage them fully, stash the rest, or use --no-verify." >&2
exit 1
fi
cd "$root"
"$ruff" check --select I --fix --quiet $py_files
"$ruff" format --quiet $py_files
git add $py_files
|