Automated Semantic Versioning with CI
This article outlines the usage of Semantic Versioning and automating it using shell scripts and Continuous integration Pipelines.
All the code for this article is available on GitHub.
Branching Strategy
GitFlow
- develop - Active development branch where new features are implemented. Feature branches are created from the develop branch. Merging a feature branch into develop triggers a snapshot build.
- ‘release/*’ - Release branches are broken off of develop branches once the features for the release have been completed. The initial commit to the release branch and every subsequent commit will trigger release candidate builds.
- ‘main’ - Represents the latest stable release. Production builds are managed here and tags are managed to separate each released version. Hotfixes are broken off and merged to the main branch.
Additionally, we use branches like ‘hotfix/*’ and ‘bugfix/*’ for addressing issues in main and release branches, respectively, and ‘feature/*’ for feature branches as mentioned above. This branching strategy follows the popular and mature GitFlow system.
Reference: GitFlow
Semantic Versioning 2.0
In this versioning system, we align with the Semantic Versioning 2.0 (SemVer 2) to ensure clarity and consistency in our application version management. The SemVer structure we follow is MAJOR.MINOR.PATCH.
- Development Version (‘develop’ branch): During active development in the ‘develop’ branch, the version is represented as ‘<MAJOR><MINOR><PATCH>-SNAPSHOT’. The ‘SNAPSHOT’ identifier indicates that this version is a dynamic and continuously evolving state, capturing ongoing changes and additions.
- Release Candidate Version (‘release/*’ branch): As we prepare for a release, version numbers on release branches take the form ‘<MAJOR><MINOR><PATCH>-rc<number>’. The ‘rc’ (release candidate) identifier is followed by a sequential number (1, 2, etc.), signifying iterations of the release candidate. These versions undergo testing in environments like QA before reaching the final release.
- Staging and Production Version (main branch): Once a release candidate has been thoroughly tested and approved, it progresses to staging and production with a version number of ‘<MAJOR><MINOR><PATCH>’. This signifies a stable and production-ready release, following the principles of SemVer.
By adopting SemVer in our versioning strategy, we enhance communication about our software changes, maintain a clear understanding of version compatibility, and ensure a systematic approach to releases across different stages of our development lifecycle.
Reference: Semantic Versioning
Branch Pipelines
These pipelines are triggered when code is pushed to the branch and are responsible of releasing to code to each environment.
main branch pipeline flow
‘main’ branch pipeline flowThe ‘main’ pipeline is responsible for deploying all code pushed to the ‘main’ branch. It begins by running the ‘version.sh’ script, removing any build identifiers (such as ‘rc1’) from the version. The pipeline then proceeds to update the ‘develop’ branch with each merged release or hotfix using ‘release.sh’ and ‘hotfix.sh’ scripts. Following this, the pipeline tags the release or hotfix and concludes by building the Docker image
File: semver_ci/bitbucket-pipelines.yml
’release/’ pipeline
release/* branch pipeline flow
When a new release branch is created using the ‘release/*’ pattern, the ‘release/*’ pipeline will be triggered. During its initial run, this pipeline dynamically adjusts the version by replacing the ‘develop’ branch’s build identifier ‘SNAPSHOT’ with ‘rc1’ using the ‘version.sh’ script. Subsequent pushes to the release branch trigger the pipeline once again, incrementing the release candidate version on each push. This seamless process ensures that the version in the ‘release/*’ branch accurately reflects the evolving release candidates. The pipeline concludes by building the Docker image.
‘develop’ pipeline
develop/* branch pipeline flow
Upon merging code from either the ‘feature/*’ or ‘main’ branches into ‘develop’, the ‘develop’ pipeline will be triggered. The ‘version.sh’ script will first add the SNAPSHOT build identifier to the version (e.g., 2.0.1-SNAPSHOT). Following this version update, the pipeline will build the Docker image.
Custom Pipelines
’version-bump’ pipeline
version-bump pipeline flow
The ‘version-bump’ pipeline, using by the ‘version.sh’ script, handles version increments in the ‘develop’ branch. Developers can trigger version bumps, choosing between major, minor, or patch increments.
‘initiate-release-branch’ pipeline
initiate-release-branch pipeline flow
The ‘initiate-release-branch’ script automates the creation of release branches from the ‘develop’ branch. When executed, it checks out a new branch with the ‘release/*’ pattern, commits an empty change to trigger a build, and pushes the branch to the remote repository.
Versioning Scripts
’version.sh’
The ‘version.sh’ script that is used for maintaining the semantic versioning system. It takes two arguments:
Release (snapshot, rc, main):
- snapshot: Sets the version to ‘2.0.0-SNAPSHOT’ in the ‘develop’ branch.
- rc: Increments and sets the release candidate version in release branches (2.0.0-rc1, 2.0.0-rc2, etc.).
- main: Cleans up build tags in the main branch (2.0.0-rc1 to 2.0.0) and creates a Git Tag with the version.
Semantic Version (major, minor, patch): Increments the specified segment of the semantic version.
File: semver_ci/version.sh
’release.sh’
The ‘release.sh’ script is part of the main pipeline. It compares release and develop versions and updates the develop version if needed.
File: semver_ci/release.sh
’hotfix.sh’
The ‘hotfix.sh’ script is part of the main pipeline. It increments the patch version for hotfixes, updates develop if needed, and commits the changes.
File: semver_ci/hotfix.sh
’initiate-release-branch.sh’
- The ‘initiate-release-branch.sh’ script creates a release branch from the develop branch.
File: semver_ci/initiate-release-branch.sh
Alternative: GitFlow CLI Tool by NVIE
- GitFlow is a collection of Git extensions to provide high-level repository operations for Vincent Driessen’s branching model.
- Highly recommend using this tool for GitFlow workflows that does not need semantic versioning, the configuration shared above are for workflows that require automated semantic versioning.
Conclusion
This article outlines the usage of Semantic Versioning and automating it using shell scripts and Continuous integration Pipelines.
Thanks for reading!