burrow/Scripts/version.sh
Conrad Kramer 4e31d54a45
Some checks failed
Build Site / Next.js Build (push) Waiting to run
Lint Governance / BEP Metadata (push) Waiting to run
Build Rust / Cargo Test (push) Has been cancelled
Make version helper CI-safe
2026-06-07 08:39:00 -07:00

147 lines
4.6 KiB
Bash
Executable file

#!/usr/bin/env bash
set -euo pipefail
burrow_user="${USER:-${LOGNAME:-runner}}"
export PATH="$PATH:/opt/homebrew/bin:/usr/local/bin:/etc/profiles/per-user/${burrow_user}/bin"
cd "$(dirname "${BASH_SOURCE[0]}")/.."
TAG_PREFIX="builds/"
DEFAULT_VERSION_REMOTE="origin"
if git remote get-url forgejo >/dev/null 2>&1; then
DEFAULT_VERSION_REMOTE="forgejo"
fi
VERSION_REMOTE="${BURROW_VERSION_REMOTE:-$DEFAULT_VERSION_REMOTE}"
VERSION_REQUIRE_REMOTE="${BURROW_VERSION_REQUIRE_REMOTE:-false}"
COMMAND="${1:-}"
truthy() {
case "$1" in
1|true|TRUE|True|yes|YES|Yes|y|Y|on|ON|On) return 0 ;;
*) return 1 ;;
esac
}
list_local_build_tags() {
git tag -l "${TAG_PREFIX}[0-9]*"
}
latest_local_build_tag() {
list_local_build_tags | sort -n -t'/' -k2 | tail -n 1
}
latest_remote_build_record() {
local raw rc=0
raw="$(git ls-remote --tags --refs "$VERSION_REMOTE" "refs/tags/${TAG_PREFIX}[0-9]*" 2>/dev/null)" || rc=$?
if [[ $rc -ne 0 ]]; then
return $rc
fi
if [[ -z "$raw" ]]; then
return 0
fi
printf '%s\n' "$raw" | awk -F'\t' -v prefix="refs/tags/${TAG_PREFIX}" '
$2 ~ ("^" prefix "[0-9]+$") {
build = $2
sub("^refs/tags/", "", build)
print build "\t" $1
}
' | sort -n -t'/' -k2 | tail -n 1
}
resolve_build_state() {
local remote_record local_latest remote_status=0
BUILD_STATE_SOURCE="local"
LATEST_BUILD=""
LATEST_BUILD_COMMIT=""
remote_record="$(latest_remote_build_record)" || remote_status=$?
if [[ $remote_status -eq 0 ]]; then
BUILD_STATE_SOURCE="remote"
if [[ -n "$remote_record" ]]; then
LATEST_BUILD="$(printf '%s\n' "$remote_record" | cut -f1)"
LATEST_BUILD_COMMIT="$(printf '%s\n' "$remote_record" | cut -f2)"
fi
else
if truthy "$VERSION_REQUIRE_REMOTE"; then
echo "error: unable to resolve authoritative build tags from ${VERSION_REMOTE}" >&2
exit "$remote_status"
fi
echo "warning: unable to resolve authoritative build tags from ${VERSION_REMOTE}; falling back to local tags" >&2
local_latest="$(latest_local_build_tag)"
if [[ -n "$local_latest" ]]; then
LATEST_BUILD="$local_latest"
LATEST_BUILD_COMMIT="$(git rev-parse -q --verify "refs/tags/${LATEST_BUILD}^{commit}" 2>/dev/null || true)"
fi
fi
if [[ -z "$LATEST_BUILD" ]]; then
LATEST_BUILD_NUMBER="0"
else
LATEST_BUILD_NUMBER="${LATEST_BUILD#$TAG_PREFIX}"
fi
}
resolve_build_state
HEAD_COMMIT="$(git rev-parse HEAD)"
ANCESTRY_STATE="ok"
if [[ -n "${LATEST_BUILD_NUMBER}" && "${LATEST_BUILD_NUMBER}" != "0" ]]; then
if [[ -n "${LATEST_BUILD_COMMIT}" ]] && git cat-file -e "${LATEST_BUILD_COMMIT}^{commit}" 2>/dev/null; then
if ! git merge-base --is-ancestor "${LATEST_BUILD_COMMIT}" HEAD; then
ANCESTRY_STATE="not-descended"
if [[ "$COMMAND" != "status" ]]; then
echo "error: HEAD is not descended from build ${LATEST_BUILD_NUMBER}" >&2
exit 1
fi
fi
else
ANCESTRY_STATE="missing-tag-commit"
echo "notice: skipping build ancestry check (missing ${LATEST_BUILD} commit, likely shallow checkout)" >&2
fi
fi
BUILD_NUMBER="$LATEST_BUILD_NUMBER"
if [[ "$COMMAND" == "increment" || "$COMMAND" == "pre-increment" ]]; then
if [[ -n "${BURROW_BUILD_NUMBER_OVERRIDE:-}" ]]; then
if [[ ! "${BURROW_BUILD_NUMBER_OVERRIDE}" =~ ^[0-9]+$ ]]; then
echo "error: BURROW_BUILD_NUMBER_OVERRIDE must be an integer" >&2
exit 1
fi
if (( BURROW_BUILD_NUMBER_OVERRIDE <= LATEST_BUILD_NUMBER )); then
echo "error: BURROW_BUILD_NUMBER_OVERRIDE must be greater than ${LATEST_BUILD_NUMBER}" >&2
exit 1
fi
NEW_BUILD_NUMBER="${BURROW_BUILD_NUMBER_OVERRIDE}"
else
NEW_BUILD_NUMBER=$((LATEST_BUILD_NUMBER + 1))
fi
NEW_TAG="$TAG_PREFIX$NEW_BUILD_NUMBER"
BUILD_NUMBER="$NEW_BUILD_NUMBER"
fi
if [[ "$COMMAND" == "increment" ]]; then
git tag "$NEW_TAG"
git push --quiet "$VERSION_REMOTE" "$NEW_TAG"
fi
CONFIG_PATH="Apple/Configuration/Version.xcconfig"
if [[ "$COMMAND" != "status" && -f "$CONFIG_PATH" ]]; then
current_config_version="$(sed -n 's/^[[:space:]]*CURRENT_PROJECT_VERSION[[:space:]]*=[[:space:]]*//p' "$CONFIG_PATH" 2>/dev/null | tail -n 1 || true)"
if [[ "$current_config_version" != "$BUILD_NUMBER" ]]; then
echo "CURRENT_PROJECT_VERSION = $BUILD_NUMBER" > "$CONFIG_PATH"
fi
git update-index --assume-unchanged "$CONFIG_PATH" 2>/dev/null || true
fi
if [[ "$COMMAND" == "status" ]]; then
if [[ "${ANCESTRY_STATE}" == "ok" && "${LATEST_BUILD_NUMBER}" != "0" && -n "${LATEST_BUILD_COMMIT}" && "${HEAD_COMMIT}" == "${LATEST_BUILD_COMMIT}" ]]; then
echo "clean"
else
echo "dirty"
fi
exit 0
fi
echo "$BUILD_NUMBER"