mirror of
https://github.com/getpaseo/paseo.git
synced 2026-07-29 12:01:31 +00:00
fix(release): publish desktop manifests atomically to close arch race
The macOS publish matrix had each arch run electron-builder with --publish always, so each runner uploaded its own latest-mac.yml to the GitHub release the moment it finished. The slower arch clobbered the faster one, leaving a window (typically 1-3 minutes) where the live manifest contained only one arch's files[]. Apple Silicon clients polling during that window could install the x64 build, ending up under Rosetta. Also closed the related window where finalize-rollout stamped releaseDate and rolloutHours after the merged manifest was already public — auto-updater treats missing rollout fields as "admit", so 100% of stable users could grab a release before staged rollout kicked in. Now every build runs --publish never. Each platform job uploads its non-yml artifacts directly via gh release upload --clobber, and stages its manifest as an Actions artifact. The renamed finalize-rollout job downloads all manifest artifacts, merges mac arm64+x64, stamps rollout metadata, validates, and uploads every manifest in one pass. Public manifests are never visible in an unmerged or unstamped state. Refs #555.
This commit is contained in:
@@ -61,10 +61,17 @@ Use the beta path when you need to:
|
||||
|
||||
## Staged rollout (stable channel)
|
||||
|
||||
Stable desktop releases go out via a linear time-based rollout: 0% admitted at publish, 100% admitted 24 hours later, linear ramp in between. Beta releases bypass the rollout entirely — beta users always receive updates immediately.
|
||||
Stable desktop releases go out via a linear time-based rollout: 0% admitted when the updater manifests appear, 100% admitted 24 hours later, linear ramp in between. Beta releases bypass the rollout entirely — beta users always receive updates immediately.
|
||||
|
||||
The rollout is driven by a `rolloutHours` field stamped into the GitHub Release manifests (`latest-mac.yml`, `latest-linux.yml`, `latest.yml`) by the `finalize-rollout` job in `desktop-release.yml`.
|
||||
|
||||
Desktop release builds now publish in two phases:
|
||||
|
||||
- Platform build jobs upload the installers/packages (`.dmg`, `.zip`, `.exe`, `.AppImage`, etc.) to the GitHub release.
|
||||
- The final job merges/stamps the manifests and uploads all `.yml` files only after they already contain the final `releaseDate` and `rolloutHours`.
|
||||
|
||||
Updater clients only discover a release through those `.yml` manifests, so there is no silent 100% admission window before rollout metadata is present.
|
||||
|
||||
### Default behavior
|
||||
|
||||
`npm run release:patch` → tag push → 24h ramp. No extra action needed.
|
||||
@@ -85,7 +92,7 @@ gh workflow run desktop-rollout.yml \
|
||||
-f rollout_hours=0
|
||||
```
|
||||
|
||||
**Why this is gap-free:** `desktop-release.yml`'s `finalize-rollout` job and `desktop-rollout.yml` share the concurrency group `desktop-rollout-<tag>`. Dispatching `desktop-rollout.yml` while the tag-push pipeline is still running queues it safely behind `finalize-rollout`. The release manifest goes from `rolloutHours=24` to `rolloutHours=0` within ~30s of publish, and the renderer polls every 30 minutes — so no stable user can admit during the gap.
|
||||
**Why this is gap-free:** `desktop-release.yml`'s `finalize-rollout` job and `desktop-rollout.yml` share the concurrency group `desktop-rollout-<tag>`. Dispatching `desktop-rollout.yml` while the tag-push pipeline is still running queues it safely behind `finalize-rollout`. The first public manifests already carry `rolloutHours=24`, then `desktop-rollout.yml` flips them to `rolloutHours=0` shortly afterward. The renderer polls every 30 minutes, so active stable users pick up the new manifest on their next check.
|
||||
|
||||
Run the dispatch right after `release:patch` returns. Don't wait for the tag-push CI to finish.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user