#!/usr/bin/env bash # Release EvoScientist to git.foksai.com. # # Usage: # scripts/release.sh 0.2.3 "Release notes text" # bump pyproject, tag, publish # scripts/release.sh 0.2.2 "Release notes text" # version == pyproject: reuse existing tag # # Requires: GITEA_TOKEN (write:repository), uv, shasum, jq, curl. # Optional: GITEA_BASE_URL (default https://git.foksai.com), GITEA_REPO (default ouyangbo/EvoScientist). # # The wheel/sdist are built in a temporary git worktree at the tag so dirty # working trees never leak into published artifacts. set -euo pipefail VERSION="${1:?usage: release.sh }" NOTES="${2:?usage: release.sh }" TAG="v${VERSION}" BASE="${GITEA_BASE_URL:-https://git.foksai.com}" REPO="${GITEA_REPO:-ouyangbo/EvoScientist}" : "${GITEA_TOKEN:?export GITEA_TOKEN with write:repository scope}" REPO_ROOT="$(git rev-parse --show-toplevel)" cd "$REPO_ROOT" PYPROJECT_VERSION="$(grep -m1 '^version = ' pyproject.toml | sed 's/version = "\(.*\)"/\1/')" if [[ "$VERSION" != "$PYPROJECT_VERSION" ]]; then echo "==> bump pyproject $PYPROJECT_VERSION -> $VERSION" sed -i '' "s/^version = \"$PYPROJECT_VERSION\"/version = \"$VERSION\"/" pyproject.toml uv lock git add pyproject.toml uv.lock git commit -m "chore(release): $TAG" git tag "$TAG" else git rev-parse --verify --quiet "refs/tags/$TAG" >/dev/null || { echo "error: pyproject is already $VERSION but tag $TAG does not exist" >&2 exit 1 } echo "==> reusing existing tag $TAG" fi echo "==> pushing tag $TAG" git push origin "$TAG" WORKTREE="$(mktemp -d)/build" trap 'git worktree remove --force "$WORKTREE" 2>/dev/null || true' EXIT echo "==> building from clean worktree at $TAG" git worktree add --detach "$WORKTREE" "$TAG" ( cd "$WORKTREE" && uv build ) DIST="$WORKTREE/dist" ( cd "$DIST" && shasum -a 256 ./*.whl ./*.tar.gz > checksums.txt ) echo "==> creating release $TAG" RELEASE_ID="$(curl -sS -f -X POST \ -H "Authorization: token $GITEA_TOKEN" \ -H 'Content-Type: application/json' \ -d "$(jq -n --arg tag "$TAG" --arg body "$NOTES" \ '{tag_name: $tag, name: "Release \($tag)", body: $body}')" \ "$BASE/api/v1/repos/$REPO/releases" | jq -r .id)" echo " release id: $RELEASE_ID" for f in "$DIST"/*.whl "$DIST"/*.tar.gz "$DIST/checksums.txt"; do echo "==> uploading $(basename "$f")" curl -sS -f -X POST \ -H "Authorization: token $GITEA_TOKEN" \ -H 'Content-Type: application/octet-stream' \ --data-binary "@$f" \ "$BASE/api/v1/repos/$REPO/releases/$RELEASE_ID/assets?name=$(basename "$f")" \ | jq -r '.browser_download_url' done echo "==> verify" curl -sS -f "$BASE/api/v1/repos/$REPO/releases/latest" | jq -r '.tag_name' echo "done: $TAG published"