What am I Doing? #
Too many times this year I’ve found myself struggling to improve my blog pipeline because I couldn’t keep track of when code stopped and started doing what it was supposed to do. This was entirely my own fault, I was not observing best-practices:
- I wasn’t using semantic versioning
- I wasn’t tagging
- all development happened on main
- etc etc
All of this worked well enough for private use monoliths, one-offs and skunkworks projects but these Drone pipelines presented a new challenge.
Drone pipelines tend to be structured as a series of docker images operating on a mount that gets injected into all of them so they can share their work. This is fine, docker images are an easy fire-and-forget solution for deploying tools.
As things grew more complex, my sloppy coding practices put me in a lot of unnecessary tight spots.
- Some parts of the pipeline were idempotent, others weren’t.
- Some parts of the pipeline were affected by each other’s work. For example, one step scans files for attachments and copies them into Hugo-appropriate directories, and the next transforms links from Obsidian to Hugo layouts.
- I frequently wanted to implement multiple features/fixes simultaneously but when this took longer than planned, rolling back to a known-good version was impossible because my docker images are only tagged with
latest
.
All of this added up to things breaking for far longer than they needed to, more often than they needed to. Eventually, enough was enough. I drew a line in the sand and decided that I wasn’t going to live like this anymore.
After some digging I found resources that helped me build a Makefile to take care of things. That first Makefile added a lot but I’m only going to cover the tooling for semantic versioning and git tagging; the rest of that Makefile was go cross-compilation and docker image stuff that I’m replacing with bazel.
To handle automatically incrementing semver values, I landed on bump
. Because it’s written in Go, I was able to fork it and patch a few minor issues and make sure that it keeps working for the foreseeable future.
Why does it work? #
My current solution relies on a few pieces: bump
and my Makefile invoking some git commands.
VERSION ?= $(shell git -C "$(MD)" describe --tags --dirty=-dev)
COMMIT_ID := $(shell git -C "$(MD)" rev-parse HEAD | head -c8)
setup-bump:
go install github.com/therealfakemoot/bump@latest
bump-major: setup-bump
bump major
bump-minor: setup-bump
bump minor
bump-patch: setup-bump
bump patch
bump is a golang utility that’ll read a git repository’s tags and apply a semantic versioning compliant version increment. bump patch
bumps v0.0.1
to v0.0.2
. bump major
goes from v2.24.5
to v3.0.0
. You get the idea.
All together, this suite works perfectly for handling tagging. I don’t have a super rigorous policy on what constitutes a major, minor, or patch version but being able to make bump-patch
to tag a specific known-good commit made a world of difference. My drone pipelines became drastically more reliable thanks to version pinning.
But what about Bazel? #
Bazel isn’t directly involved in manipulating tags yet. To do that, I’ll need to add bazel build files to the bump
repo. I’ll cover that in the next post, where I cover how to use bazel’s stamping funtionality.