Releases

Semantic releases

Introduction:

The purpose of having Semantic-Release is so that we can release workable versions to our users frequently. So we shouldn’t be releasing non-workable versions, so before we began to use semantic release, we should have our working branches ready, and releases should only happen in the master branch.

We need 3 main components:

  • Git hook: we will use husky (opens in a new tab).
  • commitlnt: it will act as linter for our commit messages.
  • Semantic-release: It will use the commit history, that are respecting the Conventional commit standards, to generate Release notes and versions automatically.

Commit Conventions:

Conventional Commits provides an easy set of rules for creating an explicit commit history; which makes it easier to write automated tools on top of .

Conventional Commits standards Official website (opens in a new tab)

To achieve such, we need to install a package called Commitlint.
Commitlint is the ESLint for commit messages. It performs validations on any text against a predefined commit format. We can configure these formats to our needs or adopt pre-built-in conventions, such as conventional commits.

We create a file under .husky folder, #!/usr/bin/env sh

. "$(dirname -- "$0")/_/husky.sh"
 
npx commitlint --edit

And finally we create a config file commitlnt.config.js where we specify the conventions

module.exports = {
  extends: ['@commitlint/config-conventional'],
};

General structre of a commit message

<type>(<scope?>): <subject!>

Where:

type:

IThe type is mandatory and determines the intent of the change. Here are possible values:

  • build: changes affecting build systems or external dependencies
  • ci: updating configuration files for continuous integration and deployment services
  • chore: updating grunt tasks etc.; no production code change
  • docs: documentation-only changes
  • feat: a new feature
  • fix: a bug fix
  • perf: a code change that improves performance -refactor: a code change that neither fixes a bug nor adds a feature
  • style: changes that do not affect the meaning of the code (white-space, formatting, missing semicolons, etc.)
  • test: adding missing tests or correcting existing tests
  • BREAKING CHANGE : Major update.

Scope

A scope is an optional value that provides additional contextual information about the change. For example, when the module’s name, npm package, or particular routine was affected.

Subject

The subject is the headline of the commit. It should summarize in one sentence the nature of change.

For the subject, consider the following rules:

  • use the imperative, present tense: “change,” not “changed” nor “changes”
  • do not capitalize the first letter
  • no dot (.) at the end

Github wokrflow for semantic release

First, we need to install package called Semantic-release npm install -D semantic-release.

Next, we add the plugings and config to package.json so we inform semantic-release about pluging and the branch of release.

 "plugins": [
    "@semantic-release/commit-analyzer",
    "@semantic-release/release-notes-generator",
    "@semantic-release/changelog",
    "@semantic-release/github",
    "@semantic-release/npm",
    "@semantic-release/git"
  ],
  "release": {
    "branches": [
      "main"
    ],
    "tagFormat": "${version}",
    "publish": [
      "@semantic-release/github"
    ],
    "prepare": [
      "@semantic-release/npm",
      "@semantic-release/changelog",
      {
        "path": "@semantic-release/git",
        "message": "release ${nextRelease.version}\n\n${nextRelease.notes}"
      }
    ]
  }

Finally,under .github/workflows/, we create file called: semantic-release.yml that will actually be triggered manually evertime we need to release a new version.

Workflow details are bellow :

name: Semantic release
 
# for manual action triggering.
on: [workflow_dispatch]
 
jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Cache node modules
        id: cache
        uses: actions/cache@v3
        with:
          path: node_modules
          key: cache-node-${{ hashFiles('package-lock.json') }}
      - name: Setup Node
        uses: actions/setup-node@v1
        if: steps.cache.outputs.cache-hit != 'true'
        with:
          node-version: 16
      - name: Install packages
        if: steps.cache.outputs.cache-hit != 'true'
        run: npm install
 
      - name: Launch Semantic release
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: npx semantic-release

Since the build is triggered manually, we need to head to Github Actions section then find semantic Release workflow, and trigger it on branch main.

Note that :

  • feat:.... commmit message will bump the minor version of the release 'major:minor:patch'
  • fix:.... commit message will bump the patch version of the release 'major:minor:patch'
  • BREAKING CHANGE commit message will trigger a major bump to the version.

Result :