Versioning Hell

Published February 19, 2021

Versioning, like naming things, can be hard. That’s why things like semver exist.


For context, I was working on a Node.js monorepo. Mo’repo mo’problem,” as they say. Maybe not more problems all the time, but certainly more tooling. Scripts (“tasks”) to do things. Many written as shell scripts.

I was working on linting all of the shell scripts with Shellcheck. After getting them all linted properly using a local install of shellcheck, I began implementing it into the version control workflow with lint-staged.

Initially, I tried using npx with a command like npx shellcheck. This worked for me, but not for another reviewer on the PR. To cut to the chase, the problem was npx checks if the command exists in $PATH (along with the local project) before installing. I already had a shellcheck on my system, which was a slightly different version than the latest stable release that you may get from a brew install.

Weirdly enough, there were linting errors when using the npm-installed shellcheck that I couldn’t replicate locally. This is where the rabbit hole began.

The Rabbit Hole

Shellcheck has always struck me as a particularly mature piece of software. It does one thing and it does it well. It has integrations into text editors & IDEs with wiki pages for each SCxxxx code you may find yourself fixing.

The npm shellcheck package is convenient little wrapper that grabs the executable as released on GitHub for your specific architecture and places it in your project’s node_modules/bin directory. This makes it easy to do npm-y things, like run it within the lint-staged section of your package.json.

So now, instead of npx shellcheck, I’m left with shellcheck:

- npx shellcheck
+ shellcheck

Cool, same error as before. Something about SC1091 which didn’t make any sense.

I dig into it further. How is it downloading the latest version? Let’s check the code.

const url = `${process.platform}.x86_64.tar.xz`;

That URL likely looks familiar. At a glance, you might even mistake it for the latest releases URL:

What’s the difference?” you might ask. The former is a URL to a release tagged latest—just like you may find in a Docker image. The latter is the latest release. As I write this, that is v0.7.1. Shellcheck also has a stable release. Hmm…

The difference is minute, but important. Shellcheck uses latest as the most recent build1 while stable is the most recent release2 e.g., v0.7.1.

D’oh. So the npm shellcheck package is actually bundling the latest build. Depending on what state the repo is in that could be good or bad. In my case it was bad. I’ve submitted an issue to track it.


2021/02/25 🎂 Update: The versioning issue was resolved:



I love hearing from readers so please feel free to reach out.

Reply via email

Last modified July 9, 2024  #bash   #js   #dev 

🔗 Backlinks

← Newer post  •  Older post →