Don't forget to update that value in those files
Tags: python, git, productivity, tutorial
Published: 2022-01-25 13:13:48

## Intro
The other day, based on a project needs, I created a pre-commit hook: **[version-checker](https://github.com/jalvaradosegura/version-checker)**. It helps you remember to update the version of your project in different files before doing a commit.

## Setup
You only need to have [`pre-commit`](https://pre-commit.coma/) installed (and to use git, but who doesn't?):

```
pip install pre-commit
```

### Create a basic project structure
Let's use a very basic project structure for the sake of the tutorial:
```
.
├── README.md
├── setup.cfg
└── src
    └── __init__.py
```
The files `README.md` and `__init__.py` will refer in some way to the version of the project, that lives in `setup.cfg`.

Let's see the content of these files:

**setup.cfg**
```config
# setup.cfg
[metadata]
name = some-project
version = 0.1.0
```

**README.md**
```markdown
# README.md

# You are using version 0.1.0 of this project
```

**src/\_\_init\_\_.py**
```py
# src/__init__.py
__version__ = "0.1.0"
```

Now, if you update the version of your project (`setup.cfg`) you have to remember to update it in 2 more files (`README.md` and `__init__.py`). That sounds like something easy to forget right? This is when the hook comes to the rescue 🦸.

### The hook
For setting up the hook you need to create a `.pre-commit-config.yaml` file (like any other pre-commit hook):

```yaml
# .pre-commit-config.yaml
repos:
-   repo: https://github.com/jalvaradosegura/version-checker
    rev: v0.4.1-alpha
    hooks:
    -   id: version-checker
        args: [
          --files, README.md, src/__init__.py,
          --grab-version-from, setup.cfg
        ]
```
Most of the content is the typical config of a hook. Let's explain the `args`:
* `--files`: mandatory argument. It indicates the path to the files that the hook will evaluate to contain the desired version.
* `--grab-version-from`: optional argument. It tells the hook from where to grab the version to evaluate (By default it tries to grab it from a `pyproject.toml` file).

Then we install it with:
```
pre-commit install
```

Congrats, everything is ready, `version-checker` won't let you forget to update the files 🎉🎉.

## See it in action 👀
Let's update the version in our `setup.cfg` to `0.2.0` and try to do a commit:

![Failure Case](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l0qemw2p3pky5lrfapur.png)

The hook is basically telling you that `README.md` and `__init__.py` are not using the latest version of the package within their content.

Update the corresponding files and try to commit again:

![Success Case](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gi4asr27wfy7pxgkjwlm.png)

## When it may be helpful and when it may not
I created this hook because I was working in a project which had a lot of files that were referring to the version of the project: python files, markdown files, some template files and even a Jenkinsfile. For python files it wasn't hard to handle the version, thanks to `version` from `importlib.metadata`, but the other files were trickier...

When do I think this hook may be helpful:
* If your project refers to the version of the project in multiple files with different extensions.
* If you are already using `pre-commit` hooks and you don't know another tool for this purpose.

When do I think it may not:
* If you already use another tool for this purpose.
* If for some reason the hook is harming the performance of `pre-commit` (in my experience the hook runs super fast). Take a look at [this](https://github.com/pre-commit/pre-commit/issues/2194).

## Other options
The other day I learned about 2 tools that seems to work for the same purpose (I haven't tried them yet):
* [bumpver](https://pypi.org/project/bumpver/)
* [bump2version](https://pypi.org/project/bump2version/)

And also I was shared this cool [list](https://github.com/c4urself/bump2version/blob/master/RELATED.md).

___
Post image created by [@circus.infernus](https://www.instagram.com/circus.infernus/)