Versioning Hell
Published February 19, 2021
Versioning, like naming things, can be hard. That’s why things like semver exist.
…
Introduction
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 = `https://github.com/koalaman/shellcheck/releases/download/latest/shellcheck-latest.${process.platform}.x86_64.tar.xz`;
That URL likely looks familiar. At a glance, you might even mistake it for the latest releases URL: https://github.com/koalaman/shellcheck/releases/latest
“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.
TGIF.
2021/02/25 🎂 Update: The versioning issue was resolved: https://github.com/gunar/shellcheck/commit/042106b03890d5cdb5f1ffcf5153c458252c3ac6