#!/bin/sh # desktop-stamp.sh -- Stempel aus Version + letztem Commit an den # Desktop-Pfaden berechnen und pruefen, ob dazu bereits fertige Pakete im # Zwischenspeicher des Runners liegen (quick-260917-jdh). # # Zweck: Der CI-Job `desktop` baut die Rust/Tauri-Pakete heute bei jedem # Push auf main, auch wenn sich an der Desktop-App seit dem letzten Bau # nichts geaendert hat. Dieses Skript berechnet einen Stempel aus der # aktuellen Versionsnummer und dem letzten Commit an den Desktop-Pfaden; # liegen zu diesem Stempel bereits geprueft-vollstaendige Pakete im # Zwischenspeicher, kann der Job den kompletten Bau ueberspringen. # # Aufrufformen: # desktop-stamp.sh stamp -- Stempel berechnen, Ausgaben: stamp, version, # sha7, skip_allowed (Version aus # desktop-version.sh --print; SHA aus dem # letzten Commit an DESKTOP_PATHS) # desktop-stamp.sh check -- prueft, ob ein per stamp-cache restaurierter # desktop-dist/ vollstaendig und stempel-echt # ist, Ausgaben: reuse, bei Treffer zusaetzlich # files # # Umgebungsvariablen: # DESKTOP_TAG nur fuer stamp, lokale Probe (siehe desktop-version.sh) # GITHUB_REF nur fuer stamp: skip_allowed=true ausschliesslich bei # refs/heads/main (Beta-Kanal) -- Tags bauen immer neu # GITHUB_OUTPUT nur fuer stamp: wenn gesetzt, werden alle Ausgaben # zusaetzlich per >> hineingeschrieben (wie im CI ueblich) # CACHE_HIT nur fuer check: Ergebnis von actions/cache/restore # (steps..outputs.cache-hit), muss exakt "true" sein # STAMP_VERSION nur fuer check: Version aus dem stamp-Schritt, muss mit # der Version im Manifest uebereinstimmen # STAMP_SHA7 nur fuer check: 7-stelliger SHA aus dem stamp-Schritt, # nur fuer die Log-Zeile bei Treffer # DESKTOP_DIST nur fuer check: Zielordner der Pakete (Vorgabe: # desktop-dist, wie desktop-collect.sh) # # DESKTOP_PATHS deckt alle Bau-Eingaben ab: apps/desktop (inkl. # Cargo.lock/package.json), die drei Skripte und die Workflow-Datei selbst # (eine Aenderung an der Stempelregel muss selbst einen Neubau ausloesen). # `pnpm-lock.yaml` steht bewusst NICHT in der Liste: die Tauri-CLI-Version # haengt an apps/desktop/package.json (darin enthalten), und der Desktop-Bau # liest ausserhalb von apps/desktop keine Werkstatt-Datei -- frontendDist ist # ../src innerhalb von apps/desktop, keine Abhaengigkeit auf packages/*. # # quick-260917-kgc: `check` verlangt zusaetzlich `updateVersion` und je # Plattform `files.

