#!/bin/bash # ๐Ÿš€ SUPER HUFTERPROOF ShotScreen Release Script V2 # Zero HTML, Zero Problems, 100% Bulletproof # ๐ŸŽฏ NEW: Auto-increment version detection! # # Usage: # ./release_hufterproof_v2.sh # Auto-increment from current version # ./release_hufterproof_v2.sh 1.15 # Use specific version set -e # Colors GREEN='\033[0;32m' BLUE='\033[0;34m' YELLOW='\033[1;33m' RED='\033[0;31m' PURPLE='\033[0;35m' NC='\033[0m' # Config GITEA_URL="https://git.plet.i234.me" RELEASES_REPO="Nick/shotscreen" echo -e "${PURPLE}๐Ÿš€ SUPER HUFTERPROOF Release Script V2${NC}" echo -e "${PURPLE}=====================================${NC}" # Get current version from Info.plist and auto-increment get_next_version() { if [ -f "Info.plist" ]; then CURRENT_VERSION=$(plutil -extract CFBundleShortVersionString raw Info.plist 2>/dev/null || echo "1.0") echo -e "${BLUE}๐Ÿ” Current version: $CURRENT_VERSION${NC}" # Split version into parts (e.g., "1.12" -> major=1, minor=12) IFS='.' read -r MAJOR MINOR <<< "$CURRENT_VERSION" # Increment minor version NEXT_MINOR=$((MINOR + 1)) SUGGESTED_VERSION="$MAJOR.$NEXT_MINOR" echo -e "${GREEN}๐Ÿš€ Suggested next version: $SUGGESTED_VERSION${NC}" return 0 else SUGGESTED_VERSION="1.0" echo -e "${YELLOW}โš ๏ธ No Info.plist found, suggesting: $SUGGESTED_VERSION${NC}" return 1 fi } # Determine version NEW_VERSION="$1" if [ -z "$NEW_VERSION" ]; then get_next_version echo -e "${YELLOW}Press ENTER to use suggested version ($SUGGESTED_VERSION) or type custom version:${NC}" read -r USER_INPUT if [ -z "$USER_INPUT" ]; then NEW_VERSION="$SUGGESTED_VERSION" echo -e "${GREEN}โœ… Using suggested version: $NEW_VERSION${NC}" else NEW_VERSION="$USER_INPUT" echo -e "${BLUE}โœ… Using custom version: $NEW_VERSION${NC}" fi fi echo -e "${BLUE}๐Ÿ“‹ Building version: $NEW_VERSION${NC}" # Update Info.plist echo -e "${BLUE}๐Ÿ“ Updating Info.plist...${NC}" plutil -replace CFBundleVersion -string "$NEW_VERSION" Info.plist plutil -replace CFBundleShortVersionString -string "$NEW_VERSION" Info.plist # Update build_release_signed.sh with new version echo -e "${BLUE}๐Ÿ“ Updating build script version...${NC}" sed -i '' "s/APP_VERSION=\".*\"/APP_VERSION=\"$NEW_VERSION\"/" build_release_signed.sh # Build app with Developer ID signing and notarization echo -e "${BLUE}๐Ÿ”จ Building app with Developer ID signing...${NC}" if ! ./build_release_signed.sh; then echo -e "${RED}โŒ Build failed${NC}" exit 1 fi # Check DMG exists DMG_PATH="./dist/ShotScreen-$NEW_VERSION.dmg" if [ ! -f "$DMG_PATH" ]; then echo -e "${RED}โŒ DMG not found: $DMG_PATH${NC}" exit 1 fi # Get signature and size echo -e "${BLUE}๐Ÿ” Getting signature...${NC}" SIG_OUTPUT=$(./.build/artifacts/sparkle/Sparkle/bin/sign_update "$DMG_PATH") SIGNATURE=$(echo "$SIG_OUTPUT" | grep -o 'sparkle:edSignature="[^"]*"' | cut -d'"' -f2) DMG_SIZE=$(stat -f%z "$DMG_PATH") if [ -z "$SIGNATURE" ]; then echo -e "${RED}โŒ Signature generation failed${NC}" exit 1 fi echo -e "${GREEN}โœ… Signature: ${SIGNATURE:0:20}...${NC}" echo -e "${GREEN}โœ… Size: $DMG_SIZE bytes${NC}" # Get release notes from TXT file (preserve original formatting) RELEASE_NOTES=$(awk ' /^ShotScreen [0-9]/ { if (count++ > 0) exit next } /^=+$/ { next } /^[A-Za-z]/ && !/^ShotScreen/ && NF > 0 { print $0 } /^ / && NF > 0 { print $0 } ' release_notes.txt) if [ -z "$RELEASE_NOTES" ]; then RELEASE_NOTES="Release version $NEW_VERSION" fi # Create Gitea release echo -e "${BLUE}๐Ÿ“ฆ Creating Gitea release...${NC}" # Format release notes beautifully for Gitea (markdown format) FORMATTED_NOTES="## ๐Ÿš€ ShotScreen $NEW_VERSION Features $RELEASE_NOTES" # Clean JSON (proper escaping for multiline text) CLEAN_NOTES=$(printf "%s" "$FORMATTED_NOTES" | sed 's/"/\\"/g' | awk '{printf "%s\\n", $0}' | sed 's/\\n$//') JSON_PAYLOAD="{ \"tag_name\": \"v$NEW_VERSION\", \"name\": \"ShotScreen v$NEW_VERSION\", \"body\": \"$CLEAN_NOTES\", \"draft\": false, \"prerelease\": false }" RESPONSE=$(curl -s -X POST \ -H "Authorization: token $GITEA_TOKEN" \ -H "Content-Type: application/json" \ -d "$JSON_PAYLOAD" \ "$GITEA_URL/api/v1/repos/$RELEASES_REPO/releases") RELEASE_ID=$(echo "$RESPONSE" | grep -o '"id":[0-9]*' | head -1 | cut -d':' -f2) if [ -z "$RELEASE_ID" ]; then echo -e "${YELLOW}โš ๏ธ Checking for existing release...${NC}" EXISTING=$(curl -s "$GITEA_URL/api/v1/repos/$RELEASES_REPO/releases/tags/v$NEW_VERSION") RELEASE_ID=$(echo "$EXISTING" | grep -o '"id":[0-9]*' | head -1 | cut -d':' -f2) fi if [ -z "$RELEASE_ID" ]; then echo -e "${RED}โŒ Could not create/find release${NC}" exit 1 fi echo -e "${GREEN}โœ… Release ID: $RELEASE_ID${NC}" # Upload DMG echo -e "${BLUE}๐Ÿ“ค Uploading DMG...${NC}" UPLOAD_RESPONSE=$(curl -s -X POST \ -H "Authorization: token $GITEA_TOKEN" \ -F "attachment=@$DMG_PATH" \ "$GITEA_URL/api/v1/repos/$RELEASES_REPO/releases/$RELEASE_ID/assets") ASSET_ID=$(echo "$UPLOAD_RESPONSE" | grep -o '"id":[0-9]*' | head -1 | cut -d':' -f2) if [ -z "$ASSET_ID" ]; then echo -e "${RED}โŒ DMG upload failed${NC}" exit 1 fi echo -e "${GREEN}โœ… DMG uploaded${NC}" # Create super simple appcast (no HTML, just plain text) echo -e "${BLUE}๐Ÿ“„ Creating simple appcast...${NC}" # Convert plain text to simple HTML for appcast HTML_NOTES=$(echo "$RELEASE_NOTES" | sed 's/^- /
  • /' | sed 's/$/<\/li>/') if [[ "$HTML_NOTES" == *"
  • "* ]]; then HTML_NOTES="" fi # Clean up any old appcast first rm -f appcast.xml echo -e "${BLUE}๐Ÿ“„ Generating appcast for version $NEW_VERSION...${NC}" cat > appcast.xml << EOF ShotScreen Updates $GITEA_URL/$RELEASES_REPO/raw/branch/main/appcast.xml ShotScreen Updates en ShotScreen $NEW_VERSION ShotScreen $NEW_VERSION $HTML_NOTES ]]> $(date -R) 13.0 EOF # Validate appcast if ! xmllint --noout appcast.xml 2>/dev/null; then echo -e "${RED}โŒ Appcast validation failed${NC}" exit 1 fi echo -e "${GREEN}โœ… Valid appcast created${NC}" # Debug: Show what we're about to deploy echo -e "${BLUE}๐Ÿ” DEBUG: Appcast content preview:${NC}" echo "Version: $(grep 'sparkle:version=' appcast.xml | head -1)" echo "URL: $(grep 'enclosure url=' appcast.xml | head -1 | cut -d'"' -f2)" # Deploy appcast echo -e "${BLUE}๐Ÿš€ Deploying appcast...${NC}" RELEASES_DIR="../shotscreen" # Clean up any existing problematic repository if [ -d "$RELEASES_DIR" ]; then echo -e "${YELLOW}๐Ÿงน Cleaning up existing repository...${NC}" rm -rf "$RELEASES_DIR" fi # Create fresh directory and clone mkdir -p "$RELEASES_DIR" cd "$RELEASES_DIR" echo -e "${BLUE}๐Ÿ“ฅ Fresh clone from remote...${NC}" git clone "$GITEA_URL/$RELEASES_REPO.git" . || { echo -e "${YELLOW}โš ๏ธ Remote repository doesn't exist or clone failed, creating new repo...${NC}" git init git remote add origin "$GITEA_URL/$RELEASES_REPO.git" } # Configure git for this repository git config pull.rebase false # Use merge instead of rebase git config user.name "ShotScreen Release Bot" || true git config user.email "releases@shotscreen.app" || true # Backup old appcast for comparison if [ -f "appcast.xml" ]; then echo -e "${BLUE}๐Ÿ“‹ Backing up old appcast...${NC}" cp "appcast.xml" "appcast.xml.backup" echo "Old version: $(grep 'sparkle:version=' "appcast.xml" | head -1)" fi # Copy new appcast cd - > /dev/null cp appcast.xml "$RELEASES_DIR/" cd "$RELEASES_DIR" # Add and commit git add appcast.xml git commit -m "Deploy appcast for v$NEW_VERSION" || true # Push with force if needed (since we're authoritative for appcast) echo -e "${BLUE}๐Ÿ“ค Pushing appcast to remote...${NC}" if ! git push origin main; then echo -e "${YELLOW}โš ๏ธ Normal push failed, force pushing appcast update...${NC}" git push origin main --force fi cd - > /dev/null # Test everything echo -e "${BLUE}๐Ÿงช Testing...${NC}" sleep 2 # Test appcast download if ! curl -s "$GITEA_URL/$RELEASES_REPO/raw/branch/main/appcast.xml" | grep -q "$NEW_VERSION"; then echo -e "${RED}โŒ Appcast test failed${NC}" exit 1 fi # Test DMG download if ! curl -I -s "$GITEA_URL/$RELEASES_REPO/releases/download/v$NEW_VERSION/ShotScreen-$NEW_VERSION.dmg" | grep -q "200"; then echo -e "${RED}โŒ DMG test failed${NC}" exit 1 fi # Git operations echo -e "${BLUE}๐Ÿ“ Git operations...${NC}" git add . git commit -m "Release v$NEW_VERSION" || true git tag -a "v$NEW_VERSION" -m "Release v$NEW_VERSION" || true git push -u origin main || git push origin main --force git push origin "v$NEW_VERSION" || true echo echo -e "${GREEN}๐ŸŽ‰ SUPER HUFTERPROOF RELEASE COMPLETE! ๐ŸŽ‰${NC}" echo -e "${GREEN}======================================${NC}" echo -e "${GREEN}โœ… Version: $NEW_VERSION${NC}" echo -e "${GREEN}โœ… DMG Size: $DMG_SIZE bytes${NC}" echo -e "${GREEN}โœ… All tests: PASSED${NC}" echo echo -e "${BLUE}๐ŸŒ Release: $GITEA_URL/$RELEASES_REPO/releases/tag/v$NEW_VERSION${NC}" echo -e "${BLUE}๐Ÿ“ก Appcast: $GITEA_URL/$RELEASES_REPO/raw/branch/main/appcast.xml${NC}" echo echo -e "${YELLOW}๐ŸŽฏ Ready to test updates on other computer!${NC}"