#!/usr/bin/env bash # # seed-demo.sh — Popola ASF con i dati DEMO del tenant t-demo-003. # # Sequenza (idempotente dal lato API - POST ritorna 201 per nuovi artifact, # ma se seed precedenti esistono già verrà creato duplicato perché non abbiamo # un controllo unique ext_id in questa fase MVP. Per sicurezza cancella TUTTI # artifacts + jobs prima di ricreare quando si specifica --clean. # # Usage: # ./scripts/seed-demo.sh # seeds normali (3 blocchi trace + code + extra) # ./scripts/seed-demo.sh --clean # PURGA artifacts + jobs t-demo-003 POI seed # ./scripts/seed-demo.sh --jobs # + 5 job echo demo in coda (devops/testing/...) # # Richiede: # • ASF Core attivo su http://localhost:8000 (scripts/start-stack.sh) # • Python .venv attivo o eseguibile in /root/ASF/.venv/bin/python # • Worker attivo se usi --jobs (altrimenti jobs stanno in QUEUED) # set -euo pipefail ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" PY="$ROOT/.venv/bin/python" CORE_URL="${ASF_CORE_URL:-http://localhost:8000}" TENANT="${X_ASF_TENANT_ID:-t-demo-003}" USER="${X_ASF_USER_ID:-u-mario}" CLEAN=0 JOBS=0 for arg in "$@"; do case "$arg" in --clean) CLEAN=1 ;; --jobs) JOBS=1 ;; -h|--help) sed -n '2,26p' "$0" exit 0 ;; esac done log() { printf " \033[1;34m→\033[0m %s\n" "$*"; } ok() { printf " \033[1;32m✔\033[0m %s\n" "$*"; } fail() { printf " \033[1;31m✘\033[0m %s\n" "$*" >&2; exit 1; } curl_h() { # $1 = method, $2 = path, stdin optional body. Prints status + JSON body. local m="$1" p="$2" shift 2 curl -s -X "$m" -H "X-ASF-Tenant-Id: $TENANT" -H "X-ASF-User-Id: $USER" \ -H "Content-Type: application/json" \ "${CORE_URL}/api/v1${p}" "$@" } # --- Sanity check: Core UP --- log "ASF Core health check su $CORE_URL" H=$(curl -s -o /dev/null -w "%{http_code}" "${CORE_URL}/api/v1/health" || true) if [[ "$H" != "200" ]]; then fail "ASF Core non risponde (HTTP $H). Avvia con: bash scripts/start-stack.sh" fi ok "ASF Core UP (health=$H)" # --- Cleanup (opzionale) --- if [[ $CLEAN == 1 ]]; then log "Cleanup artifacts + jobs per tenant $TENANT (DELETE /artifacts e /jobs listati)" # MVP: asf-core non espone DELETE /artifacts bulk. Useremo GET lista + DELETE /artifacts/{id}. A_IDS=$(curl_h GET "/artifacts?limit=500" | "$PY" -c ' import json,sys d=json.load(sys.stdin) for a in d: print(a["id"]) ') N_A=$(echo -n "$A_IDS" | grep -c . || true) log " DELETE $N_A artifacts..." if [[ -n "$A_IDS" ]]; then while read -r id; do curl -s -o /dev/null -X DELETE \ -H "X-ASF-Tenant-Id: $TENANT" -H "X-ASF-User-Id: $USER" \ "${CORE_URL}/api/v1/artifacts/${id}" || true done <<< "$A_IDS" fi J_IDS=$(curl_h GET "/jobs?limit=500" | "$PY" -c ' import json,sys d=json.load(sys.stdin) for j in d: print(j["id"]) ' 2>/dev/null || true) N_J=$(echo -n "$J_IDS" | grep -c . || true) log " PATCH CANCEL $N_J jobs..." if [[ -n "$J_IDS" ]]; then while read -r id; do curl -s -o /dev/null -X PATCH \ -H "X-ASF-Tenant-Id: $TENANT" -H "X-ASF-User-Id: $USER" \ -H "Content-Type: application/json" \ -d '{"status":"cancelled"}' \ "${CORE_URL}/api/v1/jobs/${id}" || true done <<< "$J_IDS" fi ok "Cleanup completato" fi # --- Seeds --- log "Seed 1/4: Traceability artifacts (REQ → TASK → PR → TEST/BUILD → DEPLOY)" "$PY" "$ROOT/scripts/seed-traceability.py" >/tmp/seed1.log 2>&1 \ || fail "seed-traceability fallito. Log: /tmp/seed1.log" ok " OK ($(wc -l < /tmp/seed1.log) righe log)" log "Seed 2/4: Relazioni traceability (5 edges: implements/verifies/deployed_as/generated_from)" "$PY" "$ROOT/scripts/seed-rels-only.py" >/tmp/seed2.log 2>&1 \ || fail "seed-rels fallito. Log: /tmp/seed2.log" ok " OK ($(wc -l < /tmp/seed2.log) righe log)" log "Seed 3/4: Source files + Code smells (3 files, 3 smells)" "$PY" "$ROOT/scripts/seed-code-artifacts.py" >/tmp/seed3.log 2>&1 \ || fail "seed-code-artifacts fallito. Log: /tmp/seed3.log" ok " OK ($(wc -l < /tmp/seed3.log) righe log)" log "Seed 4/4: Extra DOC / COMMIT / SEC / INC + 4 relazioni (densify graph)" "$PY" "$ROOT/scripts/seed-extra-rels.py" >/tmp/seed4.log 2>&1 \ || fail "seed-extra-rels fallito. Log: /tmp/seed4.log" ok " OK ($(wc -l < /tmp/seed4.log) righe log)" # --- Jobs demo (opzionale) --- if [[ $JOBS == 1 ]]; then log "Enqueue 5 demo jobs (echo handler DEVOPS/TESTING/...)" OUT=$(curl -s -X POST \ -H "X-ASF-Tenant-Id: $TENANT" -H "X-ASF-User-Id: $USER" \ -H "Content-Type: application/json" \ --data-raw '{ "jobs": [ {"type":"devops","priority":"normal","payload":{"name":"deploy-dev","env":"dev"}}, {"type":"testing","priority":"high","payload":{"name":"smoke-tests","framework":"pytest"}}, {"type":"devops","priority":"normal","payload":{"name":"build-image","image":"asf/app:latest"}}, {"type":"notifications","priority":"low","payload":{"channel":"email","to":"admins"}}, {"type":"indexing","priority":"normal","payload":{"source":"github/asf","branch":"main"}} ] }' "${CORE_URL}/api/v1/jobs/batch" 2>&1 || echo "fallback") # Fallback per /batch non esistente (MVP usa singolo POST per job) if [[ "$OUT" == *"fallback"* || "$OUT" == *"Not Found"* || "$OUT" == *"404"* || "$OUT" == *"405"* ]]; then log " /batch non disponibile → 5 POST singoli:" TYPES=("devops" "testing" "devops" "notifications" "indexing") PAYLOADS=( '{"name":"deploy-dev","env":"dev"}' '{"name":"smoke-tests","framework":"pytest"}' '{"name":"build-image","image":"asf/app:latest"}' '{"channel":"email","to":"admins"}' '{"source":"github/asf","branch":"main"}' ) PRIO=("normal" "high" "normal" "low" "normal") for i in 0 1 2 3 4; do JS=$(curl -s -X POST \ -H "X-ASF-Tenant-Id: $TENANT" -H "X-ASF-User-Id: $USER" \ -H "Content-Type: application/json" \ -d "{\"type\":\"${TYPES[$i]}\",\"priority\":\"${PRIO[$i]}\",\"payload\":${PAYLOADS[$i]}}" \ "${CORE_URL}/api/v1/jobs/submit") echo -n "$JS" | "$PY" -c 'import json,sys; j=json.load(sys.stdin); print(" - job id=", j.get("id","?")[:8]+"…", "accepted=", j.get("accepted"))' 2>/dev/null done else ok " /batch accettato" fi ok "5 demo jobs accodati (avvia asf-worker per completarli)" fi # --- Report finale --- log "Report finale tenant $TENANT:" echo "" curl_h GET "/artifacts?limit=500" | "$PY" - <<'PY' import json,sys from collections import Counter d=json.load(sys.stdin) c=Counter(a.get("type","?") for a in d) print(" Artifacts totali:", len(d)) for k,v in sorted(c.items(), key=lambda x:-x[1]): print(f" - {k:18s} {v}") PY echo "" curl_h GET "/traceability/graph" 2>/dev/null | "$PY" -c ' import json,sys g=json.load(sys.stdin) print(f" Traceability graph: nodes={len(g.get(\"nodes\",[]))} edges={len(g.get(\"edges\",[]))}") ' 2>/dev/null || true echo "" curl_h GET "/jobs" 2>/dev/null | "$PY" - <<'PY' import json,sys from collections import Counter d=json.load(sys.stdin) c=Counter(j.get("status","?") for j in d) print(" Jobs totali:", len(d)) for k,v in sorted(c.items(), key=lambda x:-x[1]): print(f" - {k:10s} {v}") PY echo "" ok "SEED DEMO completato." echo "" echo " Suggerimenti:" echo " • Apri http://localhost:3000 per vedere UI (hard refresh Ctrl+Shift+R se serve)" echo " • bash scripts/status-stack.sh per stato core/web/worker" echo " • bash scripts/seed-demo.sh --clean --jobs per ricreare TUTTO da zero"