Files
bricktrack/update.sh
T
unknownandClaude Opus 5.5 f2304b28e5 fix(update): update.sh als ausfuehrbar einchecken
Bisher lag das Skript mit Modus 100644 im Repo. Ein chmod +x auf dem
Server galt dann als lokale Aenderung, und update.sh brach vor dem Pull
mit "Es gibt lokale Aenderungen" ab.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 15:20:53 +01:00

150 lines
4.3 KiB
Bash
Executable File

#!/usr/bin/env bash
#
# Bricktrack aktualisieren.
#
# ./update.sh Update auf den aktuellen Stand von origin/main
# ./update.sh --no-pull Nur neu bauen und starten, ohne git pull
# ./update.sh --no-backup Ohne Sicherung (nicht empfohlen)
#
# Ablauf: sichern -> holen -> bauen -> starten -> Healthcheck.
# Schlaegt der Healthcheck fehl, wird automatisch auf den vorherigen Stand
# zurueckgerollt und die Sicherung bleibt liegen.
set -euo pipefail
cd "$(dirname "$0")"
BACKUP_DIR="./backups"
KEEP_BACKUPS=10
HEALTH_TIMEOUT=180
DO_PULL=1
DO_BACKUP=1
for arg in "$@"; do
case "$arg" in
--no-pull) DO_PULL=0 ;;
--no-backup) DO_BACKUP=0 ;;
-h|--help) sed -n '2,12p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;;
*) echo "Unbekannte Option: $arg" >&2; exit 1 ;;
esac
done
info() { printf '\033[1;34m[bricktrack]\033[0m %s\n' "$*"; }
warn() { printf '\033[1;33m[bricktrack]\033[0m %s\n' "$*"; }
error() { printf '\033[1;31m[bricktrack]\033[0m %s\n' "$*" >&2; }
# --- Vorbedingungen --------------------------------------------------------
if ! docker compose version >/dev/null 2>&1; then
error "Docker Compose (Plugin) wurde nicht gefunden."
exit 1
fi
if [ ! -f .env ]; then
error "Es gibt keine .env. Lege sie an: cp .env.example .env"
exit 1
fi
PREVIOUS_COMMIT="$(git rev-parse HEAD 2>/dev/null || echo '')"
# --- Sichern ---------------------------------------------------------------
BACKUP_FILE=""
if [ "$DO_BACKUP" -eq 1 ]; then
mkdir -p "$BACKUP_DIR"
BACKUP_FILE="$BACKUP_DIR/bricktrack-$(date +%Y%m%d-%H%M%S).tar.gz"
info "Sicherung wird angelegt: $BACKUP_FILE"
# Der Container wird kurz angehalten, damit die SQLite-Datei nicht mitten in
# einem Schreibvorgang eingepackt wird.
docker compose stop app >/dev/null 2>&1 || true
tar czf "$BACKUP_FILE" data .env 2>/dev/null || {
error "Die Sicherung ist fehlgeschlagen. Abbruch."
docker compose start app >/dev/null 2>&1 || true
exit 1
}
info "Sicherung fertig ($(du -h "$BACKUP_FILE" | cut -f1))."
# Alte Sicherungen aufraeumen, die juengsten bleiben.
ls -1t "$BACKUP_DIR"/bricktrack-*.tar.gz 2>/dev/null \
| tail -n +$((KEEP_BACKUPS + 1)) \
| xargs -r rm --
fi
# --- Holen -----------------------------------------------------------------
if [ "$DO_PULL" -eq 1 ]; then
if [ -n "$(git status --porcelain)" ]; then
error "Es gibt lokale Aenderungen im Arbeitsverzeichnis:"
git status --short >&2
error "Bitte erst aufraeumen oder mit --no-pull starten."
exit 1
fi
info "Neue Version wird geholt …"
git pull --ff-only
NEW_COMMIT="$(git rev-parse HEAD)"
if [ "$NEW_COMMIT" = "$PREVIOUS_COMMIT" ]; then
info "Es gibt nichts Neues. Der Container wird trotzdem neu gestartet."
else
info "Neuer Stand: $(git log -1 --pretty='%h %s')"
fi
fi
# --- Bauen und starten -----------------------------------------------------
info "Image wird gebaut …"
docker compose build app
info "Container wird gestartet …"
docker compose up -d app
# --- Healthcheck -----------------------------------------------------------
info "Warte auf den Healthcheck (max. ${HEALTH_TIMEOUT}s) …"
elapsed=0
healthy=0
while [ "$elapsed" -lt "$HEALTH_TIMEOUT" ]; do
status="$(docker inspect --format '{{if .State.Health}}{{.State.Health.Status}}{{else}}none{{end}}' bricktrack 2>/dev/null || echo 'missing')"
case "$status" in
healthy) healthy=1; break ;;
unhealthy) break ;;
missing) error "Der Container bricktrack laeuft nicht."; break ;;
esac
sleep 3
elapsed=$((elapsed + 3))
printf '.'
done
printf '\n'
if [ "$healthy" -eq 1 ]; then
info "Bricktrack laeuft."
docker compose ps app
exit 0
fi
# --- Rueckabwicklung -------------------------------------------------------
error "Die neue Version ist nicht gesund geworden. Die letzten Logzeilen:"
docker compose logs --tail 50 app >&2
if [ "$DO_PULL" -eq 1 ] && [ -n "$PREVIOUS_COMMIT" ]; then
warn "Rollback auf $PREVIOUS_COMMIT …"
git reset --hard "$PREVIOUS_COMMIT"
docker compose build app
docker compose up -d app
warn "Der vorherige Stand laeuft wieder."
fi
if [ -n "$BACKUP_FILE" ]; then
warn "Die Daten liegen unveraendert in $BACKUP_FILE."
warn "Zurueckspielen falls noetig:"
warn " docker compose down && tar xzf $BACKUP_FILE && sudo chown -R 1000:1000 ./data && docker compose up -d"
fi
exit 1