Update über den Git-Server, Tests, Repo ohne node_modules und Sicherungen
- Admin → Update: neuere Versionen (Tags) vom Git-Server anzeigen und per Knopf einspielen; ausgeführt vom Dienst auf dem Rechner (Docker/update-einrichten.sh, Docker/update-ausfuehren.sh), nur vorwärts, Fehler bei ausbleibendem Neustart, abgebrochene Läufe sperren nicht - Tests (npm test): Zusammenführen paralleler Änderungen, Rechteprüfung beim Speichern; SESSIONS_DIR lenkt den Datenordner für Testserver um - node_modules, Sicherungen und Uploads aus dem Repo genommen - cors und requireRole() entfernt Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
e12936444d
commit
fd44db2213
2357 files changed
+588
-514948
No files matched your search
Executable
+72
@@ -0,0 +1,72 @@
|
||||
#!/usr/bin/env bash
|
||||
# update-ausfuehren.sh — führt einen Update-Auftrag aus der App aus
|
||||
# (Admin → Update, POST /admin/update legt sessions/update/auftrag.json an).
|
||||
# Gestartet vom systemd-Dienst projektuebersicht-update (eingerichtet von
|
||||
# Docker/update-einrichten.sh), läuft als root auf dem Rechner, nicht im
|
||||
# Container: Version vom Git-Server holen, auschecken, Container neu bauen
|
||||
# und starten. Fortschritt in sessions/update/status.json, Protokoll in
|
||||
# sessions/update/update.log, die laufende Version in installiert.json.
|
||||
#
|
||||
# Alles steht in main(): bash liest ein Skript sonst zeilenweise beim
|
||||
# Ausführen — und dieses Skript wird mitten im Lauf durch den Checkout ersetzt.
|
||||
set -u
|
||||
|
||||
main(){
|
||||
local REPO DIR AUFTRAG LOG VERSION EIGNER VORHER COMPOSE
|
||||
REPO="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
DIR="$REPO/sessions/update"
|
||||
AUFTRAG="$DIR/auftrag.json"
|
||||
LOG="$DIR/update.log"
|
||||
[ -f "$AUFTRAG" ] || return 0
|
||||
|
||||
VERSION=$(sed -n 's/.*"version":"\(v[0-9]\{1,4\}\.[0-9]\{1,4\}\.[0-9]\{1,4\}\)".*/\1/p' "$AUFTRAG")
|
||||
rm -f "$AUFTRAG"
|
||||
: > "$LOG"
|
||||
EIGNER=$(stat -c %U "$REPO")
|
||||
git_(){ runuser -u "$EIGNER" -- git -C "$REPO" "$@"; }
|
||||
status(){ # $1 Schritt, $2 läuft (true/false), $3 Fehlertext (fest, ohne Anführungszeichen)
|
||||
printf '{"version":"%s","schritt":"%s","laeuft":%s,"fehler":"%s","am":"%s"}\n' \
|
||||
"$VERSION" "$1" "$2" "${3:-}" "$(date -Iseconds)" > "$DIR/status.tmp" && mv "$DIR/status.tmp" "$DIR/status.json"
|
||||
}
|
||||
fehler(){ status "$1" false "$2"; echo "FEHLER: $2" >> "$LOG"; }
|
||||
|
||||
if [ -z "$VERSION" ]; then fehler "Auftrag" "Der Auftrag enthält keine gültige Version."; return 1; fi
|
||||
echo "Update auf $VERSION, $(date)" >> "$LOG"
|
||||
|
||||
status "Version holen" true
|
||||
if ! git_ fetch --tags --force origin >> "$LOG" 2>&1; then fehler "Version holen" "Der Git-Server ist nicht erreichbar."; return 1; fi
|
||||
if ! git_ rev-parse -q --verify "refs/tags/$VERSION^{commit}" >/dev/null; then fehler "Version holen" "Die Version gibt es auf dem Git-Server nicht."; return 1; fi
|
||||
# Lokale Änderungen am Code (sessions/ ausgenommen) nie überschreiben.
|
||||
if [ -n "$(git_ status --porcelain --untracked-files=no -- . ':!sessions')" ]; then
|
||||
git_ status --short -- . ':!sessions' >> "$LOG" 2>&1
|
||||
fehler "Prüfen" "Auf dem Rechner gibt es lokale Änderungen am Code. Bitte von Hand klären."; return 1
|
||||
fi
|
||||
VORHER=$(git_ rev-parse HEAD)
|
||||
if ! git_ checkout -q --detach "$VERSION" >> "$LOG" 2>&1; then fehler "Auschecken" "Auschecken fehlgeschlagen."; return 1; fi
|
||||
|
||||
if docker compose version >/dev/null 2>&1; then COMPOSE="docker compose"; else COMPOSE="docker-compose"; fi
|
||||
status "Container bauen" true
|
||||
# Gebaut wird, während die alte Version weiterläuft; erst danach Neustart.
|
||||
if ! $COMPOSE --project-directory "$REPO" -f "$REPO/docker-compose.yml" build >> "$LOG" 2>&1; then
|
||||
git_ checkout -q --detach "$VORHER" >> "$LOG" 2>&1
|
||||
fehler "Container bauen" "Bauen fehlgeschlagen, die bisherige Version läuft weiter."; return 1
|
||||
fi
|
||||
status "Neustart" true
|
||||
if ! $COMPOSE --project-directory "$REPO" -f "$REPO/docker-compose.yml" up -d >> "$LOG" 2>&1; then
|
||||
fehler "Neustart" "Der Container ließ sich nicht starten."; return 1
|
||||
fi
|
||||
local i gesund=0
|
||||
for i in $(seq 1 60); do
|
||||
if wget -qO- http://127.0.0.1:3003/health >/dev/null 2>&1 || curl -fs http://127.0.0.1:3003/health >/dev/null 2>&1; then gesund=1; break; fi
|
||||
sleep 5
|
||||
done
|
||||
if [ "$gesund" != 1 ]; then
|
||||
$COMPOSE --project-directory "$REPO" -f "$REPO/docker-compose.yml" logs --tail 40 >> "$LOG" 2>&1
|
||||
fehler "Neustart" "Die neue Version antwortet nach 5 Minuten nicht. Protokoll prüfen."; return 1
|
||||
fi
|
||||
printf '{"version":"%s","commit":"%s","am":"%s"}\n' "$VERSION" "$(git_ rev-parse --short HEAD)" "$(date -Iseconds)" > "$DIR/installiert.json"
|
||||
status "Fertig" false
|
||||
echo "Fertig, $(date)" >> "$LOG"
|
||||
}
|
||||
main "$@"
|
||||
exit $?
|
||||
Executable
+57
@@ -0,0 +1,57 @@
|
||||
#!/usr/bin/env bash
|
||||
# update-einrichten.sh — richtet auf dem Rechner (Pi) den Dienst ein, der
|
||||
# Updates aus der App ausführt (Admin → Update). Einmal ausführen, im
|
||||
# geklonten Repo, mit sudo. Mehrfach ausführbar.
|
||||
#
|
||||
# sudo bash Docker/update-einrichten.sh
|
||||
#
|
||||
# Danach: systemd beobachtet sessions/update/auftrag.json; legt die App dort
|
||||
# einen Auftrag ab, startet Docker/update-ausfuehren.sh. Der Container selbst
|
||||
# bekommt keinen Zugriff auf Docker.
|
||||
set -u
|
||||
|
||||
if [ "$(id -u)" -ne 0 ]; then echo "Bitte mit sudo ausführen."; exit 1; fi
|
||||
REPO="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
DIR="$REPO/sessions/update"
|
||||
EIGNER=$(stat -c %U "$REPO")
|
||||
|
||||
if ! runuser -u "$EIGNER" -- git -C "$REPO" remote get-url origin >/dev/null 2>&1; then
|
||||
echo "Kein Git-Repo mit 'origin' in $REPO — die App muss aus einem Klon des Git-Servers laufen."; exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "$DIR"
|
||||
# Der Container läuft als Benutzer node (uid 1000) und legt hier den Auftrag ab.
|
||||
chown 1000:1000 "$DIR"
|
||||
|
||||
# Laufende Version vermerken: der nächstliegende Tag.
|
||||
VERSION=$(runuser -u "$EIGNER" -- git -C "$REPO" describe --tags --abbrev=0 2>/dev/null || echo "")
|
||||
COMMIT=$(runuser -u "$EIGNER" -- git -C "$REPO" rev-parse --short HEAD)
|
||||
printf '{"version":"%s","commit":"%s","am":"%s"}\n' "$VERSION" "$COMMIT" "$(date -Iseconds)" > "$DIR/installiert.json"
|
||||
printf '{"eingerichtet":"%s"}\n' "$(date -Iseconds)" > "$DIR/dienst.json"
|
||||
|
||||
cat > /etc/systemd/system/projektuebersicht-update.service <<EOF
|
||||
[Unit]
|
||||
Description=Projektübersicht: Update aus der App ausführen
|
||||
After=docker.service network-online.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/bin/bash $REPO/Docker/update-ausfuehren.sh
|
||||
TimeoutStartSec=3600
|
||||
EOF
|
||||
|
||||
cat > /etc/systemd/system/projektuebersicht-update.path <<EOF
|
||||
[Unit]
|
||||
Description=Projektübersicht: auf Update-Auftrag aus der App warten
|
||||
|
||||
[Path]
|
||||
PathExists=$DIR/auftrag.json
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
systemctl daemon-reload
|
||||
systemctl enable --now projektuebersicht-update.path
|
||||
echo " ✓ Update-Dienst eingerichtet (laufende Version: ${VERSION:-unbekannt}, $COMMIT)"
|
||||
echo " • Die App braucht UPDATE_REPO_API in docker-compose.yml; danach einmal: docker compose up -d --build"
|
||||
Reference in new issue
Block a user