From 457349d25880114f156235c543dfd3a352ced525 Mon Sep 17 00:00:00 2001 From: cproudlock Date: Wed, 12 Aug 2026 12:13:23 -0400 Subject: [PATCH] export: stop an unanchored exclude from eating a plugin The publication rsync excluded 'tools' to keep the repo-root tools/ dir off GitHub. rsync patterns without a leading slash match at any depth, so naming a plugin 'tools' meant plugins/tools/ was dropped too. It was committed, exported, bundled and deployed, and the first sign of trouble was `plugin install tools` on the server failing on a manifest.json that had never been shipped. The root-intended excludes are anchored, and the sync now verifies that every plugins/*/manifest.json in the working tree came out the other side. A silent omission of a whole plugin should not be something a deploy discovers for us. --- tools/export-github.sh | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/tools/export-github.sh b/tools/export-github.sh index d9f29af..0df5317 100755 --- a/tools/export-github.sh +++ b/tools/export-github.sh @@ -50,9 +50,9 @@ done rsync -a --delete \ --exclude '.git' \ --exclude '.gitea' \ - --exclude 'docs' \ - --exclude 'tools' \ - --exclude 'mcp' \ + --exclude '/docs' \ + --exclude '/tools' \ + --exclude '/mcp' \ --exclude 'start-api.sh' \ --exclude 'start-ui.sh' \ --exclude 'CLAUDE.md' \ @@ -69,7 +69,7 @@ rsync -a --delete \ --exclude 'frontend/dist*' \ --exclude 'frontend/src/.plugins-staged' \ --exclude 'frontend/src/router/routes.gen.js' \ - --exclude 'instance' \ + --exclude '/instance' \ --exclude '.env' \ --exclude '__pycache__' \ --exclude '.pytest_cache' \ @@ -80,6 +80,26 @@ rsync -a --delete \ --exclude 'scripts/site_imports/wjf/idmap.json' \ "$WORK/" "$PUB/" +# --- 1b. every bundled plugin must have survived the sync --- +# +# The excludes above are rsync patterns, and a pattern with no leading slash +# matches at ANY depth. 'tools' was meant to drop the repo-root tools/ dir (this +# script lives in it) and silently dropped plugins/tools/ as well, so a plugin +# was committed, exported, bundled and deployed without ever being in the +# payload - the failure only surfaced as a missing manifest.json on the server. +# The excludes are anchored now; this check is what makes a recurrence loud. +missing="" +for manifest in "$WORK"/plugins/*/manifest.json; do + [ -e "$manifest" ] || continue + plugin=$(basename "$(dirname "$manifest")") + [ -f "$PUB/plugins/$plugin/manifest.json" ] || missing="$missing $plugin" +done +if [ -n "$missing" ]; then + echo "ERROR: bundled plugin(s) missing from the publication tree:$missing" >&2 + echo " an rsync --exclude above is matching them; anchor it with a leading slash." >&2 + exit 1 +fi + cd "$PUB" # --- 2. re-apply the publication wording (idempotent) ---