2023-01-11 16:38:01 +00:00
#!/usr/bin/env bash
set -euo pipefail
# shellcheck source=scripts/lib.sh
source " $( dirname " $( dirname " ${ BASH_SOURCE [0] } " ) " ) /lib.sh "
cdroot
usage( ) {
cat <<EOH
2023-01-13 18:45:31 +00:00
Usage: ./version_tag.sh [ --dry-run] [ --old-version <version>] [ --ref <ref>] <--major | --minor | --patch>
2023-01-11 16:38:01 +00:00
This script should be called to tag a new release. It will take the suggested
increment ( major, minor, patch) and optionally promote e.g. patch -> minor if
there are breaking changes between the previous version and the given --ref
( or HEAD) .
2023-01-13 18:45:31 +00:00
Pass --old-version optionally to ensure that the version is bumped from the
provided version instead of the latest tag ( for use in release.sh) .
This script will create a git tag, it should only be called by release.sh or in
CI.
2023-01-11 16:38:01 +00:00
EOH
}
dry_run = 0
2023-01-13 18:45:31 +00:00
old_version =
2023-01-11 16:38:01 +00:00
ref = HEAD
increment =
2023-07-12 16:31:13 +00:00
force = 0
2023-01-11 16:38:01 +00:00
2023-07-12 16:31:13 +00:00
args = " $( getopt -o h -l dry-run,help,old-version:,ref:,major,minor,patch,force -- " $@ " ) "
2023-01-11 16:38:01 +00:00
eval set -- " $args "
while true; do
case " $1 " in
--dry-run)
dry_run = 1
shift
; ;
2023-01-13 18:45:31 +00:00
--old-version)
old_version = " $2 "
shift 2
; ;
2023-01-11 16:38:01 +00:00
--ref)
ref = " $2 "
shift 2
; ;
-h | --help)
usage
exit 0
; ;
--major | --minor | --patch)
if [ [ -n $increment ] ] ; then
error "Cannot specify multiple version increments."
fi
increment = ${ 1 #-- }
shift
; ;
2023-07-12 16:31:13 +00:00
--force)
force = 1
shift
; ;
2023-01-11 16:38:01 +00:00
--)
shift
break
; ;
*)
error " Unrecognized option: $1 "
; ;
esac
done
# Check dependencies.
dependencies git
2024-04-25 09:26:37 +00:00
ref_name = ${ ref :- HEAD }
ref = $( git rev-parse " ${ ref_name } " )
2023-01-11 16:38:01 +00:00
if [ [ -z $increment ] ] ; then
error "No version increment provided."
fi
2023-01-13 18:45:31 +00:00
if [ [ -z $old_version ] ] ; then
old_version = " $( git describe --abbrev= 0 " $ref ^1 " --always) "
2023-01-11 16:38:01 +00:00
fi
# shellcheck source=scripts/release/check_commit_metadata.sh
2023-02-08 12:40:52 +00:00
source " $SCRIPT_DIR /check_commit_metadata.sh " " $old_version " " $ref "
2023-01-11 16:38:01 +00:00
if ( ( COMMIT_METADATA_BREAKING = = 1) ) ; then
prev_increment = $increment
if [ [ $increment = = patch ] ] ; then
increment = minor
fi
if [ [ $prev_increment != " $increment " ] ] ; then
2023-07-12 16:31:13 +00:00
if ( ( force = = 1) ) ; then
log " Breaking change detected but --force provided, would use \" $increment \" but keeping \" $prev_increment \". "
increment = $prev_increment
else
log " Breaking change detected, changing version increment from \" $prev_increment \" to \" $increment \". "
fi
2023-01-11 16:38:01 +00:00
else
log " Breaking change detected, provided increment is sufficient, using \" $increment \" increment. "
fi
else
log " No breaking changes detected, using \" $increment \" increment. "
fi
mapfile -d . -t version_parts <<< " ${ old_version #v } "
2024-04-24 19:43:11 +00:00
release_branch_prefix = "release/"
release_ff = 0
2023-01-11 16:38:01 +00:00
case " $increment " in
patch)
2024-04-24 19:43:11 +00:00
release_branch = " ${ release_branch_prefix } ${ version_parts [0] } . ${ version_parts [1] } "
2024-04-25 09:26:37 +00:00
branch_contains_ref = $( git branch --contains " ${ ref } " --list " ${ release_branch } " --format= '%(refname)' )
2024-04-24 19:43:11 +00:00
if [ [ -z $branch_contains_ref ] ] ; then
# Allow patch if we can fast-forward to ref, no need for dry-run here
# since we're not checking out the branch and deleting it afterwards.
2024-04-25 09:26:37 +00:00
git branch --no-track " ${ release_branch } -ff " " ${ release_branch } "
# We're using git fetch here to perform a fast-forward on a
# non-checked-out branch. The "." uses the local repo as remote (faster).
if ! git fetch --quiet . " ${ ref } " :" ${ release_branch } -ff " ; then
git branch --quiet --delete --force " ${ release_branch } -ff "
2024-04-24 19:43:11 +00:00
error " Provided ref ( ${ ref_name } ) is not in the required release branch ( ${ release_branch } ) and cannot be fast-forwarded, unable to increment patch version. Please increment minor or major. "
fi
2024-04-25 09:26:37 +00:00
git branch --quiet --delete --force " ${ release_branch } -ff "
2024-04-24 19:43:11 +00:00
release_ff = 1
fi
2023-01-11 16:38:01 +00:00
version_parts[ 2] = $(( version_parts[ 2 ] + 1 ))
; ;
minor)
version_parts[ 1] = $(( version_parts[ 1 ] + 1 ))
version_parts[ 2] = 0
; ;
major)
2024-04-24 19:43:11 +00:00
version_parts[ 0] = $(( version_parts[ 0 ] + 1 ))
2023-01-11 16:38:01 +00:00
version_parts[ 1] = 0
version_parts[ 2] = 0
; ;
*)
error "Unrecognized version increment."
; ;
esac
2024-04-24 19:43:11 +00:00
release_branch = " ${ release_branch_prefix } ${ version_parts [0] } . ${ version_parts [1] } "
2023-01-11 16:38:01 +00:00
new_version = " v ${ version_parts [0] } . ${ version_parts [1] } . ${ version_parts [2] } "
log " Old version: $old_version "
log " New version: $new_version "
2024-04-24 19:43:11 +00:00
log " Release branch: $release_branch "
2024-04-25 09:26:37 +00:00
tag_exists = $( git tag --list " $new_version " )
if [ [ -n ${ tag_exists } ] ] ; then
error " Tag ${ new_version } already exists. "
fi
2024-04-24 19:43:11 +00:00
if [ [ ${ increment } = patch ] ] ; then
if ( ( release_ff = = 1) ) ; then
log "Fast-forwarding release branch"
maybedryrun " $dry_run " git checkout " ${ release_branch } "
maybedryrun " $dry_run " git merge --ff-only " ${ ref } "
else
log "Using existing release branch"
maybedryrun " $dry_run " git checkout " ${ release_branch } "
fi
else
2024-04-25 09:26:37 +00:00
remote_branch_exists = $( git branch --remotes --list " */ ${ release_branch } " --format= '%(refname)' )
local_branch_exists = $( git branch --list " ${ release_branch } " --format= '%(refname)' )
if [ [ -n ${ remote_branch_exists } ] ] || [ [ -n ${ local_branch_exists } ] ] ; then
if [ [ ${ prev_increment } = = patch ] ] ; then
error " Release branch ${ release_branch } already exists, impossible upgrade from \" ${ prev_increment } \" to \" ${ increment } \" detected. Please check your ref ( ${ ref_name } ) and that no incompatible commits were cherry-picked. "
fi
fi
if [ [ -n ${ remote_branch_exists } ] ] ; then
error " Release branch ${ release_branch } already exists on remote, please check your ref. "
fi
if [ [ -n ${ local_branch_exists } ] ] ; then
# If it exists, ensure that this release branch points to the provided ref.
release_branch_ref = $( git rev-parse " ${ release_branch } " )
if [ [ ${ release_branch_ref } != " ${ ref } " ] ] ; then
error " Local release branch ${ release_branch } already exists, but does not point to the provided ref ( ${ ref_name } ). "
fi
log "Using existing release branch"
maybedryrun " $dry_run " git checkout " ${ release_branch } "
else
log "Creating new release branch"
maybedryrun " $dry_run " git checkout -b " ${ release_branch } " " ${ ref } "
fi
fi
# Ensure the ref is in the release branch.
branch_contains_ref = $( git branch --contains " ${ ref } " --list " ${ release_branch } " --format= '%(refname)' )
2024-04-26 09:53:22 +00:00
if ( ( !dry_run) ) && [ [ -z $branch_contains_ref ] ] ; then
2024-04-25 09:26:37 +00:00
error " Provided ref ( ${ ref_name } ) is not in the required release branch ( ${ release_branch } ). "
2024-04-24 19:43:11 +00:00
fi
2024-04-25 09:26:37 +00:00
2023-01-11 16:38:01 +00:00
maybedryrun " $dry_run " git tag -a " $new_version " -m " Release $new_version " " $ref "
2024-04-24 19:43:11 +00:00
echo " ${ release_branch } ${ new_version } "