* Add R2 dual-write for nightly appcast and DMGs
Upload nightly DMGs and appcast to Cloudflare R2 (files.cmux.com)
alongside the existing GitHub Release assets. R2 uses atomic PutObject
so the appcast never 404s during replacement, fixing the transient
SUDownloadError 2001 that occurs when GitHub Release assets are
being overwritten.
DMGs are uploaded before the appcast so the feed never references a
file that doesn't exist yet. The GitHub Release upload is unchanged,
so existing nightly users are unaffected.
A follow-up PR will switch the Sparkle feed URL in the app bundle
from GitHub Releases to R2 after manual verification.
* Add continue-on-error to R2 steps
R2 upload failures should not block the existing GitHub Release
publish. This keeps the nightly pipeline safe while R2 is new.
* Add R2 dual-write for stable release appcast and DMG
Same pattern as nightly: upload DMG then appcast to R2
(files.cmux.com/stable/) alongside the GitHub Release.
Both steps use continue-on-error so R2 failures can't
block the release.
* Address review feedback: cache headers, no double build, AWS CLI guard
- Add Cache-Control headers: immutable versioned DMGs get max-age=1yr,
mutable appcast.xml and latest DMG get no-cache to prevent stale CDN
- Replace separate appcast generation step with sed URL replacement,
avoiding a second Sparkle clone+build (signature is over DMG content,
not the URL)
- Add AWS CLI availability check with fallback brew install
---------
Co-authored-by: Lawrence Chen <lawrencecchen@users.noreply.github.com>