- 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
161 lines
6.3 KiB
Bash
Executable file
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)."
|
|
}
|