|
| 1 | +# Release checklist: verifying the updater |
| 2 | + |
| 3 | +The auto-updater ships across a version hop, so **the code in a release is only |
| 4 | +exercised by the NEXT release**. A build's own updater is proven by whether the |
| 5 | +build after it lands, not by the build itself. This checklist is how a release |
| 6 | +runner confirms it, because the paths that matter most are the ones a clean, |
| 7 | +successful release never touches. |
| 8 | + |
| 9 | +## The proving hop (rehearse on prereleases, before the real release) |
| 10 | + |
| 11 | +`0.4.6` is delivered by `0.4.5`'s updater, so `0.4.6` arriving proves the OLD |
| 12 | +code worked. Only a hop that STARTS on our new code proves it. So rehearse on |
| 13 | +prereleases first: publish `0.4.6-rc.1`, then a no-op `0.4.7-rc.1`, and drive |
| 14 | +the hop `0.4.6-rc.1` -> `0.4.7-rc.1` on a test machine BEFORE the real `0.4.6` |
| 15 | +exists. Same evidence, earlier, with any failure landing on a throwaway. |
| 16 | + |
| 17 | +Why it is safe: a `-rc.1` tag publishes as a GitHub pre-release (release.yml, |
| 18 | +`prerelease: contains(ref_name, '-')`), and electron-updater only offers a |
| 19 | +pre-release to a client whose OWN version is a pre-release (allowPrerelease |
| 20 | +defaults to that, verified in 6.8.9). So a stable `0.4.5` client sees neither |
| 21 | +rc, on the native path or the notify-only fallback. Only a machine already on |
| 22 | +`0.4.6-rc.1` sees `0.4.7-rc.1`. |
| 23 | + |
| 24 | +Two things to hold: a tester must MANUALLY install `0.4.6-rc.1` first (a `0.4.5` |
| 25 | +machine sees nothing, which is the point); and a machine left on `0.4.7-rc.1` |
| 26 | +stays AHEAD of the real `0.4.6` (`0.4.7-rc.1 > 0.4.6` and we do not allow |
| 27 | +downgrade), so reset rehearsal machines by reinstalling manually afterward. A |
| 28 | +`0.4.6-rc.1` machine that does nothing self-heals to the real `0.4.6` when it |
| 29 | +ships, because a release outranks its own pre-release. |
| 30 | + |
| 31 | +If the rehearsal passes, the real `0.4.6` is that SAME tree with only |
| 32 | +`package.json`'s version bumped from `0.4.6-rc.1` to `0.4.6` (the build reads |
| 33 | +the version from package.json, not the tag), nothing else. Any CODE change |
| 34 | +between the rehearsal and the release means re-rehearse. |
| 35 | + |
| 36 | +**Release gate (hard): each rc (and the real release) must be a COMPLETE signed, |
| 37 | +notarized, stapled run of the real pipeline, not a `git tag` and not a version bump.** macOS updates |
| 38 | +through Squirrel.Mac, which needs `mac-universal.zip` + its `.blockmap` + |
| 39 | +`latest-mac.yml` (whose `path:` must point at the zip, not the dmg). A release |
| 40 | +missing those silently falls back to manual and proves nothing. |
| 41 | + |
| 42 | +## What a clean 0.4.7 proves on its own (the happy path) |
| 43 | + |
| 44 | +Install `0.4.6-rc.1`, publish a complete `0.4.7-rc.1`, then watch that client: |
| 45 | + |
| 46 | +- [ ] the badge moves check -> available -> downloading -> downloaded on its own |
| 47 | +- [ ] at `downloaded` the badge's primary action is **restart**, not a manual download |
| 48 | +- [ ] clicking it quits, installs `0.4.7-rc.1`, and relaunches into the new version |
| 49 | +- [ ] after relaunch the badge shows the "just updated" state |
| 50 | + |
| 51 | +## What a clean release CANNOT reach (inject these by hand) |
| 52 | + |
| 53 | +These only run when a user is already in trouble, so a healthy release never |
| 54 | +exercises them. A skipped check here means they ship unwitnessed. |
| 55 | + |
| 56 | +- [ ] **Timeout, fallback, and the error-state link (guards `updater.ts` + #325).** |
| 57 | + Cut the network, then trigger a check. Within ~30s the badge must reach an |
| 58 | + **error** state, never a permanent `checking` spinner, and offer a working |
| 59 | + download link (releases page). Restore the network; the next check recovers. |
| 60 | +- [ ] **Restart re-entry (#324).** With an update staged at `downloaded`, click |
| 61 | + restart twice in quick succession. It must NOT wedge with "The command is |
| 62 | + disabled and cannot be executed"; a refused or failed quit reports back and |
| 63 | + the button recovers rather than spinning. |
| 64 | +- [ ] **Success is visible (#326).** On the latest version, click the badge. It |
| 65 | + must show a positive "you are on the latest version" acknowledgement, not |
| 66 | + settle silently to a grey chip. (This one needs no real update: verify it on |
| 67 | + any build.) |
| 68 | + |
| 69 | +## Tested vs rc-only (keep this split in every report) |
| 70 | + |
| 71 | +- **Verified without a release** (unit tests, typecheck, and dev `update:simulate`): |
| 72 | + badge state-rendering and click-wiring for every state, and the no-update |
| 73 | + acknowledgement. |
| 74 | +- **Only a real signed release can exercise**: `downloadUpdate`, `quitAndInstall`, |
| 75 | + and the Squirrel install itself. Do not let this half borrow the tested half's |
| 76 | + confidence: report which is which. |
0 commit comments