301aa2c8d8
Nova Slides Render / render (push) Failing after 58s
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---
80 lines
2.8 KiB
Python
Executable File
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')})") |