Phát hành OpenClaw macOS (Sparkle)

App này giờ đã tích hợp Sparkle auto-updates. Các bản release phải được ký bằng Developer ID, nén thành zip, và publish kèm appcast entry đã ký.

Yêu cầu trước khi bắt đầu

  • Đã cài đặt Developer ID Application cert (ví dụ: Developer ID Application: <Developer Name> (<TEAMID>)).
  • Đã set đường dẫn Sparkle private key trong environment là SPARKLE_PRIVATE_KEY_FILE (đường dẫn đến Sparkle ed25519 private key của các bạn; public key được nhúng vào Info.plist). Nếu thiếu, check file ~/.profile.
  • Notary credentials (keychain profile hoặc API key) cho xcrun notarytool nếu các bạn muốn phân phối DMG/zip an toàn với Gatekeeper.
    • Mình dùng Keychain profile tên openclaw-notary, được tạo từ App Store Connect API key env vars trong shell profile:
      • APP_STORE_CONNECT_API_KEY_P8, APP_STORE_CONNECT_KEY_ID, APP_STORE_CONNECT_ISSUER_ID
      • echo "$APP_STORE_CONNECT_API_KEY_P8" | sed 's/\\n/\n/g' > /tmp/openclaw-notary.p8
      • xcrun notarytool store-credentials "openclaw-notary" --key /tmp/openclaw-notary.p8 --key-id "$APP_STORE_CONNECT_KEY_ID" --issuer "$APP_STORE_CONNECT_ISSUER_ID"
  • Đã cài pnpm deps (pnpm install --config.node-linker=hoisted).
  • Sparkle tools được tự động fetch qua SwiftPM tại apps/macos/.build/artifacts/sparkle/Sparkle/bin/ (sign_update, generate_appcast, v.v.).

Build & đóng gói

Lưu ý:

  • APP_BUILD map tới CFBundleVersion/sparkle:version; giữ nó dạng số + tăng dần (không có -beta), nếu không Sparkle sẽ so sánh như bằng nhau.
  • Mặc định là kiến trúc hiện tại ($(uname -m)). Với bản release/universal builds, set BUILD_ARCHS="arm64 x86_64" (hoặc BUILD_ARCHS=all).
  • Dùng scripts/package-mac-dist.sh cho release artifacts (zip + DMG + notarization). Dùng scripts/package-mac-app.sh cho local/dev packaging.
# Từ repo root; set release IDs để bật Sparkle feed.
# APP_BUILD phải là số + tăng dần cho Sparkle compare.
BUNDLE_ID=bot.molt.mac \
APP_VERSION=2026.1.27-beta.1 \
APP_BUILD="$(git rev-list --count HEAD)" \
BUILD_CONFIG=release \
SIGN_IDENTITY="Developer ID Application: <Developer Name> (<TEAMID>)" \
scripts/package-mac-app.sh

# Zip để phân phối (bao gồm resource forks cho Sparkle delta support)
ditto -c -k --sequesterRsrc --keepParent dist/OpenClaw.app dist/OpenClaw-2026.1.27-beta.1.zip

# Tùy chọn: cũng build một DMG có style cho người dùng (kéo vào /Applications)
scripts/create-dmg.sh dist/OpenClaw.app dist/OpenClaw-2026.1.27-beta.1.dmg

# Khuyên dùng: build + notarize/staple zip + DMG
# Đầu tiên, tạo keychain profile một lần:
#   xcrun notarytool store-credentials "openclaw-notary" \
#     --apple-id "<apple-id>" --team-id "<team-id>" --password "<app-specific-password>"
NOTARIZE=1 NOTARYTOOL_PROFILE=openclaw-notary \
BUNDLE_ID=bot.molt.mac \
APP_VERSION=2026.1.27-beta.1 \
APP_BUILD="$(git rev-list --count HEAD)" \
BUILD_CONFIG=release \
SIGN_IDENTITY="Developer ID Application: <Developer Name> (<TEAMID>)" \
scripts/package-mac-dist.sh

# Tùy chọn: ship dSYM kèm theo release
ditto -c -k --keepParent apps/macos/.build/release/OpenClaw.app.dSYM dist/OpenClaw-2026.1.27-beta.1.dSYM.zip

Appcast entry

Dùng release note generator để Sparkle render HTML notes có format:

SPARKLE_PRIVATE_KEY_FILE=/path/to/ed25519-private-key scripts/make_appcast.sh dist/OpenClaw-2026.1.27-beta.1.zip https://raw.githubusercontent.com/openclaw/openclaw/main/appcast.xml

Script này tạo HTML release notes từ CHANGELOG.md (qua scripts/changelog-to-html.sh) và nhúng chúng vào appcast entry. Commit file appcast.xml đã cập nhật cùng với release assets (zip + dSYM) khi publish.

Publish & kiểm tra

  • Upload OpenClaw-2026.1.27-beta.1.zip (và OpenClaw-2026.1.27-beta.1.dSYM.zip) lên GitHub release cho tag v2026.1.27-beta.1.
  • Đảm bảo raw appcast URL khớp với feed đã nhúng: https://raw.githubusercontent.com/openclaw/openclaw/main/appcast.xml.
  • Sanity checks:
    • curl -I https://raw.githubusercontent.com/openclaw/openclaw/main/appcast.xml trả về 200.
    • curl -I <enclosure url> trả về 200 sau khi upload assets.
    • Trên một bản public build trước đó, chạy “Check for Updates…” từ tab About và kiểm tra Sparkle cài đặt bản build mới thành công.

Definition of done: signed app + appcast đã được publish, update flow hoạt động từ phiên bản cũ đã cài, và release assets đã được đính kèm vào GitHub release.