How to increase the version number?
Volker Schukai
Posted on June 15, 2022
Abstract
The article is about writing the following small program.
The result can be downloaded here.
version init
# 0.1.0
echo "1.0.0" | version patch
# 1.0.1
echo "1.0.0" | version minor
# 1.1.0
echo "1.0.0" | version major
# 2.0.0
Small Side Project On Sunday
There are tasks that I do over and over again and am really never satisfied with the results. But often I don't manage to do it cleanly.
I think every developer has such tasks.
Some tasks don't actually stand out and others really bug you.
I would like to briefly describe here how you can come up with working solutions relatively quickly using prefabricated libraries and some glue.
One of my minor pains is continually changing the version in the project. A good introduction to version numbers is described on the SemVer page. I have noted all the links below.
The first question is always what problem is there to solve.
For JavaScript, I often use npm version
, for C or Go projects a combination of shell script or manual adjustment.
Example of a bash script:
#!/bin/bash
### Increments the part of the string
## $1: version itself
## $2: number of part: 0 – major, 1 – minor, 2 – patch
increment_version() {
local delimiter=.
local array=($(echo "$1" | tr $delimiter '\n'))
array[$2]=$((array[$2] + 1))
if [ $2 -lt 2 ]; then array[2]=0; fi
if [ $2 -lt 1 ]; then array[1]=0; fi
echo $(
local IFS=$delimiter
echo "${array[*]}"
)
}
JSON="${1}"
VERSION="${2}"
MODE="${3:-1}"
jq '.version="'$(increment_version "${VERSION}" "${MODE}")'"' "${JSON}" > "${JSON}.new"
rm "${JSON}"
mv "${JSON}.new" "${JSON}"
The manual way is of course always possible, especially for small projects. However, as soon as I use a CI tool, I want to automate this in some way.
After all, it's not a task that's really challenging. On Sunday, I felt like writing a little tool here. As a finger exercise, so to speak.
My own program is nothing more or less than the linking of excellent libraries.
I love to write something like this in go because it makes a nice little program without any big runtime dependencies.
With JavaScript or php, you always need the runtime environment.
In which language do you write such tools? Leave a comment.
Shoulder of giants
Now you have to identify the individual challenges and finally see which subtask there is to solve.
Basically, I had to solve the following tasks:
- Reading the version number from a file (json and yaml). Alternatively, via standard input or directly from a git tag
- Bump one of the three parts of the version number
- Output the new version number again, write it to the file or set a git tag.
Here I would like to present them briefly without going into more detail. If you know of a good library, post a comment. I'm constantly looking for good libraries.
Reading files is quite easy with Go. For Json, Yaml and Git there are good libraries.
JSON
GJson
and SJson
seem to be great libraries to read or write values in a JSON. The libraries make it easy.
json, _ := os.ReadFile("my.json")
value := gjson.Get(string(content), "x.y.z")
fmt.Println(value.String())
YAML
I have not found anything similar for YAML. But here you can work quite well with the YAML nodes and operate directly on them. With the library yaml-jsonpath
you can work there directly.
yaml, _ := os.ReadFile("my.yaml")
var node yaml.Node
yaml.Unmarshal(content, &node)
path, _ := yamlpath.NewPath('x.y.z')
results, _ := path.Find(&node)
result := results[0]
fmt.Println(result.Value)
Version
For working with the version number, the library semver
is recommended. It can actually do everything you need.
version, _ := semver.NewVersion("1.2.3-beta.1+build345")
next := version.IncMajor()
Git
If you work with Git tags, you want to read out the last tag, change it and set it again. The version can be retrieved via console or CI as follows:
git fetch --tags
NEXT=$(git tag --sort=-v:refname | grep -E "[0-9]+\.[0-9]+\.[0-9]+" | head -n 1 | version patch)
git tag -a "$NEXT" -m "version $NEXT"
git push --follow-tags
But I also wanted to integrate that somehow.
For working with a Git repository, the library go-git
is worth highlighting. go-git
is a highly extensible git implementation library written in pure Go.
repo, _ := git.PlainOpen(path)
h, _ := repo.Head()
repo.CreateTag(version, h.Hash(), &git.CreateTagOptions{
Message: version,
})
The Result
I put the whole thing together with tape and some glue and compiled it. The program is available for download and the source code can also be viewed.
So my finished program can now read and change version number from standard input.
echo "1.0.0" | version patch
# 1.0.1
echo "1.0.0" | version minor
# 1.1.0
echo "1.0.0" | version major
# 2.0.0
Or change the version number in a file
version patch --path my.json --selector go.to.version
Or directly set a new version as Git Tag
version patch --git
Go
In go you can include the version in the finished program via the linker. In the go program we create a variable. Here with the name version. The name is freely selectable.
package main
var {
version string
}
## bump version
version patch --path version.json --selector "version"
export VERSION=$(cat version.json | jq -r .version)
## set version
go build -ldflags "-X main.version=$(VERSION)"
Voila!
Epilog
Like I said, it's not great cinema, but maybe it will help you tackle these types of tasks on your next project.
Another note on dependencies. Libraries are good, because you save time and possibly get a better solution. But you have to look very carefully here. It can happen quickly that you get malicious code.
Update 2023-07-16
The program can now also read commit messages directly and derive a new version number from them.
Update 2023-07-30
The `version' program can now make predictions about what the next version will be via git without setting it. Read more
References
- https://github.com/go-git/go-git
- https://github.com/Masterminds/semver
- https://github.com/tidwall/sjson
- https://github.com/tidwall/gjson
- https://github.com/vmware-labs/yaml-jsonpath
- https://gitlab.schukai.com/oss/utilities/version/-/packages/147
- https://github.com/git/git/blob/master/Documentation/RelNotes/1.8.3.txt#L155-L156
- https://semver.org/
- https://www.schukai.com/
- https://docs.npmjs.com/about-semantic-versioning
- https://docs.npmjs.com/cli/v8/commands/npm-version
- https://github.com/c4urself/bump2version/#installation
- https://gitlab.schukai.com/oss/utilities/version/-/tree/master
Posted on June 15, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.