Skip to content

Commit 92be443

Browse files
committed
refactor: use Sparkle generate_appcast instead of custom XML generation
1 parent d3111bf commit 92be443

2 files changed

Lines changed: 43 additions & 257 deletions

File tree

scripts/ci/sign-and-appcast.sh

Lines changed: 43 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
#!/usr/bin/env bash
22
set -euo pipefail
33

4-
# Signs release archives with Sparkle EdDSA and generates/updates appcast.xml.
4+
# Signs release archives and generates appcast.xml using Sparkle's
5+
# generate_appcast — the official tool for building Sparkle update feeds.
6+
#
7+
# generate_appcast handles: EdDSA signing, architecture detection,
8+
# version extraction from Info.plist, CDATA release notes, and merging
9+
# new items into an existing appcast (preserving history).
510
#
611
# Usage: sign-and-appcast.sh <version>
712
# Requires: SPARKLE_PRIVATE_KEY env var, artifacts/ directory with ZIPs.
8-
#
9-
# The appcast.xml preserves history — new items are prepended to the existing
10-
# feed so Sparkle shows cumulative release notes for users skipping versions.
1113

1214
VERSION="${1:?Usage: sign-and-appcast.sh <version>}"
1315

@@ -23,58 +25,31 @@ brew list --cask sparkle &>/dev/null || brew install --cask sparkle
2325
SPARKLE_BIN="$(brew --caskroom)/sparkle/$(ls "$(brew --caskroom)/sparkle" | head -1)/bin"
2426

2527
# ---------------------------------------------------------------------------
26-
# 2. Sign archives with EdDSA
28+
# 2. Prepare staging directory
2729
# ---------------------------------------------------------------------------
28-
ARM64_ZIP="artifacts/TablePro-${VERSION}-arm64.zip"
29-
X86_64_ZIP="artifacts/TablePro-${VERSION}-x86_64.zip"
30-
31-
KEY_FILE=$(mktemp)
32-
trap 'rm -f "$KEY_FILE"' EXIT
33-
echo "$SPARKLE_PRIVATE_KEY" > "$KEY_FILE"
30+
STAGING=$(mktemp -d)
31+
trap 'rm -rf "$STAGING"' EXIT
3432

35-
parse_sig() {
36-
local output="$1" field="$2"
37-
echo "$output" | sed -n "s/.*${field}=\"\\([^\"]*\\)\".*/\\1/p"
38-
}
39-
40-
ARM64_SIG=$("$SPARKLE_BIN/sign_update" "$ARM64_ZIP" -f "$KEY_FILE")
41-
X86_64_SIG=$("$SPARKLE_BIN/sign_update" "$X86_64_ZIP" -f "$KEY_FILE")
42-
43-
ARM64_ED_SIG=$(parse_sig "$ARM64_SIG" "sparkle:edSignature")
44-
ARM64_LENGTH=$(parse_sig "$ARM64_SIG" "length")
45-
X86_64_ED_SIG=$(parse_sig "$X86_64_SIG" "sparkle:edSignature")
46-
X86_64_LENGTH=$(parse_sig "$X86_64_SIG" "length")
47-
48-
# ---------------------------------------------------------------------------
49-
# 3. Extract version metadata from the built app
50-
# ---------------------------------------------------------------------------
51-
TEMP_DIR=$(mktemp -d)
52-
unzip -q "$ARM64_ZIP" -d "$TEMP_DIR"
53-
INFO_PLIST=$(find "$TEMP_DIR" -maxdepth 3 -path "*/Contents/Info.plist" | head -1)
33+
# Copy archives
34+
cp "artifacts/TablePro-${VERSION}-arm64.zip" "$STAGING/"
35+
cp "artifacts/TablePro-${VERSION}-x86_64.zip" "$STAGING/"
5436

55-
if [ -n "$INFO_PLIST" ] && [ -f "$INFO_PLIST" ]; then
56-
BUILD_NUMBER=$(/usr/libexec/PlistBuddy -c "Print :CFBundleVersion" "$INFO_PLIST" 2>/dev/null || echo "1")
57-
SHORT_VERSION=$(/usr/libexec/PlistBuddy -c "Print :CFBundleShortVersionString" "$INFO_PLIST" 2>/dev/null || echo "$VERSION")
58-
MIN_OS=$(/usr/libexec/PlistBuddy -c "Print :LSMinimumSystemVersion" "$INFO_PLIST" 2>/dev/null || echo "14.0")
59-
else
60-
echo "⚠️ Could not find app Info.plist in ZIP, using defaults"
61-
BUILD_NUMBER="1"
62-
SHORT_VERSION="$VERSION"
63-
MIN_OS="14.0"
37+
# Copy existing appcast for history preservation
38+
if [ -f appcast.xml ]; then
39+
cp appcast.xml "$STAGING/"
6440
fi
65-
rm -rf "$TEMP_DIR"
6641

