Krill Desktop built .deb (Linux) and .msi (Windows) artifacts and the
Compose nativeDistributions block even listed TargetFormat.Dmg, but no
pipeline ever produced a macOS installer — so Mac users had nothing to download.
Two gaps, neither in application code: (1) jpackage can only emit a .dmg from
a macOS host, and there was no CI job running on the existing self-hosted macOS
runner; (2) the desktop packageVersion was a hand-edited literal, decoupled
from the canonical version.txt. macOS desktop is the same jvm("desktop")
target as Linux/Windows, so no new Kotlin target or expect/actual was
needed — only a macOS build host, packaging metadata, and a publish workflow.
composeApp/build.gradle.kts: read packageVersion from the repo-root
version.txt, and add a macOS { } block (bundle ID zone.krill.desktop, app
name, optional signing gated on the APPLE_SIGNING_IDENTITY env var so v1
ships unsigned). New .github/workflows/Deploy macOS.yml runs on
[self-hosted, macOS, ARM64], builds :composeApp:packageReleaseDmg, and
publishes versioned + latest keys to s3://cms.krill.systems/distro/macos/
with a CloudFront invalidation (E1MKRDHOFUF59Y, the same distribution the
screenshot/SDK-docs workflows use). A Download-category post documents the link
and the Gatekeeper open-steps for the unsigned build.
When a cross-platform desktop target advertises an installer format
(TargetFormat.Dmg), confirm a build host for that OS actually exists in CI —
the format being listed does not mean anything ships. Drive every installer’s
version from version.txt, never a hand-edited literal, so all platforms stay
in lockstep at release time. Platform-specific runtime surfaces in
desktopMain (the expect/actuals) are only proven on the OSes CI actually
runs the app on; a Linux-only build pipeline silently leaves the macOS paths
unexercised — track that as a manual smoke checklist until a macOS build exists.