#!/usr/bin/env bash # # Tag a release, find the most recent NSIS installer, and upload it to Forgejo. # # Prereqs: # 1. You've bumped the version in package.json, src-tauri/Cargo.toml and # src-tauri/tauri.conf.json and committed + pushed to origin/main. # 2. You've run `pnpm tauri build` on the Windows host so the installer # exists at src-tauri/target/release/bundle/nsis/*.exe. # 3. `tea login list` shows the `rdx4` login is active. # # Attaches two assets: # - -setup.exe — NSIS installer # - tiletopia.mcpb — Claude Desktop one-click MCP extension bundle # (built by this script from src/ at release time) # # Usage: # scripts/release.sh v0.1.0 # set -euo pipefail TAG="${1:-}" if [[ -z "$TAG" ]]; then echo "usage: $0 " >&2 exit 1 fi if [[ ! "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then echo "tag must look like v0.1.0 (got: $TAG)" >&2 exit 1 fi cd "$(dirname "$0")/.." # Sanity checks if ! git diff --quiet || ! git diff --cached --quiet; then echo "working tree dirty — commit or stash first" >&2 exit 1 fi branch="$(git rev-parse --abbrev-ref HEAD)" if [[ "$branch" != "main" ]]; then echo "not on main (you're on '$branch') — bail" >&2 exit 1 fi git fetch origin --quiet if [[ "$(git rev-parse HEAD)" != "$(git rev-parse origin/main)" ]]; then echo "HEAD is out of sync with origin/main — push or pull first" >&2 exit 1 fi # Verify the tag's version matches package.json (catches "I forgot to bump") pkg_version="$(node -p "require('./package.json').version" 2>/dev/null || true)" expected_tag="v${pkg_version}" if [[ "$TAG" != "$expected_tag" ]]; then echo "package.json says version $pkg_version → expected tag $expected_tag, got $TAG" >&2 echo "bump package.json + src-tauri/Cargo.toml + src-tauri/tauri.conf.json first" >&2 exit 1 fi # Find the installer nsis_dir="src-tauri/target/release/bundle/nsis" if [[ ! -d "$nsis_dir" ]]; then echo "$nsis_dir not found — did you run 'pnpm tauri build' on Windows yet?" >&2 exit 1 fi installer="$(ls -1t "$nsis_dir"/*-setup.exe 2>/dev/null | head -n1 || true)" if [[ -z "$installer" || ! -f "$installer" ]]; then echo "no *-setup.exe found in $nsis_dir" >&2 exit 1 fi echo "Installer: $installer" echo "Size: $(du -h "$installer" | cut -f1)" # Build + locate the .mcpb bundle. The McpPanel's "Download .mcpb" button # opens this release page, so the asset has to be here for the click to work. # # Called via `node` directly (not `pnpm run build:mcpb`) because pnpm # triggers an `install` step first that walks node_modules — hangs for # minutes when this script runs from WSL against the /mnt/d/ Windows # filesystem. The build:mcpb script is pure Node + fs; no deps to install. echo "Building .mcpb bundle…" node scripts/build-mcpb.mjs >/dev/null mcpb="dist-mcpb/tiletopia.mcpb" if [[ ! -f "$mcpb" ]]; then echo "build-mcpb.mjs finished but $mcpb is missing" >&2 exit 1 fi echo "Bundle: $mcpb" echo "Size: $(du -h "$mcpb" | cut -f1)" # Tag and push if git rev-parse "$TAG" >/dev/null 2>&1; then echo "tag $TAG already exists locally — bail (delete it first if intentional)" >&2 exit 1 fi git tag -a "$TAG" -m "Release $TAG" git push origin "$TAG" # Create the release with the installer + .mcpb bundle attached tea releases create \ --login rdx4 \ --tag "$TAG" \ --title "$TAG" \ --note "tiletopia $TAG. Download the .exe below, run it, accept SmartScreen (\"More info → Run anyway\") — installer isn't code-signed. tiletopia.mcpb is the Claude Desktop one-click install bundle (Settings → Extensions → drag and drop)." \ --asset "$installer" \ --asset "$mcpb" echo echo "✓ released $TAG → https://git.rdx4.com/megaproxy/tiletopia/releases/tag/$TAG"