#!/bin/bash # release.sh — build and publish a PhotoPhetch release to Gitea # # Usage (on your Mac after pulling tagged commit): # ./release.sh # # The release version and notes are read from the current git tag and # releases/.md — both committed by the dev machine before tagging. # # Requires GITEA_TOKEN environment variable. # Get a token: https://git.bolenpad.com/user/settings/applications # Add to ~/.zshrc: export GITEA_TOKEN=your_token_here set -euo pipefail # ── Config ─────────────────────────────────────────────────────────────────── GITEA_URL="https://git.bolenpad.com" GITEA_USER="kbolen" GITEA_REPO="photophetch" # ── Resolve version from current git tag ───────────────────────────────────── TAG=$(git describe --exact-match --tags HEAD 2>/dev/null || echo "") if [ -z "$TAG" ]; then echo "ERROR: HEAD is not on a tag. Pull the latest and checkout the release tag." echo " git fetch --tags && git checkout v1.0.0" exit 1 fi VERSION="${TAG#v}" # strip leading 'v' echo "→ Building release $TAG (version $VERSION)" # ── Read release notes from releases/.md ──────────────────────────────── NOTES_FILE="releases/${TAG}.md" if [ ! -f "$NOTES_FILE" ]; then echo "ERROR: Release notes file not found: $NOTES_FILE" echo " The dev machine should have committed this before tagging." exit 1 fi NOTES=$(cat "$NOTES_FILE") echo "→ Release notes: $NOTES_FILE" # ── Gitea token — from macOS Keychain, env var, or prompt ──────────────────── if [ -z "${GITEA_TOKEN:-}" ]; then # Try macOS Keychain first GITEA_TOKEN=$(security find-generic-password -a kbolen -s gitea-photophetch -w 2>/dev/null || echo "") fi if [ -z "${GITEA_TOKEN:-}" ]; then echo "No token found in Keychain or environment." echo "Store it once with:" echo " security add-generic-password -a kbolen -s gitea-photophetch -w YOUR_TOKEN" read -rsp "Or enter token now: " GITEA_TOKEN echo fi # ── Check packageVersion matches tag ───────────────────────────────────────── GRADLE_VERSION=$(grep 'packageVersion' build.gradle.kts | sed 's/.*"\(.*\)".*/\1/') if [ "$GRADLE_VERSION" != "$VERSION" ]; then echo "WARNING: build.gradle.kts packageVersion ($GRADLE_VERSION) != tag version ($VERSION)" echo "Continue anyway? [y/N]" read -r CONFIRM [[ "$CONFIRM" == "y" || "$CONFIRM" == "Y" ]] || exit 1 fi # ── Build DMG ───────────────────────────────────────────────────────────────── echo "→ Building DMG (this takes a few minutes)..." ./gradlew packageDmg DMG_PATH=$(find build/compose/binaries/main/dmg -name "*.dmg" | head -1) if [ -z "$DMG_PATH" ]; then echo "ERROR: No DMG found in build/compose/binaries/main/dmg/" exit 1 fi DMG_NAME=$(basename "$DMG_PATH") echo "→ Built: $DMG_PATH" # ── Check release doesn't already exist ────────────────────────────────────── EXISTING=$(curl -s -o /dev/null -w "%{http_code}" \ "${GITEA_URL}/api/v1/repos/${GITEA_USER}/${GITEA_REPO}/releases/tags/${TAG}" \ -H "Authorization: token ${GITEA_TOKEN}") if [ "$EXISTING" = "200" ]; then echo "ERROR: Release $TAG already exists on Gitea." exit 1 fi # ── Create Gitea release ────────────────────────────────────────────────────── echo "→ Creating Gitea release $TAG..." # Escape notes for JSON NOTES_JSON=$(echo "$NOTES" | python3 -c "import sys,json; print(json.dumps(sys.stdin.read()))") RELEASE_RESPONSE=$(curl -s -X POST \ "${GITEA_URL}/api/v1/repos/${GITEA_USER}/${GITEA_REPO}/releases" \ -H "Authorization: token ${GITEA_TOKEN}" \ -H "Content-Type: application/json" \ -d "{ \"tag_name\": \"${TAG}\", \"name\": \"PhotoPhetch ${TAG}\", \"body\": ${NOTES_JSON}, \"draft\": false, \"prerelease\": false }") RELEASE_ID=$(echo "$RELEASE_RESPONSE" | python3 -c "import sys,json; print(json.load(sys.stdin)['id'])" 2>/dev/null) if [ -z "$RELEASE_ID" ]; then echo "ERROR: Failed to create release. Response:" echo "$RELEASE_RESPONSE" exit 1 fi echo "→ Created release ID $RELEASE_ID" # ── Upload DMG ──────────────────────────────────────────────────────────────── echo "→ Uploading $DMG_NAME..." UPLOAD_RESPONSE=$(curl -s -X POST \ "${GITEA_URL}/api/v1/repos/${GITEA_USER}/${GITEA_REPO}/releases/${RELEASE_ID}/assets?name=${DMG_NAME}" \ -H "Authorization: token ${GITEA_TOKEN}" \ -H "Content-Type: application/octet-stream" \ --data-binary "@${DMG_PATH}") DOWNLOAD_URL=$(echo "$UPLOAD_RESPONSE" | python3 -c "import sys,json; print(json.load(sys.stdin).get('browser_download_url',''))" 2>/dev/null) if [ -z "$DOWNLOAD_URL" ]; then echo "WARNING: Upload response unexpected:" echo "$UPLOAD_RESPONSE" else echo "" echo "✓ Released: $DOWNLOAD_URL" echo " Release page: ${GITEA_URL}/${GITEA_USER}/${GITEA_REPO}/releases/tag/${TAG}" fi