pre-commit


<- back | tags: /dev/journal shoulds

2020 was weird. 2021 is off to a weird start. I figured I should bring some sanity back to the world where I'm able. Unfortunately, my sphere of influence barely extends past this page; however, you're here, so you get to receive a slice of stability in the form of this post on implementing pre-commit for my site.

I realize I've missed my personally imposed cadence of an article a month or so. Even the best intentions can get sidelined as we re-prioritize the various facets of our lives. This is natural. So, what happens when you come back to a project after a few months and are dedicated to making progress?

You immediately get distracted with implementing a chore. Funny how that works. How do you counter-act that? You write an article about the chore so you get the benefit of both.

On the topic of 'shoulds'

Now then, before we actually delve into pre-commit, what in tarnation is a 'shoulds'? These are those things in your career that you know you should do but often de-prioritize them in favor of other more pressing work.

You know that you should write tests.

You know that you should write more and better documentation.

You know that you should make those small improvements and cleanup for readability while you're working in that file.

The code does what it's supposed to without those changes. You're familiar with working in the codebase so the documentation feels superfluous. The function doesn't actually do much or is so simple that writing a test that is demonstrably more lines of code, more complex, and more work than the thing you're testing is inane.

I've been there, you've been there, we all get it. 'Shoulds' are hard. They're especially challenging because you don't have to. Yet, you should.

What got implemented

Implementing pre-commit on this project is one of those 'shoulds'. No one else works in this code base and whatever rules (or lack thereof) I impose are simply imposed upon myself. Rules in this context are obviously flexible, malleable, negotiable, and absolutely non-binding.

So how do I impose some good hygiene and best practices on myself in a way that doesn't allow me to be lazy about it? Well, pre-commit is certainly a way. If you didn't check out the link above then here's the gist of what pre-commit does for me: it automatically runs a variety of checks for simple issues before submitting my code to the remote.

In order to get checks to run you install pre-commit and then configure a .pre-commit-config.yaml file for your project. Mine looks like so:

repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
  rev: v3.2.0
  hooks:
  - id: trailing-whitespace
  - id: end-of-file-fixer
  - id: check-yaml
  - id: check-added-large-files
- repo: https://github.com/pycqa/isort
  rev: 5.7.0
  hooks:
  - id: isort
- repo: https://github.com/psf/black
  rev: 20.8b1
  hooks:
  - id: black
- repo: https://gitlab.com/devopshq/gitlab-ci-linter
  rev: v1.0.3
  hooks:
  - id: gitlab-ci-linter
- repo: https://github.com/igorshubovych/markdownlint-cli
  rev: v0.27.1
  hooks:
  - id: markdownlint

The above is a list of the checks that I want to perform every time I try to bundle a commit. Nested into the structure you'll see lists of id which are the explicit thing that I want to run. All of those perform helpful 'shoulds' that you might find familiar (e.g. black for formatting, markdownlint and gitlab-ci-linter to check for malformed/misconfigured issues, etc.). The rest of that file is all about where to get the thing and what version of it I want to run.

Once you've got that situated then you install the hooks, like so:

>$ pre-commit install

After that your pre-commit checks will run automatically each time you try to make a commit. If you're non-conforming then your commit isn't created and you get helpful messaging for the things you need to fix first.

If, like me, you want to run it ahead of generating a commit then you can do so manually:

>$ pre-commit run --all-files

Extending the shoulds

I implemented pre-commit here because it's been on my mind for a while and it really was something that I should have done from the get-go. It's never too late to do something you should do and, at least in this instance, it turned out to be something to pry me back into the practice of working on this project.

The benefits of something like pre-commit are much more obvious when you have a team working on a code base. You all know that one engineer who just can't seem to get their formatter working and 90% of their changes in every pull request just seem to be a battle over whose formatter should win. Let's stop the in-fighting and just programmatically define who should win.

Be kind, be patient, be safe.