Dead-simple Git pre-commit hooks
Project description
A simple tool to manage pre-commit hooks for git.
Install it with pip (outside a virtual environment so it works with multiple projects):
pip3 install iprecommit
Then, initialize a pre-commit check in your git repository:
cd path/to/some/git/repo
iprecommit init
iprecommit init
will create a file called precommit.py
in the root of your git repository that defines your pre-commit checks. It's human-editable and self-explanatory.
Now, whenever you run git commit
, the checks in precommit.py
will be run automatically. You can also run the pre-commit checks manually:
iprecommit
Many pre-commit issues can be fixed automatically. To do so, run
iprecommit fix
Pass the --working
flag to iprecommit
and iprecommit fix
to operate on both staged and unstaged changes.
User guide
Precommit file format
The precommit.py
file that precommit
generates will look something like this:
from iprecommit import checks
def init(precommit):
precommit.check(checks.NoStagedAndUnstagedChanges())
precommit.check(checks.NoWhitespaceInFilePath())
precommit.check(checks.DoNotSubmit())
# Check Python format with black.
precommit.check(checks.PythonFormat())
# Lint Python code with flake8.
precommit.check(checks.PythonLint())
# Check the order of Python imports with isort.
precommit.check(checks.PythonImportOrder())
# Check Python static type annotations with mypy.
precommit.check(checks.PythonTypes())
# Lint JavaScript code with ESLint.
precommit.check(checks.JavaScriptLint())
precommit.py
must define a function called init
that accepts a single parameter, called precommit
by convention.
precommit.check
registers a pre-commit check. Checks are run in the order they are registered. The built-in checks know what kind of files they should be invoked on, so, e.g., checks.PythonFormat
will only run on Python files. If you want to limit a check to a certain set of files, the check functions accept a exclude
parameter which should be a list of Unix filename patterns:
precommit.check(checks.NoWhiteSpaceInFilePath(exclude=["data/*.csv"]))
You can also opt-in files with the include
parameter. See the Python fnmatch
module for details on the pattern syntax for exclude
and include
.
Since precommit.py
is a Python file, you can disable checks by commenting them out.
The default precommit.py
has checks for a number of languages. There is no overhead for checks for languages that you don't use. They will simply never be run.
Some pre-commit checks require other programs to be installed on the computer, e.g. PythonFormat
requires the black
code formatter. precommit init
will not install these automatically. You have to install them yourself.
Writing your own checks
iprecommit
comes with some useful checks out of the box, but sometimes you need to write your own checks. Doing so is straightforward.
To run a shell command and check that its exit status is zero, use the built-in checks.Command
check:
precommit.check(checks.Command("UnitTests", ["./test"]))
If the command requires the names of the files to be passed to it, use pass_files=True
:
precommit.check(checks.Command("FileCheck", ["check_file"], pass_files=True))
Restrict the types of files that the command runs on with include
:
precommit.check(checks.Command("FileCheck", ["check_file"], pass_files=True, include=["*.py"]))
This will invoke the command check_file
once, passing all files ending in .py
with staged changes as command-line arguments.
If the command only accepts one file at a time, use separately
:
precommit.check(checks.Command("FileCheck", ["check_file"], pass_files=True, separately=True, include=["*.py"]))
This will invoke check_file
on each Python file with staged changes.
If you want to implement the logic of your check in Python rather than invoke a shell command, then look at the built-in checks in iprecommit/checks.py
in this repository for guidance. DoNotSubmit
is a good example of a simple custom check.
Development
The core logic for running checks and applying fixes is in iprecommit/lib.py
. The built-in checks are defined in iprecommit/checks.py
, and the pre-commit configuration template is at iprecommit/precommit.py.template
.
Run the test suite with ./functional_test
, which simulates an actual user session: creating a git repository and virtual environment, installing precommit, and running it as a shell command.
Missing features
You can see features that I've considered but ultimately rejected by looking at the issues marked 'wontfix' on GitHub. Some notable ones include:
- Support for non-UTF-8 file paths
- Support for customizing the name of
precommit.py
- Caching results of pre-commit checks
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file iprecommit-0.2.tar.gz
.
File metadata
- Download URL: iprecommit-0.2.tar.gz
- Upload date:
- Size: 6.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.7.1 CPython/3.11.5 Darwin/22.6.0
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | aa8531c9e8ba9c7dff2890b5bb901d60bead8b3e2dc1e4b9b33688ebe17719b4 |
|
MD5 | dbf63f1cfef17a5d3f8e524668755931 |
|
BLAKE2b-256 | 35e527635531e8a6fbb53045f0fb04d3abb31a521e3cedbd680db0cfad337352 |
File details
Details for the file iprecommit-0.2-py3-none-any.whl
.
File metadata
- Download URL: iprecommit-0.2-py3-none-any.whl
- Upload date:
- Size: 7.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.7.1 CPython/3.11.5 Darwin/22.6.0
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 02c45642bbfda8b8eecbab3e9418ce28a17489f81ec2452274334ee36ad6c297 |
|
MD5 | 28eb4b93940801b4296c6996e726bb7d |
|
BLAKE2b-256 | d90cce1690dee23991bf52556451f4b5877ad63899dfdf51dbd846ce2488c3bd |