How to: Npm release & changelog automation with Github Actions



One of the hallmarks of highly functioning development teams is speed of the release cycle - Highly functioning agile teams release more often than those that are still lagging behind. One of the cornerstones of such teams is high level of automation as time spent doing releases is off from development and repetitive manual work equates to high risk of human errors. Additionally, release process is also one the most critical things to automate as errors during release can have high impact on business and/or end user experience. Thus, to fix that problem, here is a quick tutorial how to set up automation to publish your packages to npm, version them correctly and create clean, human readable changelogs for each version released.
How it works
There are three pieces we need for the automation: Conventional Commits, Github Actions and semantic-release.
This setup is based on trunk based development workflow, where pull requests are merged to master and releases are made directly from there. If you have different type of workflow, you need to modify the settings according.
Conventional Commits
Conventional Commits is a convention for writing commit messages (or pull request merges if you use squash and merge) that makes them machine readable, this way automation can deduct the scope of the release and build human readable changelog based on it. We will be using Conventional Commits to write our commit messages/pull requests.
Commit message following Conventional Commits should be structured as follows:
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]
Example of simple commit message:
fix(package.json): Fixed the package namespacing
Read more at conventionalcommits.org
Github Actions
Github Actions are simple way to automate development workflows. We will be using simple Github Action
to run our release & publish action whenever anything new lands on master
branch.
Read more at github.com/features/actions
semantic-release
Semantic-release is a release automation package that does it all for you based on commit messages written following Conventional Commits. It reads the git history, figures out what is new, what should the version number be, writes changelog and publishes the package. We will be using this for doing the actual release.
Read more at github.com/semantic-release.
Setting it up
How to set everything up in three simple steps
1. Enforce Conventional Commits
In order to make sure that all of our commits/pull requests are machine readable we need to enforce that they follow the Conventional Commits. There are tons of Github actions and apps for this, one that I have personally been using is Semantic Pull requests. Whatever you choose, enable it as required pull request check for the repository.
2. Add release action
Next we need to define the release workflow that runs the semantic-release package and set it to be executed when anything gets pushed/merged to master.
Create file at .github/workflows/release.yml
name: Release
on:
push:
branches:
- master
jobs:
release:
name: Release
runs-on: ubuntu-18.04
steps:
- name: Checkout
uses: actions/checkout@v1
- name: Setup Node.js
uses: actions/setup-node@v1
with:
node-version: 12
- name: Install dependencies
run: npm ci
- name: Run build
run: npm run build --if-present
- name: Release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: npm run release
3. Configure NPM_TOKEN
In order for sematic-release to be able to publish the package to npm you need to provide an access token for it through Github secrets.
Log in to npmjs.com and generate new access token, make sure it has Publish access level.
Set it to secrets as NPM_TOKEN
in your repository settings
All done
And there you have it. You should now have automation that triggers when anything is pushed/merged to master branch, releasing your module without any human interaction.
What the automation does:
- Git history is scanned for any new commits matching Conventional Commits standard
- New version number is set according to the commit history since last release
- The module is published to npm with matching version number
- New Github release is created and human readable changelog is created for it
Published npm package:
Github release with changelog:
Happy releasing!