ziex/tools/version
2026-07-15 12:55:31 +06:00

181 lines
6.6 KiB
Bash
Executable File

#!/bin/bash
# Set or resolve the project version.
#
# In the repo, the version is kept WITHOUT a pre-release number, e.g.
# "0.1.0-dev". The full version (e.g. "0.1.0-dev.1138") is only materialized
# during the release process, so there are no "bump version" commits.
#
# Usage:
# ./version <version> Set an explicit version everywhere (e.g. 0.1.0-dev.1138)
# ./version --from=commits Compute N from git commit count, stamp 0.1.0-dev.N
# ./version --from=tag Compute N from the latest matching git tag + 1, stamp 0.1.0-dev.N
# ./version --resolve [--from=commits|tag]
# Print the resolved full version to stdout and exit
# (does not modify any files). Defaults to --from=commits.
# ./version --resolve --with-sha
# As above, but append "+<short-sha>" build metadata
# to pre-release versions (for embedding in the binary
# via -Dversion). Package versions must stay clean, so
# this is opt-in.
# ./version Equivalent to --from=commits (stamp files)
#
# The base version (everything before the pre-release number) is read from
# build.zig.zon and may be either numberless ("0.1.0-dev") or already
# numbered ("0.1.0-dev.123") - both are handled.
# TODO: delete in favour of build.zig getVersion()
BUILD_ZON_FILE="build.zig.zon"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
BUILD_ZON_PATH="$PROJECT_ROOT/$BUILD_ZON_FILE"
if [ ! -f "$BUILD_ZON_PATH" ]; then
echo "Error: $BUILD_ZON_FILE not found at $BUILD_ZON_PATH" >&2
exit 1
fi
# Extract current version (.version field only, not .jsglue_version etc.)
CURRENT_VERSION=$(grep -E '^\s*\.version\s*=' "$BUILD_ZON_PATH" | sed -E 's/.*"([^"]+)".*/\1/')
if [ -z "$CURRENT_VERSION" ]; then
echo "Error: Could not find version in $BUILD_ZON_FILE" >&2
exit 1
fi
EXPLICIT_VERSION=""
FROM="commits"
RESOLVE_ONLY=0
WITH_SHA=0
for arg in "$@"; do
case "$arg" in
--resolve) RESOLVE_ONLY=1 ;;
--with-sha) WITH_SHA=1 ;;
--from=commits) FROM="commits" ;;
--from=tag) FROM="tag" ;;
--commit) FROM="commits" ;; # backwards-compatible alias
--from=*)
echo "Error: unknown --from value: ${arg#--from=} (use commits|tag)" >&2
exit 1
;;
--*)
echo "Error: unknown flag: $arg" >&2
exit 1
;;
*)
EXPLICIT_VERSION="$arg" ;;
esac
done
# Compute the base (version without the pre-release number)
# Strip any "+<build metadata>" suffix, then a trailing ".<number>"
# pre-release counter if present.
# 0.1.0-dev -> 0.1.0-dev
# 0.1.0-dev.123 -> 0.1.0-dev
# 0.1.0-dev.123+abc1234 -> 0.1.0-dev
# 0.1.0 -> 0.1.0 (no -dev, left as-is)
BASE_VERSION=$(echo "$CURRENT_VERSION" | sed -E 's/\+.*$//; s/(-[a-zA-Z]+)\.[0-9]+$/\1/')
# Resolve the new full version
if [ -n "$EXPLICIT_VERSION" ]; then
NEW_VERSION="$EXPLICIT_VERSION"
else
case "$FROM" in
commits)
N=$(git -C "$PROJECT_ROOT" rev-list --count HEAD 2>/dev/null)
if [ -z "$N" ]; then
echo "Error: Could not get git commit count" >&2
exit 1
fi
;;
tag)
# Find the highest existing tag matching v<base>.<n> and increment n.
# E.g. base 0.1.0-dev -> match v0.1.0-dev.*, take the max n, +1.
ESCAPED_BASE=$(printf '%s' "$BASE_VERSION" | sed -E 's/[.[\*^$()+?{}|]/\\&/g')
LAST_N=$(git -C "$PROJECT_ROOT" tag --list "v${BASE_VERSION}.*" \
| sed -E "s/^v${ESCAPED_BASE}\.([0-9]+)$/\1/" \
| grep -E '^[0-9]+$' \
| sort -n \
| tail -1)
if [ -z "$LAST_N" ]; then
N=1
else
N=$((LAST_N + 1))
fi
;;
esac
NEW_VERSION="${BASE_VERSION}.${N}"
fi
if [ "$WITH_SHA" -eq 1 ] && echo "$NEW_VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+-' && ! echo "$NEW_VERSION" | grep -q '+'; then
SHA=$(git -C "$PROJECT_ROOT" rev-parse --short HEAD 2>/dev/null)
[ -n "$SHA" ] && NEW_VERSION="${NEW_VERSION}+${SHA}"
fi
# --resolve: just print and exit, touching nothing.
if [ "$RESOLVE_ONLY" -eq 1 ]; then
echo "$NEW_VERSION"
exit 0
fi
echo "Version: $CURRENT_VERSION -> $NEW_VERSION"
# Stamp the new version into all version-bearing files
# Match any X.Y.Z[-pre[.N]][+meta] version string for in-place replacement.
VERSION_PATTERN='[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z]+(\.[0-9]+)?)?(\+[0-9A-Za-z.]+)?'
# Root build.zig.zon (.version field only)
sed -i.bak -E "/^[[:space:]]*\.version[[:space:]]*=/s/$VERSION_PATTERN/$NEW_VERSION/" "$BUILD_ZON_PATH"
rm -f "$BUILD_ZON_PATH.bak"
echo "Updated $BUILD_ZON_FILE"
# pkg/ziex/build.zig.zon
ZIEX_BUILD_ZON="$PROJECT_ROOT/pkg/ziex/build.zig.zon"
if [ -f "$ZIEX_BUILD_ZON" ]; then
sed -i.bak -E "/^[[:space:]]*\.version[[:space:]]*=/s/$VERSION_PATTERN/$NEW_VERSION/" "$ZIEX_BUILD_ZON"
rm -f "$ZIEX_BUILD_ZON.bak"
echo "Updated pkg/ziex/build.zig.zon"
fi
# pkg/ziex/package.json
ZIEX_PACKAGE_JSON="$PROJECT_ROOT/pkg/ziex/package.json"
if [ -f "$ZIEX_PACKAGE_JSON" ]; then
sed -i.bak -E "/^[[:space:]]*\"version\"[[:space:]]*:/s/$VERSION_PATTERN/$NEW_VERSION/" "$ZIEX_PACKAGE_JSON"
rm -f "$ZIEX_PACKAGE_JSON.bak"
echo "Updated pkg/ziex/package.json"
fi
# ide/zed/extension.toml
ZED_EXTENSION_TOML="$PROJECT_ROOT/ide/zed/extension.toml"
if [ -f "$ZED_EXTENSION_TOML" ]; then
sed -i.bak -E "/^[[:space:]]*version[[:space:]]*=/s/$VERSION_PATTERN/$NEW_VERSION/" "$ZED_EXTENSION_TOML"
rm -f "$ZED_EXTENSION_TOML.bak"
echo "Updated ide/zed/extension.toml"
fi
# ide/vscode/package.json (uses 0.1.N format since VSCode rejects prerelease tags)
VSCODE_PACKAGE_JSON="$PROJECT_ROOT/ide/vscode/package.json"
if [ -f "$VSCODE_PACKAGE_JSON" ]; then
VSCODE_DEV_NUMBER=$(echo "${NEW_VERSION%%+*}" | grep -oE '[a-zA-Z]+\.([0-9]+)$' | grep -oE '[0-9]+$')
if [ -n "$VSCODE_DEV_NUMBER" ]; then
VSCODE_VERSION="0.1.$VSCODE_DEV_NUMBER"
sed -i.bak -E "s/\"version\": \"0\\.1\\.[0-9]+\"/\"version\": \"$VSCODE_VERSION\"/" "$VSCODE_PACKAGE_JSON"
rm -f "$VSCODE_PACKAGE_JSON.bak"
echo "Updated ide/vscode/package.json -> $VSCODE_VERSION"
fi
fi
# tree-sitter grammars
for TS in tree-sitter-zx tree-sitter-mdzx; do
TREE_SITTER_DIR="$PROJECT_ROOT/pkg/$TS"
if [ -d "$TREE_SITTER_DIR" ]; then
(cd "$TREE_SITTER_DIR" && tree-sitter version "$NEW_VERSION") 2>/dev/null || true
fi
done
exit 0