8. 2. 2021
6 min read
Automated release process for Lerna monorepo
The process of publishing (releasing) a new version of software is one of the most important steps in a development lifecycle. In this article, we will take a look at how we can automate this in a monorepository managed with lerna.
Filip Jenik
The process of publishing (releasing) a new version of software is one of the most important steps in a development lifecycle. In this article, we will take a look at how we can automate this in a monorepository managed with lerna.
Motivation
The most important things in the release process are simplicity, consistency, and clarity. A release process should be straightforward, so everybody on the team can do it easily by following a clear set of instructions. During the release process, a lot of things can go wrong - you forget to set a new version, modify the version in any of the package.json
files, or even forget to create a new tag or merge hotfixes from the master
branch. Therefore, it's good to clearly define this process and automatize it as much as possible.
Goals
The main goal of this article is to define the release process for monorepo using Lerna. It consists of the automatic creation of tags, incrementing the version, and changelog generation with the chronological arrangement of changes.
Project structure
For this project, we will be using a monorepo with two packages/modules: api
and frontend
. In the root folder, we have packages, root package.json
, and Lerna config.
+-- api| +-- package.json| +-- ...+-- frontend| +-- package.json| +-- ...+-- CHANGELOG.md+-- lerna.json+-- package.json+-- ...
In this article, we are fixed to monorepo projects managed by lerna
. That means that you should be able to use this process with any project using this structure (maybe with some little changes in configs). You can find valuable information in this article even if you are not using this kind of setup.
Setup
In our release process solution, we are using a combination of GitHub
, lerna
and lerna-changelog
.
Lerna
Lerna is a library that provides tooling to manage multi-package structure inside a single repository (sometimes called monorepos). Our main usage of lerna
is for automatic versioning and tag generation. We are using lerna
with the combination of lerna-changelog
package which is used to generate a changelog based on the labels attached to PRs merged into the origin.
In the root of the project run npm i -s -d lerna
(we are currently using 3.22.1
).
Create lerna
configuration file (lerna.json
).
{ "packages": [ "./*" ], "version": "{{your_current_repository_version}}"}
packages - Array of globs to use as package locations (locations of your not root
package.json
files)version - the current version of the project (from the root
package.json
) Morelerna
config options can be found here.
Lerna-changelog
In the root of the project run npm i -s -d lerna-changelog
(we are currently using 1.0.1
)
In the root package.json
file we need to add config for lerna-changelog
. You can map PR labels from Github to more meaningful titles here.
"changelog": { "labels": { "Type: Feature": "Features", "Type: Bug": "Bug fixes", "Type: Enhancement": "Enhancements" },},
More options can be found in lerna-changelog doc.
For changelog generation, you'll need a personal access token for the GitHub API with the repo
scope for private repositories or just public_repo
scope for public repositories.
You can set the environment variable for the GitHub authentication by running this command:
export GITHUB_AUTH="<Your Github personal access token>"
or even better, define this variable in your .bash_profile
Git workflow
To understand this process you have to be familiar with git-flow
. In our case, it's based on three main branches:
develop
staging
master
All new features or non-critical bug fixes are merged into the develop branch. When it's time for a new release (typically at the end of the sprint), all changes from develop are merged into staging branch, where we test it thoroughly if everything is working fine. After that we merge staging into the master branch.
Release process
A new release is introduced by creating a new git tag and bumping versions of packages. These are done in a semi-automatized way with lerna.
Creating a Release Candidate with changelog
Over the time, we figured out these few basic steps to create a release candidate:
Pull the latest changes from
origin
tomaster
,staging
,develop
branches to your local repositoryCheckout into the
develop
branch and make sure you have all bug fixes frommaster
merged todevelop
Run
npx lerna-changelog
to generate a changelog and append it to theCHANGELOG.md
Commit new
CHANGELOG.md
ondevelop
Run
npx lerna version
and choose the appropriate version number.This will update
version
properties for all updated packagesCommit all the changes
Create a new
git tag
on the new commit
Push changes to the
origin
Merge
develop
intostaging
branchPush staging to
origin
Create a new Pull Request with a base set as
master
fromstaging
branchCopy changes from
CHANGELOG.md
and attach to the PR body with- [ ]
list items to render a TODO list (- [ ]
is rendered as a checkbox)Let your team know that there is a Release Candidate and wait until they will check every feature / bugfix they've merged
When all checkboxes (all features / bugfixes) are checked and the PR is approved, merge it. Don't squash merge as it might cause conflicts for developed features
Example of PR from staging to master.
When to release?
It's hard to say exactly. There are few points that you should think of:
Do not release in rush - you should have enough time to fix any problem during and after release. There is always something unpredictable that can happen. Maybe you have forgotten to set a new environment variable or a migration has crashed.
You should release when there are as minimum customers as possible using the product - any error can occur and that can have a negative influence on their experience with the product. Impact on the customer experience could be minimized by using strategies like blue-green deployment or canary releases.
You should be sure of the code you are releasing.
How often to release?
The best option is to release in periodic intervals, such as one sprint. Periodicity is one of the most important factors. You don't want to release hundreds of hours of work at once. It's much easier to release smaller features more often, than one big feature after two months. Last but not least, there is a customer that wants to see some progress on his project as well. It's not a problem to release more often than you need to, but before every release, don't forget to check the points in the "When to release" paragraph!
Conclusion
In this article we've walked through the release process by creating a changelog with minimum effort. We've talked about a workflow and the tools we are currently using, and our method of creating a release candidate. As always, there is a lot of space to improve, e.g. it would be nice to automatize creating PR from staging
to master
branch with changelog description.
You might
also like