Files
guara/scripts/make-latest-json.py
T
Lucas RayanandClaude Sonnet 5.5 009c3d61de
CI / Formatação e clippy (push) Successful in 23s
CI / Auditoria de dependências (push) Successful in 25s
CI / Compila o app desktop (Linux) (push) Successful in 1m12s
Release / Cria a release (push) Successful in 5s
CI / Testes (Linux) (push) Successful in 4m20s
Release / CLI (linux-aarch64) (push) Successful in 2m28s
Release / CLI (linux-x86_64) (push) Successful in 2m38s
Release / App desktop (linux) (push) Successful in 11m25s
Release / App desktop (windows) (push) Successful in 11m8s
Release / Monta o latest.json (push) Successful in 6s
ci: find the desktop bundles in CARGO_TARGET_DIR, accept Linux aarch64 in latest.json
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-30 14:02:36 -03:00

79 lines
3.2 KiB
Python
Executable File

#!/usr/bin/env python3
"""Monta o latest.json que o atualizador do app lê (Tauri updater), a partir dos pacotes e das
assinaturas `.sig` já enviados à release no Gitea.
Roda no job de publicação, depois que os jobs de empacotamento terminaram. Montar o arquivo
aqui, em um passo só, evita a corrida de quem tenta atualizá-lo em paralelo por plataforma.
Uso: make-latest-json.py <tag> <notas.md> <saida.json>
Precisa de API (URL do repositório na API do Gitea) e TOKEN no ambiente.
"""
import json
import os
import sys
import urllib.request
from datetime import datetime, timezone
# (chaves de plataforma, padrão do nome do pacote). {v} = versão sem o "v".
# Sem macOS: não há runner para compilar essa plataforma.
PLATFORMS = [
(["linux-x86_64", "linux-x86_64-appimage"], "Guara_{v}_amd64.AppImage"),
(["linux-aarch64", "linux-aarch64-appimage"], "Guara_{v}_aarch64.AppImage"),
(["windows-x86_64", "windows-x86_64-nsis"], "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):
req = urllib.request.Request(url, headers={"Authorization": f"token {os.environ['TOKEN']}"})
return urllib.request.urlopen(req).read().decode()
def build(version, notes, assets, pub_date):
"""`assets` = {nome_do_pacote: (url, assinatura)}. Devolve o dicionário do latest.json.
Plataforma sem pacote ou sem assinatura sai da lista; o chamador decide se isso é erro."""
platforms = {}
for keys, pattern in PLATFORMS:
name = pattern.format(v=version)
if name not in assets:
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 _, pattern in PLATFORMS:
name = pattern.format(v=version)
sig_name = name + ".sig"
if name in by_name and 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"))
# O CI gera o Linux aarch64 (o runner é arm64); o x86_64 vem de uma máquina x86_64 e
# entra depois (scripts/build-gui.sh linux). Exige o Windows e ao menos um Linux.
platforms = data["platforms"]
if "windows-x86_64" not in platforms or not any(k.startswith("linux-") for k in platforms):
sys.exit(f"faltam pacotes ou assinaturas (achei {sorted(platforms)}); "
"confira se TAURI_SIGNING_PRIVATE_KEY está nos segredos")
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()