Files
hermes-agent/scripts/releases/upload_summary.py
2026-09-23 13:17:49 -04:00

82 lines
2.3 KiB
Python

"""Record each verified R2 upload for the GitHub job summary.
The record is a log. A missing summary file or a public-URL failure must not
fail an upload that already landed. The process exit writes the table, so a
step that uploads and then exits still reports its objects.
"""
from __future__ import annotations
import atexit
import json
import os
from pathlib import Path
_KEYS: list[str] = []
_REGISTERED = False
def note(key: str) -> None:
"""Remember one object key that a verified upload just wrote."""
global _REGISTERED
if not isinstance(key, str) or not key or key in _KEYS:
return
_KEYS.append(key)
if not _REGISTERED and os.environ.get("GITHUB_STEP_SUMMARY"):
atexit.register(flush)
_REGISTERED = True
def rows(keys: list[str]) -> list[tuple[str, str]]:
"""Public URL for each key, in upload order. A bad key is named, not dropped."""
from scripts.releases import r2
base = r2.public_base_url()
listed = []
for key in keys:
try:
listed.append((key, r2.public_url_for(base, key)))
except ValueError:
listed.append((key, ""))
return listed
def render(keys: list[str]) -> str:
"""One markdown table. Empty when the step uploaded nothing."""
if not keys:
return ""
lines = ["", "### R2 uploads", "", "| Object | URL |", "|---|---|"]
for key, url in rows(keys):
cell = f"[download]({url})" if url else "—"
lines.append(f"| `{key}` | {cell} |")
return "\n".join(lines) + "\n"
def flush() -> None:
"""Append the table once. A second call, or a missing summary, writes nothing."""
summary = os.environ.get("GITHUB_STEP_SUMMARY", "")
if not summary or not _KEYS:
return
text = render(list(_KEYS))
_KEYS.clear()
if not text:
return
try:
with Path(summary).open("a", encoding="utf-8") as stream:
stream.write(text)
except OSError:
return
def main() -> None:
"""Print the table for keys a caller already recorded."""
raw = os.environ.get("R2_UPLOAD_KEYS", "")
keys = json.loads(raw) if raw else []
if not isinstance(keys, list) or not all(isinstance(key, str) for key in keys):
raise SystemExit("R2_UPLOAD_KEYS must be a JSON list of object keys")
print(render(keys), end="")
if __name__ == "__main__":
main()