Files
sanderling/.github/scripts/next-version.sh
T
pj b6475e0ad3 feat(ci): resolve the release version from the tags the repo carries
The tags are the record of what has been released, so nothing in the tree
holds the version and no commit has to land on master to advance one.

Claude-Session: https://claude.ai/code/session_01ShuAy8q8ZfPi8KHxwc8JpQ
2026-08-16 14:02:09 +05:30

64 lines
2.2 KiB
Bash
Executable File

#!/usr/bin/env bash
# Resolves the version a release is cutting. The tags this repo carries are the
# record of what has been released, so the version is counted off them and
# nothing in the tree holds it: no commit has to land on master to advance a
# version, and a release cannot disagree with a package.json someone edited.
#
# BUMP is major, minor or patch. VERSION overrides it with a version named
# outright. Writes `version` and `tag` to $GITHUB_OUTPUT when it is set.
set -euo pipefail
bump="${BUMP:-patch}"
named="${VERSION:-}"
semver='^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z]+(\.[0-9A-Za-z]+)*)?$'
if [ -n "$named" ]; then
if [[ ! "$named" =~ $semver ]]; then
echo "next-version: '$named' is not a version this releases" >&2
echo "next-version: a version is MAJOR.MINOR.PATCH with an optional -prerelease, e.g. 0.1.0 or 1.0.0-rc1" >&2
exit 1
fi
version="$named"
from="named outright"
else
# Only a stable tag is a base to count from. v0.0.1-rc4 is a candidate for
# 0.0.1, so counting a patch off it would skip the very version it was a
# candidate for. `sort -V` puts 0.10.0 above 0.9.0, which a lexical sort does
# not, and `sed -n p` reports no matches as an empty line rather than as the
# failure `grep` would return under pipefail.
base="$(git tag -l 'v*' \
| sed -n 's/^v\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\)$/\1/p' \
| sort -V \
| tail -1)"
base="${base:-0.0.0}"
from="a $bump off ${base}"
IFS=. read -r major minor patch <<<"$base"
case "$bump" in
major) version="$((major + 1)).0.0" ;;
minor) version="$major.$((minor + 1)).0" ;;
patch) version="$major.$minor.$((patch + 1))" ;;
*)
echo "next-version: '$bump' is not a bump; use major, minor or patch" >&2
exit 1
;;
esac
fi
tag="v$version"
# A tag that is already there means this version was already cut. Moving it
# would relabel a release that people have installed.
if git rev-parse -q --verify "refs/tags/$tag" >/dev/null; then
echo "next-version: $tag is already tagged, so there is nothing to release at $version" >&2
exit 1
fi
echo "next-version: releasing $version, $from"
if [ -n "${GITHUB_OUTPUT:-}" ]; then
{
echo "version=$version"
echo "tag=$tag"
} >> "$GITHUB_OUTPUT"
fi