Skip to content

Instantly share code, notes, and snippets.

@akutz
Created January 25, 2019 20:40
Show Gist options
  • Save akutz/533e166cc0cb91c2cf70a7c8d7dffa69 to your computer and use it in GitHub Desktop.
Save akutz/533e166cc0cb91c2cf70a7c8d7dffa69 to your computer and use it in GitHub Desktop.
Comparing Kubernetes versions in shell script

The attached script provides a function for comparing Kubernetes versions in shell script. It's possible for the script to validate itself by invoking it with TEST_SEMVER_COMP=1:

$ TEST_SEMVER_COMP=1 semver.sh 
              a               b   exp   act
           v1.0            v1.0     0     0
          v10.0            v1.0     1     1
           v1.0           v10.0   255   255
          v1.14    v1.14.alpha1     1     1
   v1.14.alpha1           v1.14   255   255
  v1.140.alpha1           v1.14     1     1
#!/bin/sh
set -e
set -o pipefail
# Extracts the MAJOR.MINOR.PATCH.BUILD portion of a semantic version string.
mmpb() {
echo "${1}" | sed -e 's/^\(v\{0,1\}\)\([[:digit:]]\{1,\}.[[:digit:]]\{1,\}\)\(.[[:digit:]]\{1,\}\)\{0,1\}\(.[[:digit:]]\{1,\}\)\{0,1\}\(.\{0,\}\)$/\1\2\3\4/g'
}
# Returns 0 if $1>$2
version_gt() {
test "$(printf '%s\n' "${@}" | sort -V | head -n 1)" != "${1}"
}
# Compares two semantic version strings:
# 0 if eq
# 1 if a>b
# 255 if a<b
semver_comp() {
va="${1}"; vb="${2}"
# If the strings are exactly the same then return 0 to indicate the versions
# are equal.
[ "${va}" = "${vb}" ] && return 0
# Get the MAJOR.MINOR.PATCH.BUILD string for each version.
vaMMPB="$(mmpb "${va}")"; vbMMPB="$(mmpb "${vb}")"
# If the original versions are the same as the strings that are just
# MAJOR.MINOR.PATCH.BUILD, then it's safe to compare the versions with
# sort -V
if [ "${va}" = "${vaMMPB}" ] && [ "${vb}" = "${vbMMPB}" ]; then
{ version_gt "${@}" && return 1; } || return 255
fi
# If the MAJOR.MINOR.PATCH.BUILD strings are equal at this point, it means
# that one of the two semvers has a suffix, and a suffixless semver is treated
# as greater than one with a suffix.
if [ "${vaMMPB}" = "${vbMMPB}" ]; then
if [ "${va}" = "${vaMMPB}" ] && [ ! "${vb}" = "${vbMMPB}" ]; then
return 1
elif [ ! "${va}" = "${vaMMPB}" ] && [ "${vb}" = "${vbMMPB}" ]; then
return 255
else
{ version_gt "${@}" && return 1; } || return 255
fi
fi
# At this point it's known that the MAJOR.MINOR.PATCH.BUILD strings are not
# equal, and thus it is safe to compare the two versions using sort -V.
{ version_gt "${@}" && return 1; } || return 255
}
[ -z "${TEST_SEMVER_COMP}" ] && { semver_comp "${@}"; exit "${?}"; }
printf '% 15s % 15s % 5s % 5s\n' 'a' 'b' 'exp' 'act'
test_semver_comp() {
set +e
semver_comp "${1}" "${2}"; result="${?}"
set -e
printf '% 15s % 15s % 5d % 5d\n' \
"${1}" "${2}" "${3}" "${result}"
test "${result}" -eq "${3}"
}
test_semver_comp v1.0 v1.0 0
test_semver_comp v10.0 v1.0 1
test_semver_comp v1.0 v10.0 255
test_semver_comp v1.14 v1.14.alpha1 1
test_semver_comp v1.14.alpha1 v1.14 255
test_semver_comp v1.140.alpha1 v1.14 1
exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment