For a lot of my open source and side projects, I tend to release code as soon as I've finished a distinct chunk and in most cases, when the code is for a web site, I won't have any concept of managed versioning (though I do use semantic/conventional commits). This means often when I'm looking at the web site - or rather you're looking at the web site I can't always be sure which version of code you're using at the time.
Last week though, I discovered a little trick inside of Netlify that helped me surface this information in a, I think, fairly nice way.
A way to verify live changes
I wanted both a way that I could ask the users of my sites which version they were on, but also a way to check what had gone live in that latest change.
What I have now is this: a link at the bottom of each page that shows a commit sha that links to the commit diff between releases to Netlify.
This links to the previous deployed version of the code to the commit that's now live, using a github "compare" URL, such as this: https://github.com/remy/zx-tools/compare/68cc26a7d2f046c2fa7835c4d92d20198d306c10...c7024665afe86dc1a0d805b03a9c90c6448752d1
The how
Netlify includes two useful environment variables:
COMMIT_REF
: Reference ID (also known as 'SHA' or 'hash') of the commit we're building.CACHED_COMMIT_REF
: Reference ID (also known as 'SHA' or 'hash') of the last commit that we built before the current build.
The compare URL I showed you earlier is the difference between these two commits. So the task is getting those values into my code.
I get these values into my code using three steps:
- Netlify calls the
build
process on my project - I use Node and so this will runnpm run build
for me - The build process runs a shell script that generates a JavaScript file on the fly for me
- The file that's generated is then used during my main project build process
In my case I'm using JavaScript both on the server side (for a static build) and on the client side. However, there's nothing stopping you from using this process with PHP or any other language - the point is to use these values. In my case, I'm generating a new JavaScript file because I want to use this during browser runtime - so this file won't have access to environment variables at this point in time.
This is my package.json
build process - the important part being the sh ./hashit.sh
- the semi-colon ;
is used to separate two commands, so once the shell script is run, my main parcel build process runs:
{
"scripts": {
"build": "sh ./hashit.sh; parcel build public/index.html"
}
}
The hashit.sh
file contains this line of code:
echo "export default { prev: \"$CACHED_COMMIT_REF\", curr: \"$COMMIT_REF\" }" > ./public/hash.js
This shell script will generate a new file in the public
directory called hash.js
which contains the parts I need. In my codebase I'm using JavaScript modules and building using Parcel, though you could just as easily change the contents of this file to run a console.log
to show the URL to compare the release.
Finally, I have a client side JavaScript file that imports the hash.js
file and adds a useful "version" link to my code, whilst also dropping a URL into the console (note that this lives in public
so the import is relative to that directory):
import hash from './hash';
const repo = 'zx-tools';
console.info(
`Release https://github.com/remy/${repo}/compare/${hash.prev}...${hash.curr}`
);
Definitely useful for debugging some of my smaller projects, particularly when the ship with a service worker which might load a slightly behind version.
Gotcha: when this doesn't work
As I was writing this post, I thought it would be wise to check my blog, that also included this method. When I visited the compare URL, I found that it loaded up a broken page on github. Actually not broken, when I looked closer I realised that the commit sha for the cached release and the latest was the same.
That was entirely accurate and was due to the fact that I run an hourly deploy on my own blog (which keeps the timestamps and "live"-ish data fresh). So the gotcha is that this just doesn't work with projects that are auto-deployed without changes - as it is in my own blog's case.