Files
shopdb-flask/tools/export-github.sh
cproudlock bec138f5ac build(export): keep the installer's staged bundle out of publication
The sync walks the working tree rather than git, so deploy/windows/installer/
bundle came through despite being gitignored - about 100MB of build output
containing a copy of the whole application tree, the wheels and the vendor
installers. Its copies of config.py and requirements.txt then tripped the scrub
gate, which is the only reason it was noticed.

Excluded along with the installer's other generated files. Note that rsync
--exclude also protects a path from --delete, so a copy already in the
publication tree has to be removed by hand once.
2026-08-03 15:09:13 -04:00

147 lines
5.8 KiB
Bash
Executable File

#!/bin/bash
# Export the working repo to the GitHub publication repo and emit a bundle.
#
# Pipeline: working repo (full history, internal refs) -> pruned/scrubbed
# tree -> commit in ~/projects/shopdb-flask-pub (the local mirror of what
# enterprise GitHub holds) -> full git bundle in /home/camp/pxe-images/ for
# transfer to the work PC, which pushes it to GitHub.
#
# Usage:
# tools/export-github.sh "Commit message for the publication commit"
# tools/export-github.sh --dist # also rebuild BOTH frontend dists
# # (/ops = dev, /shopdb = prod)
#
# This script lives in tools/, which is itself excluded from publication.
set -euo pipefail
WORK=/home/camp/projects/shopdb-flask
PUB=/home/camp/projects/shopdb-flask-pub
OUT=/home/camp/pxe-images/github
BUILD_DIST=0
MSG=""
for arg in "$@"; do
case "$arg" in
--dist) BUILD_DIST=1 ;;
*) MSG="$arg" ;;
esac
done
[ -n "$MSG" ] || { echo "usage: $0 [--dist] \"commit message\""; exit 1; }
[ -d "$PUB/.git" ] || { echo "publication repo missing at $PUB"; exit 1; }
# --- 1. sync the tree (working -> pub), minus everything never published ---
#
# NOTE the deploy/windows/installer/bundle exclude below. That is ~100MB of build
# output holding a COPY of the whole application tree plus the wheels and vendor
# installers. It is gitignored, but this sync walks the WORKING TREE rather than
# git, so it came through anyway - and its copies of config.py and
# requirements.txt then tripped the scrub gate. Anything else generated into the
# working tree needs excluding here too, for the same reason.
rsync -a --delete \
--exclude '.git' \
--exclude '.gitea' \
--exclude 'docs' \
--exclude 'tools' \
--exclude 'mcp' \
--exclude 'start-api.sh' \
--exclude 'start-ui.sh' \
--exclude 'CLAUDE.md' \
--exclude 'frontend/CLAUDE.md' \
--exclude 'tests/test_docs_contract.py' \
--exclude 'tests/test_plugins/test_geenforce_parity.py' \
--exclude 'tests/test_plugins/test_zabbix_live.py' \
--exclude 'venv' \
--exclude 'node_modules' \
--exclude 'deploy/windows/installer/bundle' \
--exclude 'deploy/windows/installer/Output' \
--exclude 'deploy/windows/installer/plugins.iss' \
--exclude 'deploy/windows/installer/version.iss' \
--exclude 'frontend/dist*' \
--exclude 'frontend/src/.plugins-staged' \
--exclude 'frontend/src/router/routes.gen.js' \
--exclude 'instance' \
--exclude '.env' \
--exclude '__pycache__' \
--exclude '*.pyc' \
--exclude 'scripts/site_imports/wjf/idmap.json' \
"$WORK/" "$PUB/"
cd "$PUB"
# --- 2. re-apply the publication wording (idempotent) ---
# docs/ lives only in the wiki on the GitHub side.
grep -rlZ 'docs/' --include='*.py' --include='*.md' --include='*.sh' \
--include='*.tmpl' --include='*.vue' --include='*.example' . 2>/dev/null |
while IFS= read -r -d '' f; do
case "$f" in ./CHANGELOG.md) continue ;; esac
sed -i -E \
-e 's/\[`?docs\/([A-Za-z0-9_-]+)\.md`?\]\((\.\.\/)*docs\/[A-Za-z0-9_-]+\.md\)/the \1 page in the project wiki/g' \
-e 's/docs\/proposals\/ge-enforce-plugin\.md/the ge-enforce-plugin proposal in the project wiki/g' \
-e 's/`docs\/([A-Za-z0-9_-]+)\.md`/the \1 wiki page/g' \
-e 's/docs\/([A-Za-z0-9_-]+)\.md/the \1 wiki page/g' "$f"
done
sed -i 's|<code>docs/GE-ENFORCE.md</code>|the GE-ENFORCE page in the project wiki|' \
frontend/src/views/geenforce/ManifestEditor.vue 2>/dev/null || true
# internal infra never named on GitHub; this repo's own URL maps to the
# real GitHub home, anything else degrades to a placeholder.
GITHUB_URL='https://github.com/ge-aero/shopdb-flask'
grep -rlZ 'gitea\.proudtech\.net' . 2>/dev/null | while IFS= read -r -d '' f; do
sed -i -e "s|https://gitea\.proudtech\.net/ge-aerospace/shopdb-flask|$GITHUB_URL|g" \
-e 's|gitea\.proudtech\.net|<git-host>|g' "$f"
done
grep -rlZi 'gitea' --exclude-dir=.git . 2>/dev/null | while IFS= read -r -d '' f; do
sed -i -e 's/the GE Aerospace Gitea/the internal GE Aerospace git server/g' \
-e 's/Gitea Actions CI/CI/g' \
-e 's/Gitea Actions/CI/g' "$f"
done
# CHANGELOG compare/release link definitions reference tags that do not
# exist on GitHub (history is squashed there) - drop them.
sed -i '/^\[[^]]*\]: .*\/\(compare\|releases\)\//d' CHANGELOG.md
# frontend/CLAUDE.md publishes under a neutral name
if [ -f "$WORK/frontend/CLAUDE.md" ]; then
cp "$WORK/frontend/CLAUDE.md" frontend/DEVELOPMENT-STANDARDS.md
fi
sed -i "s/rootpassword/changeme/g" shopdb/config.py 2>/dev/null || true
# --- 3. scrub gate: refuse to commit if anything internal leaks ---
LEAKS=$(grep -rlIiE 'claude|anthropic|fable 5|gitea|proudtech|home/camp|rootpassword' \
--exclude-dir=.git . || true)
if [ -n "$LEAKS" ]; then
echo "SCRUB GATE FAILED - internal references in:"; echo "$LEAKS"; exit 1
fi
# --- 4. commit (no-op safe) ---
git add -A
if git diff --cached --quiet; then
echo "no changes vs publication tree - nothing to export"
else
git commit -m "$MSG"
fi
git log --oneline -3
# --- 5. bundle for transfer (full bundle: stateless, fetch takes only new) ---
git bundle create "$OUT/shopdb-flask-pub.bundle" HEAD main --tags
git bundle verify "$OUT/shopdb-flask-pub.bundle" >/dev/null
echo "bundle: $OUT/shopdb-flask-pub.bundle"
# --- 6. optional per-instance dists (both bases: /ops = dev, /shopdb = prod) ---
# Two instances run on the box; each needs its own base-path build. Always
# rebuild BOTH so prod never ships a stale frontend.
if [ "$BUILD_DIST" = 1 ]; then
cd "$WORK/frontend"
for base in ops shopdb; do
VITE_BASE_PATH=/$base/ npm run build --silent
rm -rf "$OUT/frontend-dist-subpath-$base"
cp -r dist "$OUT/frontend-dist-subpath-$base"
echo "dist: $OUT/frontend-dist-subpath-$base/ (base /$base/)"
done
fi
cat <<'EOF'
On the work PC (in the shopdb-flask-pub clone):
git fetch <path-to>\shopdb-flask-pub.bundle main
git merge --ff-only FETCH_HEAD
git push origin main
EOF