2026-05-13 16:57:35 -04:00
#!/bin/bash
2026-09-13 00:44:44 -04:00
# Merges the latest upstream stable release tag into the lotus branch, runs the
# local quality gates, and PUSHES. It no longer builds or deploys itself: the push
# triggers the normal Gitea CI run and lotus_deploy.sh deploys only once the
# "Build & Quality Checks" status is green — the same path every other lotus
# commit takes (cinny#98: this script used to build+deploy+push, bypassing CI).
2026-05-13 16:57:35 -04:00
# Triggered via webhook by LotusBot !cinny-update command.
# Requires:
# /etc/cinny-monitor.env — MATRIX_TOKEN, MATRIX_SERVER, MATRIX_ROOM
# /opt/lotus-cinny/ — git clone of code.lotusguild.org/LotusGuild/cinny
# with upstream remote: https://github.com/cinnyapp/cinny.git
set -euo pipefail
REPO_DIR = "/opt/lotus-cinny"
STATE_FILE = "/var/lib/cinny-monitor/last-upstream-tag"
ENV_FILE = "/etc/cinny-monitor.env"
LOG = "/var/log/cinny-build.log"
exec >> " $LOG " 2>& 1
echo "=== $( date) === Cinny build triggered ==="
[ -f " $ENV_FILE " ] || { echo "ERROR: $ENV_FILE missing" ; exit 1; }
set -a
# shellcheck source=/dev/null
source " $ENV_FILE "
set +a
matrix_notify() {
local msg = " $1 "
echo "[notify] $msg "
[ -z " ${ MATRIX_TOKEN :- } " ] && return
export _NOTIFY_MSG = " $msg "
python3 << 'PYEOF'
import urllib.request, urllib.parse, json, time, sys, os
token = os.environ.get('MATRIX_TOKEN', '')
server = os.environ.get('MATRIX_SERVER', '').rstrip('/')
room = os.environ.get('MATRIX_ROOM', '')
msg = os.environ.get('_NOTIFY_MSG', '')
if not all([token, server, room, msg]):
sys.exit(0)
txn = str(int(time.time() * 1000))
api = f"{server}/_matrix/client/v3/rooms/{urllib.parse.quote(room, safe='')}/send/m.room.message/{txn}"
body = json.dumps({"msgtype": "m.text", "body": msg}).encode()
req = urllib.request.Request(api, data=body, method="PUT", headers={
"Authorization": f"Bearer {token}", "Content-Type": "application/json"
})
try:
urllib.request.urlopen(req, timeout=10)
except Exception as e:
print(f"Notify failed: {e}", file=sys.stderr)
PYEOF
}
if [ ! -d " $REPO_DIR /.git" ] ; then
matrix_notify "cinny-build: FAILED — $REPO_DIR is not a git repo. Clone the lotus fork first."
exit 1
fi
cd " $REPO_DIR "
if ! git remote | grep -q '^upstream$' ; then
matrix_notify "cinny-build: FAILED — upstream remote missing. Run: git remote add upstream https://github.com/cinnyapp/cinny.git"
exit 1
fi
matrix_notify "cinny-build: fetching upstream tags..."
git fetch upstream --tags --no-recurse-submodules -q
# Get latest stable release tag from GitHub API
LATEST_TAG = $( curl -sf \
-H "Accept: application/vnd.github.v3+json" \
-H "User-Agent: lotus-cinny-monitor/1.0" \
"https://api.github.com/repos/cinnyapp/cinny/releases/latest" | python3 -c "import sys,json; print(json.load(sys.stdin)['tag_name'])" )
CURRENT_TAG = $( git describe --tags --exact-match HEAD 2>/dev/null || git log -1 --format= '%D' | grep -oP 'tag: \K[^,]+' | head -1 || echo "untagged" )
echo "Current: $CURRENT_TAG — Target: $LATEST_TAG "
if [ " $CURRENT_TAG " = " $LATEST_TAG " ] ; then
matrix_notify "cinny-build: already on $LATEST_TAG , nothing to do."
exit 0
fi
matrix_notify "cinny-build: merging $LATEST_TAG into lotus branch..."
if ! git merge " $LATEST_TAG " --no-edit 2>& 1; then
git merge --abort 2>/dev/null || true
matrix_notify "cinny-build: FAILED — merge conflict at $LATEST_TAG . SSH to LXC 106 and resolve manually. See /var/log/cinny-build.log"
exit 1
fi
2026-09-13 00:44:44 -04:00
# ── Local pre-flight (same gates CI runs, minus the build) ──────────────────
# An upstream merge touches hundreds of files we didn't write, so catch an
# obviously broken merge here before it lands on origin. CI is still the
# authority: a failure here leaves the merge commit LOCAL (not pushed) so it can
# be inspected/fixed on the box.
2026-05-13 16:57:35 -04:00
echo "Running npm ci..."
2026-09-13 00:44:44 -04:00
if ! npm ci 2>& 1 | tail -5; then
matrix_notify "cinny-build: FAILED — npm ci failed after merging $LATEST_TAG . Merge is local only (not pushed). See /var/log/cinny-build.log"
2026-05-13 16:57:35 -04:00
exit 1
fi
2026-09-13 00:44:44 -04:00
for gate in "npm run typecheck" "npm run check:eslint" "npm run check:prettier" "npm test" ; do
echo "Gate: $gate "
if ! $gate 2>& 1 | tail -20; then
matrix_notify "cinny-build: FAILED — ' $gate ' failed after merging $LATEST_TAG . Merge is local only (not pushed). SSH to LXC 106 to fix forward."
exit 1
fi
done
# ── Hand off to CI + lotus_deploy.sh ────────────────────────────────────────
# Pushing is what deploys: Gitea CI builds and runs every gate, and the
# lotus-deploy webhook polls the "Build & Quality Checks" status and only then
# rsyncs dist/ to the web root (preserving the live config.json). Nothing is copied
# to the web root from here.
2026-05-13 16:57:35 -04:00
git push origin lotus
# Update state file so upstream-check knows we're on this tag
echo " $LATEST_TAG " > " $STATE_FILE "
2026-09-13 00:44:44 -04:00
matrix_notify "cinny-build: merged $LATEST_TAG and pushed — CI is running; lotus_deploy.sh will go live once 'Build & Quality Checks' passes (~11 min). Watch https://code.lotusguild.org/LotusGuild/cinny/actions"
echo "=== Merge pushed: $LATEST_TAG (deploy via CI) ==="