Files
timmy-config/bin/ops-gitea.sh
2026-04-04 14:28:27 -04:00

126 lines
4.5 KiB
Bash
Executable File

#!/usr/bin/env bash
# ── Gitea Workflow Feed ────────────────────────────────────────────────
# Shows open PRs, review pressure, and issue queues across core repos.
# ───────────────────────────────────────────────────────────────────────
set -euo pipefail
B='\033[1m'
D='\033[2m'
R='\033[0m'
C='\033[36m'
G='\033[32m'
Y='\033[33m'
GITEA_URL="${GITEA_URL:-http://143.198.27.163:3000}"
CORE_REPOS="${CORE_REPOS:-Timmy_Foundation/the-nexus Timmy_Foundation/timmy-home Timmy_Foundation/timmy-config Timmy_Foundation/hermes-agent}"
for token_file in "$HOME/.hermes/gitea_token_vps" "$HOME/.config/gitea/token" "$HOME/.config/gitea/codex-token"; do
if [ -f "$token_file" ]; then
TOKEN=$(cat "$token_file")
break
fi
done
TOKEN="${TOKEN:-}"
echo -e "${B}${C} ◈ GITEA WORKFLOW${R} ${D}$(date '+%H:%M:%S')${R}"
echo -e "${D}────────────────────────────────────────${R}"
python3 - "$GITEA_URL" "$TOKEN" "$CORE_REPOS" <<'PY'
import json
import sys
import urllib.error
import urllib.request
base = sys.argv[1].rstrip("/")
token = sys.argv[2]
repos = sys.argv[3].split()
headers = {"Authorization": f"token {token}"} if token else {}
def fetch(path):
req = urllib.request.Request(f"{base}{path}", headers=headers)
with urllib.request.urlopen(req, timeout=5) as resp:
return json.loads(resp.read().decode())
def short_repo(repo):
return repo.split("/", 1)[1]
issues = []
pulls = []
errors = []
for repo in repos:
try:
repo_pulls = fetch(f"/api/v1/repos/{repo}/pulls?state=open&limit=20")
for pr in repo_pulls:
pr["_repo"] = repo
pulls.append(pr)
repo_issues = fetch(f"/api/v1/repos/{repo}/issues?state=open&limit=50&type=issues")
for issue in repo_issues:
issue["_repo"] = repo
issues.append(issue)
except urllib.error.URLError as exc:
errors.append(f"{repo}: {exc.reason}")
except Exception as exc: # pragma: no cover - defensive panel path
errors.append(f"{repo}: {exc}")
print(" \033[1mOpen PRs\033[0m")
if not pulls:
print(" (none)")
else:
for pr in pulls[:8]:
print(
f" #{pr['number']:3d} {short_repo(pr['_repo']):12s} "
f"{pr['user']['login'][:12]:12s} {pr['title'][:40]}"
)
print("\033[2m────────────────────────────────────────\033[0m")
print(" \033[1mNeeds Timmy / Allegro Review\033[0m")
reviewers = []
for repo in repos:
try:
repo_items = fetch(f"/api/v1/repos/{repo}/issues?state=open&limit=50&type=pulls")
for item in repo_items:
assignees = [a.get("login", "") for a in (item.get("assignees") or [])]
if any(name in assignees for name in ("Timmy", "allegro")):
item["_repo"] = repo
reviewers.append(item)
except Exception:
continue
if not reviewers:
print(" (clear)")
else:
for item in reviewers[:8]:
names = ",".join(a.get("login", "") for a in (item.get("assignees") or []))
print(
f" #{item['number']:3d} {short_repo(item['_repo']):12s} "
f"{names[:18]:18s} {item['title'][:34]}"
)
print("\033[2m────────────────────────────────────────\033[0m")
print(" \033[1mIssue Queues\033[0m")
queue_agents = ["allegro", "codex-agent", "groq", "claude", "ezra", "perplexity", "KimiClaw"]
for agent in queue_agents:
assigned = [
issue
for issue in issues
if agent in [a.get("login", "") for a in (issue.get("assignees") or [])]
]
print(f" {agent:12s} {len(assigned):2d}")
unassigned = [issue for issue in issues if not issue.get("assignees")]
print("\033[2m────────────────────────────────────────\033[0m")
print(f" Unassigned issues: \033[33m{len(unassigned)}\033[0m")
if errors:
print("\033[2m────────────────────────────────────────\033[0m")
print(" \033[1mErrors\033[0m")
for err in errors[:4]:
print(f" {err}")
PY