cocottetech/scripts/run/dist.sh
Natalie a12eedd2e0 docs: initialize placement-market feature design (client-facing discovery & placements marketplace) per approved plan
- README, parent brief with Key Decisions + 8-PR DAG
- placement-discovery sub-brief, specialist contract, screen
- 2 review rounds to 0 issues, all fixes applied
- Follows prospecting patterns, all V4 invariants, citations
2026-06-27 16:20:17 -04:00

161 lines
6.3 KiB
Bash
Executable file

#!/usr/bin/env bash
# Distributed test/build dispatch — fan the iteration loop across the DigitalOcean
# test fleet. Sourced by ./run (defines cmd_dist_*). Auto-registered via the
# cmd_<verb>_<target> name-dispatch, so no edit to the top-level `run` is needed.
#
# ./run dist:up <workers> [size] [region] spin the fleet up
# ./run dist:test run turbo test on a worker
# ./run dist:typecheck run turbo typecheck on a worker
# ./run dist:build run turbo build on a worker
# ./run dist:sync [ref] git pull + pnpm install on live workers
# ./run dist:down tear it down (zero cost)
#
# Requires: TF_VAR_do_token in env (or export in the calling shell), terraform on PATH.
# The monorepo pnpm root is @platform/.
_DIST_TF_DIR_REL="infra/terraform/test-fleet"
_dist_repo_root() { (cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd); }
_dist_tf() {
local root
root="$(_dist_repo_root)"
terraform -chdir="$root/$_DIST_TF_DIR_REL" "$@"
}
_dist_read_hosts() {
# Echo one "<user>@<ip>" per line from the inventory, skipping comments/blanks.
local inv="$1"
grep -vE '^\s*(#|$)' "$inv" 2>/dev/null || true
}
_dist_wait_ready() {
# Block until each worker's cloud-init finishes.
local root inv host ip
root="$(_dist_repo_root)"; inv="$root/.local/fleet/inventory"
[ -f "$inv" ] || return 0
while IFS= read -r host; do
ip="${host#*@}"
printf ' waiting for %s cloud-init... ' "$ip"
local _i
for _i in $(seq 1 36); do
ssh -n -o StrictHostKeyChecking=accept-new -o ConnectTimeout=8 -o BatchMode=yes -i ~/.ssh/id_cocotte_fleet "root@$ip" true 2>/dev/null && break
sleep 5
done
ssh -n -o BatchMode=yes -i ~/.ssh/id_cocotte_fleet "root@$ip" 'cloud-init status --wait >/dev/null 2>&1 || true' 2>/dev/null
echo "ready"
done < <(_dist_read_hosts "$inv")
}
cmd_dist() {
cat <<'EOF'
Distributed test/build fleet (DigitalOcean). Set TF_VAR_do_token first.
./run dist:check offline: fmt + validate + mocked test (no token/spend)
./run dist:up <workers> [size] [region] e.g. ./run dist:up 4
./run dist:test turbo test on first worker (offload heavy work)
./run dist:typecheck turbo typecheck on first worker
./run dist:build turbo build on first worker (artifacts rsync optional)
./run dist:sync [ref] git pull + pnpm on live workers
./run dist:down
EOF
}
cmd_dist_check() {
# Offline IaC verification — no DigitalOcean token, no API, no servers, no cost.
local root
root="$(_dist_repo_root)"
local dir="$root/$_DIST_TF_DIR_REL"
echo "== terraform fmt =="
terraform -chdir="$dir" fmt -check -recursive || { echo "fmt: run 'terraform -chdir=$dir fmt'" >&2; return 1; }
echo "== terraform init (providers only) =="
terraform -chdir="$dir" init -backend=false -input=false >/dev/null || return 1
echo "== terraform validate (schema typecheck) =="
terraform -chdir="$dir" validate || return 1
echo "== terraform test (mocked digitalocean) =="
terraform -chdir="$dir" test || return 1
echo "dist:check OK — config is valid, no resources touched."
}
cmd_dist_up() {
local n="${1:-}"
[[ "$n" =~ ^[0-9]+$ ]] || { echo "usage: ./run dist:up <workers> [size] [region]" >&2; return 1; }
: "${TF_VAR_do_token:?export TF_VAR_do_token=<DigitalOcean API token> first}"
local args=(-auto-approve -var "workers=$n")
[ -n "${2:-}" ] && args+=(-var "size=$2")
[ -n "${3:-}" ] && args+=(-var "region=$3")
_dist_tf init -input=false >/dev/null
_dist_tf apply "${args[@]}" || { echo "dist:up FAILED — terraform apply errored (see above)" >&2; return 1; }
echo "fleet up: $n worker(s) — waiting for cloud-init before they're usable..."
_dist_wait_ready
echo "fleet ready. inventory: $(_dist_repo_root)/.local/fleet/inventory"
}
cmd_dist_down() {
: "${TF_VAR_do_token:?export TF_VAR_do_token=<DigitalOcean API token> first}"
_dist_tf apply -auto-approve -var "workers=0"
echo "fleet down (workers=0): zero compute cost, snapshot only (~$0.40/mo)."
}
_dist_first_host() {
local inv
inv="$(_dist_repo_root)/.local/fleet/inventory"
[ -f "$inv" ] || return 1
_dist_read_hosts "$inv" | head -1
}
cmd_dist_sync() {
local ref="${1:-main}"
local root inv host
root="$(_dist_repo_root)"
inv="$root/.local/fleet/inventory"
[ -f "$inv" ] || { echo "no fleet — run ./run dist:up <N> first" >&2; return 1; }
local pids=() fail=0
while IFS= read -r host; do
echo "[$host] sync → $ref"
ssh -n -o BatchMode=yes -o StrictHostKeyChecking=accept-new "$host" "
set -e
cd ~/Code/@projects/@cocottetech
git fetch --depth=1 origin '$ref' && git reset --hard FETCH_HEAD
cd @platform && pnpm install --frozen-lockfile --prefer-offline
" &
pids+=($!)
done < <(_dist_read_hosts "$inv")
for p in "${pids[@]}"; do wait "$p" || fail=$(( fail + 1 )); done
[ "$fail" -eq 0 ] && echo "synced all workers to $ref" || { echo "$fail worker(s) failed sync" >&2; return 1; }
}
cmd_dist_test() {
local host
host="$(_dist_first_host)" || { echo "no fleet — run ./run dist:up 1 first" >&2; return 1; }
echo "[dist:test] running on $host ..."
ssh -o BatchMode=yes -o StrictHostKeyChecking=accept-new "$host" '
set -e
cd ~/Code/@projects/@cocottetech/@platform
pnpm test
'
}
cmd_dist_typecheck() {
local host
host="$(_dist_first_host)" || { echo "no fleet — run ./run dist:up 1 first" >&2; return 1; }
echo "[dist:typecheck] running on $host ..."
ssh -o BatchMode=yes -o StrictHostKeyChecking=accept-new "$host" '
set -e
cd ~/Code/@projects/@cocottetech/@platform
pnpm typecheck
'
}
cmd_dist_build() {
local host root
host="$(_dist_first_host)" || { echo "no fleet — run ./run dist:up 1 first" >&2; return 1; }
root="$(_dist_repo_root)"
echo "[dist:build] running on $host ..."
ssh -o BatchMode=yes -o StrictHostKeyChecking=accept-new "$host" '
set -e
cd ~/Code/@projects/@cocottetech/@platform
pnpm build
'
# Optionally rsync dist/ artifacts back if you extend for specific packages.
echo "build complete on worker (no auto-rsync of artifacts; extend cmd_dist_build if needed)."
}