DEV Community

Cover image for Automating Releases with Semantic Versioning and GitHub Actions
Aditya Arpan Sahoo
Aditya Arpan Sahoo

Posted on

Automating Releases with Semantic Versioning and GitHub Actions

Introduction

Automating versioning and releases is essential for maintaining a smooth and consistent development workflow. By combining Semantic Versioning (SemVer) with GitHub Actions, you can automatically manage version bumps, changelogs, and releases whenever changes are pushed to your repository. This eliminates manual tasks, improves productivity, and ensures a reliable release process. This process is a part of the broader CI/CD workflow, ensuring consistent and error-free releases.

In this guide, we’ll walk through setting up a GitHub Actions workflow that automates the release process using Semantic Versioning.

Understanding the Setup

Before diving into the implementation, let's look at the key components we'll be using to build our automation workflow:

  • Semantic Versioning: This is a versioning system that follows the format MAJOR.MINOR.PATCH.
  • GitHub Actions: A CI/CD tool provided by GitHub that allows you to automate your workflows directly from your GitHub repository.
  • Packages we'll be using:

    • semantic-release: A fully automatic version management and release publishing tool.
    • @semantic-release/changelog: Automatically generates and updates changelogs based on commit messages.
    • @semantic-release/commit-analyzer: Analyzes commits and determines the next version based on commit messages.
    • @semantic-release/git: Pushes changes made by the semantic-release (like the changelog) back to your Git repository.
    • @semantic-release/github: Creates GitHub releases and adds release notes automatically.

What is Semantic Versioning?

SemVer
Semantic versioning (often abbreviated as SemVer) is a versioning scheme that aims to make it clear whether changes in your project are backward compatible, introduce breaking changes, or simply fix bugs. A typical SemVer version number looks like this: MAJOR.MINOR.PATCH (e.g. v1.4.8).

  • MAJOR version is incremented when you make incompatible API changes that breaks the current feature.
  • MINOR version is incremented when you add functionality in a backward-compatible manner.
  • PATCH version is incremented when you make backward-compatible bug fixes.

(Note: backward-compatible means the ability to be used with older/previous versions.)

Each update to the project can be classified into one of these categories, and semantic-release automates this process by updating the version automatically based on commit messages.

The Role of GitHub Actions in Continuous Deployment

GitHub Actions allows you to automate workflows directly in your GitHub repository. These workflows can run on various GitHub events like code pushes, pull requests, and more. In this blog, we’ll use GitHub Actions to automate our release process, from building to pushing version updates to the repository.

Why Automate Release?

Automating releases offers several benefits:

  • Consistency: No manual steps for incrementing versions or tagging releases.
  • Efficiency: Reduced time spent on repetitive tasks like updating changelogs, version numbers, and creating Git tags.
  • Error-Free: Eliminates human errors during the release process.
  • Reliability: The process is repeatable and can be reused across different repositories.

Automated Versioning with semantic-release

semantic-release is a powerful tool that automates version management based on your commit messages. It relies on the commit message convention known as Conventional Commits. Here’s how it works:

  • Breaking changes (such as feat!: or fix!: in commit messages) will trigger a major version bump.
  fix!: update deprecated API endpoint
  [v1.5.2 -> v2.0.0]

Enter fullscreen mode Exit fullscreen mode
  • New features (e.g., feat: in commit messages) will trigger a minor version bump.
  feat: add new user login feature
  [v2.0.5 -> v2.1.0]

Enter fullscreen mode Exit fullscreen mode
  • Bug fixes (e.g., fix: in commit messages) will trigger a patch version bump.
  fix: update documentation
  [v4.2.7 -> v4.2.8]

Enter fullscreen mode Exit fullscreen mode

Generating the Changelog

As part of the semantic-release process, a changelog is automatically generated. Here's an example of what the changelog looks like:

# [4.0.0](<https://github.com/arpanaditya/semantic-versioning-action/compare/v3.1.0...v4.0.0>) (2024-11-26)

