Files
acdl/scripts/attach_release_asset.py
T
Jon Chery 301aa2c8d8
Nova Slides Render / render (push) Failing after 58s
docs(P3): marp deck + talking points + README + theme CSS + tests (REQ-245,251,252)
Marp deck (nova-autonomous-cloud-delivery-marp.md): synthesize from updated
source-of-truth; 18 main + 1 appendix slides; frontmatter — title 'Nova —
The Autonomous Cloud Delivery Platform', footer without version + without
'Act %{page}/5', title-slide subtitle 'Product Development & Citizen
Developer Overview'; no badges; embedded PNGs.

Talking points (nova-autonomous-cloud-delivery-talking-points.md):
re-distilled to 18-slide + A1 structure.

README.md: update deck title, audience, slide count (18 main + 1 appendix),
directory layout, remove badge docs, update deck table + render commands +
filenames. Document the v1.21 rename + restructure.

Theme CSS (nova-sp-theme.css): fix Appendix A1 table readability — tables
now have explicit white body + black text on any slide background
(including dark/title slides). Item 32.

Tests (test_slides_pipeline.py): add v1.21 assertions — no badges; no
version in footer/title slide; 18 main + 1 appendix slides; no D-###/REQ-
###/.py paths in audience-facing Marp deck or source slide body; old deck
files removed; render script default renamed; README references new deck
name. Update deck path in test_regression_cap023_024.py +
core/regression_verify.py CAP-024 (filename + 18-19 slide range, drop 'Arc
Preview' check per item 3).

attach_release_asset.py: usage example filename updated.

---ci---
project: acdl
phase: 3
milestone: v1.21
status: execute
phase_role: execution
---/ci---
2026-08-11 14:03:06 +00:00

80 lines
2.8 KiB
Python
Executable File

#!/usr/bin/env python3
"""scripts/attach_release_asset.py — upload a file as a Gitea release attachment.
REQ-228 (v1.18): PPTX (and any deck artifact) is attached to the phase's
Gitea release. Uses the Gitea API:
POST /api/v1/repos/{owner}/{repo}/releases/{id}/assets
multipart form: name=<filename>, attachment=<file bytes>
Usage:
python3 scripts/attach_release_asset.py <file-path> <release-id>
python3 scripts/attach_release_asset.py docs/presentations/nova-autonomous-cloud-delivery.pptx 522
Token resolution: reads NOVA_GITEA_TOKEN (or ACDL_GITEA_TOKEN) from .env.secrets
/ .env, matching the ship_phase.sh pattern. Never uses shell env tokens.
"""
import os
import sys
import json
import urllib.request
import urllib.error
from pathlib import Path
GITEA_BASE = "https://git.cloudinit.dev"
OWNER = "continuous-intelligence"
REPO = "acdl"
def resolve_token() -> str:
for fn in (".env.secrets", ".env"):
try:
for line in Path(fn).read_text().splitlines():
if line.startswith("NOVA_GITEA_TOKEN=") or line.startswith("ACDL_GITEA_TOKEN="):
return line.split("=", 1)[1].strip()
except (FileNotFoundError, PermissionError):
continue
raise RuntimeError("No Gitea token found in .env.secrets or .env (NOVA_GITEA_TOKEN/ACDL_GITEA_TOKEN)")
def attach_asset(file_path: str, release_id: str) -> dict:
token = resolve_token()
p = Path(file_path)
if not p.is_file():
raise FileNotFoundError(f"Asset file not found: {file_path}")
url = f"{GITEA_BASE}/api/v1/repos/{OWNER}/{REPO}/releases/{release_id}/assets"
filename = p.name
boundary = "----NovaBoundary7MAgYbk"
body = (
f"--{boundary}\r\n"
f'Content-Disposition: form-data; name="name"\r\n\r\n'
f"{filename}\r\n"
f"--{boundary}\r\n"
f'Content-Disposition: form-data; name="attachment"; filename="{filename}"\r\n'
f"Content-Type: application/octet-stream\r\n\r\n"
).encode() + p.read_bytes() + f"\r\n--{boundary}--\r\n".encode()
req = urllib.request.Request(
url,
data=body,
headers={
"Authorization": f"token {token}",
"Content-Type": f"multipart/form-data; boundary={boundary}",
},
method="POST",
)
try:
resp = urllib.request.urlopen(req, timeout=60)
return json.loads(resp.read())
except urllib.error.HTTPError as e:
err = e.read().decode()[:300]
raise RuntimeError(f"HTTP {e.code} attaching {filename} to release {release_id}: {err}") from e
if __name__ == "__main__":
if len(sys.argv) != 3:
print("Usage: attach_release_asset.py <file-path> <release-id>")
sys.exit(1)
result = attach_asset(sys.argv[1], sys.argv[2])
print(f"Attached: {result.get('name')} → release {sys.argv[2]} (asset id {result.get('id')})")