#!/usr/bin/env bash set -euo pipefail # Necessary for testing the release script export TEST_MODE=true : "${ORIGIN:=origin}" : "${STABLE_BRANCH:=master}" REPO_ROOT= FORK_ROOT=$(mktemp -d -t galaxy_release_test_XXXXXXXX) TEST_RELEASE_PREV= TEST_RELEASE_PREV_MINOR= TEST_RELEASE_CURR='99.0' TEST_RELEASE_NEXT='99.1' TEST_RELEASE_NEXT_NEXT='99.2' : "${VENV:=${FORK_ROOT}/venv}" export VENV function trap_handler() { [ -z "$FORK_ROOT" ] || rm -rf "$FORK_ROOT" } trap "trap_handler" EXIT function log() { [ -t 0 ] && echo -e '\033[1;35m#' "$@" '\033[0m' 1>&2 || echo '#' "$@" 1>&2 } function log_exec() { local rc set -x "$@" { rc=$?; set +x; } 2>/dev/null return $rc } function log_function() { local func_name="$1"; shift log ">>>> ${func_name}()" $func_name "$@" log "<<<< ${func_name}()" } function get_repo_root() { ( cd "$(dirname "$0")/.." pwd ) } function get_stable_version() { local part="$1" ( cd_fork work local restore_branch restore_branch="$(git branch --show-current)" git checkout -q --no-track -b __stable_version_check "upstream/${STABLE_BRANCH}" grep "^VERSION_${part}" lib/galaxy/version.py | sed -E -e "s/^[^'\"]*['\"]([^'\"]*)['\"]$/\1/" git checkout -q "$restore_branch" git branch -q -D __stable_version_check ) } function cd_fork() { log_exec cd "${FORK_ROOT}/${1}" } function make_forks() { [ -n "$REPO_ROOT" ] || REPO_ROOT=$(get_repo_root) # Use a "work" clone to prevent modifications to current clone log_exec git clone --no-checkout "${REPO_ROOT}" "${FORK_ROOT}/work" ( cd_fork work # A username and email address are needed to commit if [ -z "$(git config --get user.name)" ]; then log_exec git config user.name "Test User" fi if [ -z "$(git config --get user.email)" ]; then log_exec git config user.email "test@example.org" fi if [ "$(git rev-parse --abbrev-ref HEAD)" != dev ]; then CURRENT_COMMIT=$(git rev-parse HEAD) log "Checking out ref '${CURRENT_COMMIT}' as 'dev'" log_exec git checkout --no-track -b dev "$CURRENT_COMMIT" fi ) # Create bare origin and upstream repos for repo in origin upstream; do log_exec git clone --bare "${FORK_ROOT}/work" "${FORK_ROOT}/${repo}" ( cd_fork "$repo" log_exec git remote remove origin ) done # Set remotes on work repo ( cd_fork work log_exec git remote remove origin for repo in origin upstream; do log_exec git remote add "$repo" "file://${FORK_ROOT}/${repo}" done ) # Fetch release branches to upstream repo ( cd_fork upstream log_exec git fetch --no-tags "${REPO_ROOT}" refs/remotes/origin/${STABLE_BRANCH}:${STABLE_BRANCH} ) # Set current (previous) stable release from stable branch ( cd_fork work log_exec git fetch --no-tags upstream ) TEST_RELEASE_PREV=$(get_stable_version MAJOR) TEST_RELEASE_PREV_MINOR=$(get_stable_version MINOR) } function create_venv() { if [ ! -d "$VENV" ]; then if command -v uv >/dev/null; then log_exec uv venv "$VENV" log_exec uv pip install --python "$VENV/bin/python" wheel packaging else log_exec python3 -m venv "$VENV" log_exec "${VENV}/bin/pip" install wheel packaging fi fi . "${VENV}/bin/activate" } function verify_version() { local major="$1" local minor="$2" local ref="$3" local _ref="$3" local restore_branch restore_branch="$(git branch --show-current)" [ -n "$(git tag -l "$ref")" ] || _ref="upstream/${ref}" log_exec git checkout --no-track -b "__${ref}" "$_ref" if grep -q "^VERSION_MAJOR = \"${major}\"$" lib/galaxy/version.py; then log "**** Major version '${major}' is correct at ref '${ref}'" else log "**** Major version '${major}' is incorrect at ref '${ref}':" log "$(grep '^VERSION_MAJOR' lib/galaxy/version.py)" exit 1 fi if grep -q "^VERSION_MINOR = \"${minor}\"$" lib/galaxy/version.py; then log "**** Minor version '${minor}' is correct at ref '${ref}'" else log "**** Minor version '${minor}' is incorrect at ref '${ref}':" log "$(grep '^VERSION_MINOR' lib/galaxy/version.py)" exit 1 fi log_exec git checkout "$restore_branch" log_exec git branch -D "__${ref}" } function verify_makefile_version() { local major="$1" local ref="$2" local _ref="$2" local restore_branch restore_branch="$(git branch --show-current)" [ -n "$(git tag -l "$ref")" ] || _ref="upstream/${ref}" log_exec git checkout --no-track -b "__${ref}" "$_ref" if grep -q "^RELEASE_CURR:=${major}$" Makefile; then log "**** RELEASE_CURR '${major}' is correct in Makefile at ref '${ref}'" else log "**** RELEASE_CURR '${major}' is incorrect in Makefile at ref '${ref}':" log "$(grep '^RELEASE_CURR' Makefile)" exit 1 fi log_exec git checkout "$restore_branch" log_exec git branch -D "__${ref}" } function test_rc() { log "Test creation of ${TEST_RELEASE_CURR}.rc1..." ( cd_fork work log_exec "${REPO_ROOT}/scripts/release.sh" -r "$TEST_RELEASE_CURR" # simulate merging RC PRs log_exec git push upstream refs/remotes/origin/version-${TEST_RELEASE_CURR}.rc1:refs/heads/release_${TEST_RELEASE_CURR} log_exec git push upstream refs/remotes/origin/version-${TEST_RELEASE_NEXT}.dev:refs/heads/dev # verify major minor ref (branch/tag) verify_version "$TEST_RELEASE_CURR" 'rc1' "release_${TEST_RELEASE_CURR}" verify_version "$TEST_RELEASE_NEXT" 'dev0' 'dev' verify_version "$TEST_RELEASE_PREV" "$TEST_RELEASE_PREV_MINOR" "$STABLE_BRANCH" # should not have changed verify_makefile_version "$TEST_RELEASE_NEXT" 'dev' ) } function test_rc_point() { log "Test creation of ${TEST_RELEASE_CURR}.rc2..." ( cd_fork work log_exec "${REPO_ROOT}/scripts/release.sh" -c -r "$TEST_RELEASE_CURR" # verify major minor ref (branch/tag) verify_version "$TEST_RELEASE_CURR" 'rc2' "release_${TEST_RELEASE_CURR}" verify_version "$TEST_RELEASE_NEXT" 'dev0' 'dev' verify_version "$TEST_RELEASE_PREV" "$TEST_RELEASE_PREV_MINOR" "$STABLE_BRANCH" # should not have changed verify_makefile_version "$TEST_RELEASE_NEXT" 'dev' ) } function test_initial() { log "Test creation of ${TEST_RELEASE_CURR} initial (.0)..." ( cd_fork work log_exec "${REPO_ROOT}/scripts/release.sh" -r "$TEST_RELEASE_CURR" # re-fetch from upstream to ensure tags are correct log_exec git tag -d $(git tag -l) log_exec git fetch upstream # verify major minor ref (branch/tag) verify_version "$TEST_RELEASE_CURR" '' "v${TEST_RELEASE_CURR}" verify_version "$TEST_RELEASE_CURR" '1.dev0' "release_${TEST_RELEASE_CURR}" verify_version "$TEST_RELEASE_NEXT" 'dev0' 'dev' verify_version "$TEST_RELEASE_CURR" '' "$STABLE_BRANCH" verify_makefile_version "$TEST_RELEASE_NEXT" 'dev' ) } function test_point() { log "Test creation of ${TEST_RELEASE_CURR}.1..." ( cd_fork work log_exec "${REPO_ROOT}/scripts/release.sh" -r "$TEST_RELEASE_CURR" log_exec git tag -d $(git tag -l) log_exec git fetch upstream # verify major minor ref (branch/tag) verify_version "$TEST_RELEASE_CURR" '1' "$STABLE_BRANCH" verify_version "$TEST_RELEASE_CURR" '1' "v${TEST_RELEASE_CURR}.1" verify_version "$TEST_RELEASE_CURR" '2.dev0' "release_${TEST_RELEASE_CURR}" verify_version "$TEST_RELEASE_NEXT" 'dev0' 'dev' verify_makefile_version "$TEST_RELEASE_NEXT" 'dev' ) } function test_next() { log "Test creation of ${TEST_RELEASE_NEXT} rc1 -> initial (.0)..." ( cd_fork work # create RC log_exec "${REPO_ROOT}/scripts/release.sh" -r "$TEST_RELEASE_NEXT" # simulate merging RC PRs log_exec git push upstream refs/remotes/origin/version-${TEST_RELEASE_NEXT}.rc1:refs/heads/release_${TEST_RELEASE_NEXT} log_exec git push upstream refs/remotes/origin/version-${TEST_RELEASE_NEXT_NEXT}.dev:refs/heads/dev # create initial log_exec "${REPO_ROOT}/scripts/release.sh" -r "$TEST_RELEASE_NEXT" log_exec git tag -d $(git tag -l) log_exec git fetch upstream # verify major minor ref (branch/tag) verify_version "$TEST_RELEASE_NEXT" '' "$STABLE_BRANCH" verify_version "$TEST_RELEASE_NEXT" '' "v${TEST_RELEASE_NEXT}" verify_version "$TEST_RELEASE_NEXT" '1.dev0' "release_${TEST_RELEASE_NEXT}" verify_version "$TEST_RELEASE_NEXT_NEXT" 'dev0' 'dev' verify_makefile_version "$TEST_RELEASE_NEXT" "release_${TEST_RELEASE_NEXT}" verify_makefile_version "$TEST_RELEASE_NEXT_NEXT" 'dev' ) } function test_prev() { log "Test creation of ${TEST_RELEASE_CURR}.2..." ( cd_fork work log_exec "${REPO_ROOT}/scripts/release.sh" -r "$TEST_RELEASE_CURR" log_exec git tag -d $(git tag -l) log_exec git fetch upstream # verify major minor ref (branch/tag) verify_version "$TEST_RELEASE_NEXT" '' "$STABLE_BRANCH" verify_version "$TEST_RELEASE_CURR" '2' "v${TEST_RELEASE_CURR}.2" verify_version "$TEST_RELEASE_CURR" '3.dev0' "release_${TEST_RELEASE_CURR}" verify_version "$TEST_RELEASE_NEXT" '1.dev0' "release_${TEST_RELEASE_NEXT}" verify_version "$TEST_RELEASE_NEXT_NEXT" 'dev0' 'dev' verify_makefile_version "$TEST_RELEASE_NEXT" "release_${TEST_RELEASE_NEXT}" verify_makefile_version "$TEST_RELEASE_NEXT_NEXT" 'dev' ) } function main() { log "TIP: test output is magenta, release script output is green/red" log_function make_forks log_function create_venv log_function test_rc log_function test_rc_point # log_function test_initial # log_function test_point # log_function test_next # log_function test_prev log "OK" } main