Release and ops
How a Runic release ships. It is one script, Scripts/release.sh, run from a clean main.
The flow
- Preflight: working tree clean, the changelog has a dated section for the version, the appcast build number is strictly higher than the last release,
package.json,version.envandRunicVersion.swiftagree. - Gates:
swiftformat --lint,swiftlint --strictand the full test suite. Any failure aborts before anything is built for publishing. - Build, sign, notarize: a universal release build, Developer ID signing, Apple notarization. The script refuses to package a binary older than its sources, and fails if the dSYM and binary UUIDs differ.
- Tag and publish: a signed annotated tag
vX.Y.Z, then a GitHub release withRunic-X.Y.Z.zip, the dSYM and the delta updates. - Appcast: Sparkle’s appcast is regenerated and signed. Because
mainrequires pull requests, the script opens a PR fromsriinnu/appcast-X.Y.Z; merging it makes the update live. - Homebrew: the cask in
sriinnu/homebrew-tapis bumped with the zip’s sha256 and merged.
After a release
- Verify the live appcast, that each asset URL answers 200, that the cask sha equals
shasum -a 256of the zip, andgit tag -v. - Compare
dwarfdump --uuidof the zip’s binary and a fresh build, and grep the zip’s binary for a string only the new code has. A release once shipped the previous build’s binary; this is the check that catches it. - Install the notarized zip to
/Applicationsand confirmspctlreports Notarized Developer ID and a single running instance. - Local
mainnow has the appcast commit and diverges from the squash:git reset --hard origin/main.
CI
One macos-26 job. GitHub often cancels it after about 15 minutes with “job was not acquired by Runner” when arm64 capacity is short. That is not a build failure; re-run it. SwiftFormat and SwiftLint are pinned in the workflow to the versions the release gate uses locally, because the latest SwiftFormat flags files the pinned one accepts.
Updating this wiki
The wiki repo only exists after a page has been saved once in the web UI. Push with the SSH remote, git@github.com:sriinnu/Runic.wiki.git; the HTTPS remote fails authentication. Images live in images/ and are served from raw.githubusercontent.com/wiki/sriinnu/Runic/images/.