Releasing
Releases come from .github/workflows/release.yml, from main only: push a tag on a commit on
main, or run the Release workflow by hand, which tags the current main.
git tag v0.2.0 && git push origin v0.2.0gh workflow run release.yml -f version=0.2.0It tests, builds with the version from the tag and the commit count as the build number, signs with
the Developer ID, notarises and staples the disk image, writes a signed appcast.xml, and publishes
both on a GitHub release. Then it moves the cask in homebrew-tap to the new version and the published
disk image’s checksum; if only that part fails, Re-run failed jobs retries it alone.
Installed copies read releases/latest/download/appcast.xml, which GitHub redirects to the appcast
on the newest release. Publishing the release is publishing the update.
The changelog is the release notes
Section titled “The changelog is the release notes”What a release says is CHANGELOG.md’s section for its version. It becomes the GitHub release’s
description and the notes Caliper shows in its update window, so it is written for someone deciding
whether to install. A version with no section is refused before anything is built — to release,
rename [Unreleased] to the version and date it.
One-time setup
Section titled “One-time setup”-
The update key.
make update-keymakes the EdDSA key pair Sparkle checks every update against, keeps the private half in your login Keychain (accountcaliper), and writes the public half intoResources/Info.plist. Keep a copy of the private key somewhere safe: installed copies can only be moved off a lost key by a release signed with the same Developer ID. -
A
releaseenvironment. Settings ▸ Environments ▸ New environment, namedrelease. Under Deployment branches and tags, choose Selected branches and tags and add the branchmainand the tag patternv*, so its secrets are out of reach of every other branch and tag. -
Its secrets, each set with
gh secret set <NAME> --env release:Secret What it holds DEVELOPER_ID_CERTIFICATEThe Developer ID Application certificate with its private key, exported from Keychain Access as a .p12and base64-encoded:base64 -i developer-id.p12 | gh secret set DEVELOPER_ID_CERTIFICATE --env releaseDEVELOPER_ID_CERTIFICATE_PASSWORDThe password the .p12was exported withNOTARY_API_KEYAn App Store Connect API key, the whole AuthKey_….p8file, made under Users and Access ▸ Integrations ▸ App Store Connect API with the Developer roleNOTARY_API_KEY_IDThat key’s ID NOTARY_API_ISSUER_IDThe issuer ID shown above the list of keys SPARKLE_PRIVATE_KEYThe update key, exported as make update-keyshows at the end -
The tap’s deploy key. A key pair that can push to
homebrew-tapand nothing else:Terminal window ssh-keygen -t ed25519 -N '' -C 'caliper release' -f tap-keygh repo deploy-key add tap-key.pub --repo hossainalhaidari/homebrew-tap --allow-write --title 'caliper release'gh api -X PUT repos/hossainalhaidari/caliper/environments/homebrew-tapgh secret set HOMEBREW_TAP_DEPLOY_KEY --env homebrew-tap < tap-keyrm tap-key tap-key.pubThen give the new
homebrew-tapenvironment the same Deployment branches and tags asrelease—mainandv*. It is an environment of its own so that required reviewers onreleasedo not make every release wait for a second approval.
Secrets stay private when the repository is public: GitHub never shows one again once it is set, and workflows run for pull requests from forks get none at all.
Signing, piece by piece
Section titled “Signing, piece by piece”Notarisation checks every piece of code in the bundle, not only the app, so Sparkle’s helpers are
signed one by one, innermost first, by Tools/sign.sh — each with the hardened runtime and a secure
timestamp. A signature without a timestamp stops verifying the day the certificate expires.
By hand
Section titled “By hand”To try the pipeline on your own Mac, with a notary profile stored once by
xcrun notarytool store-credentials:
NOTARY_PROFILE=CaliperNotary make packageCALIPER_VERSION=0.2.0 CALIPER_BUILD=212 NOTARY_PROFILE=CaliperNotary make packageThe first makes a development build, which never updates itself; the second a release build. Without
NOTARY_PROFILE it stops after signing and says so. The disk image lands in build/.