release 1.3.2: update from Gitea, Linux-only CLI, desktop app for Linux and Windows
The updater reads latest.json from Gitea, built by scripts/make-latest-json.py against the Gitea API (no gh CLI). Release workflow builds the Linux CLI and the Linux+Windows desktop app, signs the updater artifacts and attaches everything to the release. Needs the repo secrets TAURI_SIGNING_PRIVATE_KEY and TAURI_SIGNING_PRIVATE_KEY_PASSWORD, which I could not set (secret-store writes are reserved for the user) - set them from ~/.tauri/guara-updater.key and .pass before pushing a tag. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
8ba3151512
commit
b47708126e
14 files changed
+319
-46
No files matched your search
Regular → Executable
+26
-19
@@ -1,29 +1,37 @@
|
||||
#!/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.
|
||||
assinaturas `.sig` já enviados à release no Gitea.
|
||||
|
||||
Roda no job de publicação, depois que todos os jobs de empacotamento terminaram. Montar o arquivo
|
||||
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> (usa `gh` e GH_REPO/GITHUB_REPOSITORY)
|
||||
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 subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
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"),
|
||||
(["windows-x86_64", "windows-x86_64-nsis"], "Guara_{v}_x64-setup.exe"),
|
||||
(["windows-x86_64-msi"], "Guara_{v}_x64_en-US.msi"),
|
||||
(["darwin-aarch64", "darwin-aarch64-app"], "Guara_{v}_aarch64.app.tar.gz"),
|
||||
(["darwin-x86_64", "darwin-x86_64-app"], "Guara_{v}_x64.app.tar.gz"),
|
||||
]
|
||||
|
||||
|
||||
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.
|
||||
|
||||
@@ -42,20 +50,19 @@ def build(version, notes, assets, pub_date):
|
||||
def main():
|
||||
tag, notes_path, out = sys.argv[1:4]
|
||||
version = tag.lstrip("v")
|
||||
repo = os.environ.get("GH_REPO") or os.environ["GITHUB_REPOSITORY"]
|
||||
rel = json.loads(subprocess.check_output(["gh", "release", "view", tag, "--repo", repo, "--json", "assets"]))
|
||||
urls = {a["name"]: a["url"] for a in rel["assets"]}
|
||||
rel = api_get(f"/releases/tags/{tag}")
|
||||
by_name = {a["name"]: a for a in rel["assets"]}
|
||||
assets = {}
|
||||
with tempfile.TemporaryDirectory() as d:
|
||||
for _, pattern in PLATFORMS:
|
||||
name = pattern.format(v=version)
|
||||
if name in urls and name + ".sig" in urls:
|
||||
subprocess.check_call(["gh", "release", "download", tag, "--repo", repo, "-p", name + ".sig", "-D", d])
|
||||
assets[name] = (urls[name], open(os.path.join(d, name + ".sig")).read())
|
||||
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"))
|
||||
# Sem o Linux (AppImage) o atualizador do dono do projeto não funciona: não publica pela metade.
|
||||
for must in ("linux-x86_64", "windows-x86_64", "darwin-aarch64", "darwin-x86_64"):
|
||||
# Sem Linux e Windows o atualizador não funciona para ninguém: não publica pela metade.
|
||||
for must in ("linux-x86_64", "windows-x86_64"):
|
||||
if must not in data["platforms"]:
|
||||
sys.exit(f"faltam o pacote ou a assinatura de {must}; confira se TAURI_SIGNING_PRIVATE_KEY está nos segredos")
|
||||
with open(out, "w", encoding="utf-8") as f:
|
||||
|
||||
Reference in new issue
Block a user