[ad_1]
Most software program is developed utilizing the git
model management system to replace and distribute code. One problem of writing code collaboratively is guaranteeing particular requirements whereas every contributor has their type and opinion about what constitutes clear code.
pre-commit hooks are scripts or instructions to execute robotically earlier than committing code modifications. They’ll implement styling guidelines and catch errors earlier than they’re dedicated and additional distributed. Notable hooks embody checking recordsdata for syntax errors, sorting imports, and normalizing citation marks. They’re an important instrument for any venture, particularly open-source ones with many contributors.
I wished to create pre-commit hooks to validate dataflow definitions for the Python library Hamilton, however I discovered most on-line assets scattered and restricted to fundamental use.
On this put up, you’ll discover:
- begin utilizing pre-commit hooks in your venture
- A step-by-step tutorial to develop customized pre-commit hooks
To floor the dialogue, I’ll undergo this GitHub repository containing the pre-commit hooks I developed for Hamilton.
Hooks are a mechanism constructed straight into the git
model management system. You’ll find your venture’s hooks underneath the .git/hooks
listing (it is perhaps hidden by default). Though they’re colloquially referred to as “pre-commit hooks”, git hooks cowl the entire git lifecycle. As an illustration, you may have hooks set off simply after a commit or earlier than a push. Additionally, hooks will be written in any programming language. Notably, the Ruff library reimplemented many Python-based hooks in Rust for efficiency enchancment.
In comparison with software program testing, which focuses on code conduct, you may consider hooks as light-weight checks you’ll do on every file save. When you can anticipate exams to vary and evolve together with your codebase, your code-writing tips and pre-commit hooks will probably be fixed.
Venture setup
Let’s fake we’re beginning a brand new Python venture (or utilizing an current one) within the listing /my-project
. The popular approach of working with pre-commit hooks is thru the pre-commit Python library. We will set it up with the next steps:
- Create a git repository on your venture with
git init
- Set up the pre-commit library with
pip set up pre-commit
- Add a
.pre-commit-config.yaml
to your repository. Right here’s an instance:
# .pre-commit-config.yaml
repos:
# repository with hook definitions
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v2.3.0 # launch model of the repo
hooks: # record of hooks from the repo to incorporate on this venture
- id: end-of-file-fixer
- id: trailing-whitespace
- id: check-yaml
args: ['--unsafe'] # add arguments to `check-yaml`# obtain one other repository with hooks
- repo: https://github.com/psf/black
rev: 22.10.0
hooks:
- id: black
4. Set up the hooks with pre-commit set up
. It would learn directions from .pre-commit-config.yaml
and set up hooks regionally underneath .git/hooks/pre-commit
5. Make a commit or manually run hooks with pre-commit run --all-files
to set off the hooks
Neighborhood-maintained hooks present flexibility and will be tailor-made to satisfy your most well-liked coding tips. They need to meet your wants 98% of the time. Nevertheless, off-the-shelf options don’t know concerning the particular instruments you’re utilizing or your staff’s inside conventions. For instance, you would possibly wish to validate inside configurations or implement a listing construction on your initiatives.
In our case, we wish to create a hook to validate the Python code for his or her Hamilton dataflow definition. Our hook script will leverage the hamilton
CLI instrument to conduct the validation, leaving us with a easy code instance to comply with.
1. Organising your pre-commit hook repository
As launched within the Venture setup part, pre-commit hooks must exist in a public repository to permit initiatives to reference them in .pre-commit-config.yaml
and set up them regionally with pre-commit set up
.
Beforehand, we have been in our venture listing /my-project
the place we outlined a .pre-commit-config.yaml
and put in hooks. Now, we’ll create a /my-hooks
listing the place we’ll outline our customized hooks. You’ll be able to confer with our hamilton-pre-commit
repository to view the overall construction.
2. Writing the hook’s logic
Beneath hooks/
, we’ve a file __init__.py
to make the listing a discoverable Python module and our script cli_command.py
. It comprises a single operate principal()
, which reads an inventory of hamilton
CLI instructions from sys.argv
. Then, it executes them one after the other as a subprocess wrapped in a attempt/besides
clause.
# hooks/cli_command.py
import sys
import json
import subprocessPASS = 0
FAIL = 1
def principal() -> int:
"""Execute an inventory of instructions utilizing the Hamilton CLI"""
instructions = sys.argv[1:]
if len(instructions) == 0:
return PASS
exit_code = PASS
for command in instructions:
attempt:
args = command.cut up(" ")
# insert `--json-out` for correct stdout parsing
args.insert(1, "--json-out")
end result = subprocess.run(args, stdout=subprocess.PIPE, textual content=True)
response = json.masses(end result.stdout)
if response["success"] is False:
increase ValueError
besides Exception:
exit_code |= FAIL
return exit_code
if __name__ == "__main__":
increase SystemExit(principal())
Originally, we set exit_code = PASS
, however any exception or unsuccessful instructions will set exit_code = FAIL
. The principal()
operate returns the exit code to the SystemExit
exception. For the pre-commit hook to succeed, we have to return PASS
in spite of everything instructions succeeded. It is perhaps counterintuitive to have PASS=0
and FAIL=1
however these values confer with the usual system’s exit code.
We used Python for comfort, however this easy logic might be in a lighter scripting language like Bash. You’ll be able to go to the hooks maintained by the pre-commit staff for extra examples.
3. Defining the hook entry level
Now, your hooks repository (/my-hooks
) should embody a .pre-commit-hooks.yaml
file that specifies the accessible hooks and learn how to execute them as soon as put in.
- id: cli-command
identify: Execute `hamilton` CLI instructions
description: This hook executes a command utilizing the `hamilton` CLI.
entry: cli-command
language: python
varieties: [python]
levels: [pre-commit, pre-merge-commit, manual]
pass_filenames: false
In our case, we set id: cli-command
and entry: cli-command
, add some metadata, and specify the programming language as Python. Importantly, the recordsdata
attribute wasn’t set to have our hook run as soon as per commit. In your case, you would possibly wish to set recordsdata: "*.py"
to run your hook on every edited Python file for instance (study accessible choices).
To date, we created a Python script underneath hooks/cli_command.py
and added to .pre-commit-hooks.yaml
a hook with the entry level cli-command
. Nevertheless, that you must hyperlink the 2 explicitly in your Python venture file pyproject.toml
.
[project.scripts]
cli-command = "hooks.cli_command:principal"
This line reads “the entry level cli-command
refers back to the operate principal
in hooks.cli_command
”.
see this instance for those who’re utilizing
setup.cfg
on your Python venture
4. Testing your hook regionally
First, it’s best to validate your hook’s logic with unit exams. Nevertheless, we gained’t dive into testing because it deserves its personal put up. Our hamilton-pre-commit
repository presently doesn’t have exams because the underlying CLI is examined underneath the principle Hamilton repository. You’ll be able to go to the formally maintained pre-commit hooks for check examples.
Second, it’s best to confirm that the .pre-commit-hooks.yaml
and entry factors are correctly configured by attempting your pre-commit hook regionally. Ideally, you’d wish to keep away from including a decide to set off the hook every time you wish to check modifications. The pre-commit library offers utilities to facilitate this course of, nevertheless it requires a number of handbook steps detailed in pre-commit GitHub points.
- Go to your listing
/my-project
the place you’d like to check your hook. - Execute
pre-commit try-repo ../LOCAL/PATH/TO/my-hooks
then, it’s best to see a neighborhood initialization message.
One limitation is you can’t straight go args
to your hook by way of this command.
3. Copy the configuration discovered underneath Utilizing config:
to a neighborhood file and add the args
part. We created .local-pre-commit-config.yaml
however you need to use any identify.
# my-project/.local-pre-commit-config.yaml
repos:
- repo: ../../dagworks/hamilton-pre-commit
rev: e4b77a499ba0ff3446a86ebbe4c2cbca82eb54f8
hooks:
- id: cli-command
args: [
hamilton build my_func2.py
]
4. Use your native hook by way of pre-commit run --config .local-pre-commit-config.yaml --all-files
. The --all-files
flag will apply the hook to all recordsdata in your repository as an alternative of these presently staged.
When including a check, at all times begin by making it fail. You wouldn’t wish to add a check that at all times succeeds
:^)
5. Publishing your pre-commit hook
You’re virtually there! You’ve got a working hook script that’s examined and packaged in a git repository. Now, you simply must make it accessible on-line. We are going to present the steps for GitHub-hosted initiatives, however your pre-commit hook can reside anyplace accessible by way of git clone
.
- Out of your GitHub repository, go to the Releases part
2. Click on Draft a brand new launch
3. On the brand new launch web page, that you must add a model tag, a title, and an outline. If it’s your first launch, I recommend setting the tag as v0.1.0
to comply with semantic versioning, as really useful by GitHub.
While you’re making modifications and wish to distribute experimental variations, you may set your model as v0.1.1-rc
(for “launch candidate”) and mark it as a pre-release utilizing the checkbox.
The rev
worth in your .pre-commit-config.yaml
file might want to match the model tag you set.
repos:
- repo: https://github.com/DAGWorks-Inc/hamilton-pre-commit
rev: v0.1.3rc
hooks:
- id: cli-command
# ...
Congrats! You made it by way of this put up! You at the moment are ready to make use of pre-commit hooks to enhance code high quality in your initiatives. Outfitted with an understanding of their internals, you can begin writing your individual hooks!
Don’t neglect to check out the various hooks maintained by the group earlier than reinventing the wheel: https://pre-commit.com/hooks.html
[ad_2]