114 lines
3.7 KiB
Python
Executable File
114 lines
3.7 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
import json
|
|
import mimetypes
|
|
import os
|
|
import sys
|
|
import urllib.error
|
|
import urllib.parse
|
|
import urllib.request
|
|
from pathlib import Path
|
|
|
|
|
|
def api_request(method: str, url: str, token: str, data: bytes | None = None, headers: dict | None = None):
|
|
req_headers = {
|
|
"Authorization": f"token {token}",
|
|
"Accept": "application/json",
|
|
"User-Agent": "curl/8.10.1",
|
|
**(headers or {}),
|
|
}
|
|
req = urllib.request.Request(url, data=data, headers=req_headers, method=method)
|
|
try:
|
|
with urllib.request.urlopen(req, timeout=60) as resp:
|
|
body = resp.read()
|
|
if not body:
|
|
return None
|
|
return json.loads(body)
|
|
except urllib.error.HTTPError as exc:
|
|
body = exc.read().decode("utf-8", "ignore")
|
|
raise RuntimeError(f"HTTP {exc.code} for {method} {url}: {body}") from exc
|
|
|
|
|
|
def get_or_create_release(api_base: str, owner: str, repo: str, tag: str, title: str, body: str, token: str, target: str):
|
|
tag_url = f"{api_base}/repos/{owner}/{repo}/releases/tags/{urllib.parse.quote(tag, safe='')}"
|
|
try:
|
|
release = api_request("GET", tag_url, token)
|
|
if release is not None:
|
|
return release
|
|
except RuntimeError as exc:
|
|
if "HTTP 404" not in str(exc):
|
|
raise
|
|
|
|
create_url = f"{api_base}/repos/{owner}/{repo}/releases"
|
|
payload = {
|
|
"tag_name": tag,
|
|
"name": title,
|
|
"body": body,
|
|
"draft": False,
|
|
"prerelease": False,
|
|
"target_commitish": target,
|
|
}
|
|
return api_request(
|
|
"POST",
|
|
create_url,
|
|
token,
|
|
data=json.dumps(payload).encode("utf-8"),
|
|
headers={"Content-Type": "application/json"},
|
|
)
|
|
|
|
|
|
def replace_release_assets(api_base: str, owner: str, repo: str, release: dict, files: list[Path], token: str):
|
|
release_id = release["id"]
|
|
existing_assets = {asset["name"]: asset for asset in release.get("assets", [])}
|
|
|
|
for path in files:
|
|
name = path.name
|
|
if name in existing_assets:
|
|
asset_id = existing_assets[name]["id"]
|
|
delete_url = f"{api_base}/repos/{owner}/{repo}/releases/{release_id}/assets/{asset_id}"
|
|
api_request("DELETE", delete_url, token)
|
|
|
|
upload_url = f"{api_base}/repos/{owner}/{repo}/releases/{release_id}/assets?name={urllib.parse.quote(name, safe='')}"
|
|
content_type = mimetypes.guess_type(str(path))[0] or "application/octet-stream"
|
|
data = path.read_bytes()
|
|
api_request(
|
|
"POST",
|
|
upload_url,
|
|
token,
|
|
data=data,
|
|
headers={"Content-Type": content_type},
|
|
)
|
|
|
|
|
|
def main() -> int:
|
|
token = os.environ["GITEA_TOKEN"]
|
|
api_base = os.environ["GITEA_API_URL"].rstrip("/")
|
|
owner = os.environ["REPO_OWNER"]
|
|
repo = os.environ["REPO_NAME"]
|
|
version = os.environ["VERSION"]
|
|
target = os.environ.get("TARGET_SHA", "main")
|
|
files = [Path(p) for p in sys.argv[1:]]
|
|
if not files:
|
|
raise SystemExit("usage: publish_release.py <file> [file ...]")
|
|
missing = [str(p) for p in files if not p.exists()]
|
|
if missing:
|
|
raise SystemExit(f"missing files: {', '.join(missing)}")
|
|
|
|
tag = f"iperf3-v{version}"
|
|
title = f"iperf3 {version}"
|
|
body = (
|
|
f"Static musl build for iperf3 {version}.\\n\\n"
|
|
f"Repository: {owner}/{repo}\\n"
|
|
f"Commit: {target}"
|
|
)
|
|
|
|
release = get_or_create_release(api_base, owner, repo, tag, title, body, token, target)
|
|
replace_release_assets(api_base, owner, repo, release, files, token)
|
|
print(f"published_tag={tag}")
|
|
for path in files:
|
|
print(f"asset={path.name}")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|