@@ -516,17 +516,65 @@ jobs:
516516 brew install --cask sparkle
517517 SPARKLE_BIN="$(brew --caskroom)/sparkle/$(ls "$(brew --caskroom)/sparkle" | head -1)/bin"
518518
519- # Sign ZIP files and generate appcast
520- mkdir -p appcast
521- cp artifacts/TablePro-${VERSION}-arm64.zip appcast/
522- cp artifacts/TablePro-${VERSION}-x86_64.zip appcast/
523-
524- # Generate appcast.xml with EdDSA signatures
525- echo "$SPARKLE_PRIVATE_KEY" | "$SPARKLE_BIN/generate_appcast" \
526- --ed-key-file /dev/stdin \
527- --download-url-prefix "https://github.com/datlechin/TablePro/releases/download/v${VERSION}/" \
528- appcast/
519+ ARM64_ZIP="artifacts/TablePro-${VERSION}-arm64.zip"
520+ X86_64_ZIP="artifacts/TablePro-${VERSION}-x86_64.zip"
521+
522+ # Sign each ZIP with EdDSA using sign_update
523+ KEY_FILE=$(mktemp)
524+ echo "$SPARKLE_PRIVATE_KEY" > "$KEY_FILE"
525+ ARM64_SIG=$("$SPARKLE_BIN/sign_update" "$ARM64_ZIP" -f "$KEY_FILE")
526+ X86_64_SIG=$("$SPARKLE_BIN/sign_update" "$X86_64_ZIP" -f "$KEY_FILE")
527+ rm -f "$KEY_FILE"
528+
529+ # Parse signature and length from sign_update output
530+ # Output format: sparkle:edSignature="..." length="..."
531+ ARM64_ED_SIG=$(echo "$ARM64_SIG" | sed -n 's/.*sparkle:edSignature="\([^"]*\)".*/\1/p')
532+ ARM64_LENGTH=$(echo "$ARM64_SIG" | sed -n 's/.*length="\([^"]*\)".*/\1/p')
533+ X86_64_ED_SIG=$(echo "$X86_64_SIG" | sed -n 's/.*sparkle:edSignature="\([^"]*\)".*/\1/p')
534+ X86_64_LENGTH=$(echo "$X86_64_SIG" | sed -n 's/.*length="\([^"]*\)".*/\1/p')
535+
536+ # Extract version info from the app's Info.plist inside the ZIP
537+ TEMP_DIR=$(mktemp -d)
538+ unzip -q "$ARM64_ZIP" "*/Contents/Info.plist" -d "$TEMP_DIR"
539+ INFO_PLIST=$(find "$TEMP_DIR" -name "Info.plist" -path "*/Contents/Info.plist" | head -1)
540+ BUILD_NUMBER=$(/usr/libexec/PlistBuddy -c "Print :CFBundleVersion" "$INFO_PLIST")
541+ SHORT_VERSION=$(/usr/libexec/PlistBuddy -c "Print :CFBundleShortVersionString" "$INFO_PLIST")
542+ MIN_OS=$(/usr/libexec/PlistBuddy -c "Print :LSMinimumSystemVersion" "$INFO_PLIST" 2>/dev/null || echo "13.5")
543+ rm -rf "$TEMP_DIR"
544+
545+ # Build appcast.xml with architecture-specific items (Sparkle 2 convention)
546+ # Each item has sparkle:architectures on the enclosure so the client
547+ # automatically picks the matching architecture
548+ DOWNLOAD_PREFIX="https://github.com/datlechin/TablePro/releases/download/v${VERSION}"
549+ PUB_DATE=$(date -u '+%a, %d %b %Y %H:%M:%S +0000')
529550
551+ mkdir -p appcast
552+ cat > appcast/appcast.xml << APPCAST_EOF
553+ <?xml version="1.0" standalone="yes"?>
554+ <rss xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle" version="2.0">
555+ <channel>
556+ <title>TablePro</title>
557+ <item>
558+ <title>${SHORT_VERSION}</title>
559+ <pubDate>${PUB_DATE}</pubDate>
560+ <sparkle:version>${BUILD_NUMBER}</sparkle:version>
561+ <sparkle:shortVersionString>${SHORT_VERSION}</sparkle:shortVersionString>
562+ <sparkle:minimumSystemVersion>${MIN_OS}</sparkle:minimumSystemVersion>
563+ <enclosure url="${DOWNLOAD_PREFIX}/TablePro-${VERSION}-arm64.zip" length="${ARM64_LENGTH}" type="application/octet-stream" sparkle:edSignature="${ARM64_ED_SIG}" sparkle:architectures="arm64"/>
564+ </item>
565+ <item>
566+ <title>${SHORT_VERSION}</title>
567+ <pubDate>${PUB_DATE}</pubDate>
568+ <sparkle:version>${BUILD_NUMBER}</sparkle:version>
569+ <sparkle:shortVersionString>${SHORT_VERSION}</sparkle:shortVersionString>
570+ <sparkle:minimumSystemVersion>${MIN_OS}</sparkle:minimumSystemVersion>
571+ <enclosure url="${DOWNLOAD_PREFIX}/TablePro-${VERSION}-x86_64.zip" length="${X86_64_LENGTH}" type="application/octet-stream" sparkle:edSignature="${X86_64_ED_SIG}" sparkle:architectures="x86_64"/>
572+ </item>
573+ </channel>
574+ </rss>
575+ APPCAST_EOF
576+
577+ echo "✅ Appcast generated with architecture-specific items:"
530578 cat appcast/appcast.xml
531579
532580 - name : Upload appcast artifact
0 commit comments