| index d6e9d43..d9e8530 100755 |
| --- a/deploy/release-server.sh |
| +++ b/deploy/release-server.sh |
| @@ -2,9 +2,10 @@ |
| # Publish server releases + move the channel feed (edge / beta / stable). |
| # |
| # The feed model (docs/server-releases.md): every build gets a GitHub release |
| -# `server-<ver>` on the public releases repo carrying the linux binary; one |
| -# rolling release tagged `server` carries manifest.json — the Ed25519-signed |
| -# feed saying which version each channel points at. Boxes only ever read the |
| +# `server-<ver>` on the public BUILDS repo (machine artifacts, split from the |
| +# human releases repo 2026-07-22) carrying the linux binary; one rolling |
| +# release tagged `server` on the RELEASES repo carries manifest.json — the |
| +# Ed25519-signed feed saying which version each channel points at. Boxes only ever read the |
| # manifest; promotion is a manifest edit, no rebuild. |
| # |
| # ./deploy/release-server.sh publish [notes...] # build HEAD -> release server-<sha> -> point edge at it |
| @@ -21,7 +22,7 @@ |
| # via `sudo -n` through deploy/sudoers-operators. Environment specifics live |
| # in CLAUDE.local.md, never here). `publish ... && ship` is a full deploy. |
| # |
| -# Needs: gh (authed, write access to $LCHAT_RELEASES_REPO), jq, go, and the |
| +# Needs: gh (authed, write access to $LCHAT_RELEASES_REPO AND $LCHAT_BUILDS_REPO), jq, go, and the |
| # signing key. Both publish AND promote re-sign the feed, so both need the key. |
| # |
| # The easy path — nothing to set up: with the Bitwarden CLI (`bw`) installed, |
| @@ -56,6 +57,13 @@ set -eu |
| . "$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)/vault-items.sh" |
| |
| REPO="${LCHAT_RELEASES_REPO:-elevenmessenger/releases}" |
| +# Per-commit server-<sha> build artifacts live in their own public repo so the |
| +# RELEASES repo's page stays human (Mac app, the rolling feed, enterprise) — |
| +# these are dev builds, not product releases (Paul, 2026-07-22). Public |
| +# because the fleet and self-hosters download tokenless. Builds published |
| +# before the split stay on $REPO forever — promote resolves per version, so |
| +# old pins and rollbacks never break. |
| +BUILDS_REPO="${LCHAT_BUILDS_REPO:-elevenmessenger/builds}" |
| KEY="${LCHAT_RELEASE_KEY_FILE:-}" |
| MIRROR_BUCKET="${LCHAT_RELEASE_MIRROR_BUCKET:-}" |
| BIN=lchat-linux-amd64 |
| @@ -266,18 +274,18 @@ publish) |
| echo "$(shasum -a 256 "$TMP/$SBA" | cut -d' ' -f1) $SBA" > "$TMP/$SBA.sha256" |
| echo "built $VER (service $SNAME, amd64+arm64)" |
| SVC_JSON="$(printf '%s' "$SVC_JSON" | jq --arg n "$SNAME" \ |
| - --arg url "https://github.com/$REPO/releases/download/server-$VER/$SB" \ |
| + --arg url "https://github.com/$BUILDS_REPO/releases/download/server-$VER/$SB" \ |
| --arg sha "$(cut -d' ' -f1 < "$TMP/$SB.sha256")" \ |
| --argjson size "$(wc -c < "$TMP/$SB" | tr -d ' ')" \ |
| - --arg aurl "https://github.com/$REPO/releases/download/server-$VER/$SBA" \ |
| + --arg aurl "https://github.com/$BUILDS_REPO/releases/download/server-$VER/$SBA" \ |
| --arg asha "$(cut -d' ' -f1 < "$TMP/$SBA.sha256")" \ |
| --argjson asize "$(wc -c < "$TMP/$SBA" | tr -d ' ')" \ |
| '.[$n] = {url:$url, sha256:$sha, size:$size, arm64_url:$aurl, arm64_sha256:$asha, arm64_size:$asize}')" |
| SVC_ASSETS="$SVC_ASSETS $SB $SB.sha256 $SBA $SBA.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 |
| + if gh release view "server-$VER" -R "$BUILDS_REPO" >/dev/null 2>&1; then |
| + echo "release-server: server-$VER already exists on $BUILDS_REPO (promote it, or land a new commit)" >&2; exit 1 |
| fi |
| # --latest=false: the repo's "latest" pointer belongs to the MAC app — |
| # Sparkle's baked-in SUFeedURL is releases/latest/download/appcast.xml, and |
| @@ -289,7 +297,7 @@ publish) |
| # instead of a wall of shas. Prereleases also can never take "Latest" |
| # (which belongs to the Mac releases — see refresh_release_page). |
| echo "release-server: creating server-$VER + uploading $((8 + $(echo $SVC_ASSETS | wc -w | tr -d ' '))) assets…" >&2 |
| - gh release create "server-$VER" -R "$REPO" --title "Server $VER" --notes "$NOTES" \ |
| + gh release create "server-$VER" -R "$BUILDS_REPO" --title "Server $VER" --notes "$NOTES" \ |
| --prerelease --latest=false \ |
| "$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" |
| @@ -298,7 +306,7 @@ publish) |
| SVC_PATHS="" |
| for A in $SVC_ASSETS; do SVC_PATHS="$SVC_PATHS $TMP/$A"; done |
| # shellcheck disable=SC2086 # word-splitting the paths is the point |
| - gh release upload "server-$VER" $SVC_PATHS -R "$REPO" |
| + gh release upload "server-$VER" $SVC_PATHS -R "$BUILDS_REPO" |
| # 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 |
| @@ -318,8 +326,8 @@ publish) |
| fetch_payload | jq \ |
| --arg ver "$VER" --arg sha "$SHA" --argjson size "$SIZE" --arg notes "$NOTES" \ |
| --arg sha_arm "$SHA_ARM" --argjson size_arm "$SIZE_ARM" \ |
| - --arg url "https://github.com/$REPO/releases/download/server-$VER/$BIN" \ |
| - --arg url_arm "https://github.com/$REPO/releases/download/server-$VER/$BIN_ARM" \ |
| + --arg url "https://github.com/$BUILDS_REPO/releases/download/server-$VER/$BIN" \ |
| + --arg url_arm "https://github.com/$BUILDS_REPO/releases/download/server-$VER/$BIN_ARM" \ |
| --arg now "$(date -u +%Y-%m-%dT%H:%M:%SZ)" --arg semver "$SEMVER" \ |
| --argjson svc "$SVC_JSON" \ |
| '.channels.edge = ({version:$ver, url:$url, sha256:$sha, size:$size, |
| @@ -352,6 +360,10 @@ promote) |
| |
| echo "promote: fetching the current feed…" >&2 |
| fetch_payload > "$TMP/payload.json" |
| + # Which repo holds this version's build: builds (post-split) or releases |
| + # (published before the split — those releases stay put so nothing breaks). |
| + VREPO="$BUILDS_REPO" |
| + gh release view "server-$VER" -R "$VREPO" >/dev/null 2>&1 || VREPO="$REPO" |
| # Prefer the entry already on a channel (usually promoting edge -> beta -> |
| # stable); otherwise rebuild it from the server-<ver> release's own assets |
| # (arm64 fields only when that release has an arm64 build — pre-arm64 |
| @@ -361,22 +373,22 @@ promote) |
| # A rebuilt entry can't recover the semver the build was published with — |
| # major-pinned instances hold semver-less releases, so say so. |
| echo "release-server: note: rebuilding the $VER entry from release assets — it will carry no semver (major-pinned instances will hold it)" >&2 |
| - gh release download "server-$VER" -R "$REPO" -p "$BIN.sha256" -O "$TMP/$BIN.sha256" || { |
| - echo "release-server: no server-$VER release on $REPO" >&2; exit 1; } |
| + gh release download "server-$VER" -R "$VREPO" -p "$BIN.sha256" -O "$TMP/$BIN.sha256" || { |
| + echo "release-server: no server-$VER release on $VREPO" >&2; exit 1; } |
| SHA="$(cut -d' ' -f1 < "$TMP/$BIN.sha256")" |
| - SIZE="$(gh release view "server-$VER" -R "$REPO" --json assets \ |
| + SIZE="$(gh release view "server-$VER" -R "$VREPO" --json assets \ |
| --jq ".assets[] | select(.name == \"$BIN\") | .size")" |
| - NOTES="$(gh release view "server-$VER" -R "$REPO" --json body --jq .body)" |
| + NOTES="$(gh release view "server-$VER" -R "$VREPO" --json body --jq .body)" |
| ENTRY="$(jq -n --arg ver "$VER" --arg sha "$SHA" --argjson size "${SIZE:-0}" --arg notes "$NOTES" \ |
| - --arg url "https://github.com/$REPO/releases/download/server-$VER/$BIN" \ |
| + --arg url "https://github.com/$VREPO/releases/download/server-$VER/$BIN" \ |
| --arg now "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \ |
| '{version:$ver, url:$url, sha256:$sha, size:$size, notes:$notes, published_at:$now}')" |
| - if gh release download "server-$VER" -R "$REPO" -p "$BIN_ARM.sha256" -O "$TMP/$BIN_ARM.sha256" 2>/dev/null; then |
| + if gh release download "server-$VER" -R "$VREPO" -p "$BIN_ARM.sha256" -O "$TMP/$BIN_ARM.sha256" 2>/dev/null; then |
| SHA_ARM="$(cut -d' ' -f1 < "$TMP/$BIN_ARM.sha256")" |
| - SIZE_ARM="$(gh release view "server-$VER" -R "$REPO" --json assets \ |
| + SIZE_ARM="$(gh release view "server-$VER" -R "$VREPO" --json assets \ |
| --jq ".assets[] | select(.name == \"$BIN_ARM\") | .size")" |
| ENTRY="$(printf '%s' "$ENTRY" | jq --arg sha "$SHA_ARM" --argjson size "${SIZE_ARM:-0}" \ |
| - --arg url "https://github.com/$REPO/releases/download/server-$VER/$BIN_ARM" \ |
| + --arg url "https://github.com/$VREPO/releases/download/server-$VER/$BIN_ARM" \ |
| '. + {arm64_url:$url, arm64_sha256:$sha, arm64_size:$size}')" |
| fi |
| fi |
| @@ -391,7 +403,7 @@ promote) |
| mkdir -p "$TMP/stable" |
| 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 |
| + if gh release download "server-$VER" -R "$VREPO" -p "$A" -O "$TMP/stable/$A" 2>/dev/null; then |
| gh release upload server "$TMP/stable/$A" -R "$REPO" --clobber |
| else |
| echo "note: server-$VER has no $A — rolling copy not refreshed" >&2 |