* feat!: major update from dev BREAKING CHANGE: major update from dev ([fac5eec](<https://github.com/arpanaditya/semantic-versioning-action/commit/fac5eec5533c1fe3432f96986403efcfadbc79ae>))

### BREAKING CHANGES

* major update from dev

# [3.1.0](<https://github.com/arpanaditya/semantic-versioning-action/compare/v3.0.1...v3.1.0>) (2024-11-26)

### Features

* minor update from dev ([606258b](<https://github.com/arpanaditya/semantic-versioning-action/commit/606258b3318929182319b29a6a81eae0fabb138b>))

Enter fullscreen mode Exit fullscreen mode

Step 1: Install the Required Packages

We need to install the required packages as development dependencies. Run the following command to install them:

npm install --save-dev @semantic-release/changelog@6.0.3 @semantic-release/commit-analyzer@10.0.4 @semantic-release/git@10.0.1 @semantic-release/github@11.0.1 @semantic-release/release-notes-generator@11.0.7 semantic-release@24.2.0
Enter fullscreen mode Exit fullscreen mode

Step 2: Create a GitHbu Actions Workflow

Let’s create a .github/workflows/release.yml file in your repository. This file will define the GitHub Actions workflow that will be triggered on every push to the repository.

Here’s the basic structure of the release.yml workflow:

name: Release

on:
  push:
    branches:
      - main # Triggers when code is pushed to the main branch

jobs:
  release:
    permissions:
        contents: write
        pull-requests: write
    runs-on: ubuntu-latest # Runs on an Ubuntu runner

    steps:
      # Step 1: Checkout the repository code
      - name: Checkout Repository
        uses: actions/checkout@v3

      # Step 2: Set up Node.js
      - name: Set up Node.js
        uses: actions/setup-node@v3
        with:
          node-version: "20.x" # Use the Node.js version required for your project

      # Step 3: Cache Node.js modules to speed up future builds
      - name: Cache Node.js modules
        uses: actions/cache@v3
        with:
          path: node_modules
          key: ${{ runner.os }}-node-modules-${{ hashFiles('**/package-lock.json') }}
          restore-keys: |
            ${{ runner.os }}-node-modules-

      # Step 4: Install dependencies
      - name: Install Dependencies
        run: npm ci

      # Step 5: Run semantic-release
      - name: Run Semantic Release
        run: npx semantic-release
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Provide the GitHub token for authentication
Enter fullscreen mode Exit fullscreen mode

Breakdown of the Workflow Steps

  1. Checkout the Repository: This step checks out the latest code from the repository so that GitHub Actions can work with the latest changes.

  2. Set up Node.js: This action ensures that the correct version of Node.js is set up on the runner. In our case, we’re using Node.js version 20.x .

  3. Cache Node.js Modules: GitHub Action caches the node_modules directory to speed up future builds. This is crucial for larger projects where the installation of dependencies can take time.

  4. Install Dependencies: Using npm ci, this step installs the exact dependencies defined in the package-lock.json file, ensuring that the correct versions of packages are installed.

  5. Run Semantic Release: This step uses the semantic-release package to automatically determine the type of release (major, minor, patch) based on commit messages. It also updates the version in package.json , generates a changelog, and publishes the release.

(Note: The GITHUB_TOKEN is a secure token automatically provided by GitHub for workflows running in your repository. You don’t need to manually create or add this token. It is preconfigured)

Step 3: Configure Semantic Release

Next, we need to configure the semantic-release package. Create a release.config.js file in the root directory of your project:

module.exports = {
  branches: ['main'],
  plugins: [
    '@semantic-release/commit-analyzer',
    '@semantic-release/release-notes-generator',
    '@semantic-release/changelog',
    '@semantic-release/git',
    '@semantic-release/github',
  ],
};
Enter fullscreen mode Exit fullscreen mode

Step 4: Commit message Conventions

Commit message Conventions
Semantic release uses Angular Commit Message Conventions messages to determine the type of version bump (major, minor, patch). To follow this, you or your team should follow a Conventional Commit format:

  • fix: correct a bug
  • feat: add a new feature
  • feat!: breaking change BREAKING CHANGE: change that introduces backward incompatibility

We also can use tools like Commitizen Commitizen, and commitlint to enforce valid and consistent commit messages.

By using these commit messages, semantic-release will automatically determine whether to bump the version and generate the necessary changelogs.

Step 5: Push and Test the Workflow

Workflow Screenshot

Once you have set up the workflow and configuration files, push the changes to your GitHub repository. This will trigger the GitHub Actions workflow based on the on_push event.

The action will:

  • Install the necessary dependencies.

  • Run Semantic Release to analyze your commits, bump the version, generate release notes, and update the changelog.

  • Create a new GitHub release and tag.
    You can monitor the progress of the workflow in the Actions tab of your GitHub repository.

Conclusion

Automating releases with Semantic Versioning and GitHub Actions streamlines your development workflow, ensuring consistent, error-free versioning, changelogs, and releases. By integrating semantic-release and GitHub Actions, you eliminate manual tasks, reduce human error, and enhance productivity, allowing your team to focus on writing code rather than managing releases. This setup provides a scalable, reliable, and efficient way to handle versioning and publishing, ultimately improving the quality and transparency of your project’s development cycle.

Top comments (0)