S06: Tooling-Fix: checkpoint.ps1 robust gegen problematische Eingabedaten gemacht. Commit-Message wird jetzt via Temp-Datei und git commit -F uebergeben statt via -m mit String, damit doppelte Anfuehrungszeichen im Summary nicht mehr das Argument zerlegen (Ursache des fehlgeschlagenen Hotfix-Commits zuvor). Pipe-Zeichen im Summary werden vorab abgelehnt, da sie mit dem Changelog-Format Timestamp Pipe Session Pipe Summary kollidieren. Whitespace und Zeilenumbrueche im Summary werden zu einem einzelnen Leerzeichen normalisiert. Pre-flight-Checks ergaenzt: Existenz von .git, verwaiste .git/index.lock mit klarer Anleitung melden, changelog.md muss vor dem Lauf clean sein. Atomarer Rollback bei Fehler im Hauptablauf: changelog.md wird auf Original-Stand zurueckgeschrieben und Index-Stagung von changelog.md per git restore --staged oder git reset HEAD zurueckgesetzt, sodass der naechste Lauf nicht doppelt anhaengt. Cleanup-Robustheit: Temp-Message-Datei wird in finally geloescht, das Loeschen der Pending-Datei ist nicht mehr fatal sondern nur eine Warnung.
This commit is contained in:
160
checkpoint.ps1
160
checkpoint.ps1
@@ -5,23 +5,68 @@
|
||||
# .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'
|
||||
|
||||
# Repo-Root = Ordner, in dem dieses Skript liegt
|
||||
# --- 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'
|
||||
|
||||
# --- Pending-Datei lesen -----------------------------------
|
||||
$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)."
|
||||
@@ -29,8 +74,10 @@ if ($lines.Count -lt 2) {
|
||||
}
|
||||
|
||||
$session = $lines[0].Trim()
|
||||
$summary = ($lines | Select-Object -Skip 1 | Where-Object { $_.Trim() -ne '' }) -join ' '
|
||||
$summary = $summary.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."
|
||||
@@ -44,49 +91,94 @@ 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"
|
||||
$entry = "$timestamp | $session | $summary"
|
||||
$commitMsg = "${session}: $summary"
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "[checkpoint] Neuer Eintrag:" -ForegroundColor Cyan
|
||||
Write-Host " $entry"
|
||||
Write-Host ""
|
||||
|
||||
# --- Eintrag an changelog.md anhaengen ---------------------
|
||||
# Immer erst sicherstellen, dass die Datei mit einem Zeilenumbruch endet.
|
||||
$utf8NoBom = New-Object System.Text.UTF8Encoding $false
|
||||
# --- 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")
|
||||
|
||||
if (Test-Path $changelogFile) {
|
||||
$existing = [System.IO.File]::ReadAllText($changelogFile, $utf8NoBom)
|
||||
if ($existing.Length -gt 0 -and -not ($existing.EndsWith("`n"))) {
|
||||
# --- 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)
|
||||
}
|
||||
} else {
|
||||
Write-Error "changelog.md nicht gefunden."
|
||||
|
||||
# 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
|
||||
}
|
||||
|
||||
[System.IO.File]::AppendAllText($changelogFile, $entry + "`r`n", $utf8NoBom)
|
||||
Write-Host "[checkpoint] An changelog.md angehaengt." -ForegroundColor Green
|
||||
|
||||
# --- Git add + commit --------------------------------------
|
||||
& git add -A
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Error "git add fehlgeschlagen (Exit Code $LASTEXITCODE)."
|
||||
exit $LASTEXITCODE
|
||||
# --- 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
|
||||
}
|
||||
|
||||
$commitMsg = "${session}: $summary"
|
||||
& git commit -m $commitMsg
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Error "git commit fehlgeschlagen (Exit Code $LASTEXITCODE)."
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
|
||||
Write-Host "[checkpoint] Commit erstellt: $commitMsg" -ForegroundColor Green
|
||||
|
||||
# --- Pending-Datei loeschen --------------------------------
|
||||
Remove-Item $pendingFile -Force
|
||||
Write-Host "[checkpoint] .checkpoint-pending.txt entfernt." -ForegroundColor Green
|
||||
|
||||
Reference in New Issue
Block a user