Automate npm releases using semantic-release
Tags: github, npm, devops, javascript
Published: 2019-11-29 22:39:45

In an ideal world, the source code of an npm library is in sync with the versions published to the npm registry. 

**The problem** is that the latest package versions published to npm are lacking behind their code. This results in

1. **Frustrated contributors**, whose pull requests got merged and now wait to use the new version that includes their fixes or features
2. **Confused users** that run into a bug that is marked as resolved on GitHub
3. **Stressed maintainers** that are pressured by comments such as "When will this fix be released?" on closed issues and pull requests.

**The solution**: automation. Enter [semantic-release](https://semantic-release.gitbook.io/semantic-release/)

In a nutshell, `semantic-release` relies on commit message conventions to calculate and publish a new version of your package. By default, the 3 conventions are

1.  `fix: ...` prefix in commit subject: triggers a fix release version, e.g. `1.2.3` → `1.2.4`
2.  `feat: ...` prefix in commit subject: triggers a feature version, e.g. `1.2.3` → `1.3.0`
3.  `BREAKING CHANGE:` in commit body: triggers breaking version release, e.g. `1.2.3` → `2.0.0`

**That is all you need to learn.**

Based on these conventions, new versions are continuously published to npm. Your code on GitHub and published versions on npm will never be out of sync again.

But semantic-release does much more than this:

1. It creates GitHub releases to mirror the versions published to npm and adds changelogs based on above conventions and adds them to the GitHub releases. [![GitHub release](https://thepracticaldev.s3.amazonaws.com/i/nso643pk7dhng0qu0l52.png)](https://github.com/octokit/action.js/releases/tag/v1.2.0)
2. It notifies contributors with comments in pull requests and resolved issues that a new version has been released [![Comment by semantic-release](https://thepracticaldev.s3.amazonaws.com/i/j4m50043hioerpsirk67.png)](https://github.com/octokit/action.js/pull/8#event-2829342950)
3. It lets you control in a single place who can both merge changes into the `master` branch and publish new versions to npm.

### Setup using GitHub Actions

`semantic-release` supports a variety of CI providers, git hosts and package registries. For this example, I'll use GitHub Actions to publish to npm.

Install semantic-release

```shell
npm install --save-dev semantic-release
```

If this is an existing project, make sure to create a git tag that matches the last version in the npm registiry, using a `v` prefix. For example, if the last version published to npm is `2.0.4`, create a `v2.0.4` tag and push it to your repository.

```shell
git tag v2.0.4
git push --tags
```

No need to create a tag for new packages that have not yet been published.

Next, replace the version in your `package.json` file with "0.0.0-development". The version will be updated automatically by semantic-release. You no longer need to worry about it.

Next, create an npm token for your account at `https://www.npmjs.com/settings/[YOUR USERNAME]/tokens` with the `read and publish` setting. Copy that token and store it [in your repository's secrets](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/creating-and-using-encrypted-secrets#creating-encrypted-secrets) using the name `NPM_TOKEN`.

Finally, create a `.github/workflows/release.yml` file to run semantic-release each time a change is pushed to your repository's `master` branch.

```yml
name: Release
on:
  push:
    branches:
      - master

jobs:
  release:
    name: release
    runs-on: ubuntu-latest
    steps:
      # check out repository code and setup node
      - uses: actions/checkout@v1
      - uses: actions/setup-node@v1
        with:
          node-version: "12.x"
      # install dependencies and run semantic-release
      - run: npm ci
      - run: npx semantic-release
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
```

That's it. Next time you merge a pull request with commit messages following the conventions mentioned above, semantic-release will create the npm and GitHub releases as well as comments on the pull request and linked issues.

### Closing words

You can see `semantic-release` in action all over my projects on GitHub. I usually make multiple releases each work day. I don't even think about it any longer. It frees up my time and thoughts to focus on the code instead of the chores around it.

And lastly, a tip: automating releases goes hand-in-hand with automating dependency updates. Services such as [Greenkeeper](https://greenkeeper.io) even follow the required commit conventions when they send their pull requests. Merging the PRs is all it takes to release a new version. I highly recommend to use them both!