3 Jul 2019
How to automate release logs and builds for your style guides.
As of lately design systems have been all the rage and the benefits of producing one seem to be clear. Buying into a system might seem like a straight forward decision, but keeping everyone in the loop of changes is exponentially more complicated. If you work on the development end of any type of component library you know the silent difficulties of building and publishing processes.
The boring parts are a crucial part of the process. If you maintain projects that rely on versioning you’ll probably find yourself repeatedly doing the same task. And while semver as general practise is great, it’s difficult to enforce and to not decide on versions arbitrarily. When the times comes to inform stakeholder of choices and implementation details one month has gone by, and you’ve forgotten about most of the features and fixes implemented. And what good is a system that no one remembers?
“What’s the status on this component? Did we ship this already? When did we start getting this Type Error?”
This article covers a small part of that process, giving you a few practical tips on how to maintain a clear log and automatically build changes. This method can be applied to anything, from UI Kits, to packages and apps.
In order to create this flow we’ll go through a few steps:
Creating good commit messages. Using conventional commits.
Enforcing good practises. With pre-commit hooks.
Creating releases. Our release cookbook.
This article has some companion gists. 🛠
The first step is to follow a commit convention so you can generate your changelog without any manual work. Your contributions will be grouped by commit type and will look a bit like this type(scope): short description for commit
with the type ranging from FEAT
to TEST
, determining what type of changes went into your code. To generate a template for commit messages we‘ll be using commitizen’s CLI.
Since we’re going to want this to be used on all of your projects right out of the gate we’re going to do some global installation with npm install -g commitizen
.
Every project requires different things, and commit messages are part of that. So depending on the format you need you can install one of several adapters. From emoji filled commit messages to JIRA integrations. For the purposes of this guide, we’ll use cz-conventional-changelog. We’ll now initiate the adapter.
commitizen init cz-conventional-changelog --save-dev --save-exact
Then create a .czrc on your root folder (~) with the following content:
{ "path": "cz-conventional-changelog" }
Now, every time you’re in a git repository if you use the command git czthe CLI will show up, asking you to catalogue your commit according to the type of changes you made.
This is all great, but it won’t add up to much if you write DID_STUFF
as the scope of your change. That’s certainly invalid and won’t help much when generating your logs. To solve this problem we’ll put into place a commit validator and a pre-commit hook which will validate our commit messages before they go through. To create the hook we’ll use commitlint and husky.
Add the extra layer of security to be run on pre-commit with npm install -g @commitlint/cli @commitlint/config-conventional
. And now your pre-commit checker with npm install husky --save-dev
.
Create a .huksyrc
file with the commitlint reference on "commit-msg"
.
{ "hooks": { "commit-msg": "commitlint -E HUSKY_GIT_PARAMS", "pre-commit": "npm run lint" }}
And create a configuration file to hold your preferred tests, in any of the following formats:
commitlint.config.js
.commitlintrc.js.commitlintrc.json
.commitlintrc.yml.
Then add a reference to the adapter you chose on the first step:
module.exports= { extends: ["@commitlint/config-conventional"] };
This will result in a verification triggering the husky > commit-msg
validation, which might either pass or return a message with the problem at fault. Bear in mind that if you use flags such as --no-verify
this validation won’t occur.
With the message formatting sorted we can now focus on the actual bundling and releasing of your UI. We’ll now create a script to be executed on your CI (or locally with (`dry-mode`) environment), that’ll look at your commit history and do all the magic. We’re gonna create script with the dependency on you package.json:
{
"name": "automation-for-ui-kits",
"version": "0.1.0",
"main": "dist/bundle.js",
"license": "MIT",
"private": false,
"repository": {
"type": "git",
"url": "https://github.com/automation/automation-for-ui-kits"
},
"dependencies": {
"YOUR_DEPENDENCIES_OF_CHOICE": "VERSION"
},
"scripts": {
"YOUR_SCRIPTS_OF_CHOICE": "VERSION",
"build": "YOUR_METHOD_OF_CHOICE",
"release": "semantic-release",
"lint": "eslint src/ --fix"
},
"eslintConfig": {
"extends": "react-app"
},
"devDependencies": {
"YOUR_DEV_DEPENDENCIES_OF_CHOICE": "VERSION",
"@semantic-release/commit-analyzer": "^6.1.0",
"@semantic-release/git": "^7.0.8",
"@semantic-release/github": "^5.2.10",
"@semantic-release/release-notes-generator": "^7.1.4",
"semantic-release": "^15.13.12"
}
}
Now we’ll create our recipe for releases. These will vary depending on the project, technologies and implementation details but our core recipe revolves around these plugins:
{
"plugins": [
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator",
["@semantic-release/github", {
"assets": [
{"path": "dist/bundle.js", "label": "JS distribution"}
]
}],
["@semantic-release/git", {
"assets": ["dist/**/*.{js,css}"],
"message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
}]
]
}
/COMMIT-ANALYZER
: This is what powers all of the release, and this is why our commits must be formatted exactly as specified by the chosen convention. This will ensure that certain types
will be associated with a patch, minor or major
release. This will be visible in your terminal or the virtual environment you’re running. You can see what each type of commit triggers.
/RELEASE-NOTES-GENERATOR
: What generates your changelog based on the conventional commit standard defined above. Which will result in a release log similar to the one below.
/GIT and /GITHUB
: This is the final part of the configuration enabling you to push commits with the bundled coded to your folder of choice, with the fomat defined on the .releaserc
. It’ll also release, comment and tag your pull requests and issues. Magical isn’t it?Conclusion
Like most automation scripts the configuration is cumbersome, but the time and stability you’ll gain in the long run is worth the effort. Since we’re using computers we might as well use that to our advantage and do things in a smart and efficient way.
All the examples here were quickly built for the purpose of this article and should be adapted to your project’s reality, so feel free to adapt your build scripts and the message conventions to the format that’ll best suit your needs.
Like most automation scripts the configuration is cumbersome, but the time and stability you’ll gain in the long run is worth the effort. Since we’re using computers we might as well use that to our advantage and do things in a smart and efficient way.
All the examples here were quickly built for the purpose of this article and should be adapted to your project’s reality, so feel free to adapt your build scripts and the message conventions to the format that’ll best suit your needs.
Isabel Sá
(Former) Designer
Nuno Polónia
Front-End Developer
18 October 2024
Master JavaScript web animations with requestAnimationFrame.Significa
Team
30 September 2024
Optimise your e-commerce website for better performance.Significa
Team