Files
DarkRoom/tools/set-version.sh
T
dtourolle d8b9b5a4bb Let the release script write the release commit it was never trusted with
Every release commit in the history reads `Release X.Y.Z` and none of them
carries the message this script would have written, so nobody has ever
passed it `--commit` — and the reason is in the message it wrote: a
Co-Authored-By trailer naming an assistant, which no commit in this repository
carries and none should.

The trailer goes, and so does the paragraph above it: the script's own header
already says why it exists, and a release commit is the one place a one-line
subject is the whole convention.
2026-09-11 09:33:28 +02:00

107 lines
4.1 KiB
Bash
Executable File

#!/usr/bin/env bash
# Set the project's version in the few places that must state it, from one
# source, and optionally commit the result.
#
# tools/set-version.sh --from-tag # take it from the latest git tag
# tools/set-version.sh 0.5.0 # or state it
# tools/set-version.sh --from-tag --commit
#
# Why this exists: the workspace read 0.1.0 for two releases, so every binary
# reported a version two releases stale, and the APK reported none at all. A
# version that has to be edited in several files by hand is a version that will
# be wrong in at least one of them.
#
# The number of places is kept deliberately small. Only two files state the
# version; everything else derives it:
#
# Cargo.toml the source of truth for every crate in the workspace
# packaging/PKGBUILD pacman needs it before anything is built
#
# AndroidManifest.xml states NO version on purpose — `package.sh` passes
# it to `aapt2 link` from Cargo.toml, so the APK cannot
# drift from the binary inside it.
set -euo pipefail
REPO="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "${REPO}"
COMMIT=0
VERSION=""
for arg in "$@"; do
case "${arg}" in
--commit) COMMIT=1 ;;
--from-tag) VERSION="$(git describe --tags --abbrev=0 2>/dev/null | sed 's/^v//')" ;;
-h|--help) sed -n '2,20p' "${BASH_SOURCE[0]}"; exit 0 ;;
-*) echo "error: unknown flag ${arg}" >&2; exit 2 ;;
*) VERSION="${arg#v}" ;;
esac
done
if [[ -z "${VERSION}" ]]; then
echo "error: no version given, and no tag to take one from" >&2
echo "usage: tools/set-version.sh [--from-tag | <version>] [--commit]" >&2
exit 2
fi
# Rejected rather than coerced. A version is a contract with whoever reads a
# bug report, and "0.4" or "v0.4.0-wip" silently becoming something else is
# worse than being told to type it again.
if ! [[ "${VERSION}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "error: '${VERSION}' is not MAJOR.MINOR.PATCH" >&2
exit 2
fi
CURRENT="$(sed -n 's/^version = "\(.*\)"$/\1/p' Cargo.toml | head -1)"
echo "==> ${CURRENT:-unknown} -> ${VERSION}"
# 1. The workspace. Every member inherits this through `version.workspace`.
# Anchored to the [workspace.package] table so a dependency's version
# string cannot be hit by accident.
python3 - "${VERSION}" <<'PY'
import re, sys, pathlib
version = sys.argv[1]
p = pathlib.Path("Cargo.toml")
s = p.read_text()
m = re.search(r"(\[workspace\.package\][^\[]*?\nversion = \")([^\"]+)(\")", s, re.S)
if not m:
sys.exit("error: no version under [workspace.package] in Cargo.toml")
p.write_text(s[:m.start(2)] + version + s[m.end(2):])
print(f" Cargo.toml {m.group(2)} -> {version}")
PY
# 2. pacman. `pkgrel` returns to 1: it counts packaging revisions *of one
# version*, so carrying it across a version bump would claim this is the
# second package of a version nobody has packaged yet.
python3 - "${VERSION}" <<'PY'
import re, sys, pathlib
version = sys.argv[1]
p = pathlib.Path("packaging/PKGBUILD")
s = p.read_text()
old = re.search(r"^pkgver=(.*)$", s, re.M)
s = re.sub(r"^pkgver=.*$", f"pkgver={version}", s, count=1, flags=re.M)
s = re.sub(r"^pkgrel=.*$", "pkgrel=1", s, count=1, flags=re.M)
p.write_text(s)
print(f" packaging/PKGBUILD {old.group(1) if old else '?'} -> {version}")
PY
# 3. Cargo.lock. The workspace members appear in it by version, so leaving it
# alone makes `--locked` builds fail — which is exactly what CI uses.
cargo update --workspace --offline >/dev/null 2>&1 \
|| cargo update --workspace >/dev/null 2>&1 \
|| echo " warning: could not refresh Cargo.lock; run 'cargo update --workspace'" >&2
echo " Cargo.lock refreshed"
echo "==> Android takes its version from Cargo.toml at link time; nothing to edit"
if [[ "${COMMIT}" == "1" ]]; then
git add Cargo.toml Cargo.lock packaging/PKGBUILD
if git diff --cached --quiet; then
echo "==> nothing changed; no commit made"
else
git commit -q -m "Release ${VERSION}"
echo "==> committed: $(git log --oneline -1)"
fi
else
echo "==> not committed (pass --commit to commit)"
fi