185 lines
7.0 KiB
PowerShell
185 lines
7.0 KiB
PowerShell
# ============================================================
|
|
# checkpoint.ps1
|
|
# ------------------------------------------------------------
|
|
# Wird von checkpoint.cmd aufgerufen. Liest
|
|
# .checkpoint-pending.txt, haengt einen Eintrag an changelog.md
|
|
# an (mit aktuellem Timestamp vom lokalen PC), fuehrt einen
|
|
# Git-Commit aus und loescht die Pending-Datei.
|
|
#
|
|
# Robust gegen problematische Eingabedaten:
|
|
# - Doppelte Anfuehrungszeichen in der Zusammenfassung werden
|
|
# sauber durchgereicht, weil die Commit-Message via
|
|
# "git commit -F <tempfile>" uebergeben wird (keine
|
|
# Shell-Argument-Quoting-Probleme).
|
|
# - Pipe-Zeichen "|" in der Zusammenfassung werden abgelehnt,
|
|
# weil sie mit dem Changelog-Format
|
|
# Timestamp | Session | Summary kollidieren.
|
|
# - Whitespace und Zeilenumbrueche in der Zusammenfassung
|
|
# werden zu einem Leerzeichen normalisiert.
|
|
# - Bei Fehler im Hauptablauf wird der Anhang an changelog.md
|
|
# und die Index-Stagung von changelog.md zurueckgerollt,
|
|
# sodass der naechste Lauf nicht doppelt anhaengt.
|
|
# - Eine verwaiste .git/index.lock wird vor dem Lauf erkannt
|
|
# und mit klarer Anleitung gemeldet.
|
|
# ============================================================
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
|
|
# --- Pfade -------------------------------------------------
|
|
$repoRoot = $PSScriptRoot
|
|
Set-Location $repoRoot
|
|
|
|
$pendingFile = Join-Path $repoRoot '.checkpoint-pending.txt'
|
|
$changelogFile = Join-Path $repoRoot 'changelog.md'
|
|
$gitDir = Join-Path $repoRoot '.git'
|
|
$indexLock = Join-Path $gitDir 'index.lock'
|
|
|
|
$utf8NoBom = New-Object System.Text.UTF8Encoding $false
|
|
|
|
# --- Pre-flight Checks -------------------------------------
|
|
if (-not (Test-Path $pendingFile)) {
|
|
Write-Error ".checkpoint-pending.txt nicht gefunden."
|
|
exit 1
|
|
}
|
|
if (-not (Test-Path $changelogFile)) {
|
|
Write-Error "changelog.md nicht gefunden."
|
|
exit 1
|
|
}
|
|
if (-not (Test-Path $gitDir)) {
|
|
Write-Error ".git-Verzeichnis nicht gefunden ($gitDir)."
|
|
exit 1
|
|
}
|
|
if (Test-Path $indexLock) {
|
|
Write-Error ".git/index.lock existiert bereits. Eine vorherige Git-Operation hat sich nicht aufgeraeumt. Falls kein Git-Prozess mehr laeuft, manuell loeschen: Remove-Item '$indexLock' -Force"
|
|
exit 1
|
|
}
|
|
|
|
# changelog.md darf vor dem Lauf keine lokalen Aenderungen haben,
|
|
# damit ein eventueller Rollback eindeutig bleibt.
|
|
$clStatus = & git status --porcelain -- changelog.md 2>$null
|
|
if ($LASTEXITCODE -ne 0) {
|
|
Write-Error "git status fehlgeschlagen (Exit Code $LASTEXITCODE). Liegt das Repo in einem konsistenten Zustand vor?"
|
|
exit 1
|
|
}
|
|
if ($null -ne $clStatus -and ($clStatus -join '').Trim() -ne '') {
|
|
Write-Error "changelog.md hat lokale Aenderungen. Bitte erst per Hand committen oder mit 'git checkout -- changelog.md' verwerfen, bevor checkpoint.cmd laeuft."
|
|
exit 1
|
|
}
|
|
|
|
# --- Pending-Datei einlesen --------------------------------
|
|
$lines = Get-Content $pendingFile -Encoding UTF8
|
|
if ($lines.Count -lt 2) {
|
|
Write-Error ".checkpoint-pending.txt muss mindestens 2 Zeilen enthalten (Session, Zusammenfassung)."
|
|
exit 1
|
|
}
|
|
|
|
$session = $lines[0].Trim()
|
|
$summaryLines = $lines | Select-Object -Skip 1 | Where-Object { $_.Trim() -ne '' }
|
|
$summary = ($summaryLines -join ' ')
|
|
# Whitespace und Steuerzeichen normalisieren
|
|
$summary = ($summary -replace '\s+', ' ').Trim()
|
|
|
|
if ([string]::IsNullOrWhiteSpace($session)) {
|
|
Write-Error "Session-Nummer (Zeile 1) ist leer."
|
|
exit 1
|
|
}
|
|
if ($session -notmatch '^S\d{2,}$') {
|
|
Write-Error "Session-Nummer '$session' hat nicht das Format S<NN> (z.B. S01, S12)."
|
|
exit 1
|
|
}
|
|
if ([string]::IsNullOrWhiteSpace($summary)) {
|
|
Write-Error "Zusammenfassung (Zeile 2+) ist leer."
|
|
exit 1
|
|
}
|
|
if ($summary -match '\|') {
|
|
Write-Error "Zusammenfassung enthaelt das Pipe-Zeichen '|', das mit dem Changelog-Format Timestamp | Session | Summary kollidiert. Bitte ersetzen."
|
|
exit 1
|
|
}
|
|
|
|
# --- Timestamp und Eintrag bauen ---------------------------
|
|
$timestamp = Get-Date -Format 'yyyy-MM-dd HH:mm'
|
|
$entry = "$timestamp | $session | $summary"
|
|
$commitMsg = "${session}: $summary"
|
|
|
|
Write-Host ""
|
|
Write-Host "[checkpoint] Neuer Eintrag:" -ForegroundColor Cyan
|
|
Write-Host " $entry"
|
|
Write-Host ""
|
|
|
|
# --- Backup fuer Rollback und Temp-Message-Datei -----------
|
|
$originalChangelog = [System.IO.File]::ReadAllText($changelogFile, $utf8NoBom)
|
|
$tempMsgFile = Join-Path ([System.IO.Path]::GetTempPath()) ("checkpoint-msg-" + [guid]::NewGuid().ToString() + ".txt")
|
|
|
|
# --- Hauptablauf -------------------------------------------
|
|
$success = $false
|
|
$errorMsg = $null
|
|
try {
|
|
# 1. Sicherstellen, dass changelog.md mit Newline endet
|
|
if ($originalChangelog.Length -gt 0 -and -not ($originalChangelog.EndsWith("`n"))) {
|
|
[System.IO.File]::AppendAllText($changelogFile, "`r`n", $utf8NoBom)
|
|
}
|
|
|
|
# 2. Eintrag anhaengen
|
|
[System.IO.File]::AppendAllText($changelogFile, $entry + "`r`n", $utf8NoBom)
|
|
Write-Host "[checkpoint] An changelog.md angehaengt." -ForegroundColor Green
|
|
|
|
# 3. Commit-Message-Datei schreiben (UTF-8 ohne BOM)
|
|
[System.IO.File]::WriteAllText($tempMsgFile, $commitMsg + "`n", $utf8NoBom)
|
|
|
|
# 4. git add -A
|
|
& git add -A
|
|
if ($LASTEXITCODE -ne 0) {
|
|
throw "git add fehlgeschlagen (Exit Code $LASTEXITCODE)."
|
|
}
|
|
|
|
# 5. git commit -F <tempfile> (umgeht Shell-Argument-Quoting)
|
|
& git commit -F $tempMsgFile
|
|
if ($LASTEXITCODE -ne 0) {
|
|
throw "git commit fehlgeschlagen (Exit Code $LASTEXITCODE)."
|
|
}
|
|
|
|
Write-Host "[checkpoint] Commit erstellt: $commitMsg" -ForegroundColor Green
|
|
$success = $true
|
|
}
|
|
catch {
|
|
$errorMsg = $_.Exception.Message
|
|
}
|
|
finally {
|
|
# Temp-Message-Datei aufraeumen
|
|
if (Test-Path $tempMsgFile) {
|
|
Remove-Item $tempMsgFile -Force -ErrorAction SilentlyContinue
|
|
}
|
|
}
|
|
|
|
if (-not $success) {
|
|
Write-Host ""
|
|
Write-Host "[checkpoint] FEHLER: $errorMsg" -ForegroundColor Red
|
|
Write-Host "[checkpoint] Rollback wird ausgefuehrt..." -ForegroundColor Yellow
|
|
|
|
# changelog.md auf Original-Stand zurueckschreiben
|
|
try {
|
|
[System.IO.File]::WriteAllText($changelogFile, $originalChangelog, $utf8NoBom)
|
|
Write-Host "[checkpoint] changelog.md auf Original-Stand zurueckgerollt." -ForegroundColor Yellow
|
|
} catch {
|
|
Write-Host "[checkpoint] WARNUNG: Rollback von changelog.md fehlgeschlagen ($($_.Exception.Message))." -ForegroundColor Red
|
|
}
|
|
|
|
# Index-Stagung fuer changelog.md auf HEAD zuruecksetzen
|
|
& git restore --staged -- changelog.md 2>$null | Out-Null
|
|
if ($LASTEXITCODE -ne 0) {
|
|
# Fallback fuer aelteres Git ohne 'restore'
|
|
& git reset HEAD -- changelog.md 2>$null | Out-Null
|
|
}
|
|
|
|
Write-Host "[checkpoint] FEHLGESCHLAGEN - .checkpoint-pending.txt bleibt erhalten fuer einen erneuten Lauf." -ForegroundColor Red
|
|
exit 1
|
|
}
|
|
|
|
# --- Pending-Datei loeschen (nicht fatal wenn das fehlschlaegt) ---
|
|
try {
|
|
Remove-Item $pendingFile -Force
|
|
Write-Host "[checkpoint] .checkpoint-pending.txt entfernt." -ForegroundColor Green
|
|
} catch {
|
|
Write-Host "[checkpoint] WARNUNG: .checkpoint-pending.txt konnte nicht geloescht werden ($($_.Exception.Message)). Bitte manuell entfernen." -ForegroundColor Yellow
|
|
}
|