Skip to content

Commit caf086c

Browse files
Add lintrunner pre-commit hook (#18689)
1 parent fcccda3 commit caf086c

8 files changed

Lines changed: 129 additions & 76 deletions

File tree

.githooks/README.md

Lines changed: 33 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,63 @@
11
# Git Hooks
22

3-
This directory contains Git hooks for the ExecuTorch repository.
3+
This directory contains Git hooks for the ExecuTorch repository. It is used as
4+
`core.hooksPath`, so git looks here instead of `.git/hooks/`.
45

5-
## Pre-commit Hook
6+
## Hooks
67

7-
The pre-commit hook automatically updates the PyTorch commit pin in `.ci/docker/ci_commit_pins/pytorch.txt` whenever `torch_pin.py` is modified.
8+
### pre-commit
89

9-
### How It Works
10+
Runs on every commit:
1011

11-
1. When you commit changes to `torch_pin.py`, the hook detects the change
12-
2. It parses the `NIGHTLY_VERSION` field (e.g., `dev20251004`)
13-
3. Converts it to a date string (e.g., `2025-10-04`)
14-
4. Fetches the corresponding commit hash from the PyTorch nightly branch at https://github.com/pytorch/pytorch/tree/nightly
15-
5. Updates `.ci/docker/ci_commit_pins/pytorch.txt` with the new commit hash
16-
6. Automatically stages the updated file for commit
12+
1. **torch_pin sync** — when `torch_pin.py` is staged, updates the PyTorch commit
13+
pin in `.ci/docker/ci_commit_pins/pytorch.txt` and syncs grafted c10 files.
14+
2. **lintrunner** — runs `lintrunner -a --revision HEAD^ --skip MYPY` on changed
15+
files. Auto-fixes formatting and blocks on lint errors. Soft-fails if lintrunner
16+
is not installed. Runs `lintrunner init` automatically when `.lintrunner.toml`
17+
changes.
1718

18-
### Installation
19+
### pre-push
1920

20-
To install the Git hooks, run:
21+
Delegates to `.git/hooks/pre-push` if one exists. This allows backend-specific
22+
pre-push hooks (e.g., ARM's license and commit message checks) to work alongside
23+
the repo-wide hooks.
24+
25+
## Installation
26+
27+
Hooks are installed automatically by `./install_executorch.sh`.
28+
29+
To install manually:
2130

2231
```bash
23-
.githooks/install.sh
32+
git config core.hooksPath .githooks
2433
```
2534

26-
This will copy the pre-commit hook to `.git/hooks/` and make it executable.
35+
### ARM backend pre-push
2736

28-
### Manual Usage
29-
30-
You can also run the update script manually at any time:
37+
ARM contributors should additionally install the ARM-specific pre-push hook:
3138

3239
```bash
33-
python .github/scripts/update_pytorch_pin.py
40+
cp backends/arm/scripts/pre-push .git/hooks/
3441
```
3542

36-
### Uninstalling
43+
## Bypassing
3744

38-
To remove the pre-commit hook:
45+
To skip hooks for a single commit or push:
3946

4047
```bash
41-
rm .git/hooks/pre-commit
48+
git commit --no-verify
49+
git push --no-verify
4250
```
4351

4452
## Troubleshooting
4553

46-
If the hook fails during a commit:
54+
If the torch_pin hook fails:
4755

4856
1. Check that Python 3 is available in your PATH
4957
2. Ensure you have internet connectivity to fetch commits from GitHub
5058
3. Verify that the `NIGHTLY_VERSION` in `torch_pin.py` is in the correct format (`devYYYYMMDD`)
51-
4. Make sure the corresponding nightly release exists in the PyTorch nightly branch
5259

53-
You can run the script manually to see detailed error messages:
60+
If lintrunner fails:
5461

55-
```bash
56-
python .github/scripts/update_pytorch_pin.py
57-
```
62+
1. Run `lintrunner init` to install linter tools
63+
2. Check that your virtual environment is activated

.githooks/install.sh

Lines changed: 0 additions & 23 deletions
This file was deleted.

.githooks/pre-commit

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,68 @@ if git diff --cached --name-only | grep -q "^torch_pin.py$"; then
2727
fi
2828
fi
2929

30-
exit 0
30+
# --- lintrunner ---
31+
32+
if ! command -v lintrunner >/dev/null 2>&1; then
33+
echo "Warning: lintrunner not found. Skipping lint checks."
34+
echo "Install with: pip install lintrunner lintrunner-adapters && lintrunner init"
35+
exit 0
36+
fi
37+
38+
if [ ! -f .lintrunner.toml ]; then
39+
echo "Warning: .lintrunner.toml not found. Skipping lint checks."
40+
exit 0
41+
fi
42+
43+
git_dir=$(git rev-parse --git-dir)
44+
45+
# Portable hash: sha256sum (Linux) or shasum (macOS)
46+
if command -v sha256sum >/dev/null 2>&1; then
47+
toml_hash=$(sha256sum .lintrunner.toml | cut -d' ' -f1)
48+
else
49+
toml_hash=$(shasum -a 256 .lintrunner.toml | cut -d' ' -f1)
50+
fi
51+
stored_hash=""
52+
[ -f "${git_dir}/.lintrunner_init_hash" ] && stored_hash=$(cat "${git_dir}/.lintrunner_init_hash")
53+
54+
if [ "${toml_hash}" != "${stored_hash}" ]; then
55+
echo "Running lintrunner init..."
56+
if lintrunner init; then
57+
echo "${toml_hash}" > "${git_dir}/.lintrunner_init_hash"
58+
else
59+
echo "lintrunner init failed. Run 'lintrunner init' manually."
60+
exit 1
61+
fi
62+
fi
63+
64+
staged_files=$(git diff --cached --name-only --diff-filter=ACMR)
65+
66+
# Use HEAD^ if it exists (skip on initial commit)
67+
revision_flag="--revision HEAD^"
68+
if ! git rev-parse HEAD^ >/dev/null 2>&1; then
69+
revision_flag=""
70+
fi
71+
72+
lintrunner -a $revision_flag --skip MYPY
73+
lint_status=$?
74+
75+
# Check if lintrunner modified any staged files. If so, block the commit
76+
# so the user can review the changes before committing.
77+
files_modified=0
78+
while IFS= read -r path; do
79+
[ -z "${path}" ] && continue
80+
if ! git diff --quiet -- "${path}" 2>/dev/null; then
81+
files_modified=1
82+
break
83+
fi
84+
done <<< "${staged_files}"
85+
86+
if [ $files_modified -eq 1 ]; then
87+
echo "Lintrunner modified files. Review with 'git diff', then 'git add -u && git commit'."
88+
exit 1
89+
fi
90+
91+
if [ $lint_status -ne 0 ]; then
92+
echo "Lint errors found. Fix them and try again, or use 'git commit --no-verify' to skip."
93+
exit 1
94+
fi

.githooks/pre-push

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#!/usr/bin/env bash
2+
3+
# Delegate to local pre-push hook if present (e.g., ARM backend).
4+
# .githooks/ is set as core.hooksPath, so git won't look in .git/hooks/
5+
# automatically. This passthrough ensures local hooks still run.
6+
local_hook="$(git rev-parse --git-dir)/hooks/pre-push"
7+
if [ -x "$local_hook" ]; then
8+
"$local_hook" "$@"
9+
fi

CONTRIBUTING.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,18 @@ lintrunner init
206206
Then run `lintrunner` from the root of the repo to see its suggestions, or run
207207
`lintrunner -a` to automatically apply the suggestions.
208208

209+
### Git Hooks
210+
211+
A pre-commit hook runs lintrunner automatically on every commit. Install it with:
212+
213+
```
214+
git config core.hooksPath .githooks
215+
```
216+
217+
This is also done automatically by `./install_executorch.sh`. If lintrunner
218+
auto-fixes files, the commit will be blocked so you can review the changes with
219+
`git diff` before re-committing.
220+
209221
### Python Style
210222

211223
ExecuTorch Python code follows the style used by the PyTorch core project.

backends/arm/README.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -247,12 +247,14 @@ To run these tests, you need to install the required dependencies by running the
247247
Please note that installing model test dependencies is a standalone process. When using the `--setup-test-dependency` flag,
248248
the script will install only the necessary dependencies for model tests, skipping all other setup procedures.
249249

250-
## Using pre-commit
250+
## Using git hooks
251251

252-
A pre-commit script is available in the backend to help developers. Follow the steps below to enable it:
252+
The repo-wide pre-commit hook (lintrunner + torch_pin sync) is installed automatically
253+
by `./install_executorch.sh`. To install the Arm-specific pre-push hook (license checks,
254+
commit message format, docgen):
253255

254256
```
255-
cp backends/arm/scripts/pre-commit .git/hooks/
257+
cp backends/arm/scripts/pre-push .git/hooks/
256258
```
257259

258260
## Notes on model specific and optional passes

backends/arm/scripts/pre-commit

Lines changed: 0 additions & 22 deletions
This file was deleted.

install_executorch.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,8 @@
1010
# so we avoid repeated symlink segments in downstream CMake paths.
1111
cd -- "$( realpath "$( dirname -- "${BASH_SOURCE[0]}" )" )" &> /dev/null || /bin/true
1212
./run_python_script.sh ./install_executorch.py "$@"
13+
14+
# Install git hooks if inside a git repo
15+
if git rev-parse --git-dir > /dev/null 2>&1; then
16+
git config core.hooksPath .githooks
17+
fi

0 commit comments

Comments
 (0)