#!/usr/bin/env python3 """Creates or completes a Gitea release from what scripts/release_build.sh made. Usage: scripts/release_publish.py Environment: GITEA_API (https://host/api/v1), GITEA_REPO (owner/name), GITEA_TOKEN. Run again for the same version, it replaces the files and the text instead of failing. """ import json import os import sys import urllib.error import urllib.parse import urllib.request API = os.environ.get("GITEA_API", "").rstrip("/") REPO = os.environ.get("GITEA_REPO", "") TOKEN = os.environ.get("GITEA_TOKEN", "") def call(method, path, body=None, raw=None, content_type="application/json"): data = raw if raw is not None else (json.dumps(body).encode() if body is not None else None) request = urllib.request.Request(f"{API}/repos/{REPO}{path}", data=data, method=method) request.add_header("Authorization", f"token {TOKEN}") if data is not None: request.add_header("Content-Type", content_type) try: with urllib.request.urlopen(request, timeout=300) as response: text = response.read() return response.status, json.loads(text) if text else None except urllib.error.HTTPError as e: return e.code, e.read().decode(errors="replace")[:300] def main(): if len(sys.argv) != 2 or not (API and REPO and TOKEN): sys.exit(__doc__) folder = sys.argv[1] version = open(os.path.join(folder, "version")).read().strip() notes = open(os.path.join(folder, "notes.md")).read() files = sorted(f for f in os.listdir(folder) if f not in ("version", "notes.md")) status, release = call("GET", f"/releases/tags/{urllib.parse.quote(version)}") fields = {"tag_name": version, "name": f"roro9stack {version}", "body": notes, "draft": False, "prerelease": False} if status == 200: status, release = call("PATCH", f"/releases/{release['id']}", fields) else: status, release = call("POST", "/releases", fields) if status not in (200, 201): sys.exit(f"release: Gitea answered {status}: {release}") for asset in release.get("assets") or []: # a second run replaces what the first uploaded if asset["name"] in files: call("DELETE", f"/releases/{release['id']}/assets/{asset['id']}") for name in files: with open(os.path.join(folder, name), "rb") as f: status, answer = call("POST", f"/releases/{release['id']}/assets?name={urllib.parse.quote(name)}", raw=f.read(), content_type="application/octet-stream") if status != 201: sys.exit(f"release: uploading {name}: Gitea answered {status}: {answer}") print(f"uploaded {name} ({answer['size']} bytes)") print(f"published {release['html_url']}") if __name__ == "__main__": main()