ci(release): publish the release the assets were uploaded to

Closed
LA
14d ago
+49-17

What broke

Release run 38621170537 (v0.65.2) uploaded and verified all 12 assets on draft release 414419116. The next step, softprops/action-gh-release, logged Creating new GitHub release for tag v0.65.2... and published a new release, 414419301, with no assets. From 00:55Z to 02:15Z on 2026-10-16, releases/latest/download/cmux-macos.dmg and appcast.xml returned 404: new users could not download cmux, and installs got no update. The cmux-watch P1 caught it. Someone uploaded the assets by hand at 02:15Z.

Fix

  • scripts/ci/publish-release-assets.py writes release_id to $GITHUB_OUTPUT (this is the release that got the assets).
  • Publish verified release no longer uses softprops. It checks that the DMGs, appcasts and remote manifest are on that release id, and fails if one is missing. Then it publishes that id through the API, with make_latest from the existing decide step. It generates release notes only when the body is empty, so a rerun keeps edited notes.
  • The two existing workflow-text tests now pin the new step.

On a rerun after publish, release_id() gets the published release from the tags endpoint, so the PATCH does nothing.

Verification: actionlint passes, and py_compile passes. CI runs the release publication tests. I did not run tests on the laptop.

Lawrence must approve this merge to main.


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.


Summary by cubic

Fixes the release pipeline publishing an empty release, which left stable downloads 404ing for about an hour on v0.65.2. The publish step now targets the exact release the assets were uploaded to and publishes it through the GitHub API instead of softprops/action-gh-release.

  • publish-release-assets.py now writes the release_id it uploaded to as a workflow output.
  • The publish step verifies the uploaded DMGs, appcasts, and remote manifest are on that release id, and fails if any are missing.
  • Release notes are only generated when the body is empty, so reruns preserve edited notes.

Summary by CodeRabbit

  • Release Publishing
    • Releases are published from the same draft used to upload assets, with publication blocked if required downloads or update files are missing.
    • Generated release notes are added only when the release description is empty.
    • Published releases have draft and prerelease status cleared, with the latest-release designation set.