eleven / messenger Public

deploy: publish darwin builds for the website's try flow (#1105)

The self-host page's try snippet handed every visitor lchat-linux-amd64 —
exec format error on a Mac (and wrong on arm64 linux). Publish now also
builds lchat-darwin-{arm64,amd64}; promote-stable refreshes them on the
rolling release beside the linux pair. The channel manifest and the fleet
stay linux-only.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Paul Campbell f0f78390c10d6a9f21e92dc538ca0d6ccb93d3a8 parent 98fc59b
3 files changed, +30 −12
  • deploy/build-linux.sh +6 −4
  • deploy/release-server.sh +16 −3
  • docs/server-releases.md +8 −5
diff --git a/deploy/build-linux.sh b/deploy/build-linux.sh
index 7bf40e5..c3473b0 100755
--- a/deploy/build-linux.sh
+++ b/deploy/build-linux.sh
@@ -3,9 +3,10 @@
# (the git short sha, or $1) so `lchat stage`/`deploy --version` can identify and
# health-check it. Prints the build id and the output path.
#
-# ./deploy/build-linux.sh # amd64, id = git short sha
+# ./deploy/build-linux.sh # linux/amd64, id = git short sha
# ./deploy/build-linux.sh test-scroll # id = test-scroll (e.g. a canary label)
# ARCH=arm64 ./deploy/build-linux.sh # linux/arm64 (self-hosters on ARM)
+# OS=darwin ARCH=arm64 ./deploy/build-linux.sh # macOS (the `lchat try` download)
# OUT=/tmp/lchat ./deploy/build-linux.sh
set -eu
@@ -14,10 +15,11 @@ if [ -z "$VER" ]; then
echo "build-linux: could not determine a build id (pass one as \$1)" >&2
exit 1
fi
+OS="${OS:-linux}"
ARCH="${ARCH:-amd64}"
-OUT="${OUT:-lchat-linux-$ARCH}"
+OUT="${OUT:-lchat-$OS-$ARCH}"
-GOOS=linux GOARCH="$ARCH" CGO_ENABLED=0 \
+GOOS="$OS" GOARCH="$ARCH" CGO_ENABLED=0 \
go build -ldflags "-X main.buildVersion=${VER}" -o "$OUT" .
-echo "built ${VER} (${ARCH}) -> ${OUT}"
+echo "built ${VER} (${OS}/${ARCH}) -> ${OUT}"
diff --git a/deploy/release-server.sh b/deploy/release-server.sh
index 6ea0e2d..f35ddd4 100755
--- a/deploy/release-server.sh
+++ b/deploy/release-server.sh
@@ -47,6 +47,11 @@ KEY="${LCHAT_RELEASE_KEY_FILE:-}"
MIRROR_BUCKET="${LCHAT_RELEASE_MIRROR_BUCKET:-}"
BIN=lchat-linux-amd64
BIN_ARM=lchat-linux-arm64
+# The darwin builds exist for the website's `lchat try` download (Macs hit
+# "exec format error" on a linux binary) — the fleet and the channel manifest
+# stay linux-only; these just ride the releases as extra assets.
+BIN_MAC=lchat-darwin-arm64
+BIN_MAC_X64=lchat-darwin-amd64
TMP="$(mktemp -d)"
trap 'rm -rf "$TMP"' EXIT
@@ -125,12 +130,17 @@ publish)
OUT="$TMP/$BIN" ./deploy/build-linux.sh "$VER"
ARCH=arm64 OUT="$TMP/$BIN_ARM" ./deploy/build-linux.sh "$VER"
+ OS=darwin ARCH=arm64 OUT="$TMP/$BIN_MAC" ./deploy/build-linux.sh "$VER"
+ OS=darwin ARCH=amd64 OUT="$TMP/$BIN_MAC_X64" ./deploy/build-linux.sh "$VER"
SHA="$(shasum -a 256 "$TMP/$BIN" | cut -d' ' -f1)"
SIZE="$(wc -c < "$TMP/$BIN" | tr -d ' ')"
SHA_ARM="$(shasum -a 256 "$TMP/$BIN_ARM" | cut -d' ' -f1)"
SIZE_ARM="$(wc -c < "$TMP/$BIN_ARM" | tr -d ' ')"
echo "$SHA $BIN" > "$TMP/$BIN.sha256"
echo "$SHA_ARM $BIN_ARM" > "$TMP/$BIN_ARM.sha256"
+ for M in "$BIN_MAC" "$BIN_MAC_X64"; do
+ echo "$(shasum -a 256 "$TMP/$M" | cut -d' ' -f1) $M" > "$TMP/$M.sha256"
+ done
if gh release view "server-$VER" -R "$REPO" >/dev/null 2>&1; then
echo "release-server: server-$VER already exists on $REPO (promote it, or land a new commit)" >&2; exit 1
@@ -141,12 +151,14 @@ publish)
# server publish was silently 404ing every Mac's update check (found
# 2026-07-14: the feed pointed at server-414bdeb0, no appcast there).
gh release create "server-$VER" -R "$REPO" --title "Server $VER" --notes "$NOTES" --latest=false \
- "$TMP/$BIN" "$TMP/$BIN.sha256" "$TMP/$BIN_ARM" "$TMP/$BIN_ARM.sha256"
+ "$TMP/$BIN" "$TMP/$BIN.sha256" "$TMP/$BIN_ARM" "$TMP/$BIN_ARM.sha256" \
+ "$TMP/$BIN_MAC" "$TMP/$BIN_MAC.sha256" "$TMP/$BIN_MAC_X64" "$TMP/$BIN_MAC_X64.sha256"
# Binaries mirror before the manifest that points at them, so the mirror
# never serves a feed whose mirror-side binaries don't exist yet. Keys copy
# the GitHub layout (server-<ver>/<asset>) — that's what the updater's
# mirror fallback derives from a primary binary URL.
- for A in "$BIN" "$BIN.sha256" "$BIN_ARM" "$BIN_ARM.sha256"; do
+ for A in "$BIN" "$BIN.sha256" "$BIN_ARM" "$BIN_ARM.sha256" \
+ "$BIN_MAC" "$BIN_MAC.sha256" "$BIN_MAC_X64" "$BIN_MAC_X64.sha256"; do
mirror_upload "$TMP/$A" "server-$VER/$A"
done
@@ -227,7 +239,8 @@ promote)
# fixed, JSON-free URLs deploy/install.sh downloads.
if [ "$CHAN" = stable ]; then
mkdir -p "$TMP/stable"
- for A in "$BIN" "$BIN.sha256" "$BIN_ARM" "$BIN_ARM.sha256"; do
+ for A in "$BIN" "$BIN.sha256" "$BIN_ARM" "$BIN_ARM.sha256" \
+ "$BIN_MAC" "$BIN_MAC.sha256" "$BIN_MAC_X64" "$BIN_MAC_X64.sha256"; do
if gh release download "server-$VER" -R "$REPO" -p "$A" -O "$TMP/stable/$A" 2>/dev/null; then
gh release upload server "$TMP/stable/$A" -R "$REPO" --clobber
else
diff --git a/docs/server-releases.md b/docs/server-releases.md
index 90c2caf..1843262 100644
--- a/docs/server-releases.md
+++ b/docs/server-releases.md
@@ -16,8 +16,10 @@ app's Sparkle appcast uses, see `ios/release-mac.sh`):
- **One release per build**: tag `server-<ver>` (ver = the git short sha that
`deploy/build-linux.sh` stamps into the binary as `main.buildVersion`),
- carrying **both architectures** — `lchat-linux-amd64` and `lchat-linux-arm64`,
- each with its `.sha256`.
+ carrying **both linux architectures** — `lchat-linux-amd64` and
+ `lchat-linux-arm64` — plus `lchat-darwin-{arm64,amd64}` (the website's
+ `lchat try` download for Macs; never referenced by the manifest), each with
+ its `.sha256`.
- **One rolling release**: tag `server`, whose assets live at fixed URLs
(re-uploaded with `--clobber`, so the URLs never change):
- `manifest.json` — the **feed**, updated on every publish/promote:
@@ -25,9 +27,10 @@ app's Sparkle appcast uses, see `ios/release-mac.sh`):
```
https://github.com/elevenmessenger/releases/releases/download/server/manifest.json
```
- - `lchat-linux-{amd64,arm64}` (+ `.sha256`) — copies of the current
- **stable** binaries, refreshed by `promote … stable`. These JSON-free URLs
- are what `deploy/install.sh` downloads.
+ - `lchat-linux-{amd64,arm64}` and `lchat-darwin-{arm64,amd64}`
+ (+ `.sha256`) — copies of the current **stable** binaries, refreshed by
+ `promote … stable`. These JSON-free URLs are what `deploy/install.sh`
+ (linux) and the website's try snippet (any OS) download.
- `install.sh` — the self-hoster installer, refreshed on every publish.
- **The releases repo README** is the public self-hosting guide — synced from
`docs/self-hosting.md` on every publish (this source repo is private, so the