Skip to content

Automate the release stuff on GitHub

Posted on:December 17, 2023 at 10:17 PM

Alien hive

This post aims to guide you through the process of automating release and publishing of a package stored on GitHub. We are going to use release-it tool that strikes a good balance between features and simplicity of configuration.

Table of contents

Open Table of contents

The “Why”

There are several steps required to be performed every time we want to release a new version of our package. They usually consist of:

Every manual process comes with a cost of time and possible human errors, e.g.

Fortunately, there are tools that can help us with fully automating this whole process so we can focus on important parts (like adding shiny new features to our library or fixing bugs users are complaining about).

The “How”

How all of this is going to work (or at least is supposed to):

Here are the steps required to achieve this:

1. Adding required credentials

In order to perform release and publish process we will need a couple tokens - for Github and npm.

After you generate npm token, add it to repository secrets as NPM_TOKEN here. Github token get’s created automatically and should work out of the box. If it doesn’t, create one yourself.

2. Installing packages and adding npm scripts

We will also add should-semantic-release package that will block certain commits from triggering new releases (e.g. Renovate/Dependabot ones), we don’t want to release a new version every time a dependency is updated.

npm install -D release-it @release-it/conventional-changelog should-semantic-release

yarn add -D release-it @release-it/conventional-changelog should-semantic-release

pnpm add -D release-it @release-it/conventional-changelog should-semantic-release
/* file: package.json */
"scripts": {
  "release": "release-it",
  "should-semantic-release": "should-semantic-release --verbose",
}

3. Setting up release-it configuration

Don’t hesitate to modify below config and adjust it to your needs, there are a lot of possible options to choose from.

/* file: .release-it.json */
{
  "git": {
    "requireBranch": "main", // Your main branch name
    "requireCommits": true,
    "commitMessage": "chore: release v${version}"
  },
  "github": {
    "autoGenerate": true,
    "release": true,
    "releaseName": "v${version}"
  },
  "npm": {
    "publish": true,
    "publishArgs": ["--provenance"] // https://docs.npmjs.com/generating-provenance-statements
  },
  "plugins": {
    "@release-it/conventional-changelog": {
      "preset": {
        "name": "conventionalcommits"
      },
      "infile": "CHANGELOG.md",
      "header": "# Changelog"
    }
  }
}

4. Adding github workflows

  1. Validate non-code contents of a PR (title, body, origin branch).

    # file: .github/workflows/compliance.yml
    name: Compliance
    
    on:
      pull_request:
        branches:
          - main
        types:
          - edited
          - opened
          - reopened
          - synchronize
    
    permissions:
      pull-requests: write
    
    jobs:
      compliance:
        runs-on: ubuntu-latest
        steps:
          - uses: mtfoley/pr-compliance-action@main
            with:
              body-auto-close: false
              ignore-authors: |-
                allcontributors
                allcontributors[bot]
                renovate
                renovate[bot]
                dependabot
                dependabot[bot]
              ignore-team-members: false
              issue-labels-auto-close: false
  2. Add a comment inside merged PR when it gets included into a new release.

    # file: .github/workflows/post-release.yml
    name: Post Release
    
    on:
      release:
        types:
          - published
    
    jobs:
      post_release:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v4
            with:
              fetch-depth: 0
          - run: echo "npm_version=$(npm pkg get version | tr -d '"')" >> "$GITHUB_ENV"
          - uses: apexskier/github-release-commenter@v1
            with:
              GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
              comment-template: |
                :tada: This is included in version {release_link} :tada:
    
                The release is available on:
    
                * [GitHub releases](https://github.com/JoshuaKGoldberg/create-typescript-app/releases/tag/{release_tag})
                * [npm package (@latest dist-tag)](https://www.npmjs.com/package/create-typescript-app/v/${{ env.npm_version }})
  3. Execute release-it-action to perform release and publish process if newly merged commit passes should-semantic-release check. The action takes care of saving branch protection settings, disabling them temporarily for the release commit (version and changelog update) and restoring them afterwards.

    # file: .github/workflows/release.yml
    name: Release
    on:
      push:
        branches:
          - main
    
    permissions:
      contents: write
      id-token: write
    
    concurrency:
      cancel-in-progress: true
      group: ${{ github.workflow }}
    
    jobs:
      release:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v4
            with:
              fetch-depth: 0
              ref: master
          - uses: actions/setup-node@v3
            with:
              node-version-file: package.json
          - name: Install dependencies
            run: npm ci
          - name: Release
            uses: JoshuaKGoldberg/[email protected]
            env:
              GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
              NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
            # use below in case there are 403 errors with npm authentication
            # with:
            #   npm-token: ${{ secrets.NPM_TOKEN }}

Once all above workflows complete successfully, you should be able to see a new release on GitHub’s releases page.

Github release page

A release commit should be added to the main branch.

Github commits

New version should be visible in changelog.

Changelog file

New version should be published in npm.

npm releases page

A comment will be visible in merged PR.

Github release comment

Working example can be found in this repository.

Credits