150 lines
4.4 KiB
PowerShell
150 lines
4.4 KiB
PowerShell
<#
|
|
.SYNOPSIS
|
|
QR-Code-Generator aktualisieren: neuen Stand holen, Stack neu bauen, starten.
|
|
|
|
.DESCRIPTION
|
|
Windows-Gegenstück zu update.sh. Holt den aktuellen Stand aus dem Git-Remote
|
|
und baut den Docker-Stack neu, wenn es Änderungen gab.
|
|
|
|
.PARAMETER Force
|
|
Auch dann neu bauen, wenn es keine neuen Commits gibt.
|
|
|
|
.PARAMETER Prune
|
|
Nach dem Bauen verwaiste Docker-Images entfernen.
|
|
|
|
.EXAMPLE
|
|
.\update.ps1
|
|
.\update.ps1 -Force -Prune
|
|
#>
|
|
[CmdletBinding()]
|
|
param(
|
|
[switch]$Force,
|
|
[switch]$Prune
|
|
)
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
|
|
function Write-Info { param([string]$Text) Write-Host "→ $Text" }
|
|
function Write-Ok { param([string]$Text) Write-Host "✓ $Text" -ForegroundColor Green }
|
|
function Stop-WithError {
|
|
param([string]$Text)
|
|
Write-Host "✗ $Text" -ForegroundColor Red
|
|
exit 1
|
|
}
|
|
|
|
# Immer im Projektverzeichnis arbeiten, egal von wo das Skript gestartet wird.
|
|
Set-Location -Path $PSScriptRoot
|
|
|
|
# --- Voraussetzungen --------------------------------------------------------
|
|
|
|
foreach ($tool in @('git', 'docker')) {
|
|
if (-not (Get-Command $tool -ErrorAction SilentlyContinue)) {
|
|
Stop-WithError "$tool ist nicht installiert."
|
|
}
|
|
}
|
|
|
|
docker compose version *> $null
|
|
if (-not $?) {
|
|
Stop-WithError 'docker compose ist nicht verfügbar (Docker Compose v2 wird benötigt).'
|
|
}
|
|
|
|
if (-not (Test-Path .env)) {
|
|
Stop-WithError '.env fehlt. Anlegen mit: Copy-Item .env.example .env'
|
|
}
|
|
|
|
# Ein "git pull" auf einem veränderten Arbeitsverzeichnis endet im Konflikt.
|
|
$dirty = git status --porcelain
|
|
if ($dirty) {
|
|
Write-Host '✗ Es gibt lokale Änderungen im Arbeitsverzeichnis:' -ForegroundColor Red
|
|
git status --short
|
|
Write-Host ''
|
|
Stop-WithError "Bitte zuerst committen oder mit 'git stash' beiseitelegen."
|
|
}
|
|
|
|
# --- Neuen Stand holen ------------------------------------------------------
|
|
|
|
$before = git rev-parse HEAD
|
|
$branch = git rev-parse --abbrev-ref HEAD
|
|
|
|
Write-Info "Hole neuen Stand von origin/$branch …"
|
|
git fetch --quiet origin
|
|
if (-not $?) { Stop-WithError 'Der Remote ist nicht erreichbar.' }
|
|
|
|
# --ff-only: lieber abbrechen als eine Merge-Situation erzeugen.
|
|
git merge --ff-only --quiet "origin/$branch"
|
|
if (-not $?) {
|
|
Stop-WithError 'Der lokale Stand lässt sich nicht ohne Merge aktualisieren. Bitte von Hand prüfen.'
|
|
}
|
|
|
|
$after = git rev-parse HEAD
|
|
|
|
if ($before -eq $after) {
|
|
Write-Ok "Bereits auf dem neuesten Stand ($(git rev-parse --short HEAD))."
|
|
} else {
|
|
Write-Ok "Aktualisiert: $(git rev-parse --short $before) → $(git rev-parse --short $after)"
|
|
Write-Host ''
|
|
git --no-pager log --oneline "$before..$after"
|
|
Write-Host ''
|
|
}
|
|
|
|
# --- Stack neu bauen --------------------------------------------------------
|
|
|
|
$running = @(docker compose ps --status running --quiet).Count
|
|
|
|
if (($before -eq $after) -and (-not $Force) -and ($running -gt 0)) {
|
|
Write-Ok 'Der Stack läuft und es gibt nichts Neues — kein Neubau nötig.'
|
|
Write-Host ' (Mit .\update.ps1 -Force lässt sich ein Neubau erzwingen.)'
|
|
exit 0
|
|
}
|
|
|
|
Write-Info 'Baue und starte den Stack neu — das dauert einige Minuten …'
|
|
docker compose up -d --build
|
|
if (-not $?) { Stop-WithError 'Der Neubau ist fehlgeschlagen.' }
|
|
|
|
# --- Warten, bis die Anwendung antwortet ------------------------------------
|
|
|
|
# Nur die Ziffern behalten — so stören weder Anführungszeichen noch Leerzeichen.
|
|
$portLine = Select-String -Path .env -Pattern '^APP_PORT=' | Select-Object -First 1
|
|
$appPort = if ($portLine) { ($portLine.Line -replace '\D', '') } else { '' }
|
|
if (-not $appPort) { $appPort = '3000' }
|
|
|
|
Write-Info 'Warte darauf, dass die Anwendung antwortet …'
|
|
$ready = $false
|
|
for ($attempt = 0; $attempt -lt 60; $attempt++) {
|
|
try {
|
|
Invoke-WebRequest -Uri "http://localhost:$appPort/" -UseBasicParsing -TimeoutSec 5 | Out-Null
|
|
$ready = $true
|
|
break
|
|
} catch {
|
|
Start-Sleep -Seconds 2
|
|
}
|
|
}
|
|
|
|
if (-not $ready) {
|
|
docker compose logs --tail 40 app
|
|
Stop-WithError 'Die Anwendung antwortet nach 2 Minuten nicht. Protokoll siehe oben.'
|
|
}
|
|
|
|
Write-Ok "Die Anwendung antwortet auf http://localhost:$appPort"
|
|
|
|
# --- Ergebnis ---------------------------------------------------------------
|
|
|
|
Write-Host ''
|
|
Write-Info 'Datenbankmigrationen beim Start:'
|
|
docker compose logs app |
|
|
Select-String -Pattern 'migration', 'Migration', 'pending' |
|
|
Select-Object -Last 5 |
|
|
ForEach-Object { " $($_.Line)" }
|
|
|
|
Write-Host ''
|
|
docker compose ps
|
|
|
|
if ($Prune) {
|
|
Write-Host ''
|
|
Write-Info 'Räume verwaiste Docker-Images auf …'
|
|
docker image prune --force
|
|
}
|
|
|
|
Write-Host ''
|
|
Write-Ok "Fertig — Version $(git rev-parse --short HEAD)"
|