Semantic release with commitizen and commitlint
Oct 22, 2019Versioning, Releasinghttps://git.io/JvKN0
semantic-release is an awesome tool kit to help automate the versioning and releasing of npm libraries or Node.js projects. There are varieties of plugins to extend the functionality of semantic-release. Other than that, two libraries out of the semantic-release ecosystem can help to streamline the workflow, they are commitizen and commitlint.
Please go to the GitHub page of the each libraries for detailed description and usage guide. This post will demonstrate a conventional local setup and CI steps.
Install husky for git hooks management.
npm install --save-dev husky
Create a .huskyrc.js
file:
module.exports = {
hooks: {
'prepare-commit-msg': 'exec < /dev/tty && git cz --hook || true', // commitizen
'commit-msg': 'commitlint -E HUSKY_GIT_PARAMS', // commitlint
'pre-commit': 'lint-staged', // custom hook
'pre-push': 'npm test', // custom hook
},
};
Install commitizen
npm install --save-dev commitizen
npx commitizen init cz-conventional-changelog --save-dev --save-exact
Now try it out:
git add . && git commit
You should see logs similar as blew which means it works.
husky > prepare-commit-msg (node v12.x.x)
[email protected]x.x.x, [email protected]x.x.x
? Select the type of change that you're committing: (Use arrow keys)
❯ feat: A new feature
fix: A bug fix
docs: Documentation only changes
...
Install commitlint
npm install --save-dev @commitlint/config-conventional @commitlint/cli
Create a .commitlintrc.js
file:
const { types } = require('conventional-commit-types');
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
// Follow the commit-types used by commitizen (https://git.io/Je4pr).
'type-enum': [2, 'always', Object.keys(types)],
// Blow lines are optional.
'header-max-length': [2, 'always', 100],
'body-max-line-length': [2, 'always', 100],
'footer-max-line-length': [2, 'always', 100],
},
};
Now test it out:
git add . && git commit -m "test"
Even we explicitly provide commit message, the prepare-commit-msg
hook will still be revoked and the commitizen
will show the prompts. We can just press Ctrl + C to skip it and it comes to commit-msg
hook and you can see the output as blow which means it works.
husky > commit-msg (node v12.x.x)
⧗ input: test
✖ subject may not be empty [subject-empty]
✖ type may not be empty [type-empty]
✖ found 2 problems, 0 warnings
...
Adding commitlint
locally in the git hook can prevent developers to create invalid commit messages by mistake. However, local git hooks can always being bypassed.
In order to enforce the conventional commit format in the repository so that semantic-release
can leverage on that to generate the correct version number, we need to run commitlint
in CI to check against commit messages from the pull requests.
Here's the command to serve that purpose:
npx commitlint --verbose --from origin/$TARGET_BRANCH --to $FETCH_HEAD
Here the $TARGET_BRANCH
is the branch that incoming pull request is merging to. The $FETCH_HEAD
is the hash of the last commit on the source branch of the pull request. These two values can normally get from the environmental variables of the CI system.
Install semantic-release
npm install --save-dev semantic-release
Add and optional config file .releaserc.js
:
module.exports = {
plugins: [
[
'@semantic-release/commit-analyzer',
{
// https://github.com/semantic-release/commit-analyzer#releaserules
releaseRules: [
{ scope: 'no-release', release: false },
{ breaking: true, release: 'major' },
{ type: 'feat', release: 'minor' },
{ type: 'refactor', scope: 'core-*', release: 'minor' },
{ type: '*', release: 'patch' },
],
},
],
'@semantic-release/release-notes-generator',
'@semantic-release/github',
],
};
Refer to the CI Configuration chapter for guides of running semantic-release in CI.