🎉 ShotScreen v1.0 - Initial Release
🚀 First official release of ShotScreen with complete feature set: ✨ Core Features: - Advanced screenshot capture system - Multi-monitor support - Professional UI/UX design - Automated update system with Sparkle - Apple notarized & code signed 🛠 Technical Excellence: - Native Swift macOS application - Professional build & deployment pipeline - Comprehensive error handling - Memory optimized performance 📦 Distribution Ready: - Professional DMG packaging - Apple notarization complete - No security warnings for users - Ready for public distribution This is the foundation release that establishes ShotScreen as a premium screenshot tool for macOS.
This commit is contained in:
320
release_hufterproof_v2.sh
Executable file
320
release_hufterproof_v2.sh
Executable file
@@ -0,0 +1,320 @@
|
||||
#!/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/^- /<li>/' | sed 's/$/<\/li>/')
|
||||
if [[ "$HTML_NOTES" == *"<li>"* ]]; then
|
||||
HTML_NOTES="<ul>$HTML_NOTES</ul>"
|
||||
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
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<rss version="2.0" xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle">
|
||||
<channel>
|
||||
<title>ShotScreen Updates</title>
|
||||
<link>$GITEA_URL/$RELEASES_REPO/raw/branch/main/appcast.xml</link>
|
||||
<description>ShotScreen Updates</description>
|
||||
<language>en</language>
|
||||
|
||||
<item>
|
||||
<title>ShotScreen $NEW_VERSION</title>
|
||||
<description><![CDATA[
|
||||
<h2>ShotScreen $NEW_VERSION</h2>
|
||||
$HTML_NOTES
|
||||
]]></description>
|
||||
<pubDate>$(date -R)</pubDate>
|
||||
<enclosure url="$GITEA_URL/$RELEASES_REPO/releases/download/v$NEW_VERSION/ShotScreen-$NEW_VERSION.dmg"
|
||||
sparkle:version="$NEW_VERSION"
|
||||
sparkle:shortVersionString="$NEW_VERSION"
|
||||
length="$DMG_SIZE"
|
||||
type="application/octet-stream"
|
||||
sparkle:edSignature="$SIGNATURE" />
|
||||
<sparkle:minimumSystemVersion>13.0</sparkle:minimumSystemVersion>
|
||||
</item>
|
||||
</channel>
|
||||
</rss>
|
||||
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}"
|
||||
Reference in New Issue
Block a user