After merging changes into main, open Actions → Release → Run workflow,
keep the branch on main, and enter the new version (for example, 0.4.1).
Use a version newer than the current release. Do not create a tag or Release first.
The workflow tests, builds Universal binaries, signs and notarizes the app, verifies the final ZIP, publishes a Release with generated notes, and updates Homebrew's version and checksum. Notes can be edited on GitHub afterward. Runner availability and Apple notarization affect elapsed time.
In Settings → Secrets and variables → Actions, add these repository secrets:
| Secret | Value |
|---|---|
APPLE_CERTIFICATE_BASE64 |
Base64 of a password-protected .p12 export of the existing Developer ID Application certificate and private key. |
APPLE_CERTIFICATE_PASSWORD |
The .p12 export password. |
APPLE_SIGNING_IDENTITY |
The existing full Developer ID Application: … (TEAMID) identity. |
APPLE_ID |
Apple account used for notarization. |
APPLE_TEAM_ID |
Developer Team ID. |
APPLE_APP_PASSWORD |
An Apple app-specific password for notarization. |
HOMEBREW_TAP_TOKEN |
A fine-grained GitHub token for SonghaiFan/homebrew-tap, with Contents: read and write and permission to push to main. |
Use the existing Developer ID and bundle identifier (app.leftopen.mac). Keep
signing exports outside the repository; never paste credentials into source,
logs, issues, or chat. GitHub supplies the release job's GITHUB_TOKEN automatically.
The tap needs its own token because it is another repository.
Signing credentials are installed into a temporary hosted-runner keychain and
removed by an always() cleanup step. No always-on local machine is needed.
- The version is applied to App and CLI in the temporary checkout; no version-bump
commit is pushed to
main. Source literals remain development defaults. - The build number is
1000 + github.run_number. Retries retain it. Preserve this workflow's numbering; if replacing it, choose an offset greater than the last published build number. - The tag identifies the exact source commit. Its release metadata is reproduced
with
Scripts/prepare-release.py, the workflow input and recorded build number. - Assets are uploaded to a draft before publication. The same run can retry a failed draft upload; published releases are never overwritten.
- If Homebrew fails after publication, select Re-run failed jobs. The published Release remains available. Do not create a new run for the same version.
- Releases are serialized. GitHub can replace an older pending run when another is queued, so wait for completion before requesting another version.
Installed apps still discover releases through the current GitHub update checker. This workflow does not add Sparkle or automatic installation. Sparkle requires app integration and an EdDSA-signed appcast, which can later be generated from the notarized ZIP in this workflow.
Run python3 -m unittest discover -s Tests/ReleaseTests for version validation
and actionlint .github/workflows/release.yml for workflow checks. The first
configured Actions run must still verify the real hosted runner, Apple credentials,
notarization and tap push permissions.