6742
# ---------------------------------------------------------------------------
68-
# 4. Extract release notes from CHANGELOG.md → HTML
43+
# 3. Extract release notes from CHANGELOG.md → HTML
6944
# ---------------------------------------------------------------------------
7045
if [ -f release_notes.md ]; then
71-
NOTES=$(cat release_notes.md)
46+
NOTES=$(cat release_notes.md)
7247
else
73-
NOTES=$(awk "/^## \\[${VERSION}\\]/{flag=1; next} /^## \\[/{flag=0} flag" CHANGELOG.md)
48+
NOTES=$(awk "/^## \\[${VERSION}\\]/{flag=1; next} /^## \\[/{flag=0} flag" CHANGELOG.md)
7449
fi
7550

7651
if [ -z "$NOTES" ]; then
77-
RELEASE_HTML="<li>Bug fixes and improvements</li>"
52+
RELEASE_HTML="<ul><li>Bug fixes and improvements</li></ul>"
7853
else
7954
RELEASE_HTML=$(echo "$NOTES" | sed -E \
8055
-e 's/^### (.+)$/<h3>\1<\/h3>/' \
@@ -93,31 +68,35 @@ else
9368
')
9469
fi
9570

96-
DESCRIPTION_HTML="<body style=\"font-family: -apple-system, sans-serif; font-size: 13px; padding: 8px;\">${RELEASE_HTML}</body>"
71+
# Create HTML release notes files matching each archive name.
72+
# generate_appcast picks up <archive-name>.html automatically.
73+
for zip in "$STAGING"/TablePro-*.zip; do
74+
basename="${zip%.zip}"
75+
echo "$RELEASE_HTML" > "${basename}.html"
76+
done
9777

9878
# ---------------------------------------------------------------------------
99-
# 5. Build appcast.xml — merge new items into existing feed
79+
# 4. Run generate_appcast
10080
# ---------------------------------------------------------------------------
10181
DOWNLOAD_PREFIX="${GITHUB_SERVER_URL:-https://github.com}/${GITHUB_REPOSITORY:-TableProApp/TablePro}/releases/download/v${VERSION}"
102-
PUB_DATE=$(date -u '+%a, %d %b %Y %H:%M:%S +0000')
103-
EXISTING_APPCAST="appcast.xml"
10482

105-
mkdir -p appcast
83+
KEY_FILE=$(mktemp)
84+
# Override trap to clean up both
85+
trap 'rm -rf "$STAGING" "$KEY_FILE"' EXIT
86+
echo "$SPARKLE_PRIVATE_KEY" > "$KEY_FILE"
10687

107-
python3 scripts/ci/update-appcast.py \
108-
--output appcast/appcast.xml \
109-
--existing "$EXISTING_APPCAST" \
110-
--version "$SHORT_VERSION" \
111-
--build "$BUILD_NUMBER" \
112-
--min-os "$MIN_OS" \
113-
--pub-date "$PUB_DATE" \
114-
--description "$DESCRIPTION_HTML" \
115-
--arm64-url "${DOWNLOAD_PREFIX}/TablePro-${VERSION}-arm64.zip" \
116-
--arm64-length "$ARM64_LENGTH" \
117-
--arm64-sig "$ARM64_ED_SIG" \
118-
--x86-url "${DOWNLOAD_PREFIX}/TablePro-${VERSION}-x86_64.zip" \
119-
--x86-length "$X86_64_LENGTH" \
120-
--x86-sig "$X86_64_ED_SIG"
88+
"$SPARKLE_BIN/generate_appcast" \
89+
--ed-key-file "$KEY_FILE" \
90+
--download-url-prefix "$DOWNLOAD_PREFIX" \
91+
--embed-release-notes \
92+
--maximum-versions 0 \
93+
"$STAGING"
94+
95+
# ---------------------------------------------------------------------------
96+
# 5. Copy result
97+
# ---------------------------------------------------------------------------
98+
mkdir -p appcast
99+
cp "$STAGING/appcast.xml" appcast/appcast.xml
121100

122-
echo "✅ Appcast generated:"
101+
echo "✅ Appcast generated by generate_appcast:"
123102
cat appcast/appcast.xml

scripts/ci/update-appcast.py

Lines changed: 0 additions & 193 deletions
This file was deleted.

0 commit comments

Comments
 (0)