137 lines
8 KiB
Bash
Executable file
137 lines
8 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# Auslieferung für Integrationen (→ KONZEPT.md 14.7) Ende zu Ende:
|
|
# Server starten, Integrations-Key anlegen, Pakete veröffentlichen und
|
|
# hugin-install.ps1 gegen ein Test-Repo laufen lassen.
|
|
#
|
|
# PWSH=/pfad/zu/pwsh scripts/integration-test.sh
|
|
#
|
|
# Hinweis: Läuft hier mit PowerShell 7. Ziel ist Windows PowerShell 5.1; dort
|
|
# einmal von Hand prüfen (siehe README, „Integration testen“).
|
|
set -euo pipefail
|
|
|
|
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
PWSH="${PWSH:-pwsh}"
|
|
WORK="$(mktemp -d)"
|
|
PORT="${PORT:-8766}"
|
|
URL="http://127.0.0.1:$PORT"
|
|
export HUGIN_DATABASE_URL="sqlite:///$WORK/hugin.db"
|
|
export HUGIN_ADMIN_TOKEN="integration-admin"
|
|
ADMIN=(-H "Authorization: Bearer $HUGIN_ADMIN_TOKEN")
|
|
|
|
cleanup() {
|
|
local rc=$?
|
|
[[ -n "${SERVER:-}" ]] && kill "$SERVER" 2>/dev/null && wait "$SERVER" 2>/dev/null || true
|
|
if [[ -z "${KEEP:-}" ]]; then rm -rf "$WORK"; else echo "Arbeitsordner: $WORK"; fi
|
|
exit $rc
|
|
}
|
|
trap cleanup EXIT
|
|
|
|
api() { curl -fsS -H "Content-Type: application/json" "$@"; }
|
|
key() { python3 -c 'import json,sys; print(json.load(sys.stdin)["key"])'; }
|
|
|
|
(cd "$ROOT/server" && uv run -q hugin-server migrate)
|
|
(cd "$ROOT/server" && exec uv run -q hugin-server run --host 127.0.0.1 --port "$PORT") >"$WORK/server.log" 2>&1 &
|
|
SERVER=$!
|
|
for _ in $(seq 50); do curl -fsS "$URL/readyz" >/dev/null 2>&1 && break; sleep 0.2; done
|
|
|
|
api "${ADMIN[@]}" "$URL/api/v1/admin/tenants" -d '{"slug":"plattform","name":"Plattform"}' >/dev/null
|
|
api "${ADMIN[@]}" "$URL/api/v1/admin/tenants/plattform/projects" -d '{"slug":"kern","name":"Kern"}' >/dev/null
|
|
api "${ADMIN[@]}" "$URL/api/v1/admin/tenants" -d '{"slug":"werk","name":"Werk"}' >/dev/null
|
|
AUTHOR=$(api "${ADMIN[@]}" "$URL/api/v1/admin/tenants/plattform/keys" -d '{"kind":"project","name":"autor","project":"kern","roles":["pub_author"]}' | key)
|
|
REVIEWER=$(api "${ADMIN[@]}" "$URL/api/v1/admin/tenants/plattform/keys" -d '{"kind":"project","name":"pruefer","project":"kern","roles":["pub_reviewer"]}' | key)
|
|
INTEGRATION=$(api "${ADMIN[@]}" "$URL/api/v1/admin/tenants/werk/keys" -d '{"kind":"integration","name":"Softwareverteilung"}' | key)
|
|
|
|
publish() {
|
|
local zip="$WORK/package.zip"
|
|
rm -f "$zip"; (cd "$ROOT/contract/examples/packages/$1" && zip -qr "$zip" .)
|
|
curl -fsS -H "Authorization: Bearer $AUTHOR" -H "Content-Type: application/zip" --data-binary "@$zip" "$URL/api/v1/drafts" >/dev/null
|
|
local base="$URL/api/v1/packages/${1%/*}/versions/${1#*/}"
|
|
api -H "Authorization: Bearer $AUTHOR" -X POST "$base/submit" >/dev/null
|
|
api -H "Authorization: Bearer $REVIEWER" "$base/approve" -d '{}' >/dev/null
|
|
}
|
|
for p in pub-munin-nutzen/1.4.0 pub-hausregeln/1.0.0 pub-munin-anbindung/1.0.0 pub-code-review/1.0.0; do publish "$p"; done
|
|
curl -fsS "${ADMIN[@]}" -X PUT -H "Content-Type: application/json" "$URL/api/v1/admin/mandatory/pub-munin-anbindung" -d '{"tenant":null}'
|
|
|
|
echo "== Status und Übersicht"
|
|
curl -fsS -H "Authorization: Bearer $INTEGRATION" "$URL/api/v1/delivery/status"; echo
|
|
curl -fsS -H "Authorization: Bearer $INTEGRATION" "$URL/api/v1/delivery/packages" | python3 -c 'import json,sys; print([(p["id"], p["channels"]) for p in json.load(sys.stdin)])'
|
|
code=$(curl -s -o /dev/null -w '%{http_code}' -H "Authorization: Bearer $AUTHOR" "$URL/api/v1/delivery/status")
|
|
[[ $code == 403 ]] || { echo "Projekt-Key hätte abgelehnt werden müssen ($code)"; exit 1; }
|
|
|
|
echo "== Skript laden und ausführen"
|
|
curl -fsS -H "Authorization: Bearer $INTEGRATION" "$URL/api/v1/delivery/client.ps1" -o "$WORK/hugin-install.ps1"
|
|
REPO="$WORK/repo"; mkdir -p "$REPO"
|
|
printf '# Werk\r\n\r\nUnser Projekt.\r\n' > "$REPO/CLAUDE.md"
|
|
printf '{\n "model": "anthropic/claude-sonnet-5-5"\n}\n' > "$REPO/opencode.json"
|
|
run() {
|
|
HUGIN_KEY="$INTEGRATION" "$PWSH" -NoProfile -NonInteractive -File "$WORK/hugin-install.ps1" \
|
|
-Server "$URL" -Repo "$REPO" -Tools 'claude=2.1.302,opencode=1.19.3' -Client werk-pc-01 "$@"
|
|
}
|
|
run -Packages pub-munin-nutzen,pub-hausregeln,pub-code-review
|
|
|
|
check() { grep -q -- "$2" "$REPO/$1" || { echo "$1 enthält nicht: $2"; cat "$REPO/$1"; exit 1; }; }
|
|
check .claude/skills/pub-munin-nutzen/SKILL.md "pub-munin-nutzen 1.4.0"
|
|
check .claude/agents/pub-code-review.md "tools: Read, Grep, Glob"
|
|
check .opencode/agents/pub-code-review.md "webfetch: deny"
|
|
check CLAUDE.md "@.hugin/rules/pub-hausregeln.md"
|
|
check .mcp.json '"type": *"http"'
|
|
check opencode.json '.hugin/rules/\*.md'
|
|
python3 - "$REPO" <<'PY'
|
|
import json, sys, pathlib
|
|
repo = pathlib.Path(sys.argv[1])
|
|
claude = (repo / "CLAUDE.md").read_bytes()
|
|
assert claude.startswith(b"# Werk\r\n\r\nUnser Projekt.\r\n\r\n<!-- hugin:begin"), claude[:80]
|
|
assert b"\n" not in claude.replace(b"\r\n", b""), "Zeilenenden gemischt"
|
|
for f in ["opencode.json", ".mcp.json", "hugin.lock.json"]:
|
|
roh = (repo / f).read_bytes()
|
|
assert not roh.startswith(b"\xef\xbb\xbf"), f + " mit BOM"
|
|
json.loads(roh)
|
|
oc = json.loads((repo / "opencode.json").read_text())
|
|
assert oc["model"] == "anthropic/claude-sonnet-5-5" and oc["mcp"]["munin"]["type"] == "remote", oc
|
|
skill = (repo / ".claude/skills/pub-munin-nutzen/SKILL.md").read_bytes()
|
|
assert b"\r\n" not in skill and not skill.startswith(b"\xef\xbb\xbf")
|
|
print("Inhalte ok")
|
|
PY
|
|
|
|
echo "== Zweiter Lauf ändert nichts"
|
|
run -Packages pub-munin-nutzen,pub-hausregeln,pub-code-review | tee "$WORK/lauf2.txt"
|
|
grep -q "Dateien: 0 schreiben, 0 löschen" "$WORK/lauf2.txt" || { echo "zweiter Lauf hätte nichts ändern dürfen"; exit 1; }
|
|
|
|
echo "== Aktualisierung und Abbestellen"
|
|
publish pub-munin-nutzen/1.5.0
|
|
run -Packages pub-munin-nutzen
|
|
check .claude/skills/pub-munin-nutzen/SKILL.md "pub-munin-nutzen 1.5.0"
|
|
[[ ! -e "$REPO/.claude/skills/pub-munin-nutzen/referenz" ]] || { echo "referenz/ nicht entfernt"; exit 1; }
|
|
[[ ! -e "$REPO/.claude/agents/pub-code-review.md" ]] || { echo "Subagent nicht entfernt"; exit 1; }
|
|
grep -q "hugin:begin" "$REPO/CLAUDE.md" && { echo "Block nicht entfernt"; exit 1; }
|
|
cmp -s <(printf '# Werk\r\n\r\nUnser Projekt.\r\n') "$REPO/CLAUDE.md" || { echo "CLAUDE.md nicht wie vorher"; exit 1; }
|
|
python3 -c "import json,sys; oc=json.load(open('$REPO/opencode.json')); assert 'instructions' not in oc and 'munin' in oc['mcp'], oc"
|
|
|
|
echo "== Handänderung wird erkannt"
|
|
echo "von Hand" >> "$REPO/.claude/skills/pub-munin-nutzen/SKILL.md"
|
|
publish pub-hausregeln/1.0.0 2>/dev/null || true
|
|
set +e; run -Packages pub-munin-nutzen,pub-hausregeln > "$WORK/lauf4.txt" 2>&1; RC=$?; set -e
|
|
[[ $RC -ne 0 ]] && grep -q "von Hand geändert" "$WORK/lauf4.txt" || { cat "$WORK/lauf4.txt"; echo "Handänderung nicht erkannt"; exit 1; }
|
|
[[ ! -e "$REPO/.hugin/rules/pub-hausregeln.md" ]] || { echo "trotz Befund geschrieben"; exit 1; }
|
|
run -Packages pub-munin-nutzen,pub-hausregeln -Overwrite >/dev/null
|
|
check .hugin/rules/pub-hausregeln.md "Hausregeln"
|
|
|
|
echo "== JSON mit Kommentaren wird nicht angefasst"
|
|
REPO2="$WORK/repo2"; mkdir -p "$REPO2"
|
|
printf '{\n // eigenes\n "model": "x"\n}\n' > "$REPO2/opencode.json"
|
|
set +e; HUGIN_KEY="$INTEGRATION" "$PWSH" -NoProfile -NonInteractive -File "$WORK/hugin-install.ps1" \
|
|
-Server "$URL" -Repo "$REPO2" -Tools 'opencode=1.19.3' -Packages pub-hausregeln > "$WORK/lauf5.txt" 2>&1; RC=$?; set -e
|
|
[[ $RC -ne 0 ]] && grep -q "Kommentare" "$WORK/lauf5.txt" || { cat "$WORK/lauf5.txt"; echo "JSONC nicht erkannt"; exit 1; }
|
|
grep -q "// eigenes" "$REPO2/opencode.json" || { echo "opencode.json verändert"; exit 1; }
|
|
|
|
echo "== Kein Schreiben über Links nach draußen"
|
|
REPO3="$WORK/repo3"; OUTSIDE="$WORK/draussen"; mkdir -p "$REPO3" "$OUTSIDE"
|
|
ln -s "$OUTSIDE" "$REPO3/.opencode"
|
|
set +e; HUGIN_KEY="$INTEGRATION" "$PWSH" -NoProfile -NonInteractive -File "$WORK/hugin-install.ps1" \
|
|
-Server "$URL" -Repo "$REPO3" -Tools 'opencode=1.19.3' -Packages pub-code-review > "$WORK/lauf6.txt" 2>&1; RC=$?; set -e
|
|
[[ $RC -ne 0 ]] && grep -q "Link oder eine Junction" "$WORK/lauf6.txt" || { cat "$WORK/lauf6.txt"; echo "Link nicht erkannt"; exit 1; }
|
|
[[ -z "$(ls -A "$OUTSIDE")" ]] || { echo "außerhalb des Repos geschrieben"; ls -R "$OUTSIDE"; exit 1; }
|
|
|
|
echo "== Nutzung"
|
|
sqlite3 "$WORK/hugin.db" "select repo, package_id, version, tools from hugin_usage order by package_id" 2>/dev/null || true
|
|
echo "Integrationstest ok."
|