From 250882da1f4c8d0dda0dd41e7eba7ba1c43b4fa3 Mon Sep 17 00:00:00 2001 From: eric Date: Wed, 4 Mar 2026 18:45:55 +0100 Subject: [PATCH] test: ensure versions are consistent --- README.md | 2 + flake.nix | 18 ++++++ packages/release/release.sh | 10 +++- tests/release.sh | 115 ++++++++++++++++++++++++++++++++++++ 4 files changed, 143 insertions(+), 2 deletions(-) create mode 100644 tests/release.sh diff --git a/README.md b/README.md index f282384..f7acf52 100644 --- a/README.md +++ b/README.md @@ -64,9 +64,11 @@ Run releases with: ```bash release release patch +release beta release minor beta release stable release set 1.2.3 ``` The release script uses `./VERSION` as the source of truth and creates tags like `v1.2.3`. +When switching from stable to a prerelease channel without an explicit bump (for example, `release beta`), it applies a patch bump automatically (for example, `1.0.0` -> `1.0.1-beta.1`). diff --git a/flake.nix b/flake.nix index 93017e4..d0830dd 100644 --- a/flake.nix +++ b/flake.nix @@ -301,10 +301,28 @@ checks = forAllSystems ( system: let + pkgs = import nixpkgs { inherit system; }; env = self.lib.mkDevShell { inherit system; }; in { inherit (env) pre-commit-check; + release-tests = + pkgs.runCommand "release-tests" + { + nativeBuildInputs = with pkgs; [ + bash + git + gnused + coreutils + gnugrep + ]; + } + '' + export REPO_LIB_ROOT=${./.} + export HOME="$TMPDIR" + ${pkgs.bash}/bin/bash ${./tests/release.sh} + touch "$out" + ''; } ); diff --git a/packages/release/release.sh b/packages/release/release.sh index 90a4d0d..3aa79b6 100644 --- a/packages/release/release.sh +++ b/packages/release/release.sh @@ -23,11 +23,12 @@ usage() { " (none) bump patch, keep current channel" \ " major/minor/patch bump the given part, keep current channel" \ " stable / full remove prerelease suffix" \ - " __CHANNEL_LIST__ switch channel (bumps prerelease number if same base+channel)" \ + " __CHANNEL_LIST__ switch channel (from stable, auto-bumps patch unless bump is specified)" \ "" \ "Examples:" \ " ${cmd} # patch bump on current channel" \ " ${cmd} minor # minor bump on current channel" \ + " ${cmd} beta # from stable: patch bump + beta.1" \ " ${cmd} patch beta # patch bump, switch to beta channel" \ " ${cmd} rc # switch to rc channel" \ " ${cmd} stable # promote to stable release" \ @@ -310,7 +311,7 @@ main() { esac else - local part="" target_channel="" + local part="" target_channel="" was_channel_only=0 case "$action" in "") part="patch" ;; @@ -331,6 +332,7 @@ main() { if [[ $is_channel == 1 ]]; then [[ -n ${1-} ]] && echo "Error: channel-only bump takes no second argument" >&2 && usage && exit 1 target_channel="$action" + was_channel_only=1 else echo "Error: unknown argument '$action'" >&2 usage @@ -343,6 +345,10 @@ main() { [[ $target_channel == "full" ]] && target_channel="stable" validate_channel "$target_channel" + if [[ -z $part && $was_channel_only -eq 1 && $CHANNEL == "stable" && $target_channel != "stable" ]]; then + part="patch" + fi + local old_base="$BASE_VERSION" old_channel="$CHANNEL" old_pre="$PRERELEASE_NUM" [[ -n $part ]] && bump_base_version "$part" diff --git a/tests/release.sh b/tests/release.sh new file mode 100644 index 0000000..7a745e0 --- /dev/null +++ b/tests/release.sh @@ -0,0 +1,115 @@ +#!/usr/bin/env bash + +set -euo pipefail + +ROOT_DIR="${REPO_LIB_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}" +RELEASE_TEMPLATE="$ROOT_DIR/packages/release/release.sh" + +fail() { + echo "[test] FAIL: $*" >&2 + exit 1 +} + +assert_eq() { + local expected="$1" + local actual="$2" + local message="$3" + if [[ "$expected" != "$actual" ]]; then + fail "$message (expected '$expected', got '$actual')" + fi +} + +make_release_script() { + local target="$1" + sed \ + -e 's/__CHANNEL_LIST__/alpha beta rc internal/g' \ + -e 's/__RELEASE_STEPS__/:/' \ + -e 's/__POST_VERSION__/:/' \ + "$RELEASE_TEMPLATE" >"$target" + chmod +x "$target" +} + +setup_repo() { + local repo_dir="$1" + local remote_dir="$2" + + mkdir -p "$repo_dir" + git -C "$repo_dir" init >/dev/null + git -C "$repo_dir" config user.name "Release Test" + git -C "$repo_dir" config user.email "release-test@example.com" + + cat >"$repo_dir/flake.nix" <<'EOF' +{ + description = "release test"; + outputs = { self }: { }; +} +EOF + + printf '1.0.0\nstable\n0\n' >"$repo_dir/VERSION" + git -C "$repo_dir" add -A + git -C "$repo_dir" commit -m "init" >/dev/null + + git init --bare "$remote_dir" >/dev/null + git -C "$repo_dir" remote add origin "$remote_dir" + git -C "$repo_dir" push -u origin HEAD >/dev/null +} + +version_from_file() { + local repo_dir="$1" + local base channel n + base="$(sed -n '1p' "$repo_dir/VERSION" | tr -d '\r')" + channel="$(sed -n '2p' "$repo_dir/VERSION" | tr -d '\r')" + n="$(sed -n '3p' "$repo_dir/VERSION" | tr -d '\r')" + + if [[ -z "$channel" || "$channel" == "stable" ]]; then + echo "$base" + else + echo "$base-$channel.$n" + fi +} + +run_case() { + local case_name="$1" + local command_args="$2" + local expected_version="$3" + + local workdir + workdir="$(mktemp -d)" + local repo_dir="$workdir/repo" + local remote_dir="$workdir/remote.git" + + setup_repo "$repo_dir" "$remote_dir" + make_release_script "$repo_dir/release" + + mkdir -p "$repo_dir/bin" + cat >"$repo_dir/bin/nix" <<'EOF' +#!/usr/bin/env bash +if [[ "${1-}" == "fmt" ]]; then + exit 0 +fi +echo "unexpected nix invocation: $*" >&2 +exit 1 +EOF + chmod +x "$repo_dir/bin/nix" + + ( + cd "$repo_dir" + PATH="$repo_dir/bin:$PATH" ./release $command_args >/dev/null + ) + + local got_version + got_version="$(version_from_file "$repo_dir")" + assert_eq "$expected_version" "$got_version" "$case_name: VERSION mismatch" + + if ! git -C "$repo_dir" tag --list | grep -qx "v$expected_version"; then + fail "$case_name: expected tag v$expected_version was not created" + fi + + rm -rf "$workdir" + echo "[test] PASS: $case_name" >&2 +} + +run_case "channel-only from stable bumps patch" "beta" "1.0.1-beta.1" +run_case "explicit minor bump keeps requested bump" "minor beta" "1.1.0-beta.1" + +echo "[test] All release tests passed" >&2