convcommitlint, a simple tool for a simple problem!
Those who work with me, have worked with me, or follow me know I like to automate as much as possible and that I hate complex solutions for simple problems. They know I have an aversion to the Node.js ecosystem and I run from any project that asks me to run npm like the devil runs from the cross, and the Python ecosystem is almost heading the same way! As a user, I don’t give a damn about dependencies: I want to install the application through the package manager, and I want it to work; at the limit, I want to grab the application’s binary and run it, and if I can avoid using configuration files, even better! Did I already tell you I’m lazy? If not, now you know! I want tools to be simple, do what they have to do, and that’s it! Obviously, in some cases, this isn’t always possible, but those are the exception, not the rule.
Nobody wants to think!
Ready to ‘read’ me grumbling? In any project that makes sense, the first thing I add is automatic versioning. To do that, I follow a few rules:
- the first: all my projects follow semantic versioning, or semver; this way, there’s clarity about what happens in each version!
- The second: conventional commits; this way, each commit has meaningful messages and is directly related to versioning!
These two simple rules, combined with tools like go-semantic-release, enable not only versioning but also creating releases and release notes all at once! Everything automated: communication, transparency, and meaning! Git commit > Git push and voilà! A few seconds later, I have a release, with release notes, Docker images, binaries – everything needed to make life easier, not just for me as a tool creator, but also for any user who uses them! Yes… yes… I can already hear you pointing out the various problems with semver and conventional commits; yes, I’m well aware! But do you want a few hot takes? Do you know why you don’t like both?
Because it forces you to think before you even have to do anything!
Because it’s one of two things: either someone does that work for you manually, and it’s already ‘manually automated,’ as I like to call it; or because you think you feel valuable and indispensable for being the gatekeepers of release and versioning knowledge, and that it’s too important a job to be done by a machine! You know what? I’ve been automating shit for 20 years, and I still have a job; I’m still dispensable with or without that knowledge, life goes on without you. So, the more you automate, the more time you have for cool stuff! Do you know why I like combining both so much? For the same reasons you don’t like them! Because I’m forced to segment my work: if I’m working on feature X, I’m not going to refactor function Z that only affects feature Y! Yes… it only takes a minute or two; therefore, that minute or two can be dealt with later. I add it to my notes, and when I finish feature X, then I add the refactor of function Z, and this way, everything I did is crystal clear! I’m forced to work backwards, with my users in mind! Nothing pisses me off more than updating an application that supposedly follows semver, adds a feature, increments the minor version, and in the end, it stops working because they broke the API, or changed a behavior without documenting or informing! So, I think twice before breaking behaviors or APIs; and if I have to, I have no problem doing so, as it will be duly communicated in the commits, in the versioning, and in the release notes! Wonderful world, right? How many problems are solved here just by following two simple rules? In the end, these two rules made me a better professional. But, as it couldn’t be otherwise, after a solution, there’s always another problem!
The world we live in
Just like nobody wants to think, nobody wants to read documentation. README? What’s that? Contribution rules? So, now I have to follow rules to make Git commits? I’m doing you a favor by contributing to your project, and I still have to follow rules?
Releases? Release notes? Someone else will do it. I think it’s great they exist, as a user, but that’s not for me to worry about! Most contributors like to see everything happen automatically; most developers just want to open their editor, make the changes they want, how they want, without any rhyme or reason, git commit -m "Fixed this shit that wasn't working!"
, git push, and move on, that’s the way! Whoever comes after can close the door, even if they are the ones who benefit most from following simple rules.
Complex tools for simple problems
For all these reasons, I decided to look for a commit linter. You don’t follow the rules? I won’t even look at your pull request! When all the little dots are green, then I’ll bother to look! But, for a change, conventional commits, contains a list of several related tools, and not a single one is dedicated to being just… simple! I don’t want to go into detail, as each project on this list was made with the intent of solving the problems of those who created them (which I might not even fully understand). That said: NPM? No, thanks. Python? No, thanks. PHP? Pass! Go, yes please! But I couldn’t understand any of the options (skill issues?). Others do different kinds of tasks, like releases and release notes, but none are dedicated to simply being a linter! To run locally or in a CI environment and warn that the commits are not in order, even before trying to release a new version. That can run on a pull request and notify that the commits don’t follow the rules… And so, once again, I decided to roll up my sleeves and created convcommitlint.
Convcommitlint
convcommitlint is dedicated to being just that: simple! A linter that can run locally or in a CI environment, focusing solely and exclusively on the basic principles of conventional commits. Naturally, written in Go, it allows producing just a single binary that can be downloaded in any environment and executed to do its job: if the commits don’t follow conventional commit rules, it prints the errors and exits with code 1; if there are no errors, it simply says nothing. Obviously, I added a few more bells and whistles, for example, a GitHub Action that can be integrated into any workflow with just one line: uses: coolapso/convcommitlint@v0
. By default, it just works and does what it’s supposed to do: no necessary configurations, no rules to be defined, no configuration files. And no! I don’t want to, nor will I, support all cases and different flavors of conventional commits; I focus only on the essentials but without sacrificing flexibility. All CLI application switches are also accompanied by environment variables that can be used to turn features on/off, whether locally or in the CI environment. Don’t want to validate pull requests? You just have to disable the feature with the switch or environment variable. Simple! You don’t need to please everyone; sometimes, just being that is enough: small and simple!
Basically, convcommitlint
is my modest contribution to a development ecosystem that’s a little less chaotic and, who knows, more productive. It might not be the solution to all evils, nor does it aim to please everyone, but if it can make some developers think twice before complicating what can be simple, or before ignoring rules that benefit everyone, then my ‘rant’ and effort have already been worthwhile. After all, the goal is for things to work, preferably without us having to tear our hair out in the process.