Problem Description
Whether you are developing an executable or library to be consumed by end-users, release management is a critical consideration from the inception of the project. Thankfully this is a well-defined problem within software projects and thus many established solutions exist.
SemVer version tagging is a universally adopted standard by package managers, software tooling and authors to universally describe in a concise manner the impact of change. Integrating your release management within your day-to-day git flow is a massive automation win that brings reliability and consistency to your project. Open source tooling such as release-please makes this easier than ever to incorporate release management in all software projects you own.
Release Please
Release-please integrates within your trunk-based git development flow relying on a specific commit message structure called conventional-commits to automatically generate changelog release notes and make appropriate semver bumps to your project version.
The release-please-actions Github action makes this tooling easily accessible to you within your Github repositories allowing you to seemlessly integrate release-please within your established continuious delivery pipeline.
Quick Start Github Guide
Setup your release management such that it is managed through the release-please-actions
utility. Ensure your respositories git flow is following the trunk-based development flow. There are a number of reasons to adopt this flow over other paradigms (see here).
Your release-please.yml
workflow file might look something like this:
on:
push:
branches:
- default
name: release-please
jobs:
release-please:
runs-on: ubuntu-latest
steps:
- uses: google-github-actions/release-please-action@v4
id: release
with:
release-type: node
...
Your deployment pipeline should be configured to trigger following the creation of a Github Release thus isolating your path-to-production from any branch updates and instead establishing a dependency on changes in a release(s) semver.
Supporting Multiple Releases
In a well established project, support for multiple releases or legacy version lifecycle support may be a priority. The basic setup above can be easily extended to offer this support.
Targetting a specific release-branch is simply introduced like so
on:
push:
branches:
- default
- v1.x
- v2.x
name: release-please
jobs:
release-please:
runs-on: ubuntu-latest
steps:
- uses: google-github-actions/release-please-action@v4
id: release
with:
release-type: node
target-branch: ${{ github.ref_name }}
You can review the documentation of the multiple releases release-please-action
workflow yourself. An important consideration to be made is to ensure your CI/CD flow supports the core principles of trunk-based development. By that I emphasis the need to squash-merge new features or bug fixes into the trunk or default branch with priority and then git cherry-pick
any necessary legacy release branch fixes in order to ensure the trunk remains the 'most developed' of the commit branches.
Handling Hotfixes
Once any new feature development on the trunk becomes too progressive for a particular release (i.e a major version BREAKING_CHANGE
is introduced) a release branch should be established.
Creating the Release Branch
This is particularly easy using the release-please-action
as you are able to setup an action-step that updates the commit hash that a particular major version git tag
is pointed to:
...
- uses: google-github-actions/release-please-action@v4
id: release
with:
release-type: node
...
- name: tag major and minor versions
if: ${{ steps.release.outputs.release_created }}
run: |
git config user.name github-actions[bot]
git config user.email 41898282+github-actions[bot]@users.noreply.github.com
git tag -d v${{ steps.release.outputs.major }} || true
git push origin :v${{ steps.release.outputs.major }} || true
git tag -a v${{ steps.release.outputs.major }} -m "Release v${{ steps.release.outputs.major }}"
git push origin v${{ steps.release.outputs.major }}
That way cutting a release branch is a piece of cake. Just reference the tag for the major version and create a release branch of the form v[major-version].x
git tag --list
git checkout [tag-name]
git checkout -b v[major-version].x
git push -u origin v[major-version].x
You'll need to ensure the appropriate Github branch protection rules have been setup for this release branch. All other triggers based on a Github release should work as usual.
Create the Release Branch Fix
Thus, in order to release a hotfix for a legacy major-version that is still in support, all you will have to do is follow the following process:
- Reproduce the issue in the offending release major version
- Create a pull-request targetting the trunk branch
- git cherry-pick the fix to the relevant release branch
- Resolve any merge conflicts and create a pull-request targetting the release branch
- Following approval, allow
release-please
to manage the creation of an appropriate semver release bump - Your deployment pipeline will be triggered and follow the necessary approval process to deploy the release branch hotfix.
Conclusion
This is a fast-tracked method to handle release management within your Github repositories. I recommend consulting the release-please-action documentation as well as listed example repositories to gather further inspiration.