CI / Format and clippy (push) Successful in 1m57s
CI / Dependency audit (push) Successful in 13s
CI / Check desktop app (Linux) (push) Successful in 3m54s
CI / Tests (Linux) (push) Failing after 7m25s
Release / Create release (push) Successful in 6s
Release / CLI (linux-aarch64) (push) Successful in 1m48s
Release / CLI (linux-x86_64) (push) Successful in 2m39s
Release / Desktop app (linux-aarch64) (push) Successful in 10m9s
Release / Desktop app (linux-x86_64) (push) Successful in 12m20s
Release / Desktop app (windows) (push) Successful in 7m32s
Release / Build latest.json (push) Successful in 5s
Completes the English-only standardization for code, comments, scripts and CI templates (UI/CLI-facing strings stay bilingual pt-BR/en, untouched). Covers the remaining crates/, apps/gui/ui/ and apps/gui/src-tauri/ comments, .gitea/ workflow and template comments, .githooks/ hooks, and the scripts/ source comments for the files already renamed in a prior commit (check.sh, generate-logo.py, install-hooks.sh). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VAyr8d7HuAdUGB6aA5xmDD
83 lines
3.4 KiB
Python
Executable File
83 lines
3.4 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""Builds the latest.json manifest read by the Tauri updater from the release
|
|
bundles and `.sig` signatures already uploaded to the Gitea release.
|
|
|
|
Runs in the final publish job after all matrix packaging jobs complete. Building
|
|
the manifest in a single step avoids race conditions from parallel matrix jobs.
|
|
|
|
Usage: make-latest-json.py <tag> <notes.md> <out.json>
|
|
Requires API (Gitea repository API URL) and TOKEN in the environment.
|
|
"""
|
|
import json
|
|
import os
|
|
import sys
|
|
import urllib.parse
|
|
import urllib.request
|
|
from datetime import datetime, timezone
|
|
|
|
# (platform keys, package filename patterns). {v} = version without leading "v".
|
|
# No macOS: no Apple hardware/signing runner is available.
|
|
PLATFORMS = [
|
|
(["linux-x86_64", "linux-x86_64-appimage"], ("Guará_{v}_amd64.AppImage", "Guara_{v}_amd64.AppImage")),
|
|
(["linux-aarch64", "linux-aarch64-appimage"], ("Guará_{v}_aarch64.AppImage", "Guara_{v}_aarch64.AppImage")),
|
|
(["windows-x86_64", "windows-x86_64-nsis"], ("Guará_{v}_x64-setup.exe", "Guara_{v}_x64-setup.exe")),
|
|
]
|
|
|
|
|
|
def api_get(path):
|
|
req = urllib.request.Request(f"{os.environ['API']}{path}", headers={"Authorization": f"token {os.environ['TOKEN']}"})
|
|
return json.load(urllib.request.urlopen(req))
|
|
|
|
|
|
def api_get_text(url):
|
|
safe_url = urllib.parse.quote(url, safe=":/?&=%")
|
|
req = urllib.request.Request(safe_url, headers={"Authorization": f"token {os.environ['TOKEN']}"})
|
|
return urllib.request.urlopen(req).read().decode()
|
|
|
|
|
|
def build(version, notes, assets, pub_date):
|
|
"""`assets` = {package_name: (url, signature)}. Returns the latest.json dict.
|
|
|
|
Platforms missing a package or signature are omitted; the caller decides whether that is fatal."""
|
|
platforms = {}
|
|
for keys, patterns in PLATFORMS:
|
|
name = next((n for p in patterns if (n := p.format(v=version)) in assets), None)
|
|
if name is None:
|
|
continue
|
|
url, sig = assets[name]
|
|
for k in keys:
|
|
platforms.setdefault(k, {"signature": sig.strip(), "url": url})
|
|
return {"version": version, "notes": notes.strip(), "pub_date": pub_date, "platforms": platforms}
|
|
|
|
|
|
def main():
|
|
tag, notes_path, out = sys.argv[1:4]
|
|
version = tag.lstrip("v")
|
|
rel = api_get(f"/releases/tags/{tag}")
|
|
by_name = {a["name"]: a for a in rel["assets"]}
|
|
assets = {}
|
|
for _, patterns in PLATFORMS:
|
|
name = next((n for p in patterns if (n := p.format(v=version)) in by_name), None)
|
|
if name is None:
|
|
continue
|
|
sig_name = name + ".sig"
|
|
if sig_name in by_name:
|
|
sig = api_get_text(by_name[sig_name]["browser_download_url"])
|
|
assets[name] = (by_name[name]["browser_download_url"], sig)
|
|
data = build(version, open(notes_path, encoding="utf-8").read(), assets,
|
|
datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"))
|
|
# Require signed packages for Linux (x86_64 and aarch64) and Windows.
|
|
platforms = data["platforms"]
|
|
for must in ("linux-x86_64", "linux-aarch64", "windows-x86_64"):
|
|
if must not in platforms:
|
|
sys.exit(f"missing package or signature for {must} (found {sorted(platforms)}); "
|
|
"verify that TAURI_SIGNING_PRIVATE_KEY is set in repository secrets")
|
|
with open(out, "w", encoding="utf-8") as f:
|
|
json.dump(data, f, indent=2, ensure_ascii=False)
|
|
f.write("\n")
|
|
print(f"{out}: {sorted(data['platforms'])}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|