.app bundles launch with minimal PATH (/usr/bin:/bin only), missing Homebrew paths. ExternalTools.resolve() searches: - /usr/local/bin (Homebrew Intel) - /opt/homebrew/bin (Homebrew Apple Silicon) - ~/.local/bin (pipx installs) Updated: exiftool (ConnectScreen + Copier), adb (AndroidConnector). This fixes 'exiftool not installed' warning when launching as .app.
127 lines
5.6 KiB
Bash
Executable File
127 lines
5.6 KiB
Bash
Executable File
#!/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/<tag>.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/<tag>.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
|