Gsemver
gsemver uses git commit convention to automate the generation of your next semver version
Install / Use
/learn @arnaud-deprez/GsemverREADME
gsemver
gsemver is a command line tool developed in Go (Golang) that uses git commit convention to automate the generation of your next version compliant with semver 2.0.0 spec.
Table of Contents
Motivations
Why yet another git version tool ?
When you try to implement DevOps pipeline for applications and libraries from different horizons (java, go, javascript, etc.), you always need to deal with versions from the moment you want to release your application/library to the deployment in production.
As DevOps is all about automation, you need a way to automate the generation of your next version.
Then, you have 2 choices:
- you can use no human meaningful information:
- forever increment a number
- use git commit hash
- use build number injected by your CI server
- etc.
- you can use a human meaningful convention such as semver.
The first option is easy and does not required any tool.
However some tools/tech require you to use a semver compatible format version (eg. go modules, helm, etc.). You can still decide to always bump the major, minor or patch number but then your version is not meaningful in you are just doing a hack to be compliant with the spec format but not with spec semantic.
So for the second option, in order to provide human meaningful information by following the spec semantic, you need to rely on some conventions.
You can find some git convention such as:
- conventional commits: generalization of angular commit convention to other projects
- angular commit convention
- gitflow
Then I looked for existing tools and here is a non exhaustive list of what I've found so far:
- GitVersion: tool written in .NET.
- semantic-release: tool for npm
- standard-version: tool for npm
- jgitver: CLI running on java, maven and gradle plugins.
- hartym/git-semver: git plugin written in python.
- markchalloner/git-semver: another git plugin written in bash
- semver-maven-plugin
All these tools have at least one of these problems:
- They rely on a runtime environment (nodejs, python, java). But what if I want to build an application on another runtime ? On a VM, this is probably not a big deal but in a container where we try keep them as small as possible, this can be annoying.
- They are not designed to automatically generate a new version based on a convention. Instead, you have to specify what number you want to bump (major, minor, patch) and/or what type of version you want to generate (alpha, beta, build, etc.)
- They manage the full release lifecycle and so they are tightly coupled to some build tools like
npm,mavenorgradle.
I've found some libraries written in go but they don't deal with git commits/tags convention:
I needed a tool to generate the next release semver compatible version based on previous git tag that I could use on every type of application/library and so that is not relying on a specific runtime environment.
That's why I decided to build this tool using go with inspirations and credits from the tools I've found.
Thanks
Thank you all for the inspirations!
I'd like also to thanks 2 projects that are used in combination with gsemver to better automate the release of this tool:
- conventional commits a commit convention I've decided to adopt in all my commits.
- git-chglog is a customizable CHANGELOG generator implemented in go based on commits log.
- GoGeleaser is a release automation tool for Go projects.
With these 3 tools and gsemver, it gets easier to automate the release your projects.
Getting Started
Installation
Please install gsemver in a way that matches your environment.
Go users
go install github.com/arnaud-deprez/gsemver@latest
Manual
For a manual installation, you can download binary from release page and place it in directory registered in your $PATH environment variable.
Test Installation
You can check with the following command whether the gsemver command was included in a valid $PATH.
$ gsemver version
# output the gsemver version
Usage
Pre-requisites
Most of CI server uses - by default - shallow git clone when cloning your git repository.
When performing such a clone, the local copy of your git repository will contain a truncated history and most probably will be detached from HEAD.
As gsemver is currently using git describe to compute the next version, it means you should use annotated tag instead of lightweight tag to release your code (see lightweight vs annotated tag).
Likewise, it also needs to have access to at least to the last parent annotated tag.
For these reasons, gsemver will execute git fetch --tags before computing the next version.
As gsemver also needs to know the current branch and it tries to retrieve it with git symbolic-ref HEAD command.
However most of CI server execute the build in detached from HEAD state and then it becomes hard in git to retrieve the branch from where the build has been triggered.
Fortunately, most of CI server injects the branch name in an environment variable.
That's why gsemver allows you to use the GIT_BRANCH environment variable as a backup solution.
CLI
Automatic version bump
gsemver bump
This will use the git commits convention to generate the next version.
The only current supported convention is conventional commits.
It also uses by default main, master and release/* branches by default as release branches and it generates version with build metadata for any branch that does not match.
This is a current limitation but the roadmap is to make more configurable.
The conventional commits integration tests shows you in depth how version is generated. For a more comprehension view, here an example of the logs graph these tests generate:
* 34385d9 (HEAD -> main, tag: v1.2.2) Merge from feature/merge2-release-1.1.x
|\
| * b884197 Merge from release/1.1.x
| |\
|/ /
| * 869c83f (tag: v1.1.3, release/1.1.x) Merge from fix/fix-3
| |\
| | * 22eabaf fix: my bug fix 3 on release/1.1.x
| |/
* | 704fde4 (tag: v1.2.1) Merge from feature/merge-release-1.1.x
|\ \
| * \ 61b6a7c Merge from release/1.1.x
| |\ \
|/ / /
| | _
| * f2d9b5e (tag: v1.1.2) Merge from fix/fix-2
| |\
| | * f95ccbe fix: my bug fix 2 on release/1.1.x
| |/
* | 99a3662 (tag: v1.2.0) Merge from feature/awesome-3
|\ \
| |/
|/|
| * cc6c1ed feat: my awesome 3rd change
|/
* 145cbff (tag: v1.1.1) Merge from bug/fix-1
|\
| * 681a11b fix: my bug fix on main
|/
* e9e7644 (tag: v1.1.0) Merge from feature/awesome-2
|\
| * f30042e feat: my awesome 2nd change
|/
* fba50a2 (tag: v1.0.0, tag: v0.2.0) Merge from feature/awesome-1
|\
| * bf05218 feat: my awesome change
|/
* c619bff (tag: v0.1.1) fix(doc): fix documentation
* 128a5d9 (tag: v0.1.0) fe
