mailwolt-installer/scripts/update.sh

715 lines
29 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#!/usr/bin/env bash
set -euo pipefail
# -------- Konfiguration -------------------------------------------------------
APP_USER="${APP_USER:-mailwolt}"
APP_GROUP="${APP_GROUP:-www-data}" # Fallback; setz das in deiner Umgebung falls anders
APP_DIR="${APP_DIR:-/var/www/mailwolt}"
BRANCH="${BRANCH:-main}" # nur relevant bei UPDATE_MODE=branch
MODE="${UPDATE_MODE:-tags}" # tags | branch
ALLOW_DIRTY="${ALLOW_DIRTY:-0}" # 1 = Dirty-Working-Tree zulassen
# npm / CI Defaults für weniger Lärm
export CI=1
export NPM_CONFIG_FUND=false
export NPM_CONFIG_AUDIT=false
export npm_config_loglevel=warn
# -------- Helper --------------------------------------------------------------
as_app(){ sudo -u "$APP_USER" -H bash -lc "$*"; }
restart_if_exists(){
local u="$1"
systemctl list-unit-files | grep -q "^${u}\.service" && systemctl restart "$u" || true
}
reload_if_active(){
local u="$1"
systemctl is-active --quiet "$u" && systemctl reload "$u" || true
}
restart_php_fpm(){
for u in php8.3-fpm php8.2-fpm php8.1-fpm php-fpm; do
if systemctl list-unit-files | grep -q "^${u}\.service"; then
systemctl restart "$u"
return 0
fi
done
}
git_safe(){
# Falls nötig: Repo als safe markieren (z.B. wenn Root den Wrapper aufruft)
as_app "git -C ${APP_DIR} config --global --add safe.directory ${APP_DIR} >/dev/null 2>&1 || true"
}
git_dirty_check(){
if [[ "$ALLOW_DIRTY" != "1" ]]; then
local dirty
dirty="$(as_app "git -C ${APP_DIR} status --porcelain")"
if [[ -n "$dirty" ]]; then
echo "[!] Arbeitsbaum hat uncommitted Änderungen. Abbruch (ALLOW_DIRTY=1 zum Überschreiben)."
exit 2
fi
fi
}
get_version(){
as_app "cd ${APP_DIR} && (git describe --tags --always 2>/dev/null || git rev-parse --short=7 HEAD)"
}
write_build_info(){
local ver="$1" rev="$2"
install -d -m 0755 /etc/mailwolt || true
printf "version=%s\nrev=%s\nupdated=%s\n" "$ver" "$rev" "$(date -Is)" > /etc/mailwolt/build.info || true
}
# --- Frontend build (quiet & robust) ------------------------------------------
frontend_build_quiet() {
local LOG="/var/log/mailwolt-frontend-build.log"
local NPM_ENV="CI=1 NPM_CONFIG_FUND=false NPM_CONFIG_AUDIT=false npm_config_loglevel=warn"
# Logfile vorbereiten
install -d -m 0755 "$(dirname "$LOG")"
: > "$LOG" || true
chmod 0644 "$LOG"
echo "[i] Frontend: vorbereiten …"
# Build-Ziele & Temp besitzbar machen
as_app "mkdir -p '${APP_DIR}/public/build' '${APP_DIR}/node_modules' '${APP_DIR}/.vite' '${APP_DIR}/.npm-cache'"
chown -R "$APP_USER":"$APP_GROUP" "${APP_DIR}/public/build" "${APP_DIR}/node_modules" "${APP_DIR}/.vite" "${APP_DIR}/.npm-cache" || true
chmod -R g+rwX "${APP_DIR}/public/build" "${APP_DIR}/node_modules" "${APP_DIR}/.vite" || true
# evtl. störrische Reste entfernen (vermeidet EACCES beim Unlink/Rimraf)
rm -rf "${APP_DIR}/node_modules/.vite" "${APP_DIR}/public/build/"* 2>/dev/null || true
# npm Config (kein Fund/Audit, eigener Cache unter App-User)
as_app "printf 'fund=false\naudit=false\ncache=${APP_DIR}/.npm-cache\n' > ~/.npmrc" >>"$LOG" 2>&1 || true
echo "[i] Frontend: Dependencies … (Details: $LOG)"
if ! as_app "cd '${APP_DIR}' && ${NPM_ENV} npm ci --no-audit --no-fund --no-progress" >>"$LOG" 2>&1; then
if ! as_app "cd '${APP_DIR}' && ${NPM_ENV} npm install --no-audit --no-fund --no-progress" >>"$LOG" 2>&1; then
echo "[!] npm install fehlgeschlagen. Letzte 60 Zeilen:"
tail -n 60 "$LOG" || true
return 1
fi
fi
echo "[i] Frontend: Build … (Details: $LOG)"
if ! as_app "cd '${APP_DIR}' && ${NPM_ENV} npm run build --silent --loglevel=warn" >>"$LOG" 2>&1; then
echo "[!] Build fehlgeschlagen. Letzte 80 Zeilen:"
tail -n 80 "$LOG" || true
return 1
fi
# Nach dem Build noch einmal Rechte begradigen
chown -R "$APP_USER":"$APP_GROUP" "${APP_DIR}/public/build" || true
find "${APP_DIR}/public/build" -type d -exec chmod 2775 {} \; 2>/dev/null || true
find "${APP_DIR}/public/build" -type f -exec chmod 0664 {} \; 2>/dev/null || true
echo "[✓] Frontend gebaut."
}
# -------- Guards --------------------------------------------------------------
[[ "$(id -u)" -eq 0 ]] || { echo "[!] Bitte als root ausführen"; exit 1; }
[[ -d "$APP_DIR/.git" ]] || { echo "[!] $APP_DIR scheint kein Git-Repo zu sein"; exit 1; }
git_safe
git_dirty_check
# -------- Git: neuen Stand holen ---------------------------------------------
echo "[i] Prüfe Repository …"
OLD_REV="$(as_app "git -C ${APP_DIR} rev-parse HEAD")"
OLD_VER="$(get_version)"
NEW_REV="$OLD_REV"
if [[ "$MODE" = "tags" ]]; then
# → Neueste Tags holen
as_app "git -C ${APP_DIR} fetch --quiet origin && git -C ${APP_DIR} fetch --tags --quiet origin || true"
LATEST_TAG="$(as_app "git -C ${APP_DIR} tag --list | sort -V | tail -n1")"
if [[ -z "$LATEST_TAG" ]]; then
echo "[!] Keine Tags gefunden falle auf origin/${BRANCH} zurück"
as_app "git -C ${APP_DIR} checkout -q ${BRANCH} && git -C ${APP_DIR} pull --ff-only origin ${BRANCH}"
else
TARGET_REV="$(as_app "git -C ${APP_DIR} rev-list -n1 ${LATEST_TAG}")"
if [[ "$TARGET_REV" = "$OLD_REV" ]]; then
echo "[✓] Bereits auf neuestem Release (${LATEST_TAG}) nichts zu tun."
write_build_info "$(get_version)" "$OLD_REV"
exit 0
fi
echo "[i] Checkout auf Release ${LATEST_TAG} (${TARGET_REV:0:7}) …"
as_app "git -C ${APP_DIR} checkout -q ${LATEST_TAG}"
fi
NEW_REV="$(as_app "git -C ${APP_DIR} rev-parse HEAD")"
else
# Rolling: branch folgen
as_app "git -C ${APP_DIR} fetch --quiet origin ${BRANCH}"
BEHIND="$(as_app "git -C ${APP_DIR} rev-list --count HEAD..origin/${BRANCH} || echo 0")"
if [[ "$BEHIND" -eq 0 ]]; then
echo "[✓] Branch origin/${BRANCH} ist bereits aktuell nichts zu tun."
write_build_info "$(get_version)" "$OLD_REV"
exit 0
fi
echo "[i] Es gibt ${BEHIND} neue Commit(s) ziehe Änderungen …"
as_app "git -C ${APP_DIR} checkout -q ${BRANCH} && git -C ${APP_DIR} pull --ff-only origin ${BRANCH}"
NEW_REV="$(as_app "git -C ${APP_DIR} rev-parse HEAD")"
fi
# -------- Änderungstypen ermitteln -------------------------------------------
CHANGED_FILES="$(as_app "git -C ${APP_DIR} diff --name-only ${OLD_REV}..${NEW_REV}")"
NEED_COMPOSER=0
NEED_MIGRATIONS=0
NEED_FRONTEND=0
NEED_PHP_RESTART=0
echo "$CHANGED_FILES" | grep -qE '(^|/)composer\.(json|lock)$' && NEED_COMPOSER=1
echo "$CHANGED_FILES" | grep -qE '^database/migrations/' && NEED_MIGRATIONS=1
echo "$CHANGED_FILES" | grep -qE '^(package(-lock)?\.json|vite\.config(\.ts|\.js)?|resources/|public/.*\.(js|css))' && NEED_FRONTEND=1
echo "$CHANGED_FILES" | grep -qE '^(app/|routes/|config/|resources/views/)' && NEED_PHP_RESTART=1
echo "[i] Zusammenfassung:"
echo " Composer : $([[ $NEED_COMPOSER -eq 1 ]] && echo JA || echo nein)"
echo " Migrations : $([[ $NEED_MIGRATIONS -eq 1 ]] && echo JA || echo nein)"
echo " Frontend : $([[ $NEED_FRONTEND -eq 1 ]] && echo JA || echo nein)"
echo " PHP restart : $([[ $NEED_PHP_RESTART -eq 1 ]] && echo JA || echo nein)"
# Wenn gar nichts relevantes geändert wurde → sauber beenden
if [[ $NEED_COMPOSER -eq 0 && $NEED_MIGRATIONS -eq 0 && $NEED_FRONTEND -eq 0 && $NEED_PHP_RESTART -eq 0 ]]; then
echo "[✓] Code-Stand aktualisiert, aber keine Build/Runtime-Änderungen keine Neustarts nötig."
NEW_VER="$(get_version)"
write_build_info "$NEW_VER" "$NEW_REV"
echo "[i] Version: ${OLD_VER}${NEW_VER}"
exit 0
fi
# -------- Gezielter Build/Deploy ---------------------------------------------
if [[ $NEED_COMPOSER -eq 1 ]]; then
echo "[i] Composer …"
as_app "cd ${APP_DIR} && composer install --no-interaction --prefer-dist --optimize-autoloader"
fi
if [[ $NEED_MIGRATIONS -eq 1 ]]; then
echo "[i] DB-Migrationen …"
as_app "cd ${APP_DIR} && php artisan migrate --force"
fi
if [[ $NEED_PHP_RESTART -eq 1 || $NEED_COMPOSER -eq 1 || $NEED_MIGRATIONS -eq 1 ]]; then
echo "[i] Cache/Optimierungen …"
as_app "cd ${APP_DIR} && php artisan config:cache && php artisan route:cache || true"
as_app "cd ${APP_DIR} && php artisan queue:restart || true"
as_app "cd ${APP_DIR} && php artisan optimize:clear || true"
fi
# -------- Frontend: nur wenn nötig -------------------------------------------
if [[ $NEED_FRONTEND -eq 1 ]]; then
echo "[i] Frontend-Änderungen erkannt baue Assets …"
if ! frontend_build_quiet; then
echo "[!] Frontend-Build ist fehlgeschlagen (siehe /var/log/mailwolt-frontend-build.log)."
exit 1
fi
fi
# -------- Dienste nur wenn nötig ---------------------------------------------
echo "[i] Dienste neu laden/neustarten (gezielt) …"
if [[ $NEED_PHP_RESTART -eq 1 || $NEED_COMPOSER -eq 1 || $NEED_MIGRATIONS -eq 1 ]]; then
restart_php_fpm
restart_if_exists "${APP_USER}-queue"
restart_if_exists "${APP_USER}-schedule"
restart_if_exists "${APP_USER}-ws"
fi
if [[ $NEED_FRONTEND -eq 1 || $NEED_PHP_RESTART -eq 1 ]]; then
reload_if_active nginx
fi
# -------- Build-Info ablegen --------------------------------------------------
NEW_VER="$(get_version)"
write_build_info "$NEW_VER" "$NEW_REV"
echo "[✓] Update abgeschlossen: ${OLD_REV:0:7}${NEW_REV:0:7} (Version: ${NEW_VER})"
##!/usr/bin/env bash
#set -euo pipefail
#
## -------- Konfiguration --------
#APP_USER="${APP_USER:-mailwolt}"
#APP_DIR="${APP_DIR:-/var/www/mailwolt}"
#BRANCH="${BRANCH:-main}" # nur relevant bei UPDATE_MODE=branch
#MODE="${UPDATE_MODE:-tags}" # tags | branch
#ALLOW_DIRTY="${ALLOW_DIRTY:-0}" # 1 = Dirty-Working-Tree zulassen
#export CI=1
#export NPM_CONFIG_FUND=false
#export NPM_CONFIG_AUDIT=false
#
## -------- Helper --------
#as_app(){ sudo -u "$APP_USER" -H bash -lc "$*"; }
#restart_if_exists(){ local u="$1"; systemctl list-unit-files | grep -q "^${u}\.service" && systemctl restart "$u" || true; }
#reload_if_active(){ local u="$1"; systemctl is-active --quiet "$u" && systemctl reload "$u" || true; }
#restart_php_fpm(){
# for u in php8.3-fpm php8.2-fpm php8.1-fpm php-fpm; do
# if systemctl list-unit-files | grep -q "^${u}\.service"; then
# systemctl restart "$u"
# return 0
# fi
# done
#}
#
#git_safe(){
# # Falls nötig: Repo als safe markieren (manche Root-Umgebungen meckern sonst)
# as_app "git -C ${APP_DIR} config --global --add safe.directory ${APP_DIR} >/dev/null 2>&1 || true"
#}
#
#git_dirty_check(){
# if [[ "$ALLOW_DIRTY" != "1" ]]; then
# local dirty
# dirty="$(as_app "git -C ${APP_DIR} status --porcelain")"
# if [[ -n "$dirty" ]]; then
# echo "[!] Arbeitsbaum hat uncommitted Änderungen. Abbruch (ALLOW_DIRTY=1 zum Überschreiben)."
# exit 2
# fi
# fi
#}
#
#get_version(){
# as_app "cd ${APP_DIR} && (git describe --tags --always 2>/dev/null || git rev-parse --short=7 HEAD)"
#}
#
#write_build_info(){
# local ver="$1" rev="$2"
# printf "version=%s\nrev=%s\nupdated=%s\n" "$ver" "$rev" "$(date -Is)" > /etc/mailwolt/build.info || true
#}
#
## -------- Guards --------
#[[ "$(id -u)" -eq 0 ]] || { echo "[!] Bitte als root ausführen"; exit 1; }
#[[ -d "$APP_DIR/.git" ]] || { echo "[!] $APP_DIR scheint kein Git-Repo zu sein"; exit 1; }
#
#git_safe
#git_dirty_check
#
#echo "[i] Prüfe Repository …"
#OLD_REV="$(as_app "git -C ${APP_DIR} rev-parse HEAD")"
#OLD_VER="$(get_version)"
#NEW_REV="$OLD_REV"
#
#if [[ "$MODE" = "tags" ]]; then
# # → Neueste Tags holen
# as_app "git -C ${APP_DIR} fetch --quiet origin && git -C ${APP_DIR} fetch --tags --quiet origin || true"
#
# LATEST_TAG="$(as_app "git -C ${APP_DIR} tag --list | sort -V | tail -n1")"
# if [[ -z "$LATEST_TAG" ]]; then
# echo "[!] Keine Tags gefunden falle auf origin/${BRANCH} zurück"
# as_app "git -C ${APP_DIR} checkout -q ${BRANCH} && git -C ${APP_DIR} pull --ff-only origin ${BRANCH}"
# else
# TARGET_REV="$(as_app "git -C ${APP_DIR} rev-list -n1 ${LATEST_TAG}")"
# if [[ "$TARGET_REV" = "$OLD_REV" ]]; then
# echo "[✓] Bereits auf neuestem Release (${LATEST_TAG}) nichts zu tun."
# write_build_info "$(get_version)" "$OLD_REV"
# exit 0
# fi
# echo "[i] Checkout auf Release ${LATEST_TAG} (${TARGET_REV:0:7}) …"
# as_app "git -C ${APP_DIR} checkout -q ${LATEST_TAG}"
# fi
# NEW_REV="$(as_app "git -C ${APP_DIR} rev-parse HEAD")"
#else
# # Rolling: branch folgen
# as_app "git -C ${APP_DIR} fetch --quiet origin ${BRANCH}"
# BEHIND="$(as_app "git -C ${APP_DIR} rev-list --count HEAD..origin/${BRANCH} || echo 0")"
# if [[ "$BEHIND" -eq 0 ]]; then
# echo "[✓] Branch origin/${BRANCH} ist bereits aktuell nichts zu tun."
# write_build_info "$(get_version)" "$OLD_REV"
# exit 0
# fi
# echo "[i] Es gibt ${BEHIND} neue Commit(s) ziehe Änderungen …"
# as_app "git -C ${APP_DIR} checkout -q ${BRANCH} && git -C ${APP_DIR} pull --ff-only origin ${BRANCH}"
# NEW_REV="$(as_app "git -C ${APP_DIR} rev-parse HEAD")"
#fi
#
## -------- Änderungstypen ermitteln --------
#CHANGED_FILES="$(as_app "git -C ${APP_DIR} diff --name-only ${OLD_REV}..${NEW_REV}")"
#
#NEED_COMPOSER=0
#NEED_MIGRATIONS=0
#NEED_FRONTEND=0
#NEED_PHP_RESTART=0
#
#echo "$CHANGED_FILES" | grep -qE '(^|/)composer\.(json|lock)$' && NEED_COMPOSER=1
#echo "$CHANGED_FILES" | grep -qE '^database/migrations/' && NEED_MIGRATIONS=1
#echo "$CHANGED_FILES" | grep -qE '^(package(-lock)?\.json|vite\.config(\.ts|\.js)?|resources/|public/.*\.(js|css))' && NEED_FRONTEND=1
#echo "$CHANGED_FILES" | grep -qE '^(app/|routes/|config/|resources/views/)' && NEED_PHP_RESTART=1
#
#echo "[i] Zusammenfassung:"
#echo " Composer : $([[ $NEED_COMPOSER -eq 1 ]] && echo JA || echo nein)"
#echo " Migrations : $([[ $NEED_MIGRATIONS -eq 1 ]] && echo JA || echo nein)"
#echo " Frontend : $([[ $NEED_FRONTEND -eq 1 ]] && echo JA || echo nein)"
#echo " PHP restart : $([[ $NEED_PHP_RESTART -eq 1 ]] && echo JA || echo nein)"
#
## Wenn gar nichts relevantes geändert wurde → sauber beenden
#if [[ $NEED_COMPOSER -eq 0 && $NEED_MIGRATIONS -eq 0 && $NEED_FRONTEND -eq 0 && $NEED_PHP_RESTART -eq 0 ]]; then
# echo "[✓] Code-Stand aktualisiert, aber keine Build/Runtime-Änderungen keine Neustarts nötig."
# NEW_VER="$(get_version)"
# write_build_info "$NEW_VER" "$NEW_REV"
# echo "[i] Version: ${OLD_VER} → ${NEW_VER}"
# exit 0
#fi
#
## -------- Gezielter Build/Deploy --------
#if [[ $NEED_COMPOSER -eq 1 ]]; then
# echo "[i] Composer …"
# as_app "cd ${APP_DIR} && composer install --no-interaction --prefer-dist --optimize-autoloader"
#fi
#
#if [[ $NEED_MIGRATIONS -eq 1 ]]; then
# echo "[i] DB-Migrationen …"
# as_app "cd ${APP_DIR} && php artisan migrate --force"
#fi
#
#if [[ $NEED_PHP_RESTART -eq 1 || $NEED_COMPOSER -eq 1 || $NEED_MIGRATIONS -eq 1 ]]; then
# echo "[i] Cache/Optimierungen …"
# as_app "cd ${APP_DIR} && php artisan config:cache && php artisan route:cache || true"
# as_app "cd ${APP_DIR} && php artisan queue:restart || true"
# as_app "cd ${APP_DIR} && php artisan optimize:clear || true"
#fi
#
##if [[ $NEED_FRONTEND -eq 1 ]]; then
## echo "[i] Frontend build …"
## as_app "cd ${APP_DIR} && (npm ci --no-audit --no-fund || npm install)"
## as_app "cd ${APP_DIR} && npm run build"
##fi
#
## -------- Frontend build (hardened) --------
#if [[ $NEED_FRONTEND -eq 1 ]]; then
# echo "[i] Frontend build (vite) …"
#
# # Preflight: Schreibrechte sicherstellen
# as_app "mkdir -p ${APP_DIR}/public/build ${APP_DIR}/node_modules ${APP_DIR}/.vite"
# chown -R "$APP_USER":"$APP_GROUP" "${APP_DIR}/public/build" "${APP_DIR}/node_modules" "${APP_DIR}/.vite" || true
# chmod -R g+rwX "${APP_DIR}/public/build" "${APP_DIR}/node_modules" "${APP_DIR}/.vite" || true
#
# # Nicht-interaktive / leise npm-Runs
# NPM_ENV="CI=1 NPM_CONFIG_FUND=false NPM_CONFIG_AUDIT=false npm_config_loglevel=warn"
#
# echo "[i] npm ci …"
# as_app "cd ${APP_DIR} && ${NPM_ENV} npm ci --no-audit --no-fund --loglevel=warn --no-progress || \
# ${NPM_ENV} npm install --no-audit --no-fund --loglevel=warn --no-progress"
#
# echo "[i] npm run build …"
# as_app "cd ${APP_DIR} && ${NPM_ENV} npm run build --silent --loglevel=warn"
#fi
#
## -------- Dienste nur wenn nötig --------
#echo "[i] Dienste neu laden/neustarten (gezielt) …"
#if [[ $NEED_PHP_RESTART -eq 1 || $NEED_COMPOSER -eq 1 || $NEED_MIGRATIONS -eq 1 ]]; then
# restart_php_fpm
# restart_if_exists "${APP_USER}-queue"
# restart_if_exists "${APP_USER}-schedule"
# restart_if_exists "${APP_USER}-ws"
#fi
#if [[ $NEED_FRONTEND -eq 1 || $NEED_PHP_RESTART -eq 1 ]]; then
# reload_if_active nginx
#fi
#
## -------- Build-Info ablegen --------
#NEW_VER="$(get_version)"
#write_build_info "$NEW_VER" "$NEW_REV"
#
#echo "[✓] Update abgeschlossen: ${OLD_REV:0:7} → ${NEW_REV:0:7} (Version: ${NEW_VER})"
#
###!/usr/bin/env bash
##set -euo pipefail
##
### -------- Konfiguration --------
##APP_USER="mailwolt"
##APP_DIR="/var/www/mailwolt"
##BRANCH="${BRANCH:-main}" # nur relevant bei UPDATE_MODE=branch
##MODE="${UPDATE_MODE:-tags}" # tags | branch
##
### -------- Helper --------
##as_app(){ sudo -u "$APP_USER" -H bash -lc "$*"; }
##restart_if_exists(){ local u="$1"; systemctl list-unit-files | grep -q "^${u}\.service" && systemctl restart "$u" || true; }
##reload_if_active(){ local u="$1"; systemctl is-active --quiet "$u" && systemctl reload "$u" || true; }
##restart_php_fpm(){
## for u in php8.3-fpm php8.2-fpm php8.1-fpm php-fpm; do
## if systemctl list-unit-files | grep -q "^${u}\.service"; then
## systemctl restart "$u"
## return 0
## fi
## done
##}
##
### -------- Guards --------
##[[ "$(id -u)" -eq 0 ]] || { echo "[!] Bitte als root ausführen"; exit 1; }
##[[ -d "$APP_DIR/.git" ]] || { echo "[!] $APP_DIR scheint kein Git-Repo zu sein"; exit 1; }
##
##echo "[i] Prüfe Repository …"
##OLD_REV="$(as_app "cd ${APP_DIR} && git rev-parse HEAD")"
##NEW_REV="$OLD_REV"
##
##if [[ "$MODE" = "tags" ]]; then
## # Auf neuesten Release-Tag wechseln (semantisch sortiert)
## LATEST_TAG="$(as_app "cd ${APP_DIR} && git fetch --tags --quiet origin && git tag --list | sort -V | tail -n1")"
## if [[ -z "$LATEST_TAG" ]]; then
## echo "[!] Keine Tags gefunden falle auf origin/${BRANCH} zurück"
## as_app "cd ${APP_DIR} && git fetch --quiet origin ${BRANCH} && git checkout -q ${BRANCH} && git pull --ff-only origin ${BRANCH}"
## else
## TARGET_REV="$(as_app "cd ${APP_DIR} && git rev-list -n1 ${LATEST_TAG}")"
## if [[ "$TARGET_REV" = "$OLD_REV" ]]; then
## echo "[✓] Bereits auf neuestem Release (${LATEST_TAG}) nichts zu tun."
## exit 0
## fi
## echo "[i] Checkout auf Release ${LATEST_TAG} (${TARGET_REV:0:7}) …"
## as_app "cd ${APP_DIR} && git checkout -q ${LATEST_TAG}"
## fi
## NEW_REV="$(as_app "cd ${APP_DIR} && git rev-parse HEAD")"
##else
## # Rolling: branch folgen
## as_app "cd ${APP_DIR} && git fetch --quiet origin ${BRANCH}"
## BEHIND="$(as_app "cd ${APP_DIR} && git rev-list --count HEAD..origin/${BRANCH} || echo 0")"
## if [[ "$BEHIND" -eq 0 ]]; then
## echo "[✓] Branch origin/${BRANCH} ist bereits aktuell nichts zu tun."
## exit 0
## fi
## echo "[i] Es gibt ${BEHIND} neue Commit(s) ziehe Änderungen …"
## as_app "cd ${APP_DIR} && git checkout -q ${BRANCH} && git pull --ff-only origin ${BRANCH}"
## NEW_REV="$(as_app "cd ${APP_DIR} && git rev-parse HEAD")"
##fi
##
### -------- Änderungstypen ermitteln --------
##CHANGED_FILES="$(as_app "cd ${APP_DIR} && git diff --name-only ${OLD_REV}..${NEW_REV}")"
##
##NEED_COMPOSER=0
##NEED_MIGRATIONS=0
##NEED_FRONTEND=0
##NEED_PHP_RESTART=0
##
##echo "$CHANGED_FILES" | grep -qE '(^|/)composer\.(json|lock)$' && NEED_COMPOSER=1
##echo "$CHANGED_FILES" | grep -qE '^database/migrations/' && NEED_MIGRATIONS=1
##echo "$CHANGED_FILES" | grep -qE '^(package(-lock)?\.json|vite\.config|resources/|public/.*\.(js|css))' && NEED_FRONTEND=1
##echo "$CHANGED_FILES" | grep -qE '^(app/|routes/|config/|resources/views/)' && NEED_PHP_RESTART=1
##
##echo "[i] Zusammenfassung:"
##echo " Composer : $([[ $NEED_COMPOSER -eq 1 ]] && echo JA || echo nein)"
##echo " Migrations : $([[ $NEED_MIGRATIONS -eq 1 ]] && echo JA || echo nein)"
##echo " Frontend : $([[ $NEED_FRONTEND -eq 1 ]] && echo JA || echo nein)"
##echo " PHP restart : $([[ $NEED_PHP_RESTART -eq 1 ]] && echo JA || echo nein)"
##
### Wenn gar nichts relevantes geändert wurde → sauber beenden
##if [[ $NEED_COMPOSER -eq 0 && $NEED_MIGRATIONS -eq 0 && $NEED_FRONTEND -eq 0 && $NEED_PHP_RESTART -eq 0 ]]; then
## echo "[✓] Code-Stand aktualisiert, aber keine Build/Runtime-Änderungen keine Neustarts nötig."
## # Build-Info trotzdem aktualisieren
## INST_VER="$(as_app "cd ${APP_DIR} && (cat VERSION 2>/dev/null || echo dev)")"
## printf "version=%s\nrev=%s\nupdated=%s\n" "$INST_VER" "$NEW_REV" "$(date -Is)" > /etc/mailwolt/build.info || true
## exit 0
##fi
##
### -------- Gezielter Build/Deploy --------
##if [[ $NEED_COMPOSER -eq 1 ]]; then
## echo "[i] Composer …"
## as_app "cd ${APP_DIR} && composer install --no-interaction --prefer-dist --optimize-autoloader"
##fi
##
##if [[ $NEED_MIGRATIONS -eq 1 ]]; then
## echo "[i] DB-Migrationen …"
## as_app "cd ${APP_DIR} && php artisan migrate --force"
##fi
##
##if [[ $NEED_PHP_RESTART -eq 1 || $NEED_COMPOSER -eq 1 || $NEED_MIGRATIONS -eq 1 ]]; then
## echo "[i] Cache/Optimierungen …"
## as_app "cd ${APP_DIR} && php artisan config:cache && php artisan route:cache || true"
## as_app "cd ${APP_DIR} && php artisan queue:restart || true"
## as_app "cd ${APP_DIR} && php artisan optimize:clear || true"
##fi
##
##if [[ $NEED_FRONTEND -eq 1 ]]; then
## echo "[i] Frontend build …"
## as_app "cd ${APP_DIR} && (npm ci --no-audit --no-fund || npm install)"
## as_app "cd ${APP_DIR} && npm run build"
##fi
##
### -------- Dienste nur wenn nötig --------
##echo "[i] Dienste neu laden/neustarten (gezielt) …"
##if [[ $NEED_PHP_RESTART -eq 1 || $NEED_COMPOSER -eq 1 || $NEED_MIGRATIONS -eq 1 ]]; then
## restart_php_fpm
## restart_if_exists "${APP_USER}-queue"
## restart_if_exists "${APP_USER}-schedule"
## restart_if_exists "${APP_USER}-ws"
##fi
##if [[ $NEED_FRONTEND -eq 1 || $NEED_PHP_RESTART -eq 1 ]]; then
## reload_if_active nginx
##fi
##
### -------- Build-Info ablegen --------
##INST_VER="$(as_app "cd ${APP_DIR} && (cat VERSION 2>/dev/null || echo dev)")"
##printf "version=%s\nrev=%s\nupdated=%s\n" "$INST_VER" "$NEW_REV" "$(date -Is)" > /etc/mailwolt/build.info || true
##
##echo "[✓] Update abgeschlossen: ${OLD_REV:0:7} → ${NEW_REV:0:7} (Version: ${INST_VER})"
#
###!/usr/bin/env bash
##set -euo pipefail
##
##APP_USER="mailwolt"
##APP_DIR="/var/www/mailwolt"
##BRANCH="${BRANCH:-main}" # bei Bedarf anpassen
##
##as_app(){ sudo -u "$APP_USER" -H bash -lc "$*"; }
##
##restart_if_exists(){ local u="$1"; systemctl list-unit-files | grep -q "^${u}\.service" && systemctl restart "$u" || true; }
##reload_if_active(){ local u="$1"; systemctl is-active --quiet "$u" && systemctl reload "$u" || true; }
##
##restart_php_fpm(){
## for u in php8.3-fpm php8.2-fpm php8.1-fpm php-fpm; do
## systemctl list-unit-files | grep -q "^${u}\.service" && { systemctl restart "$u"; return 0; }
## done
## return 0
##}
##
##[[ "$(id -u)" -eq 0 ]] || { echo "[!] Bitte als root ausführen"; exit 1; }
##
###!/usr/bin/env bash
##set -euo pipefail
##APP_USER="mailwolt"
##APP_DIR="/var/www/mailwolt"
##MODE="${UPDATE_MODE:-tags}"
##
##as_app(){ sudo -u "$APP_USER" -H bash -lc "$*"; }
##
### --- Ab hier wie gehabt ---
##echo "[i] Prüfe Repository …"
##if [[ "$MODE" = "tags" ]]; then
## LATEST_TAG="$(as_app "cd ${APP_DIR} && git fetch --tags --quiet origin && git tag --list | sort -V | tail -n1")"
## if [[ -n "$LATEST_TAG" ]]; then
## OLD_REV="$(as_app "cd ${APP_DIR} && git rev-parse HEAD")"
## echo "[i] Checkout auf neuesten Release: ${LATEST_TAG}"
## as_app "cd ${APP_DIR} && git checkout -q ${LATEST_TAG}"
## NEW_REV="$(as_app "cd ${APP_DIR} && git rev-parse HEAD")"
## else
## echo "[!] Keine Tags gefunden, falle auf origin/main zurück"
## as_app "cd ${APP_DIR} && git pull --ff-only origin main"
## fi
##else
## as_app "cd ${APP_DIR} && git fetch --quiet origin main && git pull --ff-only origin main"
##fi
##
##echo "[i] Prüfe Repository …"
##OLD_REV="$(as_app "cd ${APP_DIR} && git rev-parse HEAD")"
##as_app "cd ${APP_DIR} && git fetch --tags --quiet origin ${BRANCH}"
##BEHIND="$(as_app "cd ${APP_DIR} && git rev-list --count HEAD..origin/${BRANCH} || echo 0")"
##
##if [[ "${BEHIND}" -eq 0 ]]; then
## echo "[✓] Bereits aktuell nichts zu tun."
## exit 0
##fi
##
##echo "[i] Es gibt ${BEHIND} neue Commit(s) ziehe Änderungen …"
##as_app "cd ${APP_DIR} && git pull --ff-only origin ${BRANCH}"
##NEW_REV="$(as_app "cd ${APP_DIR} && git rev-parse HEAD")"
##
### Welche Bereiche haben sich geändert?
##CHANGED_FILES="$(as_app "cd ${APP_DIR} && git diff --name-only ${OLD_REV}..${NEW_REV}")"
##
##NEED_COMPOSER=0
##NEED_MIGRATIONS=0
##NEED_FRONTEND=0
##NEED_PHP_RESTART=0
##
##if echo "$CHANGED_FILES" | grep -qE '^(composer\.json|composer\.lock)'; then
## NEED_COMPOSER=1
##fi
##if echo "$CHANGED_FILES" | grep -qE '^database/migrations/'; then
## NEED_MIGRATIONS=1
##fi
##if echo "$CHANGED_FILES" | grep -qE '^(package(-lock)?\.json|vite\.config\.|resources/|public/.*\.(js|css))'; then
## NEED_FRONTEND=1
##fi
### PHP-Code/Views/Config geändert?
##if echo "$CHANGED_FILES" | grep -qE '^(app/|routes/|config/|resources/views/)'; then
## NEED_PHP_RESTART=1
##fi
##
##echo "[i] Zusammenfassung:"
##echo " Composer : $([[ $NEED_COMPOSER -eq 1 ]] && echo JA || echo nein)"
##echo " Migrations : $([[ $NEED_MIGRATIONS -eq 1 ]] && echo JA || echo nein)"
##echo " Frontend : $([[ $NEED_FRONTEND -eq 1 ]] && echo JA || echo nein)"
##echo " PHP restart : $([[ $NEED_PHP_RESTART -eq 1 ]] && echo JA || echo nein)"
##
##echo "[i] Führe Build/Deploy (gezielt) aus …"
##if [[ $NEED_COMPOSER -eq 1 ]]; then
## as_app "cd ${APP_DIR} && composer install --no-interaction --prefer-dist --optimize-autoloader"
##fi
##
##if [[ $NEED_MIGRATIONS -eq 1 ]]; then
## as_app "cd ${APP_DIR} && php artisan migrate --force"
##fi
##
### Cache & Queue nur wenn relevant
##if [[ $NEED_PHP_RESTART -eq 1 || $NEED_COMPOSER -eq 1 || $NEED_MIGRATIONS -eq 1 ]]; then
## as_app "cd ${APP_DIR} && php artisan config:cache && php artisan route:cache || true"
## as_app "cd ${APP_DIR} && php artisan queue:restart || true"
## as_app "cd ${APP_DIR} && php artisan optimize:clear || true"
##fi
##
##if [[ $NEED_FRONTEND -eq 1 ]]; then
## as_app "cd ${APP_DIR} && (npm ci --no-audit --no-fund || npm install)"
## as_app "cd ${APP_DIR} && npm run build"
##fi
##
### Dienste nur neu laden/starten wenn nötig
##ANY_RUNTIME_CHANGE=0
##[[ $NEED_COMPOSER -eq 1 || $NEED_MIGRATIONS -eq 1 || $NEED_FRONTEND -eq 1 || $NEED_PHP_RESTART -eq 1 ]] && ANY_RUNTIME_CHANGE=1
##
##if [[ $ANY_RUNTIME_CHANGE -eq 1 ]]; then
## echo "[i] Dienste neu laden/neustarten (gezielt) …"
## if [[ $NEED_PHP_RESTART -eq 1 || $NEED_COMPOSER -eq 1 || $NEED_MIGRATIONS -eq 1 ]]; then
## restart_php_fpm
## restart_if_exists "${APP_USER}-queue"
## restart_if_exists "${APP_USER}-schedule"
## restart_if_exists "${APP_USER}-ws"
## fi
## # Webserver nur bei Assets/Views/Config
## if [[ $NEED_FRONTEND -eq 1 || $NEED_PHP_RESTART -eq 1 ]]; then
## reload_if_active nginx
## fi
##else
## echo "[i] Nichts zum Updaten."
##fi
##
##echo "[✓] Update auf ${NEW_REV:0:7} abgeschlossen."
#
###!/usr/bin/env bash
##set -euo pipefail
##
##APP_USER="mailwolt"
##APP_DIR="/var/www/mailwolt"
##
##as_app(){ sudo -u "$APP_USER" -H bash -lc "$*"; }
##
##restart_if_exists(){ local u="$1"; systemctl list-unit-files | grep -q "^${u}\.service" && systemctl restart "$u" || true; }
##reload_if_active(){ local u="$1"; systemctl is-active --quiet "$u" && systemctl reload "$u" || true; }
##
##restart_php_fpm(){
## for u in php8.3-fpm php8.2-fpm php8.1-fpm php-fpm; do
## systemctl list-unit-files | grep -q "^${u}\.service" && { systemctl restart "$u"; return 0; }
## done
## return 0
##}
##
##[[ "$(id -u)" -eq 0 ]] || { echo "[!] Bitte als root ausführen"; exit 1; }
##
##echo "[i] Code-Update & Build als ${APP_USER} …"
##as_app "cd ${APP_DIR} && git pull --ff-only"
##as_app "cd ${APP_DIR} && composer install --no-interaction --prefer-dist --optimize-autoloader"
##as_app "cd ${APP_DIR} && php artisan migrate --force"
##as_app "cd ${APP_DIR} && php artisan config:cache && php artisan route:cache || true && php artisan queue:restart || true && php artisan optimize:clear"
##as_app "cd ${APP_DIR} && (npm ci --no-audit --no-fund || npm install)"
##as_app "cd ${APP_DIR} && npm run build"
##
##echo "[i] Dienste neu laden/neustarten …"
##restart_php_fpm
##restart_if_exists "${APP_USER}-queue"
##restart_if_exists "${APP_USER}-schedule"
##restart_if_exists "${APP_USER}-ws"
##reload_if_active nginx
##reload_if_active opendkim
##reload_if_active postfix
##reload_if_active dovecot
##reload_if_active rspamd
##
##echo "[✓] Update abgeschlossen."