eleven / messenger Public

Clone
git clone https://amadan.net/eleven/messenger

Plain git — no account needed to clone.

Download

Download this file

1#!/usr/bin/env sh
2# πŸ€– ops publish / promote / ship β€” the release path, one verb per stage.
3#
4# ./deploy/ops publish "release notes" # build HEAD -> server-<sha> release -> edge
5# ./deploy/ops promote <ver> beta # move a channel pointer (re-signs the feed)
6# ./deploy/ops ship # every fleet box catches up NOW
7#
8# The machinery is deploy/release-server.sh (which pulls the Bitwarden signing
9# key itself, unlocking interactively when the vault is locked β€” no key setup).
10# This wrapper adds only the rules that used to live in prose:
11#
12# - a release must correspond to LANDED MAIN CODE β€” publish refuses a HEAD
13# that origin/main doesn't contain, so a feature branch can't become the
14# fleet's edge build by accident;
15# - there are exactly three channels, edge / beta / stable. There is NO dev
16# channel β€” the dev mesh is deployed by `ops dev deploy`, never the feed;
17# - `ship` means every box, not one: it loops the fleet (same aliases doctor
18# checks), so a second box can't quietly stay behind;
19# - box SSH sessions incur a why-entry in the public access ledger.
20set -eu
21
22here="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
23root="$(CDPATH= cd -- "$here/.." && pwd)"
24# Fleet box ssh aliases β€” user/hostname come from ~/.ssh/config (operator SSH
25# rides WireGuard; specifics in CLAUDE.local.md). Same default as doctor.sh.
26BOXES="${LCHAT_BOXES:-elevenbox kepler}"
27
28usage() {
29 echo "usage: ops publish [notes...] | ops promote <ver> edge|beta|stable | ops ship [--expedite] [box...]" >&2
30 exit 2
31}
32
33cmd="${1:-}"
34[ $# -gt 0 ] && shift
35case "$cmd" in
36
37publish)
38 # Refuse to publish code main doesn't have: edge tracks main, and a branch
39 # build published by accident would auto-update the whole edge fleet onto
40 # unreviewed code within the hour. (Branch builds belong on a pinned canary:
41 # `ops canary deploy`.) Fetch first so the check is against today's main,
42 # not a stale ref; offline, fall back to the last-known one.
43 git -C "$root" fetch -q origin main 2>/dev/null \
44 || echo "ops publish: warning: could not fetch origin/main β€” checking against the last-known ref" >&2
45 if ! git -C "$root" merge-base --is-ancestor HEAD origin/main 2>/dev/null; then
46 echo "ops publish: HEAD is not on origin/main β€” a release must be landed main code." >&2
47 echo " merge the PR, pull main, and publish from there" >&2
48 echo " (branch builds go to a pinned canary instead: ops canary deploy <slug>)" >&2
49 exit 1
50 fi
51 # release-server.sh re-checks this, but 20 minutes earlier is kinder.
52 if [ -n "$(git -C "$root" status --porcelain 2>/dev/null)" ]; then
53 echo "ops publish: working tree is dirty β€” publish from a clean main" >&2
54 exit 1
55 fi
56 exec "$here/release-server.sh" publish "$@"
57 ;;
58
59promote)
60 ver="${1:-}"; chan="${2:-}"
61 # Catch the swapped-argument habit before release-server's terser usage line.
62 case "$ver" in edge|beta|stable)
63 echo "ops promote: arguments are <version> then <channel> β€” try: ops promote $chan $ver" >&2
64 exit 2 ;;
65 esac
66 case "$chan" in
67 edge|beta|stable) ;;
68 dev)
69 echo "ops promote: there is no 'dev' channel β€” the channels are edge / beta / stable." >&2
70 echo " the dev mesh is not on the release feed at all; deploy it with: ops dev deploy" >&2
71 exit 2 ;;
72 *) usage ;;
73 esac
74 [ -n "$ver" ] || usage
75 exec "$here/release-server.sh" promote "$ver" "$chan"
76 ;;
77
78ship)
79 # Ship converges the WHOLE fleet: one release-server.sh ship pass per box
80 # (each box runs its own updater). Naming boxes limits the sweep; the
81 # default is every fleet box, so nobody has to remember there are two.
82 # `ship --expedite [box...]` overrides the supply-chain bake window β€” the
83 # encoded form of the update-run --ignore-bake incident precedent.
84 EXPEDITE=""
85 if [ "${1:-}" = "--expedite" ]; then EXPEDITE="--expedite"; shift; fi
86 [ $# -gt 0 ] && BOXES="$*"
87 failed=""
88 for box in $BOXES; do
89 echo "ops ship: converging $box"
90 # One box lagging (GitHub's CDN serves fresh manifests stale for a few
91 # minutes) must not stop the others from converging β€” finish the sweep,
92 # then report.
93 LCHAT_BOX="$box" "$here/release-server.sh" ship $EXPEDITE || failed="$failed $box"
94 done
95 echo
96 echo "note: this opened operator SSH sessions β€” the public access ledger wants a"
97 echo " why-entry for this session: ops ledger \"shipped <ver>\" (web/status/ssh/)"
98 if [ -n "$failed" ]; then
99 echo "ops ship: still behind:$failed β€” usually the CDN window; retry in a few minutes" >&2
100 exit 1
101 fi
102 ;;
103
104*) usage ;;
105esac
106