You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

137 lines
4.9 KiB
Bash

#!/usr/bin/env bash
# Cut a client-ready branch out of main: .env.example defaults set to only
# that client's licensed features, internal-only files stripped.
#
# Usage:
# scripts/export_client.sh <client-slug> <FLAG1,FLAG2,...> [--push <remote-url>]
#
# Flags are the VITE_ALLOW_ACCESS_<FLAG> suffixes already used in
# .env.example: EFFICIENCY, PFI, RELIABILITY, RISK_MATRIX, LCCA, RBD, OH,
# IRCFA, AHM. auth/dashboard/admin/ops-dock have no flag and always ship.
#
# Example:
# scripts/export_client.sh client-a EFFICIENCY,PFI
# scripts/export_client.sh client-a EFFICIENCY,PFI --push git@gitlab.client-a.com/fe-digitaltwin-v2.git
#
# Unlike the backend, this does NOT remove any src/features or src/pages
# folders — router/index.tsx statically imports every page regardless of
# flags (they're still code-split via lazy(), just all reachable by direct
# URL). Flags only hide nav entries. See GIT_BRANCHES.md for what that
# does and doesn't protect.
set -euo pipefail
cd "$(dirname "${BASH_SOURCE[0]}")/.."
ALL_FLAGS=(EFFICIENCY PFI RELIABILITY RISK_MATRIX LCCA RBD OH IRCFA AHM)
CLIENT_SLUG="${1:-}"
FLAGS_CSV="${2:-}"
PUSH_REMOTE=""
if [ "${3:-}" = "--push" ]; then
PUSH_REMOTE="${4:-}"
fi
if [ -z "$CLIENT_SLUG" ] || [ -z "$FLAGS_CSV" ]; then
echo "Usage: $0 <client-slug> <FLAG1,FLAG2,...> [--push <remote-url>]"
echo "Available flags: ${ALL_FLAGS[*]}"
exit 1
fi
if [ -n "$(git status --porcelain)" ]; then
echo "Working tree isn't clean. Commit or stash before exporting."
exit 1
fi
BRANCH="client/${CLIENT_SLUG}"
IFS=',' read -ra SELECTED_FLAGS <<< "$FLAGS_CSV"
for f in "${SELECTED_FLAGS[@]}"; do
known=false
for a in "${ALL_FLAGS[@]}"; do [ "$f" = "$a" ] && known=true; done
if [ "$known" = false ]; then
echo "Unknown flag '${f}'. Available: ${ALL_FLAGS[*]}"
exit 1
fi
done
echo "==> Building ${BRANCH} from main with flags: ${FLAGS_CSV}"
git checkout -q -B "$BRANCH" main
# --- 1. Set .env.example defaults so a plain `cp .env.example .env` on the
# client's side turns on only what they licensed. Does not touch a
# real .env — that's gitignored and never part of any branch. ---
FLAGS_CSV="$FLAGS_CSV" python3 - <<'PYEOF'
import os
import re
selected = set(os.environ["FLAGS_CSV"].split(","))
path = ".env.example"
with open(path) as f:
content = f.read()
def set_flag(match):
key = match.group(1)
value = "true" if key in selected else "false"
return f"VITE_ALLOW_ACCESS_{key}={value}"
content = re.sub(r"VITE_ALLOW_ACCESS_(\w+)=\w+", set_flag, content)
with open(path, "w") as f:
f.write(content)
PYEOF
# --- 2. Internal-only files that don't belong in a client's pipeline ---
[ -f Jenkinsfile ] && { git rm -q Jenkinsfile || rm -f Jenkinsfile; }
[ -d memory ] && { git rm -rq memory || rm -rf memory; } # dev notes, migration log
[ -d ref ] && { git rm -rq ref || rm -rf ref; } # PRD docs, reference screenshots
[ -d scripts ] && { git rm -rq scripts 2>/dev/null || rm -rf scripts; }
true
git add -A
git commit -q -m "Export for ${CLIENT_SLUG}: ${FLAGS_CSV}"
# --- 3. Merge in this client's permanent overlay branch, if one exists ---
# See GIT_BRANCHES.md — overlay/<slug> is an orphan branch, no shared
# history with main, holding only what's unique to this client: routes
# under src/router/overlay/, or other new files. Kept to additions only.
OVERLAY_BRANCH="overlay/${CLIENT_SLUG}"
if git show-ref --verify --quiet "refs/heads/${OVERLAY_BRANCH}"; then
echo "==> Merging ${OVERLAY_BRANCH}"
if ! git merge --no-edit --allow-unrelated-histories -m "Merge ${OVERLAY_BRANCH} into ${BRANCH}" "$OVERLAY_BRANCH"; then
echo
echo "Merging ${OVERLAY_BRANCH} conflicted — that means it touched a file"
echo "the base export also generates or already ships, which defeats the"
echo "point of an overlay. Resolve it here (or 'git merge --abort'), then"
echo "keep the overlay to new files only going forward."
exit 1
fi
fi
# --- 4. Guard: same idea as be-digitaltwin's — catch a leaked engine
# mention. Not a load-bearing check here (this repo talks to the
# engine only indirectly, through the backend's API), but cheap
# and consistent to keep. ---
if git grep -niE '\baimo\b' -- . ; then
echo "^^ literal mention found — this must stay generic."
exit 1
fi
# --- 5. Non-fatal: known gap this script does not fix. See GIT_BRANCHES.md. ---
if git grep -lqiE 'Logo_PLN|logo-tjb' -- src public 2>/dev/null; then
echo
echo "NOTE: this export still ships PLN/TJB-specific branding assets and"
echo "hardcoded references (logos, plant names). That's a real content"
echo "change, not something this script attempts — see GIT_BRANCHES.md."
fi
echo
echo "==> ${BRANCH} is ready ($(git rev-parse --short HEAD))."
if [ -n "$PUSH_REMOTE" ]; then
echo "==> Pushing to ${PUSH_REMOTE}"
git push "$PUSH_REMOTE" "${BRANCH}:main"
else
echo "Push manually when ready, e.g.:"
echo " git push <client-remote> ${BRANCH}:main"
fi
git checkout -q main