162 lines
6.0 KiB
Bash
Executable File
162 lines
6.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# CASAN level-based release packager.
|
|
#
|
|
# scripts/package-release.sh core # Level 1 — always buildable
|
|
# scripts/package-release.sh devkit # Level 2 — always buildable
|
|
# scripts/package-release.sh platform # Level 3 — PREVIEW (dashboard only today)
|
|
# scripts/package-release.sh all-in-one-demo # everything runnable + OKR demo domain
|
|
# scripts/package-release.sh enterprise # Level 4 — FUTURE → fails clearly
|
|
#
|
|
# Contents + maturity are driven by packaging/levels.json (single source of truth).
|
|
# A bundle whose level is `future` is REFUSED (no fake-complete package). A `preview`
|
|
# bundle is built but clearly stamped PREVIEW/INCOMPLETE and named *-preview.
|
|
set -euo pipefail
|
|
|
|
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
cd "$ROOT"
|
|
MANIFEST="packaging/levels.json"
|
|
VERSION="$(cat VERSION 2>/dev/null || echo 0.0.0)"
|
|
DIST="${CASAN_DIST_DIR:-$ROOT/dist}"
|
|
|
|
BUNDLE="${1:-}"
|
|
if [[ -z "$BUNDLE" ]]; then
|
|
echo "Usage: package-release.sh <core|devkit|platform|all-in-one-demo|enterprise>" >&2
|
|
exit 64
|
|
fi
|
|
[[ -f "$MANIFEST" ]] || { echo "package-release: missing $MANIFEST" >&2; exit 1; }
|
|
|
|
# --- read bundle definition from the manifest via python3 ---------------------
|
|
read -r BUNDLE_STATUS BUILDS < <(python3 - "$MANIFEST" "$BUNDLE" <<'PY'
|
|
import json, sys
|
|
m = json.load(open(sys.argv[1])); b = sys.argv[2]
|
|
bundles = m["bundles"]
|
|
if b not in bundles:
|
|
print("UNKNOWN -"); sys.exit(0)
|
|
spec = bundles[b]
|
|
print(spec.get("status", "unknown"), ",".join(spec.get("builds", [])))
|
|
PY
|
|
)
|
|
|
|
if [[ "$BUNDLE_STATUS" == "UNKNOWN" ]]; then
|
|
echo "package-release: unknown bundle '$BUNDLE'. Valid: core devkit platform all-in-one-demo enterprise" >&2
|
|
exit 64
|
|
fi
|
|
|
|
# --- refuse to build a fake-complete package for a not-implemented level -------
|
|
if [[ "$BUNDLE_STATUS" == "future" ]]; then
|
|
cat >&2 <<EOF
|
|
package-release: '$BUNDLE' is a FUTURE / structure-only level — refusing to build.
|
|
|
|
Level 4 (enterprise / governed console) is documented + scaffolded but NOT implemented
|
|
in this task. Some building blocks already exist inside core (RBAC, tenant isolation,
|
|
approval workflow, KMS, WORM) — see packages/casan-enterprise/README.md — but the
|
|
Governed Chat Console / Prompt Router / Model-Provider Management do not exist yet, so
|
|
no 'complete' enterprise artifact can be produced. This is intentional (no fake-complete
|
|
packages). Build 'core', 'devkit', 'platform', or 'all-in-one-demo' instead.
|
|
EOF
|
|
exit 3
|
|
fi
|
|
|
|
PREVIEW=0
|
|
SUFFIX=""
|
|
[[ "$BUNDLE_STATUS" == "preview" ]] && { PREVIEW=1; SUFFIX="-preview"; }
|
|
|
|
# --- gather include globs for the levels this bundle builds -------------------
|
|
gather_includes() { # <level>
|
|
python3 - "$MANIFEST" "$1" <<'PY'
|
|
import json, sys
|
|
m = json.load(open(sys.argv[1])); lvl = sys.argv[2]
|
|
# a "level" here is a levels.* key; the demo pseudo-paths are handled by the caller
|
|
node = m["levels"].get(lvl)
|
|
if node:
|
|
for inc in node.get("includes", []):
|
|
print(inc)
|
|
PY
|
|
}
|
|
|
|
STAGE="$(mktemp -d)"
|
|
PKGDIR="$STAGE/casan-$BUNDLE$SUFFIX-v$VERSION"
|
|
mkdir -p "$PKGDIR"
|
|
trap 'rm -rf "$STAGE"' EXIT
|
|
|
|
copy_path() { # <relpath>
|
|
local src="$ROOT/$1"
|
|
if [[ ! -e "$src" ]]; then
|
|
echo " ! skip (missing): $1" >&2
|
|
return 0
|
|
fi
|
|
local dest="$PKGDIR/$1"
|
|
mkdir -p "$(dirname "$dest")"
|
|
case "$1" in
|
|
packages/casan-harness)
|
|
python3 "$ROOT/scripts/copy-runtime.py" \
|
|
--source-root "$ROOT" --destination-root "$PKGDIR" --component harness
|
|
return
|
|
;;
|
|
packages/casan-devkit)
|
|
python3 "$ROOT/scripts/copy-runtime.py" \
|
|
--source-root "$ROOT" --destination-root "$PKGDIR" --component devkit
|
|
return
|
|
;;
|
|
esac
|
|
# copy, dropping caches/artifacts
|
|
if [[ -d "$src" ]]; then
|
|
rsync -a --exclude='__pycache__' --exclude='*.pyc' --exclude='.DS_Store' "$src/" "$dest/" 2>/dev/null \
|
|
|| cp -R "$src/" "$dest/"
|
|
else
|
|
cp "$src" "$dest"
|
|
fi
|
|
}
|
|
|
|
echo "==> building bundle '$BUNDLE' (status=$BUNDLE_STATUS) version=$VERSION"
|
|
SEEN=" " # space-delimited dedup (bash 3.2 compatible — no associative arrays)
|
|
seen() { case "$SEEN" in *" $1 "*) return 0;; *) SEEN="$SEEN$1 "; return 1;; esac; }
|
|
IFS=',' read -ra LEVELS <<< "$BUILDS"
|
|
for lvl in "${LEVELS[@]}"; do
|
|
# Entries that are level keys (core/devkit/platform/enterprise) expand via the manifest;
|
|
# anything else is a literal path (demo snapshot: backend, frontend, apps/okr/domain, ...).
|
|
case "$lvl" in
|
|
core|devkit|platform|enterprise) ;;
|
|
*) seen "$lvl" && continue
|
|
echo " + $lvl"; copy_path "$lvl"; continue ;;
|
|
esac
|
|
echo " level: $lvl"
|
|
while IFS= read -r inc; do
|
|
[[ -z "$inc" ]] && continue
|
|
seen "$inc" && continue
|
|
echo " + $inc"; copy_path "$inc"
|
|
done < <(gather_includes "$lvl")
|
|
done
|
|
|
|
# --- bundle manifest + preview notice ----------------------------------------
|
|
{
|
|
echo "CASAN release bundle"
|
|
echo "bundle: $BUNDLE"
|
|
echo "version: $VERSION"
|
|
echo "status: $BUNDLE_STATUS"
|
|
echo "built: $(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
echo "builds: $BUILDS"
|
|
} > "$PKGDIR/BUNDLE-MANIFEST.txt"
|
|
|
|
if [[ "$PREVIEW" == 1 ]]; then
|
|
cat > "$PKGDIR/PREVIEW-INCOMPLETE.txt" <<EOF
|
|
⚠️ PREVIEW / INCOMPLETE BUNDLE — NOT production-complete.
|
|
|
|
This '$BUNDLE' bundle is a PREVIEW. Only the components that exist today are included
|
|
(see packaging/levels.json -> levels.$BUNDLE.implemented_components). Pending components
|
|
are listed under pending_components. Do not treat this as a finished product.
|
|
EOF
|
|
fi
|
|
|
|
# --- checksums + tar ----------------------------------------------------------
|
|
( cd "$PKGDIR" && find . -type f ! -name SHA256SUMS -print0 | sort -z | xargs -0 shasum -a 256 > SHA256SUMS 2>/dev/null || true )
|
|
mkdir -p "$DIST"
|
|
ARTIFACT="casan-$BUNDLE$SUFFIX-v$VERSION.tar.gz"
|
|
tar -czf "$DIST/$ARTIFACT" -C "$STAGE" "casan-$BUNDLE$SUFFIX-v$VERSION"
|
|
SIZE="$(du -h "$DIST/$ARTIFACT" | cut -f1)"
|
|
( cd "$DIST" && shasum -a 256 "$ARTIFACT" > "$ARTIFACT.sha256" )
|
|
|
|
echo "==> BUILT $DIST/$ARTIFACT ($SIZE)"
|
|
[[ "$PREVIEW" == 1 ]] && echo " (PREVIEW — incomplete; see PREVIEW-INCOMPLETE.txt inside)"
|
|
echo " sha256: $(cut -d' ' -f1 "$DIST/$ARTIFACT.sha256")"
|