Embracing Automated Versioning with Semantic Release

In the ever-evolving landscape of software development, managing version numbers and ensuring consistent releases can often become a challenging task. Enter Semantic Release: a tool designed to automate the entire versioning and release process. In this post, we’ll dive deep into what Semantic Release is, how it works, and why it’s an essential tool for modern development practices.

What is Semantic Release?

Semantic Release is an automated version management and package publishing tool. It automates the process of determining the next version number, generating release notes, and publishing the package. By doing so, it ensures that every change to your codebase that meets certain criteria results in a new release. This process helps maintain a consistent and predictable versioning scheme, reducing the overhead and potential errors associated with manual releases.

Angular Commit Message Pattern

At the heart of Semantic Release is the Angular commit message convention. This convention standardizes commit messages, making it easier for Semantic Release to determine the nature of changes made in the codebase. The commit messages follow a specific pattern:

  • feat: A new feature
  • fix: A bug fix
  • docs: Documentation-only changes
  • style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
  • refactor: A code change that neither fixes a bug nor adds a feature
  • perf: A code change that improves performance
  • test: Adding missing or correcting existing tests
  • chore: Changes to the build process or auxiliary tools and libraries such as documentation generation

For instance:

feat: add user authentication
fix: resolve issue with data fetching
docs: update API documentation

Semantic Versioning

Semantic Release leverages Semantic Versioning (SemVer) to ensure that version numbers convey meaning about the underlying changes. Semantic Versioning uses a three-part version number: MAJOR.MINOR.PATCH. Incrementing these numbers follows a set of rules:

  • MAJOR version when you make incompatible API changes,
  • MINOR version when you add functionality in a backwards-compatible manner, and
  • PATCH version when you make backwards-compatible bug fixes.

For a detailed guide on Semantic Versioning, refer to our previous post: Understanding Semantic Versioning: A Guide for Developers.

Why Semantic Versioning Matters

The majority of the software development community adopts Semantic Versioning because it provides a clear and transparent way to communicate changes to the users of your software. It helps in setting expectations regarding the impact of changes and maintaining a predictable release cycle.

The Release Process

At the end of the release process, Semantic Release also commits the new version number to your project’s configuration file (like package.json or pom.xml) with a [skip ci] tag. This tag ensures that the commit itself does not trigger another build or release process, preventing an infinite loop of releases.

For example, after a release, your package.json might be updated and committed with:

{
  "name": "your-project",
  "version": "1.2.3",
  // other config...
}

And the commit message would look like:

chore(release): 1.2.3 [skip ci]

Using Semantic Release in a React Application with Next.js

Let’s walk through a simple example of setting up Semantic Release for a React application using Next.js.

Step 1: Install Dependencies

First, you need to install Semantic Release and its plugins:

npm install --save-dev semantic-release @semantic-release/changelog @semantic-release/git @semantic-release/github @semantic-release/npm

Step 2: Configure Semantic Release

Create a .releaserc configuration file in the root of your project:

{
  "branches": ["main"],
  "plugins": [
    "@semantic-release/commit-analyzer",
    "@semantic-release/release-notes-generator",
    "@semantic-release/changelog",
    "@semantic-release/npm",
    "@semantic-release/github",
    "@semantic-release/git"
  ]
}

Step 3: Add a Configuration Script

Add a script to your package.json to run Semantic Release:

{
  "scripts": {
    "release": "semantic-release"
  }
}

Step 4: Setup CI/CD

Configure your CI/CD pipeline to run the npm run release command after your tests pass. Here’s an example using GitHub Actions:

Create a .github/workflows/release.yml file:

name: Release

on:
  push:
    branches:
      - main
jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Use Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
      - run: npm install
      - run: npm run release
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # variable used by Semantic Release
          NPM_TOKEN: ${{ secrets.NPM_TOKEN }} # variable used by Semantic Release

Step 5: Commit and Push

Commit your changes and push them to your repository:

git add .
git commit -m "chore: setup semantic release"
git push origin main

Now, every push to the main branch will trigger a release process that includes versioning, changelog generation, and publishing to npm and GitHub.

There are several tools available to make easier to commit following the Angular convention, like Commitizen, that opens an interactive shell on every commit, guiding you to react the best commit message possible for that change.

For example, let’s say we just updated the README of our project, then this is familiar for you probably:

Regular commit process

But, instead of finishing the git commit command with -m "Adding API docs to README" , we can just hit Enter and then the Commitizen shows up withe the interactive terminal:

Interactive Commitizen shell

And then, following it’s instructions you will get the final commit message as:

Angular convetional commit message made by Commitizen

Conclusion

Semantic Release is a powerful tool that automates the tedious and error-prone process of versioning and releasing software. By adopting it, you can ensure consistent, meaningful versioning and streamline your release workflow. Its integration with Semantic Versioning and the Angular commit message convention makes it a valuable addition to any modern development pipeline. Start using Semantic Release today to enhance your project’s release process and maintain a predictable, reliable versioning scheme.