pre-commit Advices

What is pre-commit

At first, let me remind what pre-commit is. pre-commit is a tool to manage git hooks inside your projects, package them and import them from other sources. Also it make very convinient to manage them using it's declarative YAML configuration.

Git hooks are useful if you have some linters/formatters, and you want to make sure your commited changes are checked by your dev tools.

Advices

Prefer system hooks over hooks managed by pre-commit

pre-commit suggests to use their environment management for hooks:

-   repo: https://github.com/psf/black
    rev: 22.10.0
    hooks:
    -   id: black

Inside black repo there is defined hook that will be installed in separate python virtual environment alongside with it's dependencies. It may look good from programmer's perspective, but it introduces two problems: - You can't run the linter/formatter by yourself. Especially it's useful with formatters, so you have to format code by yourself. Of course you can install the same tool using another package manager, but it leads to another problem. - If you have tool installed via pre-commit and another package manager, then their versions can differ. It applies to list of plugins too, so you can end to have a different set of linters with their plugins inside pre-commit and your dev environment.

The solution is simple: install tools outside pre-commit and use language: system to run them. For example, we're using poetry as package manager, so we use something like this:

- repo: local
  hooks:
    - id: black
      entry: poetry run black  # poetry run ... ensures to run command inside it's venv
      language: system

It uses the same black as you have inside venv. The same applies to flake8 and it's plugins.

pre-commit and CI

CI is a place where our code is checked, built, tested and deployed. And it's important to ensure checks which are ran locally on developers' machines and checks inside CI are the same. So lint job should consist of pre-commit calling only.

pre-commit run --all --verbose

Of course base Docker image must provide pre-commit command. For Python-based projects you can use your package manager (poetry in dev section for example), install it via pip or some other way.

links