.signature` im gecachten Manifest -- ein Cache-Stand # aus der Zeit vor der Update-Funktion (oder aus einem Bau mit --no-sign) # wird nie uebernommen, sonst lieferte der Update-Endpunkt dauerhaft 204. # Ein Schluesselwechsel (`pubkey` in tauri.conf.json unter apps/desktop) # aendert den Stempel automatisch, weil apps/desktop in DESKTOP_PATHS liegt. # # Dieses Skript kennt kein Secret. set -eu DESKTOP_PATHS="apps/desktop .gitea/scripts/desktop-version.sh .gitea/scripts/desktop-collect.sh .gitea/scripts/desktop-stamp.sh .gitea/workflows/ci.yml" out() { printf '%s=%s\n' "$1" "$2" if [ -n "${GITHUB_OUTPUT:-}" ]; then printf '%s=%s\n' "$1" "$2" >> "$GITHUB_OUTPUT" fi } cmd_stamp() { VERSION="$("$(dirname "$0")/desktop-version.sh" --print)" # Bewusst ungequotet: Wortaufteilung der leerzeichengetrennten Pfadliste. LAST="$(git log -1 --format=%H -- $DESKTOP_PATHS)" if [ -z "$LAST" ]; then echo "Keine Historie zu den Desktop-Pfaden -- im CI ist fetch-depth: 0 Pflicht." >&2 exit 1 fi SHA7="$(git rev-parse --short=7 "$LAST")" SUBJECT="$(git log -1 --format=%s "$LAST")" SKIP=false REF="${GITHUB_REF:-}" if [ "$REF" = "refs/heads/main" ]; then SKIP=true echo "Stempel $VERSION-$LAST ($SHA7: $SUBJECT) -- Ueberspringen erlaubt (main)." else echo "Stempel $VERSION-$LAST ($SHA7: $SUBJECT) -- Tag oder fremder Zweig, es wird immer gebaut." fi out stamp "$VERSION-$LAST" out version "$VERSION" out sha7 "$SHA7" out skip_allowed "$SKIP" } cmd_check() { CACHE_HIT="${CACHE_HIT:-}" STAMP_VERSION="${STAMP_VERSION:-}" STAMP_SHA7="${STAMP_SHA7:-}" DESKTOP_DIST="${DESKTOP_DIST:-desktop-dist}" MANIFEST="$DESKTOP_DIST/manifest.json" no_reuse() { echo "Kein uebernehmbarer Stand ($1) -- Desktop wird gebaut." rm -f "$DESKTOP_DIST"/*.AppImage "$DESKTOP_DIST"/*.exe "$MANIFEST" out reuse false exit 0 } check_file() { # $1 = Manifest-Schluessel (linux|windows), $2 = Dateiname FPATH="$DESKTOP_DIST/$2" if [ ! -f "$FPATH" ]; then no_reuse "Datei $2 fehlt" fi SIZE="$(stat -c %s "$FPATH")" EXP_SIZE="$(jq -r ".files.$1.size" "$MANIFEST")" if [ "$SIZE" != "$EXP_SIZE" ]; then no_reuse "Groesse von $2 weicht ab ($SIZE statt $EXP_SIZE)" fi SHA="$(sha256sum "$FPATH" | cut -d' ' -f1)" EXP_SHA="$(jq -r ".files.$1.sha256" "$MANIFEST")" if [ "$SHA" != "$EXP_SHA" ]; then no_reuse "Pruefsumme von $2 weicht ab" fi SIG="$(jq -r ".files.$1.signature // empty" "$MANIFEST")" if [ -z "$SIG" ]; then no_reuse "Signatur fuer $2 fehlt im Manifest" fi } if [ "$CACHE_HIT" != "true" ]; then no_reuse "kein Zwischenspeicher zum Stempel" fi if [ ! -f "$MANIFEST" ] || ! jq -e . "$MANIFEST" >/dev/null 2>&1; then no_reuse "Manifest fehlt oder ist kein gueltiges JSON" fi CHANNEL="$(jq -r .channel "$MANIFEST")" if [ "$CHANNEL" != "beta" ]; then no_reuse "Kanal $CHANNEL statt beta" fi MVERSION="$(jq -r .version "$MANIFEST")" if [ "$MVERSION" != "$STAMP_VERSION" ]; then no_reuse "Version $MVERSION statt $STAMP_VERSION" fi UPDATE_VERSION="$(jq -r '.updateVersion // empty' "$MANIFEST")" if [ -z "$UPDATE_VERSION" ]; then no_reuse "updateVersion fehlt im Manifest (Stand vor der Update-Funktion)" fi LINUX_NAME="$(jq -r '.files.linux.name // empty' "$MANIFEST")" WINDOWS_NAME="$(jq -r '.files.windows.name // empty' "$MANIFEST")" if [ -z "$LINUX_NAME" ] || [ -z "$WINDOWS_NAME" ]; then no_reuse "Dateiname fehlt im Manifest" fi check_file linux "$LINUX_NAME" check_file windows "$WINDOWS_NAME" COMMIT="$(jq -r .commit "$MANIFEST")" BUILD_TIME="$(jq -r .buildTime "$MANIFEST")" echo "Desktop unveraendert seit $STAMP_SHA7: Pakete $LINUX_NAME, $WINDOWS_NAME aus dem Zwischenspeicher (gebaut aus $COMMIT am $BUILD_TIME)" out reuse true out files "$LINUX_NAME,$WINDOWS_NAME" } case "${1:-}" in stamp) cmd_stamp ;; check) cmd_check ;; *) echo "Aufruf: $0 stamp|check" >&2 exit 1 ;; esac