feat(e2e): add run-on-host.sh for automated cron on railiance01

CUST-WP-0028-T06:
- e2e/run-on-host.sh: standalone script for native execution on railiance01
  (no SSH from workstation). git pull → compose up → health wait →
  test_full_flow.py → compose down → report to state-hub via ops-bridge.

Install via: make e2e-cron-install REPO=activity-core  (from ~/the-custodian)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-27 01:02:21 +01:00
parent a57eee51f4
commit 6ef34b4e0d

74
e2e/run-on-host.sh Executable file
View File

@@ -0,0 +1,74 @@
#!/usr/bin/env bash
# activity-core E2E — runs natively on the sandbox host (railiance01).
# Installed as a cron job via: make e2e-cron-install (from ~/the-custodian)
#
# Cron line (Sunday 03:13):
# 13 3 * * 0 /home/tegwick/activity-core/e2e/run-on-host.sh >> /var/log/activity-core-e2e.log 2>&1
#
# Env vars (override defaults by exporting before calling or editing cron):
# REPO_DIR path to activity-core checkout (default: dirname of this script's parent)
# STATE_HUB_URL state-hub API base (default: http://127.0.0.1:18000 via ops-bridge)
# ACTCORE_DB_URL app DB connection string
# TEMPORAL_HOST Temporal frontend (default: localhost:7233)
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_DIR="${REPO_DIR:-$(dirname "$SCRIPT_DIR")}"
STATE_HUB_URL="${STATE_HUB_URL:-http://127.0.0.1:18000}"
ACTCORE_DB_URL="${ACTCORE_DB_URL:-postgresql+asyncpg://actcore:actcore@localhost:5433/actcore}"
TEMPORAL_HOST="${TEMPORAL_HOST:-localhost:7233}"
START_TS=$(date +%s)
echo "=== activity-core E2E ==="
echo "Start: $(date -u +%Y-%m-%dT%H:%M:%SZ)"
echo "Repo: $REPO_DIR"
# ── 1. Pull latest code ──────────────────────────────────────────────────────
echo "--- git pull"
cd "$REPO_DIR"
git pull --ff-only || { echo "WARN: git pull failed — continuing with current checkout"; true; }
# ── 2. Start stack ───────────────────────────────────────────────────────────
echo "--- docker compose up"
docker compose -f docker-compose.dev.yml up -d
# ── 3. Wait for Temporal UI (proxy for full stack health) ────────────────────
echo "--- waiting for Temporal UI (up to 180s)"
DEADLINE=$(( $(date +%s) + 180 ))
while ! curl -sf --max-time 5 http://localhost:8080 > /dev/null 2>&1; do
if [ "$(date +%s)" -ge "$DEADLINE" ]; then
echo "FAIL: Temporal UI did not become healthy within 180s"
docker compose -f docker-compose.dev.yml down -v --remove-orphans || true
exit 1
fi
sleep 5
done
echo "Temporal UI is up"
# ── 4. Run tests ─────────────────────────────────────────────────────────────
echo "--- running test_full_flow.py"
EXIT_CODE=0
ACTCORE_DB_URL="$ACTCORE_DB_URL" TEMPORAL_HOST="$TEMPORAL_HOST" \
uv run python e2e/tests/test_full_flow.py || EXIT_CODE=$?
# ── 5. Tear down stack ───────────────────────────────────────────────────────
echo "--- docker compose down"
docker compose -f docker-compose.dev.yml down -v --remove-orphans || true
# ── 6. Report to state-hub ───────────────────────────────────────────────────
END_TS=$(date +%s)
DURATION=$(( END_TS - START_TS ))
PASSED=$([ "$EXIT_CODE" -eq 0 ] && echo "true" || echo "false")
SUMMARY="E2E $([ "$EXIT_CODE" -eq 0 ] && echo 'PASSED' || echo 'FAILED'): activity-core (${DURATION}s, $(date -u +%Y-%m-%dT%H:%M:%SZ))"
DETAILS="{\"event_type\":\"e2e_result\",\"repo\":\"activity-core\",\"passed\":$PASSED,\"exit_code\":$EXIT_CODE,\"duration_s\":$DURATION,\"host\":\"$(hostname)\"}"
curl -sf -X POST "$STATE_HUB_URL/progress/" \
-H "Content-Type: application/json" \
-d "{\"summary\":\"$SUMMARY\",\"details\":\"$DETAILS\",\"event_type\":\"e2e_result\"}" \
&& echo "Result posted to state-hub" \
|| echo "WARN: could not reach state-hub at $STATE_HUB_URL"
echo "=== $([ "$EXIT_CODE" -eq 0 ] && echo 'PASSED' || echo 'FAILED') (exit=$EXIT_CODE, ${DURATION}s) ==="
exit $EXIT_CODE