Startseite und Heroes - Hero-Slideshow (11 Motive inkl. Febrü) mit Infokarte, Laufzeit-Linie, größeren Klickflächen, Goldrahmen und mobiler Karte unter dem Bild; Zeile über der Überschrift, neue Vertrauenspunkte - Hero-Stil auf Marken, Über uns und Kontakt übertragen, Breadcrumb entfernt - Gründer-Leiste, Vision-Box auf Ocker, Showroom-Display in Box mit „Größer ansehen“/Vollbild - Akzentfarbe #a8741f, größere Serif-Überschriften in der Interior-Welt - Marken: Bildpause mit Zitat; Vereine aktualisiert und verlinkt Inhalte - Lektorat aller angezeigten Texte, /about-Korrekturen, Rechtstexte (DDG, TDDDG, Hosting Hetzner) - Ablauf Maßanfertigung überall einheitlich, Magazin-Beitrag neu, alte Beiträge offline, deutsches Datum/Lesezeit, FAQ Projektausstattung, Otterpohl - Referenzen-Seite per CMS-Schalter ausblendbar CMS und Technik - Tote Sektionen, Felder, Seiten und Komponenten entfernt und archiviert (dev/2026-08-28/archiv-*) - Entwurf /entwurf, Farb-Schalter und /welcome entfernt; Test-Routen nur noch lokal - Seitenbaum-Beschreibungen geprüft, fehlende CMS-Felder ergänzt, Markenliste aus „Kernmarken“ - Admin-Bildvorschauen repariert, verwendete Bilder in die Mediathek übernommen - Seeder für das Deployment siehe dev/2026-08-28/entwicklungsplan.md Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
176 lines
5.6 KiB
Bash
Executable file
176 lines
5.6 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
#
|
|
# Deploy eines Git-Tags auf Live — Vorlage aus dev/git-deploy-monitoring
|
|
# (Anleitung: 01-git-deploy.md). Im Projekt z. B. als dev/betrieb/deploy.sh
|
|
# ablegen; Pfad und Einstellungen im Block „Projekt-Einstellungen“ anpassen.
|
|
#
|
|
# Aufruf im App-Verzeichnis auf dem Server:
|
|
#
|
|
# cd ~/meine-app.de
|
|
# bash dev/betrieb/deploy.sh v1.2.0 # ohne neue Migrationen
|
|
# bash dev/betrieb/deploy.sh v1.2.0 --migrations # mit Migrationen, DB-Backup vorher!
|
|
#
|
|
# Optionen:
|
|
# --migrations Neue Migrationen ausführen. Ohne diese Option bricht das
|
|
# Skript ab, sobald der Tag neue Migrationen mitbringt.
|
|
# --clear-schedule php artisan schedule:clear-cache (alte withoutOverlapping-Sperren).
|
|
#
|
|
# Umgebung (optional):
|
|
# DEPLOY_FPM_RELOAD Befehl zum Neuladen von PHP-FPM (Standard siehe unten).
|
|
# Leer setzen, wenn FPM von Hand im Server-Panel neu geladen
|
|
# wird — dann wartet das Skript auf Enter. Nie „Restart“:
|
|
# der entfernt kurz den Socket, Nginx liefert 502.
|
|
#
|
|
# Exit-Codes: 0 fertig, 1 abgebrochen (siehe Ausgabe), 2 falscher Aufruf,
|
|
# 3 live, aber kein Queue-Worker hat den Test-Job abgeholt.
|
|
#
|
|
# Rollback: dasselbe Skript mit dem vorherigen Tag.
|
|
|
|
set -euo pipefail
|
|
|
|
# ---- Projekt-Einstellungen --------------------------------------------------
|
|
DEPLOY_SCRIPT="dev/betrieb/deploy.sh" # Pfad dieses Skripts im Repository
|
|
PHP_FPM_SERVICE="php8.4-fpm" # systemd-Name des FPM-Dienstes
|
|
ABOUT_SECTION="" # z. B. "meineapp" (AboutCommand::add), leer = RELEASE ausgeben
|
|
QUEUE_PROBE=1 # 1 = monitoring:queue-probe am Ende, 0 = Projekt ohne Queue
|
|
# -----------------------------------------------------------------------------
|
|
|
|
# Git ersetzt diese Datei beim Checkout. Bash liest Skripte stückweise, deshalb
|
|
# läuft der Deploy aus einer Kopie.
|
|
if [[ -z "${DEPLOY_COPY:-}" ]]; then
|
|
copy="$(mktemp)"
|
|
cp "$0" "$copy"
|
|
DEPLOY_COPY="$copy" exec bash "$copy" "$@"
|
|
fi
|
|
trap 'rm -f "$DEPLOY_COPY"' EXIT
|
|
|
|
tag="${1:-}"
|
|
shift || true
|
|
run_migrations=0
|
|
clear_schedule=0
|
|
|
|
for option in "$@"; do
|
|
case "$option" in
|
|
--migrations) run_migrations=1 ;;
|
|
--clear-schedule) clear_schedule=1 ;;
|
|
*) echo "Unbekannte Option: $option" >&2; exit 2 ;;
|
|
esac
|
|
done
|
|
|
|
if [[ ! "$tag" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
|
echo "Aufruf: bash $DEPLOY_SCRIPT vX.Y.Z [--migrations] [--clear-schedule]" >&2
|
|
exit 2
|
|
fi
|
|
|
|
if [[ ! -f artisan || ! -d .git ]]; then
|
|
echo "Im App-Verzeichnis aufrufen (artisan und .git fehlen hier)." >&2
|
|
exit 2
|
|
fi
|
|
|
|
step() { printf '\n==> %s\n' "$*"; }
|
|
|
|
step "Arbeitsverzeichnis prüfen"
|
|
drift="$(git status --porcelain)"
|
|
if [[ -n "$drift" ]]; then
|
|
echo "Das Arbeitsverzeichnis weicht vom ausgecheckten Stand ab:" >&2
|
|
echo "$drift" >&2
|
|
echo "Erst klären (git diff), dann deployen. Nichts wurde verändert." >&2
|
|
exit 1
|
|
fi
|
|
|
|
step "Tags von origin holen"
|
|
git fetch --quiet --tags origin
|
|
|
|
if ! git rev-parse --quiet --verify "refs/tags/$tag^{commit}" > /dev/null; then
|
|
echo "Tag $tag gibt es auf origin nicht." >&2
|
|
exit 1
|
|
fi
|
|
|
|
previous="$(cat RELEASE 2>/dev/null || git describe --tags --always)"
|
|
echo "Live: $previous → Ziel: $tag"
|
|
|
|
if [[ "$(git rev-parse HEAD)" == "$(git rev-parse "$tag^{commit}")" ]]; then
|
|
echo "$tag ist bereits ausgecheckt. Nichts zu tun."
|
|
exit 0
|
|
fi
|
|
|
|
new_migrations="$(git diff --name-only --diff-filter=A HEAD "$tag" -- database/migrations)"
|
|
if [[ -n "$new_migrations" ]]; then
|
|
echo "Neue Migrationen:"
|
|
echo "$new_migrations" | sed 's/^/ /'
|
|
if [[ "$run_migrations" -ne 1 ]]; then
|
|
echo "Abbruch: DB-Backup ziehen und mit --migrations erneut aufrufen. Nichts wurde verändert." >&2
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
trap 'echo; echo "!! Deploy abgebrochen. Die Seite bleibt im Wartungsmodus." >&2; echo "!! Rollback: bash $DEPLOY_SCRIPT $previous" >&2; rm -f "$DEPLOY_COPY"' ERR
|
|
|
|
step "Wartungsmodus"
|
|
php artisan down --retry=60
|
|
|
|
step "Checkout $tag"
|
|
git checkout --quiet --detach "$tag"
|
|
echo "$tag" > RELEASE
|
|
|
|
step "Composer"
|
|
composer install --no-dev --optimize-autoloader --no-interaction
|
|
|
|
if [[ -n "$new_migrations" ]]; then
|
|
step "Migrationen"
|
|
php artisan migrate --force
|
|
fi
|
|
|
|
if [[ -d public/vendor/livewire ]]; then
|
|
php artisan vendor:publish --tag=livewire:assets --force
|
|
fi
|
|
|
|
step "Caches"
|
|
php artisan config:cache
|
|
php artisan route:cache
|
|
php artisan view:clear
|
|
php artisan view:cache
|
|
php artisan event:cache
|
|
|
|
if [[ "$clear_schedule" -eq 1 ]]; then
|
|
php artisan schedule:clear-cache
|
|
fi
|
|
|
|
step "Worker und PHP-FPM"
|
|
php artisan queue:restart
|
|
default_fpm_reload="echo '' | sudo -S service $PHP_FPM_SERVICE reload"
|
|
fpm_reload="${DEPLOY_FPM_RELOAD-$default_fpm_reload}"
|
|
if [[ -n "$fpm_reload" ]]; then
|
|
bash -c "$fpm_reload"
|
|
else
|
|
echo "PHP-FPM jetzt im Server-Panel neu laden (Reload, nicht Restart), danach Enter."
|
|
read -r
|
|
fi
|
|
|
|
step "Wartungsmodus aus"
|
|
php artisan up
|
|
|
|
step "Version"
|
|
if [[ -n "$ABOUT_SECTION" ]]; then
|
|
php artisan about --only="$ABOUT_SECTION"
|
|
else
|
|
cat RELEASE
|
|
fi
|
|
|
|
trap - ERR
|
|
|
|
# Läuft ein Worker? `queue:restart` oben beendet ihn; neu starten muss ihn
|
|
# Supervisor. Läuft Supervisor nicht, steht die Queue still, ohne dass es
|
|
# jemand merkt.
|
|
if [[ "$QUEUE_PROBE" -eq 1 ]]; then
|
|
step "Queue-Worker"
|
|
if ! php artisan monitoring:queue-probe --wait=60; then
|
|
echo
|
|
echo "!! Deploy $tag ist live, aber KEIN Queue-Worker läuft." >&2
|
|
echo "!! Jetzt Supervisor und den Worker im Server-Panel prüfen — sonst bleiben Jobs und Mails liegen." >&2
|
|
exit 3
|
|
fi
|
|
fi
|
|
|
|
echo
|
|
echo "Deploy $tag fertig (vorher $previous). Weiter mit den Prüfungen aus der Deploy-Anleitung."
|