#!/bin/bash # 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). # 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 # ── 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. echo "Running npm ci..." 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" exit 1 fi 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. git push origin lotus # Update state file so upstream-check knows we're on this tag echo "$LATEST_TAG" > "$STATE_FILE" 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) ==="