ae8fecb538
Die duenne Strecke Skript -> Abbild -> API beweisen (D-08, D-10): - desktop-collect.sh sammelt AppImage/exe ein, schreibt manifest.json (Version, Kanal, Commit, Groesse, SHA-256) ohne Secrets - apps/api/src/desktop/: neues Modul mit GET /desktop/latest und GET /desktop/download/:platform, beide @Public(); Plattform-Whitelist vor jedem Dateisystemzugriff, Dateiname ausschliesslich aus dem Manifest (T-18-01, T-18-02) - packages/shared: DesktopPlatform/-Manifest(File)/-Latest(Response) Typen - Dockerfile kopiert desktop-dist/ in die runner-Stufe; desktop-dist/ per .gitkeep + .gitignore versioniert (leeres Verzeichnis, Pakete bleiben ungetrackt) - HTTP-Durchstich-Spec (8 Tests) via NestFactory, kein fs-Mock; echtes Temp-Verzeichnis + unabhaengig berechneter SHA-256 Abweichung: DesktopController braucht @Inject(DesktopService) explizit — Vitest transpiliert ueber esbuild, das emitDecoratorMetadata nicht abbildet, sonst bleibt desktopService bei einem echten NestFactory-Bau undefined (Rule 3, Blocker). Lokal bewiesen: neu gebautes API-Abbild liefert /desktop/latest (200) und /desktop/download/linux (200, attachment) aus, auch ueber /api-proxy/ des Web-Containers. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
157 lines
5.0 KiB
Bash
Executable File
157 lines
5.0 KiB
Bash
Executable File
#!/bin/sh
|
|
# desktop-collect.sh -- Desktop-Pakete aus dem Tauri-Bau einsammeln, unter
|
|
# kanonischem Namen ablegen und manifest.json schreiben (Phase 18, D-08).
|
|
#
|
|
# Kanalmodell (identisch zu publish-images.sh, an GITHUB_REF entschieden,
|
|
# damit lokale Proben ohne Runner pruefbar sind):
|
|
# refs/tags/v* -> Kanal live, kein Namenssuffix
|
|
# refs/heads/main -> Kanal beta, Suffix -beta.{7-stelliger SHA} am Dateinamen
|
|
# alles andere -> Kanal dev, kein Suffix (lokale Proben tragen den
|
|
# Freigabe-Namen, damit desktop-version.sh/desktop-collect.sh
|
|
# ohne Pipeline durchgespielt werden koennen)
|
|
#
|
|
# Aufruf: sh .gitea/scripts/desktop-collect.sh --require linux[,windows]
|
|
#
|
|
# Umgebung:
|
|
# GITHUB_REF Kanalentscheidung (siehe oben)
|
|
# DESKTOP_DIST Zielordner fuer die Pakete (Vorgabe: desktop-dist)
|
|
# TAURI_DIR Tauri-Projektordner (Vorgabe: apps/desktop/src-tauri)
|
|
#
|
|
# Die Version kommt aus tauri.conf.json (von desktop-version.sh geschrieben
|
|
# oder als eingecheckte Basislinie vorhanden) -- dieses Skript liest sie nur,
|
|
# es schreibt sie nicht. Dieses Skript kennt kein Secret.
|
|
set -eu
|
|
|
|
REQUIRE=""
|
|
while [ $# -gt 0 ]; do
|
|
case "$1" in
|
|
--require)
|
|
shift
|
|
REQUIRE="${1:-}"
|
|
;;
|
|
*)
|
|
echo "Unbekanntes Argument: $1" >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
shift
|
|
done
|
|
|
|
if [ -z "$REQUIRE" ]; then
|
|
echo "Aufruf: $0 --require linux[,windows]" >&2
|
|
exit 1
|
|
fi
|
|
|
|
DESKTOP_DIST="${DESKTOP_DIST:-desktop-dist}"
|
|
TAURI_DIR="${TAURI_DIR:-apps/desktop/src-tauri}"
|
|
REF="${GITHUB_REF:-}"
|
|
|
|
case "$REF" in
|
|
refs/tags/v*)
|
|
CHANNEL=live
|
|
SUFFIX=""
|
|
;;
|
|
refs/heads/main)
|
|
CHANNEL=beta
|
|
SHA_SHORT="$(git rev-parse --short=7 HEAD)"
|
|
SUFFIX="-beta.$SHA_SHORT"
|
|
;;
|
|
*)
|
|
CHANNEL=dev
|
|
SUFFIX=""
|
|
;;
|
|
esac
|
|
|
|
VERSION="$(jq -r .version "$TAURI_DIR/tauri.conf.json")"
|
|
case "$VERSION" in
|
|
[0-9]*.[0-9]*.[0-9]*)
|
|
if ! printf '%s' "$VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+$'; then
|
|
echo "Version '$VERSION' aus $TAURI_DIR/tauri.conf.json ist nicht rein numerisch (X.Y.Z)." >&2
|
|
exit 1
|
|
fi
|
|
;;
|
|
*)
|
|
echo "Version '$VERSION' aus $TAURI_DIR/tauri.conf.json ist nicht rein numerisch (X.Y.Z)." >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
COMMIT="$(git rev-parse --short=7 HEAD)"
|
|
BUILD_TIME="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
|
|
mkdir -p "$DESKTOP_DIST"
|
|
# Alte Pakete/Manifest entfernen, Platzhalter (.gitkeep) bleibt erhalten.
|
|
rm -f "$DESKTOP_DIST"/*.AppImage "$DESKTOP_DIST"/*.exe "$DESKTOP_DIST/manifest.json"
|
|
|
|
MANIFEST_ARGS=""
|
|
TMP_MANIFEST="$(mktemp)"
|
|
trap 'rm -f "$TMP_MANIFEST"' EXIT INT TERM
|
|
|
|
LINUX_NAME=""
|
|
LINUX_SIZE=""
|
|
LINUX_SHA=""
|
|
WINDOWS_NAME=""
|
|
WINDOWS_SIZE=""
|
|
WINDOWS_SHA=""
|
|
|
|
case ",$REQUIRE," in
|
|
*,linux,*)
|
|
APPIMAGE_DIR="$TAURI_DIR/target/release/bundle/appimage"
|
|
APPIMAGE_COUNT="$(find "$APPIMAGE_DIR" -maxdepth 1 -name '*.AppImage' 2>/dev/null | wc -l | tr -d ' ')"
|
|
if [ "$APPIMAGE_COUNT" -ne 1 ]; then
|
|
echo "Erwartet genau eine .AppImage-Datei in $APPIMAGE_DIR, gefunden: $APPIMAGE_COUNT" >&2
|
|
exit 1
|
|
fi
|
|
APPIMAGE_SRC="$(find "$APPIMAGE_DIR" -maxdepth 1 -name '*.AppImage')"
|
|
LINUX_NAME="Tessera-${VERSION}${SUFFIX}.AppImage"
|
|
cp "$APPIMAGE_SRC" "$DESKTOP_DIST/$LINUX_NAME"
|
|
LINUX_SIZE="$(stat -c %s "$DESKTOP_DIST/$LINUX_NAME")"
|
|
LINUX_SHA="$(sha256sum "$DESKTOP_DIST/$LINUX_NAME" | cut -d' ' -f1)"
|
|
echo "linux: $LINUX_NAME (${LINUX_SIZE} Bytes, sha256 $LINUX_SHA)"
|
|
;;
|
|
esac
|
|
|
|
case ",$REQUIRE," in
|
|
*,windows,*)
|
|
NSIS_DIR="$TAURI_DIR/target/x86_64-pc-windows-msvc/release/bundle/nsis"
|
|
NSIS_COUNT="$(find "$NSIS_DIR" -maxdepth 1 -name '*.exe' 2>/dev/null | wc -l | tr -d ' ')"
|
|
if [ "$NSIS_COUNT" -ne 1 ]; then
|
|
echo "Erwartet genau eine .exe-Datei in $NSIS_DIR, gefunden: $NSIS_COUNT" >&2
|
|
exit 1
|
|
fi
|
|
NSIS_SRC="$(find "$NSIS_DIR" -maxdepth 1 -name '*.exe')"
|
|
WINDOWS_NAME="Tessera-Setup-${VERSION}${SUFFIX}.exe"
|
|
cp "$NSIS_SRC" "$DESKTOP_DIST/$WINDOWS_NAME"
|
|
WINDOWS_SIZE="$(stat -c %s "$DESKTOP_DIST/$WINDOWS_NAME")"
|
|
WINDOWS_SHA="$(sha256sum "$DESKTOP_DIST/$WINDOWS_NAME" | cut -d' ' -f1)"
|
|
echo "windows: $WINDOWS_NAME (${WINDOWS_SIZE} Bytes, sha256 $WINDOWS_SHA)"
|
|
;;
|
|
esac
|
|
|
|
# manifest.json ausschliesslich ueber jq -n mit --arg/--argjson bauen (kein
|
|
# manuelles String-Zusammenbauen von JSON).
|
|
jq -n \
|
|
--arg version "$VERSION" \
|
|
--arg channel "$CHANNEL" \
|
|
--arg commit "$COMMIT" \
|
|
--arg buildTime "$BUILD_TIME" \
|
|
--arg linuxName "$LINUX_NAME" \
|
|
--argjson linuxSize "${LINUX_SIZE:-null}" \
|
|
--arg linuxSha "$LINUX_SHA" \
|
|
--arg windowsName "$WINDOWS_NAME" \
|
|
--argjson windowsSize "${WINDOWS_SIZE:-null}" \
|
|
--arg windowsSha "$WINDOWS_SHA" \
|
|
'{
|
|
version: $version,
|
|
channel: $channel,
|
|
commit: $commit,
|
|
buildTime: $buildTime,
|
|
files: (
|
|
{}
|
|
+ (if $linuxName != "" then { linux: { name: $linuxName, size: $linuxSize, sha256: $linuxSha } } else {} end)
|
|
+ (if $windowsName != "" then { windows: { name: $windowsName, size: $windowsSize, sha256: $windowsSha } } else {} end)
|
|
)
|
|
}' > "$DESKTOP_DIST/manifest.json"
|
|
|
|
echo "Manifest geschrieben: $DESKTOP_DIST/manifest.json (Version $VERSION, Kanal $CHANNEL)"
|