git-semver-compute/calculate-version.sh
Diego Fernando Carrión d77c6a6b4c
iniitalize script
2023-06-05 14:55:19 +02:00

96 lines
3.1 KiB
Bash
Executable File

#!/bin/bash
# RegEx source:
# https://web.archive.org/web/20221230095605/https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string
SEMVER_REGEX='^(?P<major>0|[1-9]\d*)\.(?P<minor>0|[1-9]\d*)\.(?P<patch>0|[1-9]\d*)(?:-(?P<prerelease>(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?P<buildmetadata>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$'
# Get the most recent tag in Git.
tag=$(git describe --tags --abbrev=0 2>/dev/null)
# If there are no tags, use 0.0.0
if [ -z "$tag" ]
then
tag=0.0.0
fi
# If the most recent tag is not a valid semantic version, rewind until we find one.
while ! (echo $tag | perl -p -e 's/^v//i' | perl -ne "/$SEMVER_REGEX/ && (\$found=1); END {exit !\$found}")
do
# # Get the hash for the most recent tag
tag_hash=$(git rev-list -n 1 $tag)
# Get the hash for the commit before the latest tag
previous_tag_hash=$(git rev-list $tag_hash | sed '2q;d')
# Rewind commits to the previous tag.
while (git describe --tags $previous_tag_hash 2>/dev/null | perl -ne '/.+?-\d+-g[[:xdigit:]]{7}$/ && ($found=1); END {exit !$found}')
do
tag_hash=$previous_tag_hash
previous_tag_hash=$(git rev-list $tag_hash | sed '2q;d')
# If we've reached the beginning of the commit history, break out of the
# loop. This should never happen.
if [ -z "$previous_tag_hash" ]
then
break
fi
done
# Get the tag, or return 0.0.0 if there are no tags or if we've reached the
# end of the commit history.
tag=$(git describe --tags $previous_tag_hash --abbrev=0 2>/dev/null || echo 0.0.0)
done
# Strip the leading 'v' from the tag, if it exists.
VERSION=$(echo $tag | perl -p -e 's/^v//i')
# Get the number of commits since the last valid tag.
if [ "$tag" == "0.0.0" ]
then
commits=$(git rev-list --count --no-merges HEAD)
else
commits=$(git rev-list --count --no-merges $tag..HEAD)
fi
short_hash=$(git rev-parse --short HEAD)
# If any tracked files have been modified, add a hash of the diff to the
# version.
drift_digest=$(git status --porcelain | perl -ne '/^\s?(M|A|D)/ && ($found=1); END {exit !$found}' && git diff HEAD | sha1sum | awk '{print $1}')
# Determine if the version already has metadata.
has_metadata=$(echo $VERSION | perl -ne '/\+/ && ($found=1); END {exit !$found}' && echo 1 || echo 0)
# Add commit count and hash to the version if there are any commits since the
# last tag.
if [ $commits -gt 0 ]
then
# If the version already has metadata, add a dash. Otherwise, add a plus.
if [ $has_metadata -eq 0 ]
then
VERSION=$VERSION+
has_metadata=1
else
VERSION=$VERSION-
fi
# Add the g prefix to the hash to indicate that it is a Git hash.
# Just like `git describe --tags` does.
VERSION=$VERSION$commits-g$short_hash
fi
# Add a hash of the diff to the version if there are any tracked files that
# have been modified.
if [ -n "$drift_digest" ]
then
# If the version already has metadata, add a dash. Otherwise, add a plus.
if [ $has_metadata -eq 0 ]
then
VERSION=$VERSION+
has_metadata=1
else
VERSION=$VERSION-
fi
VERSION=$VERSION$drift_digest
fi
# Print the version.
echo -n $VERSION