Writing code that ages well: Pre-commit Hooks

From the day code was born the never ending bottle on code formatting was born, Here is how we keep our code formatted, updated, type safe and secure all in 5 minutes of setup.

Kai Ashkenazy
5 min readApr 12, 2023
code that ages well
code that ages well

Have you heard about the 10 commandments of Good Code? Some very interesting and important stuff can be learned from them.

But as code evolves and grows, new developers join the team, some urgent task that must be fixed yesterday, etc … it is almost unavoidable that the quality of code will drop at some point.

If there was only a way to enforce Good Code standards like the 10 commandments … well you are in the correct place!

Today’s Menu!

What are we covering here

Part 1: Introducing Git-Hooks
Part 2: Pre-Commit Framework
- Getting started & installations
- Are Pre-Commit hooks safe
Part 3: Must know Pre-Commit hooks
Part 4: Creating you own rules
Part 5: Skipping Pre-Commit hooks

What are Pre-Commit Hooks

A pre-commit hook is a Git feature that allows us to triggered some action before a commit is made.

It allows you to run scripts to check the changes being committed and ensure that they meet certain quality standards.

Pre-Commit hooks run locally before the commit is created, so it can catch errors early and prevent them from being committed.

Python Pre-Commit hooks framework

Getting started

So, how do you get started with pre-commit hooks? Well, it’s actually pretty simple. First, you’ll need to install the pre-commit package. You can do this with pip:

pip install pre-commit

Once you’ve got pre-commit installed, you’ll need to create a .pre-commit-config.yaml file. This file will tell pre-commit which hooks to run, and how to run them. Here's an example:

# See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v3.3.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-added-large-files

This tells pre-commit to use the pre-commit-hooks repository, and to run the check-yaml, trailing-whitespace, and end-of-file-fixer hooks before each commit.

And that’s it! With just a few lines of code, you’ve set up a powerful system for ensuring the quality of your code. Of course, you can customize the pre-commit hooks to suit your specific needs, but the basic setup is always the same.

Lets commit our changes

git add .pre-commit-config
$ git commit -m "Add pre-commit"
Trim Trailing Whitespace………………………………………………………………………………………………………………………Passed
Fix End of Files……………………………………………………………………………………………………………………………………………Passed
Check Yaml……………………………………………………………………………………………………………………………………………………………Passed
Check for added large files………………………………………………………………………………………………………………Passed
[master (root-commit) e8a1234] Add pre-commit
1 file changed, 10 insertions(+)
create mode 100755 .pre-commit-config.yaml

Letting some script edit my code! This is dangerous

Indeed letting some automated tool edit and change your code sounds like a horrible idea, how can we be sure that these scripts will not insert bugs to my code?

Thank god python gave us the AST Module — Abstract Syntax Tree, which is a potent tool of the Python programming language. It allows us to interact with the Python code itself and can modify it.

The AST module allows python scripts that modify our code to verify the AST before the changes is identical to the AST after the changes — and hence it ensures that the python code will execute without any changes or bugs.

Some Pre-Commit hooks will not change your code, but will notify you that some of your code is not following best practices and will force you to fix it.

git pre commit hooks
Python Pre-Commit hooks framework

Must know Pre-Commit hooks

First things first — you are always able to go and read the official pre-commit documentation and find there the latest hooks.

Here are some of the industry standard.

Black — the de facto standard for code formatting. Also will make your git merge conflicts easier.

blacken-docs — black formatter for docs.

MyPy — developed by the father of python, Guido van Rossum who is known as Python’s BDFL, static type checker.

Prospector — a wrapper to many power full static analysis tools.

Bandit — Checks your code for security issues.

PyUpgrad — automatically upgrades your code from older standards to current standards.

McCabe — complexity checker.

Pylint — Static code analyser without running your code (static)

You can further customize your Pre-Commit hooks with configuration files, for example for black you can create a file named .black and add to it additional configurations for example line-length

Creating you own Pre-Commit hooks

Every person has his own opinion on what is important for him in his code base.

For example it is important to me that all test code will be in a test folder, and not test code in production — so I created a static analysis tool that checks for the keywords “test” and “mock” in file names and in the code and will let you know if those keywords are not in the test directory.

Some other ideas we are working on are:
- Making sure third party libraries are imported from a single place, and not all over the code, every third party library has a single “client” that handles the interaction with it
- A static analysis tool that creates a Jira ticket when one of our libraries needs to be updates, for example if some there is a new major release.

The Pre-Commit hooks framework is very easy to integrate with, all you need to do is fork this repository.

Pre-Commit hooks cleaning your mess
Pre-Commit hooks cleaning your mess

Skipping Pre-Commit Hooks

As in every tool there must be away to avoid these static checks, and it is very simple, just add --no-verify to your git commit command

git commit --no-verify -m "skipping commit hooks"

Some additional notes

What should be checked in you CICD pipeline and what should be a git hook? Thats a good question! (Well thank you :)

Generally tools that take more then few seconds and tools that check the entire code base should be in your CICD pipeline.

Tools that are checking trivial errors should definitely be triggered as Pre-Commit hooks, there is nothing I hate more then to wait to my pipeline and deployment to finish to find out few minutes later that I forgot to close a curly bracket.

print('hello world!'      # static analysis find this fast and simple

--

--

Kai Ashkenazy

Teach Bishop 🐱‍🐉 | Software Engineer Ninja🐱‍👤| Entrepreneur & Investor 😎