You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
ci: automate the release — draft notes, sign in CI, publish behind approval
Replaces the hybrid model (CI builds unsigned, you sign on your laptop, then
hand-juggle six `gh` commands) with three chained workflows. The only manual
steps left are the two that need judgement: writing the prose, and deciding to
ship.
prepare-release.yml → you edit the PR → tag-on-merge.yml → release.yml
(drafts the notes) (the prose) (pushes the tag) (builds, signs,
notarizes, waits)
**Notes.** `draft-release-notes.mjs` already filled in every fact and left TODO
markers where judgement is needed — its header argues that a changelog generated
from commit subjects is why most release notes go unread. So the workflow opens a
PR with that draft rather than committing it, and `tag-on-merge.yml` refuses to
tag while a TODO or the scaffolding block survives, or when the first line doesn't
name the version being tagged. Automation cannot ship scaffolding, and it cannot
ship last release's notes either.
**Signing.** `notarize.sh` already took APPLE_ID + TEAM_ID + APP_SPECIFIC_PASSWORD
as the CI alternative to a local keychain profile, so no build script changed. The
workflow imports the Developer ID cert into a temporary keychain in RUNNER_TEMP,
runs the existing `make-dmg.sh`, verifies with codesign + stapler + spctl, and
deletes the keychain in an `always()` step. Two details that are load-bearing:
`set-key-partition-list` (without it codesign blocks on a GUI prompt nobody can
click and the job hangs to timeout) and a 6h keychain lock timeout (the 5-minute
default re-locks mid-notarization and the next codesign fails with a misleading
"user interaction is not allowed").
Also `fetch-depth: 0` on the build checkout: `build-macos.sh` stamps the version
from `git describe --tags`, and its failure mode is silent — it warns and ships a
build whose About box reads 1.126.0, the Code-OSS base.
**The gate.** Publishing is deploying: the Squirrel updater installs a published
release on every existing install at its next check, with no staged rollout, and
the rollback pin cannot un-update anyone who already took it. So the publish job
sits in a `release` Environment with required reviewers. Everything before it is
reversible — a branch, a tag, a draft. That step is not. After publishing it polls
the update feed and warns (not fails — the release is already correct) if the feed
hasn't picked it up.
The draft job also refuses to publish unless all four assets are present. Losing
only the x64 job would otherwise strand every Intel user silently, since the feed
serves per-arch.
RELEASING.md §7 rewritten: the six secrets, the environment setup (called out
hard — GitHub creates a missing environment with NO protection rules, so skipping
it makes the gate decorative), the new flow, and the trade-off the old §7 named
when it described this as the road not taken: the signing identity now lives in
the cloud. Revocation path and blast-radius limits documented, along with how to
go back.
Verified: actionlint (which shellchecks every run: block) clean on all three.
The notes gate was extracted from the workflow and exercised — real v1.0.4 notes
pass; a real generated draft fails on TODOs and scaffolding; TODOs-removed-but-
scaffolding-left still fails; v1.0.4 notes presented as v1.0.5 fail as stale; and
generate → fill → delete scaffolding passes.
0 commit comments