Files
watchdog-discord-route/scripts/owner_report_driver.py

119 lines
3.7 KiB
Python

#!/usr/bin/env python3
"""Minimal owner-report driver.
Consumes one pending owner report, calls an external send command, and only moves
it to sent/ after the send command succeeds.
This is a deliberately small manual driver for debugging the owner-report chain.
It does not watch directories, retry, or send anything by itself.
"""
from __future__ import annotations
import argparse
import json
import os
import subprocess
from pathlib import Path
from owner_report_consumer import OWNER_REPORT_ROOT, PENDING_DIR, parse_pending_report, resolve_input
SENT_DIR = OWNER_REPORT_ROOT / "sent"
def _build_send_env(payload: dict) -> dict[str, str]:
env = os.environ.copy()
env.update(
{
"OWNER_REPORT_JSON": json.dumps(payload, ensure_ascii=False),
"OWNER_REPORT_ID": str(payload.get("report_id") or ""),
"OWNER_REPORT_TEAM": str(payload.get("team") or ""),
"OWNER_REPORT_SOURCE": str(payload.get("source") or ""),
"OWNER_REPORT_KIND": str(payload.get("report_kind") or "checkpoint"),
"OWNER_REPORT_CREATED_AT": str(payload.get("created_at") or ""),
"OWNER_REPORT_MESSAGE": str(payload.get("message") or ""),
"OWNER_REPORT_PATH": str(payload.get("path") or ""),
}
)
return env
def _sent_path(src: Path) -> Path:
SENT_DIR.mkdir(parents=True, exist_ok=True)
return SENT_DIR / src.name
def _finalize_successful_send(src: Path) -> dict[str, object]:
dest = _sent_path(src)
if src.exists():
src.rename(dest)
return {"moved": True, "already_archived": False, "final_path": str(dest)}
if dest.exists():
return {"moved": False, "already_archived": True, "final_path": str(dest)}
raise FileNotFoundError(
f"successful send completed but pending report disappeared before archiving: pending={src} sent={dest}"
)
def main() -> int:
ap = argparse.ArgumentParser(description="Send one pending owner report via external command")
ap.add_argument("report", help="Pending report path, filename, or report_id")
ap.add_argument(
"--send-cmd",
help="Shell command used to send the report. Can also come from OWNER_REPORT_SEND_CMD.",
)
ap.add_argument("--dry-run", action="store_true", help="Print what would be sent and do not move files")
args = ap.parse_args()
src = resolve_input(args.report)
payload = parse_pending_report(src)
send_cmd = args.send_cmd or os.environ.get("OWNER_REPORT_SEND_CMD")
if not send_cmd and not args.dry_run:
raise SystemExit("missing send command: use --send-cmd or OWNER_REPORT_SEND_CMD")
if args.dry_run:
print(json.dumps({
"ok": True,
"dry_run": True,
"action": "would_send",
"pending_path": str(src),
"sent_path": str(_sent_path(src)),
"payload": payload,
"send_cmd": send_cmd,
}, ensure_ascii=False, indent=2))
return 0
proc = subprocess.run(
["bash", "-lc", send_cmd],
text=True,
capture_output=True,
env=_build_send_env(payload),
)
result = {
"ok": proc.returncode == 0,
"dry_run": False,
"pending_path": str(src),
"sent_path": str(_sent_path(src)),
"send_cmd": send_cmd,
"exit_code": proc.returncode,
"stdout": proc.stdout,
"stderr": proc.stderr,
"payload": payload,
}
if proc.returncode != 0:
print(json.dumps(result, ensure_ascii=False, indent=2))
return proc.returncode
result.update(_finalize_successful_send(src))
print(json.dumps(result, ensure_ascii=False, indent=2))
return 0
if __name__ == "__main__":
raise SystemExit(main())