This post shows how to set up automated, tagged, semantically-versioned releases, changelog generation, and CI testing using a Gitlab pipeline, Standard Version and Conventional Commits.
In order to make this work, we need a few files:
- A
gitlab-ci.yml
pipeline file with a correct configuration - A package.json file for the sake of pulling
standard-version
and tracking the current version number. - [Optional] A
verion_bump.js
file to replace static version strings within the codebase (if required)
MY MISSION
This blog started nearly 10 years ago to help me document my technical adventures in home automation and various side projects. Since then, my audience has grown significantly thanks to readers like you.
While blog content can be incredibly valuable to visitors, it’s difficult for bloggers to capture any of that value – and we still have to work for a living too. There are many ways to support my efforts should you choose to do so:
Consider joining my newsletter or shouting a coffee to help with research, drafting, crafting and publishing of new content or the costs of web hosting.
It would mean the world if gave my Android App a go or left a 5-star review on Google Play. You may also participate in feature voting to shape the apps future.
Alternatively, leave the gift of feedback, visit my Etsy Store or share a post you liked with someone who may be interested. All helps spread the word.
BTC network: 32jWFfkMQQ6o4dJMpiWVdZzSwjRsSUMCk6
Challenges faced
- Gitlab would get stuck in an infinite loop when a releases
chore
commit is pushed back tomaster
anddevelop
, triggering further builds and releases. - Replacing static strings in files was difficult to make work with
standard-version
. I eventually compromised by having the aforementionedversion_bump.js
file output a commit message. - Having
standard-version
commit additional files was also difficult to figure out.
Caveats
- Gitlab caches branches locally and uses
git fetch
. Change this togit clone
if you are struggling with getting changes back into Git due to errors on push. - Rerunning the same Gitlab job reuses the same workspace, including any stale commits leftover from before a
--force-push
. Nasty.
For these reasons (and to document the process for myself) I wrote this post in the hope that it will save you some time.
Advertisement Begins
Advertisement End
Step 1. Add a .gitlab-ci.yml
file
The pipeline configuration involves a job for testing (executed on all branches) and a release job which is executed exclusively on the master
branch.
gitlab-ci.yml
variables:
CI_NAME: "gitlab"
CI_EMAIL: "gitlab-ci@example.com"
stages:
- test
- release
test:
stage: test
except:
variables:
- $GITLAB_USER_LOGIN == $CI_NAME
script:
- echo $GITLAB_USER_LOGIN
- echo $CI_USER
- echo $CI_NAME
release:
stage: release
when: on_success
except:
variables:
- $GITLAB_USER_LOGIN == $CI_NAME
tags:
- npm
only:
- master
image: tarampampam/node:alpine
script:
- npm install
- git config --global user.email $CI_EMAIL
- git config --global user.name $CI_NAME
- git config receive.advertisePushOptions true
- git checkout -B "$CI_COMMIT_REF_NAME" "$CI_COMMIT_SHA"
- npm run release
- git push http://${CI_USER}:${CI_ACCESS_TOKEN}@REPO_URL --follow-tags master:master
- git checkout develop
- git merge master
- git push http://${CI_USER}:${CI_ACCESS_TOKEN}@REPO_URL --follow-tags develop:develop
Replace REPO_URL
with the URL to your repository. I had to include the port number (80
in my case) as well.
Affiliate Content Start
Apple AirPods 4 Wireless Earbuds, Bluetooth Headphones, with Active Noise Cancellation, Adaptive Audio, Transparency Mode, Personalized Spatial Audio, USB-C Charging Case, Wireless Charging, H2 Chip
$158.39 (as of December 19, 2024 06:18 GMT +08:00 - More infoProduct prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on [relevant Amazon Site(s), as applicable] at the time of purchase will apply to the purchase of this product.)TOZO Hybrid Active Noise Cancelling Wireless Earbuds, 6 Mics Smart Noise Cancelling 55H Playtime, 32 Preset EQs via APP, Bluetooth 5.3 ENC AI Call Ear buds, IPX8 Waterproof Headphones with LED Display
$24.99 (as of December 19, 2024 06:18 GMT +08:00 - More infoProduct prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on [relevant Amazon Site(s), as applicable] at the time of purchase will apply to the purchase of this product.)New Amazon Fire HD 8 Kids tablet, ages 3-7. With bright 8" HD screen. Includes ad-free and exclusive content, parental controls and 13-hr battery, 32GB, Blue, (2024 release)
$69.99 (as of December 19, 2024 06:18 GMT +08:00 - More infoProduct prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on [relevant Amazon Site(s), as applicable] at the time of purchase will apply to the purchase of this product.)Affiliate Content End
Step 2: Add Project level CI variables in Gitlab
Add CI_ACCESS_TOKEN
and CI_USER
variables with an access token/user that has access to the project.
Step 3: Add package.json
The following package.json
file contains the minimum configuration required to make standard-version
work. (The replace-in-file
dependency is only required if you need to replace the version string in some files.)
package.json
{
"name": "jekyll-browser-startpage",
"version": "0.1.0",
"description": "A browser startpage.",
"main": "index.js",
"directories": {
"test": "tests"
},
"scripts": {
"release": "standard-version -a"
},
"repository": {
"type": "git",
"url": "https://github.com/danobot/jekyll-browser-start"
},
"author": "Daniel Mason",
"license": "MIT",
"devDependencies": {
"semantic-release": "^15.13.3",
"standard-version": "^4.4.0",
"replace-in-file": "^3.4.3"
},
"standard-version": {
"scripts": {
"precommit": "node version_bump.js && git add startpage/_includes"
}
}
}
Notes:
- In my experience, the precommit
node
script must reference a Javascript file in the root of the project directory. - If you have issues with node not running your script or Gitlab not committing the changed file, then copy the directory layout exactly. There are weird issues where subfolders cannot be found.
Step 4: Add a custom script to substitute version strings
This step is optional. if there are files where the version string is referenced (such as a HTML partial), then use the version+bump.js
file below to regex replace the version string. The output of this file is used by standard-version
as the commit message.
Kitchen Multi-Timer Pro
Now you’re cooking
Multi Timer Pro is your ultimate meal prep companion, keeping track of multiple cooking times and making adjustments on the fly. Give it a try today and become a better home cook!
version_bump.js
var v = require('./package.json').version
console.log(v)
const replace = require('replace-in-file');
const regex = new RegExp(/.*/, 'i');
const options = {
files: 'startpage/_includes/version.html',
from: regex,
to: "v" + v,
};
var changes = replace.sync(options)
console.log("chore(release): " + v)
That’s it
You should now have a working pipeline that will run the test
job on non-master branches and will prepare a release version with an auto-generated changelog when Merge Requests are merged onto master
. The image below shows the pipeline.
1 Comment
Hey Daniel! Excellent article! Just a suggestion: I would add an explanation regarding in which part of the job you tell gitlab to avoid the infinite loop when pushing.
Thanks a lot for sharing! This saved me!