Skip to content
Open
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
10 changes: 9 additions & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ ci:
autoupdate_branch: ''
autoupdate_commit_msg: '[pre-commit.ci] pre-commit autoupdate'
autoupdate_schedule: quarterly
skip: [lychee]
skip: [lychee, check-precommit-installed]
submodules: false

# Please update the rev: SHAs below with this command:
Expand All @@ -26,6 +26,14 @@ repos:

- repo: local
hooks:
- id: check-precommit-installed
name: Warn if the pre-commit git hook is not installed
entry: python ./toolshed/check_precommit_installed.py
language: python
always_run: true
pass_filenames: false
verbose: true

- id: check-spdx
name: Check SPDX Headers
entry: python ./toolshed/check_spdx.py
Expand Down
19 changes: 8 additions & 11 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,21 +61,18 @@ This project uses [pre-commit.ci](https://pre-commit.ci/) with GitHub Actions. A
To set yourself up for running pre-commit checks locally and to catch issues before pushing your changes, follow these steps:

* Install pre-commit with: `pip install pre-commit`
* Run this once per checkout: `pre-commit install`

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Non-blocking: I thought pre-commit -a below would take care of this step?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It only takes care of it if you remember to run it before every single commit.

The driver for this change is that some people forget to run it with every commit (easy to do), and CI only checks the last commit. Most of the time, that's equivalent, but with copyright year handling (which needs to know what changed) and .pyi handling (which can introduce conflicts) it isn't equivalent.

* You can manually check all files at any time by running: `pre-commit run --all-files`

This command runs all configured hooks (such as linters and formatters) across your repository, letting you review and address issues before committing.

**Optional: Enable automatic checks on every commit**
If you want pre-commit hooks to run automatically each time you make a commit, install the git hook with:

`pre-commit install`

This sets up a git pre-commit hook so that all configured checks will run before each commit is accepted. If any hook fails, the commit will be blocked until the issues are resolved.

**Note on workflow flexibility**
Some contributors prefer to commit intermediate or work-in-progress changes that may not pass all pre-commit checks, and only clean up their commits before pushing (for example, by squashing and running `pre-commit run --all-files` manually at the end). If this fits your workflow, you may choose not to run `pre-commit install` and instead rely on manual checks. This approach avoids disruption during iterative development, while still ensuring code quality before code is shared or merged.

Choose the setup that best fits your workflow and development style.
Installing the hook is required, not optional. Some of the automated checks
(the SPDX header updater and the `.pyi` stub generator for `cuda_core`) only
keep the tree consistent if they run on *every* commit. Relying on manual
`pre-commit run --all-files` invocations means these checks can be skipped
between commits, leaving stale headers or out-of-date stubs in the history.
If the hook isn't installed, `pre-commit run` (and CI) will print a visible
warning reminding you to run `pre-commit install`.


## Signing Your Work
Expand Down
62 changes: 62 additions & 0 deletions toolshed/check_precommit_installed.py

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, thanks.

Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

"""Warn (without failing) if the pre-commit git hook is not installed.

This repo relies on pre-commit running on *every* commit: the SPDX header
updater and the .pyi stub generator only keep the tree consistent if they
run automatically via the installed git hook. Contributors who only run
`pre-commit run --all-files` manually (or never run pre-commit at all) can
end up with stale headers or stubs. This check can't block the commit
(if pre-commit isn't installed as a git hook, this script never runs
during `git commit` in the first place) but it does fire during manual
`pre-commit run` invocations and in CI, where it gives contributors a
visible nudge to run `pre-commit install`.
"""

import subprocess
import sys

MARKER = b"File generated by pre-commit"


def _git_hooks_dir() -> str:
result = subprocess.run(
["git", "rev-parse", "--git-path", "hooks"], # noqa: S607
capture_output=True,
check=True,
text=True,
)
return result.stdout.strip()


def main() -> int:
hooks_dir = _git_hooks_dir()
hook_path = f"{hooks_dir}/pre-commit"

try:
with open(hook_path, "rb") as f:
installed = MARKER in f.read()
except FileNotFoundError:
installed = False

if not installed:
print(
"\n"
"==================== pre-commit WARNING ====================\n"
"The pre-commit git hook is not installed in this checkout.\n"
"Without it, checks only run when you invoke pre-commit\n"
"manually, and will NOT run automatically on `git commit`.\n"
"\n"
"Fix this by running:\n"
"\n"
" pre-commit install\n"
"==============================================================\n",
file=sys.stderr,
)

return 0


if __name__ == "__main__":
sys.exit(main())
Loading