From 215a3ac40594f9a6e54a184ff42b8a5f6a334403 Mon Sep 17 00:00:00 2001 From: Julian Cuni Date: Wed, 24 Jun 2026 10:32:29 +0200 Subject: [PATCH] fix(ci): publish desktop installers via Gitea Release, not upload-artifact actions/upload-artifact@v4's backend fails on the Gitea runner (Upload installers step errored). Mirror release.yml's proven path instead: curl + the built-in token to the Releases API, into a ROLLING per-branch prerelease (tag desktop-, deleted+recreated each push). Installers renamed space-free (parking-desktop--.{deb,AppImage}). Signed v* releases unchanged. Claude-Session: https://claude.ai/code/session_01Xcm6ikLgGoCxxHrxtjkk5V --- .gitea/workflows/build-desktop.yml | 53 +++++++++++++++++++++++---- wiki/decisions/desktop-shell-tauri.md | 20 +++++++--- 2 files changed, 59 insertions(+), 14 deletions(-) diff --git a/.gitea/workflows/build-desktop.yml b/.gitea/workflows/build-desktop.yml index 8c43638..cee90a3 100644 --- a/.gitea/workflows/build-desktop.yml +++ b/.gitea/workflows/build-desktop.yml @@ -81,17 +81,54 @@ jobs: - name: Collect installers id: collect + # Copy out the two installers under SPACE-FREE names (tauri names them + # "Parking System_0.0.0_amd64.deb" — spaces break asset URLs). Short SHA in the + # name so a downloaded file is traceable to its commit. run: | set -e BUNDLE=apps/desktop/src-tauri/target/release/bundle + SHA="$(echo "${GITHUB_SHA}" | cut -c1-7)" mkdir -p dist - find "$BUNDLE" \( -name '*.AppImage' -o -name '*.deb' \) -exec cp {} dist/ \; + deb=$(find "$BUNDLE/deb" -name '*.deb' | head -1) + app=$(find "$BUNDLE/appimage" -name '*.AppImage' | head -1) + cp "$deb" "dist/parking-desktop-${GITHUB_REF_NAME}-${SHA}.deb" + cp "$app" "dist/parking-desktop-${GITHUB_REF_NAME}-${SHA}.AppImage" echo "Artifacts:"; ls -la dist/ - - name: Upload installers - uses: actions/upload-artifact@v4 - with: - name: desktop-${{ github.ref_name }}-${{ github.sha }} - path: dist/* - if-no-files-found: error - retention-days: 14 + - name: Publish to a rolling per-branch pre-release + # actions/upload-artifact's backend isn't reliable on this Gitea runner, so we + # publish to a Gitea RELEASE via the API instead (the proven pattern from + # release.yml — built-in token, plain curl). One ROLLING pre-release per branch + # (tag desktop-): delete + recreate each push so it always holds the + # latest dev/main installer. This is NOT the signed updater release (release.yml, + # tag v*) — it's a prerelease, unsigned, with no latest.json. + env: + TOKEN: ${{ secrets.GITHUB_TOKEN }} + API: ${{ github.api_url }} + REPO: ${{ github.repository }} + TAG: desktop-${{ github.ref_name }} + run: | + set -e + auth="Authorization: token ${TOKEN}" + # Drop any existing rolling release for this branch (ignore if absent) so its + # tag + stale assets don't pile up; recreate it fresh below. + OLD=$(curl -sS -H "$auth" "${API}/repos/${REPO}/releases/tags/${TAG}" \ + | grep -o '"id":[0-9]*' | head -1 | cut -d: -f2 || true) + if [ -n "$OLD" ]; then + curl -sS -X DELETE -H "$auth" "${API}/repos/${REPO}/releases/${OLD}" || true + # Also delete the tag itself so the recreate points at this commit. + curl -sS -X DELETE -H "$auth" "${API}/repos/${REPO}/git/refs/tags/${TAG}" || true + fi + REL=$(curl -sS -X POST -H "$auth" -H "Content-Type: application/json" \ + -d "{\"tag_name\":\"${TAG}\",\"target_commitish\":\"${GITHUB_SHA}\",\"name\":\"Desktop build (${GITHUB_REF_NAME})\",\"body\":\"Unsigned per-commit desktop installers from ${GITHUB_REF_NAME} @ ${GITHUB_SHA}. Rolling — overwritten each push. Not an updater release.\",\"draft\":false,\"prerelease\":true}" \ + "${API}/repos/${REPO}/releases") + REL_ID=$(printf '%s' "$REL" | grep -o '"id":[0-9]*' | head -1 | cut -d: -f2) + echo "release id: ${REL_ID}" + for f in dist/*; do + name=$(basename "$f") + echo "uploading ${name}" + curl -sS -X POST -H "$auth" -H "Content-Type: application/octet-stream" \ + --data-binary @"${f}" \ + "${API}/repos/${REPO}/releases/${REL_ID}/assets?name=${name}" >/dev/null + done + echo "done" diff --git a/wiki/decisions/desktop-shell-tauri.md b/wiki/decisions/desktop-shell-tauri.md index a3494d7..e2d8bba 100644 --- a/wiki/decisions/desktop-shell-tauri.md +++ b/wiki/decisions/desktop-shell-tauri.md @@ -177,12 +177,20 @@ The desktop bundle now runs in CI under **two distinct workflows** — keep the and publishes a Gitea Release. This is what the auto-updater consumes. Unchanged. - **`.gitea/workflows/build-desktop.yml`** (push to `dev`/`main`) — a **per-commit test build**: compiles `.deb` + `.AppImage` only (`pnpm --filter @parking/desktop bundle --bundles deb,appimage`) - and uploads them as **workflow artifacts** (14-day retention). **Unsigned** — no `TAURI_SIGNING_*`, - no Release, no `latest.json` — so it must NEVER be wired to the updater (an unsigned artifact would - be rejected anyway). It exists so each branch push yields a downloadable installer for manual - testing of the native shell, and catches a broken Tauri/Rust build early. Same system-deps + cargo - cache as `release.yml`. The container images (`build-images.yml`) and the desktop installers are - deliberately separate pipelines — the desktop app is **not** containerized ([[container-deployment]]). + and publishes them to a **rolling per-branch pre-release** (tag `desktop-`). **Unsigned** — + no `TAURI_SIGNING_*`, no `latest.json` — so it must NEVER be wired to the updater (an unsigned + artifact would be rejected anyway). It exists so each branch push yields a downloadable installer + for manual testing of the native shell, and catches a broken Tauri/Rust build early. Same + system-deps + cargo cache as `release.yml`. The container images (`build-images.yml`) and the + desktop installers are deliberately separate pipelines — the desktop app is **not** containerized + ([[container-deployment]]). + - **Delivery: a rolling pre-release, NOT `actions/upload-artifact`.** That action's artifact + backend isn't reliable on the Gitea runner (the *Upload installers* step failed). Instead the + workflow mirrors `release.yml`'s proven path — plain `curl` + the built-in `GITHUB_TOKEN` to the + **Releases API**. It DELETEs any existing `desktop-` release + tag, recreates it against + the new commit as a **prerelease**, and uploads the two installers (renamed space-free, + `parking-desktop--.{deb,AppImage}`). So `desktop-dev` always holds the newest dev + build; `v*` tags remain the only *signed* releases. - **Gotcha (the unsigned build still demands the key).** `tauri.conf.json` sets `bundle.createUpdaterArtifacts: true` (so `release.yml` produces the `.sig` updater signatures). With that on, `tauri build` **fails** if `TAURI_SIGNING_PRIVATE_KEY` is absent — *"A public key