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 featurefix
: A bug fixdocs
: Documentation-only changesstyle
: 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 featureperf
: A code change that improves performancetest
: Adding missing or correcting existing testschore
: 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:
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:
And then, following it’s instructions you will get the final commit message as:
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.