# Prepare Cargo.toml, Cargo.lock, and CHANGELOG.md for a versioned release.
release version range='':
#!/usr/bin/env bash
set -euo pipefail
version='{{version}}'
version="${version#v}"
range='{{range}}'
tag="v${version}"
if [[ ! "${version}" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?(\+[0-9A-Za-z.-]+)?$ ]]; then
echo "Expected a semver version like 0.31.0 or 0.31.0-rc.1; got '${version}'." >&2
exit 1
fi
for tool in git-cliff cargo git perl awk sed grep; do
if ! command -v "${tool}" >/dev/null 2>&1; then
echo "Missing required tool: ${tool}" >&2
exit 1
fi
done
if [[ -n "$(git status --porcelain)" ]]; then
echo "Release prep expects a clean working tree before it edits Cargo.toml, Cargo.lock, and CHANGELOG.md." >&2
git status --short >&2
exit 1
fi
if git rev-parse -q --verify "refs/tags/${tag}" >/dev/null; then
echo "Tag ${tag} already exists." >&2
exit 1
fi
if [[ -z "${range}" ]] && ! git describe --tags --abbrev=0 --match 'v[0-9]*' >/dev/null 2>&1; then
echo "No previous v* tag found. Run 'git fetch --tags' or pass an explicit range, for example:" >&2
echo " just release ${version} <base>..HEAD" >&2
exit 1
fi
if [[ -f CHANGELOG.md ]]; then
escaped_version="$(printf '%s' "${version}" | sed 's/[][\\.^$*+?{}|()]/\\&/g')"
if grep -Eq "^## \\[?v?${escaped_version}(\\]| |$)" CHANGELOG.md; then
echo "CHANGELOG.md already has an entry for ${version}." >&2
exit 1
fi
fi
current_version="$(awk '
$0 == "[package]" { in_package = 1; next }
in_package && $0 ~ /^\[/ { exit }
in_package && $1 == "version" {
gsub(/"/, "", $3)
print $3
exit
}
' Cargo.toml)"
if [[ -z "${current_version}" ]]; then
echo "Could not read the root package version from Cargo.toml." >&2
exit 1
fi
if [[ "${current_version}" == "${version}" ]]; then
echo "Cargo.toml is already at ${version}." >&2
exit 1
fi
tmpdir="$(mktemp -d)"
cp Cargo.toml "${tmpdir}/Cargo.toml"
cp Cargo.lock "${tmpdir}/Cargo.lock"
if [[ -f CHANGELOG.md ]]; then
cp CHANGELOG.md "${tmpdir}/CHANGELOG.md"
else
touch "${tmpdir}/NO_CHANGELOG"
fi
rollback() {
status=$?
if [[ ${status} -ne 0 ]]; then
cp "${tmpdir}/Cargo.toml" Cargo.toml
cp "${tmpdir}/Cargo.lock" Cargo.lock
if [[ -f "${tmpdir}/NO_CHANGELOG" ]]; then
rm -f CHANGELOG.md
else
cp "${tmpdir}/CHANGELOG.md" CHANGELOG.md
fi
fi
rm -rf "${tmpdir}"
exit "${status}"
}
trap rollback EXIT
VERSION="${version}" perl -0pi -e 's/(\[package\][\s\S]*?\nversion\s*=\s*")[^"]+(")/$1$ENV{VERSION}$2/s' Cargo.toml
cargo update -p betex --precise "${version}"
if [[ -n "${range}" ]]; then
git-cliff --tag "${tag}" --prepend CHANGELOG.md "${range}"
else
git-cliff --unreleased --tag "${tag}" --prepend CHANGELOG.md
fi
echo "Prepared ${tag}."
echo "Review CHANGELOG.md, especially rationale and migration notes for API changes, then commit and tag:"
echo " git add Cargo.toml Cargo.lock CHANGELOG.md"
echo " git commit -m 'chore(release): ${tag}'"
echo " git tag -a ${tag} -m '${tag}'"
# Publish betex-macros first, then publish the root crate once the macro crate is available.
publish:
#!/usr/bin/env bash
set -euo pipefail
macro_pkg='betex-macros'
root_pkg='betex'
macro_version="$(cargo pkgid -p "${macro_pkg}" | sed -E 's/.*#//')"
cargo publish --locked -p "${macro_pkg}"
echo "Waiting for ${macro_pkg} ${macro_version} to become available in the registry..."
for attempt in {1..60}; do
if cargo info "${macro_pkg}@${macro_version}" >/dev/null 2>&1; then
cargo publish --locked -p "${root_pkg}"
exit 0
fi
sleep 5
done
echo "Timed out waiting for ${macro_pkg} ${macro_version} to appear in the registry." >&2
exit 1