Here is a script to find out the next suggested SemVer versions for a Github project. The script works on both private and public repositories. If using a private repo, you need to export an environment variable named GITHUB_PAT with the value of your github personal access token. This script depends mainly on the git tags. If you use a custom prefix for your git tags, you need to provide it as an option.

You can run the script without any options to view the help content.

Prerequisites

The script requires git command to be available in the PATH. Please ensure that you have git installed on your system.

Using the script

Below are the steps to use the script.

  • Copy the below script and save it as next-github-project-version.sh.
  • Change the executable bit by running: chmod +x next-github-project-version.sh.
  • The script is now ready to be run. It takes two mandatory commandline arguments and an optional third argument.
    • The first argument is the github organization name.
    • The second argument is the github project name.
    • The optional, third argument is the tag-prefix which you might be using while adding git tags. Ex., v is the tag-prefix in v1.2.0.
  1#!/bin/bash
  2
  3set -e
  4set -m
  5
  6if [ $# -lt 2 ]; then
  7  echo -e "Usage: $(basename $0) <github-org> <github-project> [tag-prefix]"
  8  echo -e "NOTE: If the project needs authentication, export GITHUB_PAT env variable with your Github personal access token."
  9  echo -e "tag-prefix is optional and is empty by default."
 10
 11  exit 1
 12fi
 13
 14org_name=$1
 15project_name=$2
 16tag_prefix=$3
 17
 18OLD_IFS=$IFS
 19
 20## Generate the Github base-url
 21if [ -n "${GITHUB_PAT}" ]; then
 22  url_base="https://${GITHUB_PAT}@github.com"
 23else
 24  url_base="https://github.com"
 25fi
 26
 27## We are not considering versions with alphanumeric endings.
 28## The supported version number format is major.minor.patch.build
 29ver_regex="(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)?$"
 30extver_regex="(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$"
 31
 32## Sample version values for testing
 33#ver_tag="ref/tags/v2.1.3"
 34#extver_tag="ref/tags/v2.1.3-alpha.19+asfs.239"
 35
 36sorted_tags="$(git ls-remote --tags --sort=version:refname ${url_base}/${org_name}/${project_name}.git | awk {'print $2'})"
 37
 38if [ -n "$tag_prefix" ]; then
 39  ver_tag=$(echo "$sorted_tags" | grep -P "refs/tags/${tag_prefix}${ver_regex}" | tail -1)
 40  extver_tag=$(echo "$sorted_tags" | grep -P "refs/tags/${tag_prefix}${extver_regex}" | tail -1)
 41else
 42  ver_tag=$(echo "$sorted_tags" | grep -P "refs/tags/${ver_regex}" | tail -1)
 43  extver_tag=$(echo "$sorted_tags" | grep -P "refs/tags/${extver_regex}" | tail -1)
 44fi
 45
 46## Suggest next possible versions
 47if [ -n "${ver_tag}" ]; then
 48  if [ -n "$tag_prefix" ]; then
 49    curr_ver=$(echo $ver_tag | awk -F '/' {'print $3'} | sed -e "s%${tag_prefix}%%")
 50  else
 51    curr_ver=$(echo $ver_tag | awk -F '/' {'print $3'})
 52  fi
 53
 54  IFS='.' read -r -a ver_parts <<<"$curr_ver"
 55
 56  ver_major=${ver_parts[0]}
 57  ver_minor=${ver_parts[1]}
 58  ver_patch=${ver_parts[2]}
 59fi
 60
 61if [ -n "${extver_tag}" ]; then
 62  if [ -n "$tag_prefix" ]; then
 63    curr_extver=$(echo $extver_tag | awk -F '/' {'print $3'} | sed -e "s%${tag_prefix}%%")
 64  else
 65    curr_extver=$(echo $extver_tag | awk -F '/' {'print $3'})
 66  fi
 67
 68  IFS='-' read -ra parts <<<"$curr_extver"
 69  IFS='.' read -r -a core_parts <<<"${parts[0]}"
 70  IFS='+' read -r -a ext_parts <<<"${parts[1]}"
 71
 72  extver_major=${core_parts[0]}
 73  extver_minor=${core_parts[1]}
 74  extver_patch=${core_parts[2]}
 75  extver_pre=${ext_parts[0]}
 76  extver_bld=${ext_parts[1]}
 77
 78  echo -e "Current version information:"
 79  echo -e "############################\n"
 80  echo -e "Major: $extver_major, Minor: $extver_minor, Patch: $extver_patch"
 81  echo -e "Pre-release: $extver_pre, Build: $extver_bld"
 82fi
 83
 84if [ -n "$extver_pre" ]; then
 85  if [ -n "$ver_tag" ]; then
 86    curr_major=$ver_major
 87    curr_minor=$ver_minor
 88    curr_patch=$ver_patch
 89
 90    use_extver=0
 91
 92    if [ $extver_major -gt $ver_major ]; then
 93      use_extver=1
 94    elif [ $extver_major -eq $ver_major ] && [ $extver_minor -gt $ver_minor ]; then
 95      use_extver=1
 96    elif [ $extver_major -eq $ver_major ] && [ $extver_minor -eq $ver_minor ] && [ $extver_patch -gt $ver_patch ]; then
 97      use_extver=1
 98    fi
 99
100    if [ $use_extver -eq 1 ]; then
101      curr_major=$extver_major
102      curr_minor=$extver_minor
103      curr_patch=$extver_patch
104    fi
105  else
106    curr_major=$extver_major
107    curr_minor=$extver_minor
108    curr_patch=$extver_patch
109  fi
110
111  ## Compute next versions of pre-release and build parts.
112  if [ -n "$extver_bld" ]; then
113    bldver_num=$(echo $extver_bld | grep -o -E "[0-9]+$")
114
115    if [ -n "$bldver_num" ]; then
116      bldver_txt=$(echo $extver_bld | sed -e "s|${bldver_num}$||")
117      nxtver_bld="${bldver_txt}$((bldver_num + 1))"
118    fi
119
120    nxtver_pre=$extver_pre
121  fi
122
123  prever_num=$(echo $extver_pre | grep -o -E "[0-9]+$")
124
125  if [ -n "$prever_num" ]; then
126    prever_txt=$(echo $extver_pre | sed -e "s|${prever_num}$||")
127    nxtver_pre="${prever_txt}$((prever_num + 1))"
128  fi
129else
130  curr_major=$ver_major
131  curr_minor=$ver_minor
132  curr_patch=$ver_patch
133fi
134
135echo -e "\nNEXT SUGGESTED VERSIONS:"
136echo -e "########################\n"
137echo -e "Next Major: $((curr_major + 1)).0.0"
138echo -e "Next Minor: ${curr_major}.$((curr_minor + 1)).0"
139
140if [ -n "$nxtver_pre" ]; then
141  if [ $use_extver -eq 1 ]; then
142    echo -e "Next Patch (GA): ${curr_major}.${curr_minor}.${curr_patch}"
143  else
144    echo -e "Next Patch: ${curr_major}.${curr_minor}.$((curr_patch + 1))"
145  fi
146  echo -e "Next Pre-Release: ${curr_major}.${curr_minor}.${curr_patch}-${nxtver_pre}"
147else
148  echo -e "Next Patch: ${curr_major}.${curr_minor}.$((curr_patch + 1))"
149fi
150
151if [ -n "$nxtver_bld" ]; then
152  echo -e "Next Build: ${curr_major}.${curr_minor}.${curr_patch}-${extver_pre}+${nxtver_bld}"
153fi
154
155IFS=$OLD_IFS
156
157exit 0