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
+317
-44
No files matched your search
@@ -1,14 +1,25 @@
|
||||
name: Release
|
||||
|
||||
# Cria a entrada em "Releases" quando uma tag v* é enviada, com as notas da
|
||||
# seção correspondente do CHANGELOG.md (scripts/release-notes.sh).
|
||||
# Quando uma tag v* é enviada: cria a entrada em "Releases" com as notas do
|
||||
# CHANGELOG.md, compila o CLI (Linux x86_64 e aarch64) e o app desktop (Linux
|
||||
# e Windows, este por compilação cruzada com cargo-xwin), e monta o
|
||||
# latest.json que o atualizador do app lê.
|
||||
#
|
||||
# Só as notas: os binários para macOS e Windows exigiam runners que o Gitea daqui
|
||||
# não tem (o único runner é Linux arm64), então não são gerados neste fluxo.
|
||||
# Sem macOS: o Tauri precisa do SDK e da assinatura da Apple, presos a
|
||||
# hardware Apple e a uma conta de desenvolvedor, que este runner não tem.
|
||||
#
|
||||
# Segredos de usuário necessários: REGISTRY_TOKEN (não usado aqui, fica para o
|
||||
# registro de containers de outros projetos), TAURI_SIGNING_PRIVATE_KEY e
|
||||
# TAURI_SIGNING_PRIVATE_KEY_PASSWORD (assinam os pacotes para o atualizador).
|
||||
on:
|
||||
push:
|
||||
tags: ['v*']
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
CARGO_HOME: /opt/hostedtoolcache/cargo
|
||||
RUSTUP_HOME: /opt/hostedtoolcache/rustup
|
||||
|
||||
jobs:
|
||||
release:
|
||||
name: Cria a release
|
||||
@@ -23,9 +34,99 @@ jobs:
|
||||
TOKEN: ${{ gitea.token }}
|
||||
API: ${{ gitea.server_url }}/api/v1/repos/${{ gitea.repository }}
|
||||
run: |
|
||||
# Uma execução repetida não recria a release.
|
||||
if curl -fsS -H "Authorization: token $TOKEN" "$API/releases/tags/$TAG" >/dev/null 2>&1; then
|
||||
echo "a release $TAG já existe"; exit 0
|
||||
fi
|
||||
scripts/release-notes.sh "$TAG" > notes.md
|
||||
pre=false; case "$TAG" in *-*) pre=true ;; esac
|
||||
jq -n --arg tag "$TAG" --arg name "Guará ${TAG#v}" --rawfile body notes.md --argjson pre "$pre" \
|
||||
'{tag_name:$tag, name:$name, body:$body, prerelease:$pre}' > release.json
|
||||
curl -fsS -X POST "$API/releases" -H "Authorization: token $TOKEN" \
|
||||
-H 'Content-Type: application/json' -d @release.json
|
||||
-H 'Content-Type: application/json' -d @release.json >/dev/null
|
||||
|
||||
cli:
|
||||
name: CLI (${{ matrix.platform }})
|
||||
needs: release
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
CARGO_TARGET_DIR: /opt/hostedtoolcache/cargo-target/guara-release-cli
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- { platform: linux-aarch64, target: aarch64-unknown-linux-gnu, apt: "" }
|
||||
- { platform: linux-x86_64, target: x86_64-unknown-linux-gnu, apt: "gcc-x86-64-linux-gnu" }
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
targets: ${{ matrix.target }}
|
||||
- name: Linker desta plataforma
|
||||
if: ${{ matrix.apt != '' }}
|
||||
run: |
|
||||
apt-get update -qq
|
||||
apt-get install -y -qq ${{ matrix.apt }}
|
||||
- name: Compila e empacota
|
||||
run: scripts/package-cli.sh "${{ gitea.ref_name }}" "${{ matrix.platform }}" "${{ matrix.target }}" | tee packages.txt
|
||||
- name: Anexa à release
|
||||
env:
|
||||
TOKEN: ${{ gitea.token }}
|
||||
API: ${{ gitea.server_url }}/api/v1/repos/${{ gitea.repository }}
|
||||
run: scripts/release-upload.sh "${{ gitea.ref_name }}" $(cat packages.txt)
|
||||
|
||||
gui:
|
||||
name: App desktop (${{ matrix.platform }})
|
||||
needs: release
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
CARGO_TARGET_DIR: /opt/hostedtoolcache/cargo-target/guara-release-gui
|
||||
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
|
||||
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [linux, windows]
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: actions/setup-node@v7
|
||||
with:
|
||||
node-version: 22
|
||||
- name: Dependências do Tauri (Linux)
|
||||
if: matrix.platform == 'linux'
|
||||
timeout-minutes: 25
|
||||
run: scripts/apt-install.sh ~/apt-cache libwebkit2gtk-4.1-dev libayatana-appindicator3-dev librsvg2-dev patchelf
|
||||
- name: Ferramentas para compilação cruzada (Windows)
|
||||
if: matrix.platform == 'windows'
|
||||
run: |
|
||||
apt-get update -qq
|
||||
apt-get install -y -qq nsis lld llvm clang
|
||||
command -v cargo-xwin >/dev/null || cargo install cargo-xwin --locked
|
||||
- name: Compila e empacota
|
||||
run: scripts/build-gui.sh "${{ matrix.platform }}"
|
||||
- name: Anexa à release
|
||||
env:
|
||||
TOKEN: ${{ gitea.token }}
|
||||
API: ${{ gitea.server_url }}/api/v1/repos/${{ gitea.repository }}
|
||||
run: scripts/release-upload.sh "${{ gitea.ref_name }}" dist-gui/*
|
||||
|
||||
atualizador:
|
||||
name: Monta o latest.json
|
||||
needs: gui
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- name: latest.json
|
||||
env:
|
||||
TAG: ${{ gitea.ref_name }}
|
||||
TOKEN: ${{ gitea.token }}
|
||||
API: ${{ gitea.server_url }}/api/v1/repos/${{ gitea.repository }}
|
||||
run: |
|
||||
scripts/release-notes.sh "$TAG" > notes.md
|
||||
python3 scripts/make-latest-json.py "$TAG" notes.md latest.json
|
||||
- name: Anexa à release
|
||||
env:
|
||||
TOKEN: ${{ gitea.token }}
|
||||
API: ${{ gitea.server_url }}/api/v1/repos/${{ gitea.repository }}
|
||||
run: scripts/release-upload.sh "${{ gitea.ref_name }}" latest.json
|
||||
@@ -17,3 +17,7 @@ node_modules/
|
||||
*.img
|
||||
*.guara-session.json
|
||||
.DS_Store
|
||||
|
||||
# Pacotes gerados por scripts/package-cli.sh
|
||||
/guara-v*
|
||||
/dist-gui
|
||||
@@ -4,6 +4,23 @@
|
||||
|
||||
Format based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versions follow SemVer.
|
||||
|
||||
## [1.3.2] - 2026-10-30
|
||||
|
||||
The project moved from GitHub to Gitea, and the update check followed it.
|
||||
|
||||
### Changed
|
||||
- **Updates now come from Gitea.** The desktop app's update card reads
|
||||
`latest.json` from `git.lucasrguerra.dev.br` instead of GitHub Releases.
|
||||
Versions up to 1.3.1 still look at GitHub, which is no longer reachable, so
|
||||
they cannot find this release: download 1.3.2 once, and later updates are
|
||||
automatic.
|
||||
- The CLI is published for Linux x86_64 and aarch64 only, built by the Gitea CI
|
||||
when a `v*` tag is pushed, with a `.sha256` next to each package. **There is
|
||||
no Windows CLI any more.** The desktop app still ships for Linux (AppImage,
|
||||
`.deb`) and Windows (NSIS `.exe`, cross-compiled from Linux). There is no
|
||||
macOS build: it needs Apple's SDK and code signing, which this project's CI
|
||||
(one Linux runner) cannot provide.
|
||||
|
||||
## [1.3.1] - 2026-10-23
|
||||
|
||||
### Changed
|
||||
|
||||
@@ -4,6 +4,23 @@
|
||||
|
||||
Formato baseado em [Keep a Changelog](https://keepachangelog.com/pt-BR/1.1.0/); versões seguem SemVer.
|
||||
|
||||
## [1.3.2] - 2026-10-30
|
||||
|
||||
O projeto saiu do GitHub para o Gitea, e a verificação de atualização foi junto.
|
||||
|
||||
### Alterado
|
||||
- **As atualizações agora vêm do Gitea.** O cartão de atualização do app
|
||||
desktop lê o `latest.json` em `git.lucasrguerra.dev.br`, e não mais as
|
||||
Releases do GitHub. As versões até a 1.3.1 ainda olham o GitHub, que não
|
||||
responde mais, e por isso não enxergam esta release: baixe a 1.3.2 uma vez, e
|
||||
as próximas atualizações são automáticas.
|
||||
- O CLI é publicado só para Linux x86_64 e aarch64, compilado pelo CI do Gitea
|
||||
quando uma tag `v*` é enviada, com um `.sha256` ao lado de cada pacote. **Não
|
||||
há mais CLI para Windows.** O app desktop continua saindo para Linux
|
||||
(AppImage, `.deb`) e Windows (`.exe` NSIS, compilado a partir do Linux). Não
|
||||
há build para macOS: exige o SDK e a assinatura da Apple, que o CI deste
|
||||
projeto (um único runner Linux) não tem.
|
||||
|
||||
## [1.3.1] - 2026-10-23
|
||||
|
||||
### Alterado
|
||||
|
||||
Generated
+2
-2
@@ -416,7 +416,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "guara-cli"
|
||||
version = "1.3.1"
|
||||
version = "1.3.2"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"ctrlc",
|
||||
@@ -429,7 +429,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "guara-core"
|
||||
version = "1.3.1"
|
||||
version = "1.3.2"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"argon2",
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ resolver = "2"
|
||||
members = ["crates/guara-core", "crates/guara-cli"]
|
||||
|
||||
[workspace.package]
|
||||
version = "1.3.1"
|
||||
version = "1.3.2"
|
||||
edition = "2021"
|
||||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/lucasrguerra/guara"
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
[package]
|
||||
name = "guara-gui"
|
||||
description = "Guará: interface gráfica de recuperação de arquivos"
|
||||
version = "1.3.1"
|
||||
version = "1.3.2"
|
||||
edition = "2021"
|
||||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/lucasrguerra/guara"
|
||||
repository = "https://git.lucasrguerra.dev.br/lucasrguerra/guara"
|
||||
rust-version = "1.80"
|
||||
|
||||
[workspace]
|
||||
|
||||
@@ -39,7 +39,7 @@ async fn update_check(app: tauri::AppHandle) -> Result<Option<UpdateInfo>, Strin
|
||||
Ok(found.map(|u| UpdateInfo {
|
||||
current: u.current_version.clone(),
|
||||
notes: u.body.clone().unwrap_or_default(),
|
||||
url: format!("https://github.com/lucasrguerra/guara/releases/tag/v{}", u.version),
|
||||
url: format!("https://git.lucasrguerra.dev.br/lucasrguerra/guara/releases/tag/v{}", u.version),
|
||||
version: u.version,
|
||||
auto: self_update_possible(),
|
||||
}))
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://schema.tauri.app/config/2",
|
||||
"productName": "Guara",
|
||||
"version": "1.3.1",
|
||||
"version": "1.3.2",
|
||||
"identifier": "dev.guara.app",
|
||||
"build": {
|
||||
"frontendDist": "../ui"
|
||||
@@ -41,7 +41,7 @@
|
||||
"updater": {
|
||||
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDhENzRCRUU5NEI3QTAxQzgKUldUSUFYcEw2YjUwamFzMnpXM3ZKTEZPN1JIeXdLL3Q5SEF1M1FxQ284WFM0UWNsdlAyNUloWTEK",
|
||||
"endpoints": [
|
||||
"https://github.com/lucasrguerra/guara/releases/latest/download/latest.json"
|
||||
"https://git.lucasrguerra.dev.br/lucasrguerra/guara/releases/latest/download/latest.json"
|
||||
],
|
||||
"windows": {
|
||||
"installMode": "passive"
|
||||
|
||||
Executable
+70
@@ -0,0 +1,70 @@
|
||||
#!/usr/bin/env bash
|
||||
# Compila o app desktop (Tauri) e deixa os pacotes em dist-gui/.
|
||||
#
|
||||
# scripts/build-gui.sh linux # AppImage e .deb
|
||||
# scripts/build-gui.sh windows # instalador NSIS, compilado a partir do Linux
|
||||
# scripts/build-gui.sh windows-docker # o mesmo, num container, sem instalar nada
|
||||
#
|
||||
# O updater do Tauri assina cada pacote (createUpdaterArtifacts: true), então
|
||||
# TAURI_SIGNING_PRIVATE_KEY e TAURI_SIGNING_PRIVATE_KEY_PASSWORD precisam estar
|
||||
# no ambiente. Sem eles no ambiente, e com uma chave local em ~/.tauri (gerada
|
||||
# por `tauri signer generate`), este script a carrega sozinho.
|
||||
#
|
||||
# O Windows usa cargo-xwin (SDK do Windows baixado na hora) e o NSIS; o Tauri
|
||||
# documenta isso como compilação cruzada experimental. Precisa de: nsis, lld,
|
||||
# llvm, clang e `cargo install cargo-xwin`. O .msi não sai daqui (o WiX é só do
|
||||
# Windows).
|
||||
set -euo pipefail
|
||||
|
||||
cd "$(dirname "$0")/.."
|
||||
platform=${1:?uso: build-gui.sh <linux|windows|windows-docker>}
|
||||
tauri() { npx --yes @tauri-apps/cli@2 "$@"; }
|
||||
|
||||
if [ -z "${TAURI_SIGNING_PRIVATE_KEY:-}" ] && [ -f "$HOME/.tauri/guara-updater.key" ]; then
|
||||
export TAURI_SIGNING_PRIVATE_KEY="$(cat "$HOME/.tauri/guara-updater.key")"
|
||||
[ -f "$HOME/.tauri/guara-updater.pass" ] && export TAURI_SIGNING_PRIVATE_KEY_PASSWORD="$(cat "$HOME/.tauri/guara-updater.pass")"
|
||||
fi
|
||||
: "${TAURI_SIGNING_PRIVATE_KEY:?defina TAURI_SIGNING_PRIVATE_KEY (ou gere a chave local com 'tauri signer generate')}"
|
||||
|
||||
if [ "$platform" = windows-docker ]; then
|
||||
docker volume create guara-cargo >/dev/null
|
||||
docker volume create guara-rustup >/dev/null
|
||||
mkdir -p dist-gui
|
||||
exec docker run --rm -v "$PWD":/src -v guara-cargo:/root/.cargo -v guara-rustup:/root/.rustup \
|
||||
-w /src -e HOST_UID="$(id -u)" -e HOST_GID="$(id -g)" \
|
||||
-e TAURI_SIGNING_PRIVATE_KEY -e TAURI_SIGNING_PRIVATE_KEY_PASSWORD \
|
||||
ubuntu:24.04 bash -c '
|
||||
set -e
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
apt-get update -qq
|
||||
apt-get install -y -qq curl ca-certificates build-essential pkg-config nsis lld llvm clang nodejs npm unzip >/dev/null
|
||||
[ -x /root/.cargo/bin/rustup ] || curl -fsSL https://sh.rustup.rs | sh -s -- -y --profile minimal >/dev/null
|
||||
export PATH=/root/.cargo/bin:$PATH
|
||||
command -v cargo-xwin >/dev/null || cargo install cargo-xwin --locked
|
||||
scripts/build-gui.sh windows
|
||||
chown -R "$HOST_UID:$HOST_GID" dist-gui apps/gui/src-tauri/target 2>/dev/null || true'
|
||||
fi
|
||||
|
||||
mkdir -p dist-gui
|
||||
cd apps/gui/src-tauri
|
||||
|
||||
[ -f icons/icon.ico ] || tauri icon icons/source.png -o icons
|
||||
|
||||
case "$platform" in
|
||||
linux)
|
||||
tauri build --bundles appimage,deb
|
||||
bundle=target/release/bundle
|
||||
cp "$bundle"/appimage/*.AppImage "$bundle"/deb/*.deb ../../../dist-gui/
|
||||
cp "$bundle"/appimage/*.AppImage.sig ../../../dist-gui/ 2>/dev/null || true
|
||||
;;
|
||||
windows)
|
||||
rustup target add x86_64-pc-windows-msvc >/dev/null
|
||||
tauri build --runner cargo-xwin --target x86_64-pc-windows-msvc --bundles nsis
|
||||
bundle=target/x86_64-pc-windows-msvc/release/bundle/nsis
|
||||
cp "$bundle"/*-setup.exe ../../../dist-gui/
|
||||
cp "$bundle"/*-setup.exe.sig ../../../dist-gui/ 2>/dev/null || true
|
||||
;;
|
||||
*) echo "plataforma desconhecida: $platform" >&2; exit 2 ;;
|
||||
esac
|
||||
|
||||
ls -1 ../../../dist-gui
|
||||
Regular → Executable
+24
-17
@@ -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())
|
||||
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:
|
||||
|
||||
Executable
+36
@@ -0,0 +1,36 @@
|
||||
#!/usr/bin/env bash
|
||||
# Compila o CLI para uma plataforma e empacota: guara-<tag>-<plataforma>.tar.gz
|
||||
# com um .sha256 ao lado.
|
||||
#
|
||||
# scripts/package-cli.sh v1.3.2 linux-x86_64 x86_64-unknown-linux-gnu
|
||||
#
|
||||
# Plataformas: linux-x86_64 e linux-aarch64. O alvo diferente da máquina de
|
||||
# build usa o linker cruzado correspondente (gcc-x86-64-linux-gnu). Escreve os
|
||||
# arquivos na raiz do repositório e imprime os nomes.
|
||||
set -euo pipefail
|
||||
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
tag=${1:?uso: package-cli.sh <tag> <plataforma> <alvo-rust>}
|
||||
platform=${2:?uso: package-cli.sh <tag> <plataforma> <alvo-rust>}
|
||||
target=${3:?uso: package-cli.sh <tag> <plataforma> <alvo-rust>}
|
||||
|
||||
if [ "$target" = x86_64-unknown-linux-gnu ] && [ "$(uname -m)" != x86_64 ]; then
|
||||
export CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=x86_64-linux-gnu-gcc
|
||||
export CC_x86_64_unknown_linux_gnu=x86_64-linux-gnu-gcc
|
||||
fi
|
||||
|
||||
rustup target add "$target" >/dev/null 2>&1 || true
|
||||
cargo build --release --locked -p guara-cli --target "$target"
|
||||
|
||||
name="guara-${tag}-${platform}"
|
||||
rm -rf "$name"; mkdir "$name"
|
||||
cp "${CARGO_TARGET_DIR:-target}/${target}/release/guara" "$name/"
|
||||
cp README.md LICENSE-MIT LICENSE-APACHE "$name/"
|
||||
|
||||
tar czf "$name.tar.gz" "$name"
|
||||
asset="$name.tar.gz"
|
||||
rm -rf "$name"
|
||||
sha256sum "$asset" > "$asset.sha256"
|
||||
echo "$asset"
|
||||
echo "$asset.sha256"
|
||||
Executable
+24
@@ -0,0 +1,24 @@
|
||||
#!/usr/bin/env bash
|
||||
# Anexa arquivos a uma release do Gitea, trocando os de mesmo nome (assim uma
|
||||
# execução repetida do CI não falha por anexo duplicado).
|
||||
#
|
||||
# API=https://git.exemplo.com/api/v1/repos/dono/repo TOKEN=... \
|
||||
# scripts/release-upload.sh v1.2.3 arquivo1 arquivo2
|
||||
set -euo pipefail
|
||||
|
||||
: "${API:?defina API (URL do repositório na API do Gitea)}"
|
||||
: "${TOKEN:?defina TOKEN}"
|
||||
tag=${1:?uso: release-upload.sh <tag> <arquivo>...}
|
||||
shift
|
||||
|
||||
auth=(-H "Authorization: token $TOKEN")
|
||||
id=$(curl -fsS "${auth[@]}" "$API/releases/tags/$tag" | jq -r .id)
|
||||
|
||||
for file in "$@"; do
|
||||
name=$(basename "$file")
|
||||
for old in $(curl -fsS "${auth[@]}" "$API/releases/$id/assets" | jq -r --arg n "$name" '.[] | select(.name == $n) | .id'); do
|
||||
curl -fsS -X DELETE "${auth[@]}" "$API/releases/$id/assets/$old"
|
||||
done
|
||||
curl -fsS -X POST "${auth[@]}" -F "attachment=@$file" "$API/releases/$id/assets?name=$name" >/dev/null
|
||||
echo "enviado: $name"
|
||||
done
|
||||
@@ -8,37 +8,34 @@ spec = importlib.util.spec_from_file_location("m", os.path.join(os.path.dirname(
|
||||
m = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(m)
|
||||
|
||||
BASE = "https://github.com/x/y/releases/download/v1.3.0/"
|
||||
BASE = "https://git.lucasrguerra.dev.br/lucasrguerra/guara/releases/download/v1.3.2/"
|
||||
|
||||
|
||||
def assets(version="1.3.0"):
|
||||
def assets(version="1.3.2"):
|
||||
names = [p.format(v=version) for _, p in m.PLATFORMS]
|
||||
return {n: (BASE + n, f"assinatura-de-{n}\n") for n in names}
|
||||
|
||||
|
||||
class LatestJson(unittest.TestCase):
|
||||
def test_all_platforms_and_variants(self):
|
||||
d = m.build("1.3.0", "### Novidades\n", assets(), "2026-10-23T12:00:00Z")
|
||||
self.assertEqual(d["version"], "1.3.0")
|
||||
d = m.build("1.3.2", "### Novidades\n", assets(), "2026-10-30T12:00:00Z")
|
||||
self.assertEqual(d["version"], "1.3.2")
|
||||
self.assertEqual(d["notes"], "### Novidades")
|
||||
p = d["platforms"]
|
||||
for k in ("linux-x86_64", "linux-x86_64-appimage", "windows-x86_64", "windows-x86_64-nsis",
|
||||
"windows-x86_64-msi", "darwin-aarch64", "darwin-x86_64"):
|
||||
for k in ("linux-x86_64", "linux-x86_64-appimage", "windows-x86_64", "windows-x86_64-nsis"):
|
||||
self.assertIn(k, p)
|
||||
# a chave genérica do Windows aponta para o instalador NSIS, não para o MSI
|
||||
self.assertTrue(p["windows-x86_64"]["url"].endswith("x64-setup.exe"))
|
||||
self.assertTrue(p["windows-x86_64-msi"]["url"].endswith(".msi"))
|
||||
self.assertEqual(p["linux-x86_64"]["signature"], "assinatura-de-Guara_1.3.0_amd64.AppImage")
|
||||
self.assertEqual(p["linux-x86_64"]["signature"], "assinatura-de-Guara_1.3.2_amd64.AppImage")
|
||||
|
||||
def test_missing_package_is_left_out(self):
|
||||
a = assets()
|
||||
del a["Guara_1.3.0_x64.app.tar.gz"]
|
||||
d = m.build("1.3.0", "", a, "2026-10-23T12:00:00Z")
|
||||
self.assertNotIn("darwin-x86_64", d["platforms"])
|
||||
self.assertIn("darwin-aarch64", d["platforms"])
|
||||
del a["Guara_1.3.2_x64-setup.exe"]
|
||||
d = m.build("1.3.2", "", a, "2026-10-30T12:00:00Z")
|
||||
self.assertNotIn("windows-x86_64", d["platforms"])
|
||||
self.assertIn("linux-x86_64", d["platforms"])
|
||||
|
||||
def test_other_versions_do_not_leak(self):
|
||||
d = m.build("1.3.0", "", assets("1.2.0"), "2026-10-23T12:00:00Z")
|
||||
d = m.build("1.3.2", "", assets("1.2.0"), "2026-10-30T12:00:00Z")
|
||||
self.assertEqual(d["platforms"], {})
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user