Single click code-versioning (Complimenting cloud-native Architecture)
In a typical software development lifecycle, code goes through various stages between the developer’s machine and production. Typical stages would be Development, Testing, User-Acceptance Testing, Pre-Production, and Production. With all these stages into play, there are various means by which a team can maintain code and its versions.
Problem statement
With the growing complexity of businesses and an increase in the pace of change in customer needs, more and more companies are adopting microservices architecture to deliver highly scalable products in highly agile manners. A common pattern in a microservices architecture is to maintain different code repositories for different independently deployable microservices. More code repositories generally mean, at any given point of time, a product is a combination of different versions of those different code bases i.e. few of the microservices might need more frequent changes than others. Maintaining and merging multiple code repositories for different versions manually could be very time-consuming and error-prone.
Pieces of solution
This blog will present a few options for maintaining code and how we have built ‘one-click’ solution to automate code versioning following semantic versioning and code merging using Git and Jenkins pipeline.
There are three main pieces of this ‘one-click’ code-versioning solution :
1. Git workflows
2. Semantic versioning
3. JGit-Flow plugin
I will present all the pieces at a high level and will weave them together to reach to a final solution.
1. Code Workflow with Git
Below, I am going to discuss the two most popular and recommended workflows for git users :
a. Git Flow
Git Flow was created by Vincent Driessen in 2010 and it is based on two main branches.
· master
— this branch contains the production code. All development code is merged into master
at some point in some time.
· develop
— this branch contains the pre-production code. When the features are finished they are merged into develop
.
The Lifecycle of these branches is infinite (in other terms they are permanent branches).
Various stages of code such as the Testing phase, UAT phase, Pre-production, etc. are aided by other supporting branches and tags:
· feature-*
— this branch is used to develop new features for the upcoming releases. It branches off from develop
and must merge into develop
. Developers typically use features branches for development.
· hotfix-*
— this branch is necessary to act immediately upon an undesired status of master
. It branches off from master
and must merge both into master
and develop
. This is essentially meant for bug fixing on the master
branch.
· release-*
— this branch supports the preparation of a new production release. It allows many minor bugs to be fixed and helps in the preparation of meta-data for a release. It branches off from develop
and must merge into master
and develop
.
The official blog — https://nvie.com/posts/a-successful-git-branching-model/
b. Github Flow
Github Flow is a more mature and lightweight workflow. This workflow complements continuous delivery practices.
Essentially there is only one main branch that is master
.
· At any given point of time,master
is, in theory, stable and deployable and ready for production.
· For any code change, whether development or bug fix, create a branch off from master
.
· Open a pull request when development is complete in that branch and code is ready for merging.
· Once the code is reviewed and the feature is signed off, the code is merged back to master
by the reviewer (or group of reviewers).
· Finally, when the code is in master
, code is ready to deploy on production or pre-production.
Given the above two workflows, depending upon the dev team’s maturity team’s select one of these.
Other code workflows
There are two other workflows that are basically derived from the above two basic workflows :
c. GitLab flow
d. Oneflow
Both workflows provide more flexibility based on individual product requirements by introducing the concept of environment branches and other things. Read through the given official document to understand each workflow advantages and disadvantages and select what suits you best.
Now moving ahead from git workflows, the second part of the solution is semantic versioning.
2. Semantic versioning
Semantic versioning (Semver) aims to bring some rationality to the management of rapidly moving software release targets. Versioning our code helps us to track every transition in the software development phase. Moreover, it helps to track what’s been added/removed and at what point.
Semantic Versioning is a 3-component number in the format of X.Y.Z, where :
· X stands for a major version.
· Y stands for a minor version.
· Z stands for a patch.
Given a version number MAJOR.MINOR.PATCH, increment the:
1. MAJOR version when you make incompatible API changes
2. MINOR version when you add functionality in a backward-compatible manner
3. PATCH version when you make bug fixes in a backward-compatible manner
Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format.
Official blog
Moving onto the third piece of solution JGit-Flow plugin.
3. JGit-Flow plugin
JGit-flow plugin is a Maven plugin that supports git-flow workflow in maven projects. This plugin abstracts git-flow workflow stages via maven goals and also incorporates semantic versioning concepts.
JGit-flow plugin features
It provides commands and abstracts out all git-flow functionalities
· starting a release — creates a release
branch and updates pom(s) with release versions.
· finishing a release — runs a maven build (deploy or install), merges the release
branch into both master
and develop
, updates pom(s) with development versions.
· starting a hotfix — creates a hotfix branch and updates pom(s) with hotfix versions.
· finishing a hotfix — runs a maven build (deploy or install), merges the hotfix branch into both master
and develop
, updates pom(s) with previous versions.
· starting a feature — creates a feature branch
· finishing a feature — merges the feature branch into develop
.
Example of JGit-flow maven goal
Suppose the code in the develop
the branch is 1.0.0-SNAPSHOT and now you want to create a release
branch out of the develop
branch to promote the code for Testing or UAT, the following command will do both — create a release
branch with the desired semantic version and change the code version in the develop
branch. For example, if you want your release
code version to be 1.0.0-RC and develop
code version to be 1.1.0-SNAPSHOT, the following JGit-flow plugin will do version changes and will create a new git release branch.
mvn jgitflow:release-start -DallowSnapshots -DreleaseVersion1.0.0-RC -DdevelopmentVersion=1.1.0-SNAPSHOT
Similarly, you can end the release, and thereafter the code will be merged in master
and a tag will be created.
Enough of context-setting :). Let’s tie all these pieces together to reach a target state where all these concepts are weaved into a one-click solution for code versioning via Jenkins Pipeline. We use this single pipeline to version our code for all the microservices (currently we have 8 microservices, which essentially means 8 different GIT repositories for our product).
JGit Jenkins Pipeline
JGit Jenkins pipeline is an abstraction over gitflow-workflow and helps to orchestrate code branching and release management.
How JGit pipeline works :
1. First step is to add configure JGit-plugin in your maven project.
2. The Pipeline takes all the code repository references as input.
3. This pipeline offers two modes right now -
· start-release
· end-release
Start-Release
Start-Release will execute the following steps for all the code repositories :
o It will compare the code of configured develop
and master
branch, and smartly figure out if there are any code changes to be released.
o If there are code changes to be released, the pipeline will execute ‘jgitflow:release-start’ command to create release-[version]
branch from develop
branch taking into account semantic versioning for both the branches.
o If no code changes are found then nothing happens for that code repository.
End-Release
End-Release will execute the following steps for all the code repositories :
o It will figure out for what all code repositories’ release
branch exists by the configured release
branch pattern.
o If release branch is found then ‘jgitflow:release-end’ command is triggered to finish the release
branch and code is merged in master
and the tag is created on the merged code. It will also merge the release
in develop
branch
o If no release
branch is found then that code repository will be skipped for release end operation.
Summary
With the help of this solution, we are able to automate the code merge and semantic versioning of around 10 microservices in a single click. Automating this task has helped us save a lot of time and manual effort and made our delivery and release process faster and less error-prone.
Git hub repo
This repository has code for the pipeline and all supporting documentation on how to configure the pipeline in Jenkins and the internal working of the pipeline.
Contributors
Kudos to Vatsalya Singh who contributed and helped in releasing 1.0 version of this pipeline.