openvibers/openvibe.sites Commits

Release notifications (roadmap WS-P task 9): deploy.sh announces each placeholder's release through ovhost

OP OpenVibers committed 26 Sept 2026 · 5665e14d9e · 2 files, +24 −1

After the vhosts are in place, the script runs `ovhost announce <service> --release <id> --origin https://<domain>` once per dist/<domain>/release.json (the service and release that placeholder's /release.json names). OpenVibe.Host publishes host.deploy.activated for it to OpenVibe.Events, and open tabs (openvibe-shared 1.17.0 release-watch, on the Events realtime stream) check /release.json within seconds instead of at their next poll. ovhost sends a release once, so an unchanged placeholder sends nothing. Best effort: skipped without an ovhost on PATH (OVHOST sets another) or with one whose --help has no `announce <service>` (said once); `sudo -n` when not root (ovhost reads Host's credentials as root); `timeout 20` each, stdin closed; the first failure stops the loop (Events or the credentials would fail the rest the same way) with one line; the deploy's exit status never depends on it. Checked by running the block against a fake ovhost: all 15 placeholders with a release.json announced; a failure on the third stops the rest; an ovhost without announce is skipped; exit 0 each time. README says so.

Changes

ddiff --git a/README.md b/README.md
iindex 76a1add..a1a87c5 100644
---- a/README.md
++++ b/README.md
@@@ -39,6 +39,10 @@ never the front page.
Deploy (host): the repo lives at `/opt/openvibe.sites`; `deploy/scripts/deploy.sh` runs `npm ci`, rebuilds, installs
the vhosts into `/etc/nginx/sites-available`, enables them and reloads nginx. Each domain has a
Let's Encrypt wildcard certificate (`certbot --dns-cloudflare`, see the host's renewal configs).
++Then, for each placeholder, it runs `ovhost announce <service> --release <id> --origin https://<domain>`
++with the service and release id from that placeholder's `release.json`. OpenVibe.Host publishes each release once, as
++`host.deploy.activated`, and open tabs check `/release.json` within seconds (WS-P task 9). This is best
++effort: it is skipped without an `ovhost` that has `announce`, stops at the first failure, and never fails the deploy.
When a domain becomes a real app, delete it from `sites.json`, remove its vhost, and point the
domain's nginx block at the new service — nothing else references it.
ddiff --git a/deploy/scripts/deploy.sh b/deploy/scripts/deploy.sh
iindex fbe9f83..6e51be6 100755
---- a/deploy/scripts/deploy.sh
++++ b/deploy/scripts/deploy.sh
@@@ -1,5 +1,5 @@
#!/bin/bash
--# OpenVibe.Sites — pull, rebuild, install vhosts, reload nginx. Run on the host:
++# OpenVibe.Sites — pull, rebuild, install vhosts, reload nginx, announce each placeholder's release. Run on the host:
# sudo -u ubuntu git -C /opt/openvibe.sites pull --ff-only && /opt/openvibe.sites/deploy/scripts/deploy.sh
set -euo pipefail
REPO="${REPO:-/opt/openvibe.sites}"
@@@ -15,3 +15,22 @@ for conf in deploy/nginx/*.conf; do
done
if [ "$changed" = 1 ]; then sudo nginx -t && sudo systemctl reload nginx && echo "[sites] nginx reloaded"; else echo "[sites] vhosts unchanged"; fi
echo "[sites] $(ls dist | wc -l) sites in place"
++# Release notifications (roadmap WS-P task 9): one `ovhost announce <service> --release <id> --origin
++# https://<domain>` per placeholder, from its dist/<domain>/release.json. OpenVibe.Host publishes
++# host.deploy.activated and open tabs check /release.json now instead of at their next poll; ovhost sends a
++# release once, so an unchanged placeholder sends nothing. Best effort: skipped without an ovhost whose
++# --help has `announce <service>`, 20 s at most each, stops at the first failure (the rest would fail the
++# same way), and never fails the deploy (OpenVibe.Host docs/release-notifications.md).
++OVHOST_BIN=$(command -v "${OVHOST:-ovhost}" 2>/dev/null || true)
++if [ -n "$OVHOST_BIN" ]; then
++ case "$("$OVHOST_BIN" --help 2>/dev/null || true)" in
++ *"announce <service>"*)
++ SUDO=""; [ "$(id -u)" -eq 0 ] || SUDO="sudo -n"
++ node -e 'const fs = require("fs"); for (const d of fs.readdirSync("dist").sort()) { try { const m = JSON.parse(fs.readFileSync(`dist/${d}/release.json`, "utf8")); if (/^[a-z][a-z0-9-]{1,39}$/.test(m.service) && /^[0-9a-f]{7,40}$/.test(m.release) && /^[a-z0-9.-]+$/.test(d)) console.log(`${m.service} ${m.release} ${d}`); } catch { /* no release.json */ } }' |
++ while read -r svc rel domain; do
++ timeout 20 $SUDO "$OVHOST_BIN" announce "$svc" --release "$rel" --origin "https://$domain" </dev/null 2>&1 | sed 's/^/[sites] /' \
++ || { echo "[sites] release notification not sent for $domain; the rest are skipped (the deploy stands)"; break; }
++ done ;;
++ *) echo "[sites] release notification skipped: this ovhost has no announce" ;;
++ esac
++fi