#!/bin/sh # Creates (or reuses) the Gitea release for this version, uploads the desktop bundles to it, and writes # updater/latest.json, which the Windows app checks for updates (src-tauri/src/updates.rs). # # GITEA_TOKEN=… TAURI_SIGNING_PRIVATE_KEY_PATH=… scripts/gitea-release.sh [dir-with-files] (default ../release/desktop) # # GITEA_TOKEN: a Gitea access token with the write:repository scope (Settings → Applications). The tag # v must already be pushed. Files: *.AppImage, *.deb, *.rpm, *-setup.exe, kestrove-nmh-*, SHA256SUMS. # # Updates: the Windows installer needs an updater signature (.sig) from the Kestrove updater key, whose # public half is in src-tauri/tauri.conf.json. Sign after Authenticode signing: the signature covers the final # file. With TAURI_SIGNING_PRIVATE_KEY_PATH set, a missing .sig is made here (the key's password is asked for, or # read from TAURI_SIGNING_PRIVATE_KEY_PASSWORD). Optional NOTES: the text shown with the update. # Users get the update only once updater/latest.json is committed and pushed to main (printed at the end). set -eu cd "$(dirname "$0")/.." : "${GITEA_TOKEN:?set GITEA_TOKEN (Gitea → Settings → Applications → token with write:repository)}" API=${GITEA_API:-https://gitea.samialabri.com/api/v1} REPO=${GITEA_REPO:-kestrove/kestrove-desktop} DIR=${1:-../release/desktop} V=$(node -p 'require("./package.json").version') TAG="v$V" AUTH="Authorization: token $GITEA_TOKEN" SETUP="$DIR/Kestrove_${V}_x64-setup.exe" if [ -f "$SETUP" ] && [ ! -f "$SETUP.sig" ]; then : "${TAURI_SIGNING_PRIVATE_KEY_PATH:?$SETUP.sig is missing: set TAURI_SIGNING_PRIVATE_KEY_PATH to the updater key to sign it}" # --app-version binds the signature to this version (the app requires it), so an older signed installer can't # be offered again under a newer version number. npx tauri signer sign -f "$TAURI_SIGNING_PRIVATE_KEY_PATH" ${TAURI_SIGNING_PRIVATE_KEY_PASSWORD+-p "$TAURI_SIGNING_PRIVATE_KEY_PASSWORD"} \ --app-version "$V" "$SETUP" fi (cd "$DIR" && rm -f SHA256SUMS && shasum -a 256 -- *.AppImage *.deb *.rpm *-setup.exe kestrove-nmh-* 2>/dev/null > SHA256SUMS; cat SHA256SUMS) ID=$(curl -fsS -H "$AUTH" "$API/repos/$REPO/releases/tags/$TAG" 2>/dev/null | node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>{try{console.log(JSON.parse(s).id||"")}catch{console.log("")}})') if [ -z "$ID" ]; then BODY=$(node -e 'console.log(JSON.stringify({tag_name: process.argv[1], name: "Kestrove " + process.argv[2], body: "Kestrove desktop " + process.argv[2] + " for Windows and Linux. On a Mac, use the Kestrove app from the Mac App Store instead.\n\nVerify downloads with SHA256SUMS.", draft: false, prerelease: false}))' "$TAG" "$V") ID=$(curl -fsS -X POST -H "$AUTH" -H "Content-Type: application/json" -d "$BODY" "$API/repos/$REPO/releases" | node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>console.log(JSON.parse(s).id))') fi for f in "$DIR"/*.AppImage "$DIR"/*.deb "$DIR"/*.rpm "$DIR"/*-setup.exe "$DIR"/*-setup.exe.sig "$DIR"/kestrove-nmh-* "$DIR"/SHA256SUMS; do [ -f "$f" ] || continue echo "uploading $(basename "$f")" curl -fsS -X POST -H "$AUTH" -F "attachment=@$f" "$API/repos/$REPO/releases/$ID/assets?name=$(basename "$f")" >/dev/null done echo "Release: ${API%/api/v1}/$REPO/releases/tag/$TAG" # The update manifest, written only after the installer it points to is uploaded. if [ -f "$SETUP.sig" ]; then mkdir -p updater node -e ' const [v, url, sigFile, notes] = process.argv.slice(1); const signature = require("fs").readFileSync(sigFile, "utf8").trim(); const doc = { version: v, notes, pub_date: new Date().toISOString().replace(/\.\d+Z$/, "Z"), platforms: { "windows-x86_64": { signature, url } } }; require("fs").writeFileSync("updater/latest.json", JSON.stringify(doc, null, 2) + "\n"); ' "$V" "${API%/api/v1}/$REPO/releases/download/$TAG/$(basename "$SETUP")" "$SETUP.sig" "${NOTES:-Kestrove $V}" echo "Wrote updater/latest.json. To offer the update, commit it and push to main:" echo " git add updater/latest.json && git commit -m \"Offer $V as an update\" && git push origin main" fi