When you have a npm package, it requires to provide a version number. It can be pretty tedious to edit it, that's why I tend to use a tool like semantic-release to automate this process.
Why using a tool ?
When you have to handle manually the version, I need to think about several things :
- Is this project follow specific convention ? (ex: semantic versioning)
- If yes, do my changes correspond to a fix, a feature or a breaking change ?
- Update the places where the version is used (here,
package.json
) - Maitain a changelog with the changes
- Publish the package on npm
- Create a git tag
- Create a Github release (or Gitlab depending where you put the source code)
All of this add an useless "mental overhead" after the end of the development phase. It's also why I tend to use the same convention on every project I start that need a version number.
The semantic versioning convention
It's a principle with few rules :
Given a version number MAJOR.MINOR.PATCH, increment the: 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. Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format.
Use a formatted commit message
By using a specific format in our commits messages, it allows 2 things :
- Have an explicit git history
- Use a tool that analyze the commits (if you know what I mean π)
Since few years now, the Angular message format has become really popular.
The basic usage is :
<type>(<scope>): <short summary>
β β β
β β βββ«Έ Summary in present tense. Not capitalized. No period at the end.
β β
β βββ«Έ Commit Scope: animations|bazel|benchpress|common|compiler|compiler-cli|core|
β elements|forms|http|language-service|localize|platform-browser|
β platform-browser-dynamic|platform-server|router|service-worker|
β upgrade|zone.js|packaging|changelog|docs-infra|migrations|ngcc|ve
β
βββ«Έ Commit Type: build|ci|docs|feat|fix|perf|refactor|test
With that, a tool like semantic-release will able to analyze our commits and determine the version.
Setup
To add semantic-release to our project, we must first create a .releaserc.json
file at the root of our project which held our desired configuration.
For our example, we will start from the principle that our project is a npm on Github. We want to have a CI that is triggered everytime we push something on our main branch in order to analyze our commits and do theses actions :
- generate a CHANGELOG.md file
- publish a release on npm
- create a tag on git
- publish a release on Github
Without going too much further in detail, and being very well documented, here is the default configuration without adding any plugin :
{
"branches": ["main"],
"plugins": [
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator",
"@semantic-release/npm",
"@semantic-release/github"
]
}
Plugins are executed in the declaration order, keep that in mind if you would like to customize this later !
With theses defaults plugins, we can already publish a release on npm and Github. For the rest, we have to use dedicated plugins :
@semantic-release/changelog
: will generate the CHANGELOG.md file@semantic-release/git
: will generate a commit with the version on our main branch and create a tag
By the end, it would look like this :
{
"branches": ["main"],
"plugins": [
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator",
"@semantic-release/changelog",
"@semantic-release/npm",
"@semantic-release/git",
"@semantic-release/github"
]
}
Our configuration file is ready, all that's left is to setup the CI in Github.
Create a Github action
To create a Github action, we need to add a config file in the .github/workflows
folder (if it doesn't exist, you have to create them)
It's entirely possible to execute semantic-release in our local environment. But, it would be a shame to not profit about a complete automation of the process.
Luckily, there already exist a Github Action facilitating us our task because this image take care of the plugins and dependencies installation.
We just have to take care of the exta plugins used and create a release.yaml
file :
on:
push:
branches:
- main
jobs:
release:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Semantic Release
uses: cycjimmy/semantic-release-action@v2
with:
extra_plugins: |
@semantic-release/changelog
@semantic-release/git
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
In order to make this action working, it needs 2 paramounts things :
- a
GITHUB_TOKEN
that will allow semantic-release to execute Github actions (like release creation).
NOTE : this
GITHUB_TOKEN
is automatically generated for each CI run
- a
NPM_TOKEN
to publish our module on npm from the action
NOTE : during the npm token creation, lors de la crΓ©ation de votre token npm, choose the
Automation
type so you will not have trouble if you had enabled the 2FA on your npm account.
If your package is in an organization or behind your username, and you want to make it public, you have to put this in your .npmrc
access=public
Without that, you'll have an authentication error in your workflow.
Once your NPM_TOKEN
added as a secret in your Github repo, you can do your first commit :
git add .
git commit -m "feat: Add semantic-release :tada:"
git push origin main
Endnotes
Each plugins has is own configuration, and there are a lot ! I invite you to read the documentation and do some adjustements to make it perfect for your use case.