Add optional Cosmos/Engine-X/act-runner templates, CWUSDC/EI-matrix tooling, non-EVM route planner in multi-chain-execution (tests passing), token list and extraction updates, and documentation (MetaMask matrix, GRU/CWUSDC packets). Ignore institutional evidence tarballs/sha256 under reports/status. Validated with: bash scripts/verify/run-all-validation.sh --skip-genesis Co-authored-by: Cursor <cursoragent@cursor.com>
73 lines
2.1 KiB
Bash
Executable File
73 lines
2.1 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Delete Gitea Actions runners that are **offline** (stale rows after re-register).
|
|
# Uses Admin API — requires GITEA_TOKEN (admin) in repo root .env.
|
|
#
|
|
# Usage (repo root):
|
|
# bash scripts/dev-vm/delete-offline-gitea-actions-runners.sh --dry-run
|
|
# bash scripts/dev-vm/delete-offline-gitea-actions-runners.sh --apply
|
|
#
|
|
# Over SSH (from a host with this repo and .env):
|
|
# ssh user@workstation 'cd /path/to/proxmox && bash scripts/dev-vm/delete-offline-gitea-actions-runners.sh --apply'
|
|
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
|
|
[[ -f "${PROJECT_ROOT}/.env" ]] && set -a && source "${PROJECT_ROOT}/.env" && set +a
|
|
|
|
GITEA_URL="${GITEA_URL:-https://gitea.d-bis.org}"
|
|
GITEA_URL="${GITEA_URL%/}"
|
|
MODE="${1:-}"
|
|
|
|
if [[ -z "${GITEA_TOKEN:-}" ]]; then
|
|
echo "ERROR: GITEA_TOKEN not set (root .env)." >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [[ "$MODE" != "--dry-run" && "$MODE" != "--apply" ]]; then
|
|
echo "Usage: $0 --dry-run | --apply" >&2
|
|
exit 1
|
|
fi
|
|
|
|
export GITEA_URL GITEA_TOKEN
|
|
export DELETE_MODE="$MODE"
|
|
|
|
python3 <<'PY'
|
|
import json, os, sys, urllib.request
|
|
|
|
base = os.environ["GITEA_URL"].rstrip("/")
|
|
token = os.environ["GITEA_TOKEN"]
|
|
mode = os.environ["DELETE_MODE"]
|
|
|
|
req = urllib.request.Request(
|
|
f"{base}/api/v1/admin/actions/runners?limit=100",
|
|
headers={"Authorization": f"token {token}"},
|
|
)
|
|
with urllib.request.urlopen(req, timeout=60) as resp:
|
|
data = json.loads(resp.read().decode())
|
|
|
|
runners = data.get("runners") or []
|
|
offline = [r for r in runners if r.get("status") == "offline"]
|
|
|
|
if not offline:
|
|
print("No offline runners.")
|
|
sys.exit(0)
|
|
|
|
for r in offline:
|
|
print(f"offline id={r.get('id')} name={r.get('name')!r}")
|
|
|
|
if mode == "--dry-run":
|
|
print("--dry-run: no DELETE issued.")
|
|
sys.exit(0)
|
|
|
|
for r in offline:
|
|
rid = r["id"]
|
|
dreq = urllib.request.Request(
|
|
f"{base}/api/v1/admin/actions/runners/{rid}",
|
|
method="DELETE",
|
|
headers={"Authorization": f"token {token}"},
|
|
)
|
|
with urllib.request.urlopen(dreq, timeout=60) as resp:
|
|
print(f"DELETE runner id={rid} -> HTTP {resp.status}")
|
|
PY
|