Workflow highlights

The only requirement to be able to automate versioning and publication of a package is that every commit should follow a message convention, we follow the Conventional Commits Specification.

So our commits look like this:

6f88099 - (tag: v1.8.0, master) chore(release): 1.8.0

333dce9 - feat: add composable Avatar component

ffb2263 - fix: add correct styles to Label component

7d34334 - chore: update Jest to 24.7.1

You can check different examples of Conventional Commits in their documentation site.

Enforce conventional commits

It’s easy to forget about the commit convention so to be consistent we use commitzen to generate our commits and husky to manage a Git commit-msg hook to validate the commit message.

You can install husky and commitzen easily:

npm i -D husky @commitlint/{config-conventional,cli}

And this setup needs to be added to your package.json :

"config": {

"commitizen": {

"path": "cz-conventional-changelog"

}

},

"husky": {

"hooks": {

"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"

}

}

To test it just try to commit a change with a message that doesn’t follow the commit convention and it will throw an error.

In our case we are also using a pre-commit hook triggering lint-staged to lint and format the changes before commiting them, in the last section you can see an example from our package.json .

Update package version based on commits

We use standard-version to automatically change the version based on the commit history.

To install standard-version just run:

npm i -D standard-version

And then you can create the release script in your package.json :

{

"scripts": {

"release": "standard-version"

}

}

Now you could run npm run release to trigger a version update.

Take into account that standard-version will change your version number following these guides:

A git commit -m “fix: …” commit will trigger a patch update (1.0.0 → 1.0.1)

commit will trigger a (1.0.0 → 1.0.1) A git commit -m “feat: …” commit will trigger a minor update (1.0.0 → 1.1.0)

commit will trigger a (1.0.0 → 1.1.0) A BREAKING CHANGE: … in the commit body and with any type of commit will trigger a major update (1.0.0 → 2.0.0)

As a summary, standard-version will do these tasks:

Bumps the version in package.json

Updates CHANGELOG.md

Commits both files

Tags a new release

What standard-version doesn’t do is pushing the commit to your remote repository, so after running npm run release you need to perform

git push --follow-tags origin master and publish the package.

Some cool extras you can do in the release process

There are a several extra tasks that can be done automatically during the release process, for example:

A Github Release using conventional-github-releaser (creates a nicer release in Github listing the new features, fixes or breaking changes)

Automatically update contributors in package.json using git-authors-cli

using git-authors-cli Generate a static version of a styleguide (could be Storybook, Styleguidist, Docz…)

Check that your package doesn’t reach a predefined maximum size, using size-limit

You can see an example on how to use some of these extras in the last section of this article.

Trigger a release

Once a commit reaches master, to perform a release just needs one command: npm run release

What happens next? A lot of things could happen behind the curtain, all the magic is done using some npm packages and npm scripts.

This could be a normal workflow using standard-version, but the possibilities are endless:

Validate the changes (running tests, checking that changes satisfy ESLint or Prettier, or checking maximum size of a package) If all the previous checks were successful, then a static build of any Styleguide could be build or even deployed After that CHANGELOG.md and package version are updated and a new commit is generated The next step is to push to Github both the tags and a release version (for this step is needed a Github auth token) The last step is to publish the new version to npm, this is usually done in a CI server but can be done locally as well

Keep reading if you wanna see the packages and the setup we use to perform a similar workflow.