DEV Community

Cover image for How to increase the version number?
Volker Schukai
Volker Schukai

Posted on • Edited on

How to increase the version number?

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
Enter fullscreen mode Exit fullscreen mode

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}"
Enter fullscreen mode Exit fullscreen mode

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())
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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()
Enter fullscreen mode Exit fullscreen mode

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

Enter fullscreen mode Exit fullscreen mode

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,
    })
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Or change the version number in a file

version patch --path my.json --selector go.to.version
Enter fullscreen mode Exit fullscreen mode

Or directly set a new version as Git Tag

version patch --git
Enter fullscreen mode Exit fullscreen mode

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
}

Enter fullscreen mode Exit fullscreen mode

## 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)" 

Enter fullscreen mode Exit fullscreen mode

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

Top comments (0)