diff --git a/deploy/lib/release.sh b/deploy/lib/release.sh index 4cd9117..3300009 100644 --- a/deploy/lib/release.sh +++ b/deploy/lib/release.sh @@ -38,8 +38,17 @@ release_manifest_commit() { # failed in between leaves a newer number on disk than is serving. Deciding # "is there something newer" against the file would then offer nothing, because # the checkout already claims to be the version it never finished installing. +# +# `|| true` at the end, same idiom as release_version()'s `|| echo '0.0.0'`: +# guarantee a zero exit status regardless of what happened upstream. Without +# it, a missing manifest — an ordinary state before the first install — makes +# `sed` exit 2, `pipefail` carries that out of the pipeline, and the caller's +# `DEPLOYED_VERSION="$(release_manifest_version)"` is a bare assignment: under +# `set -e` that ends the agent on every tick, before it ever writes a status. +# Empty output either way, so the caller's existing fallback to +# release_version() still fires exactly as before. release_manifest_version() { - sed -n 's/.*"version"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$MANIFEST_FILE" 2>/dev/null | head -1 + sed -n 's/.*"version"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$MANIFEST_FILE" 2>/dev/null | head -1 || true } # release_version_gt A B — true when A is strictly a higher version than B. diff --git a/tests/Feature/ReleaseComparisonTest.php b/tests/Feature/ReleaseComparisonTest.php index 4042b1a..fccd3ca 100644 --- a/tests/Feature/ReleaseComparisonTest.php +++ b/tests/Feature/ReleaseComparisonTest.php @@ -115,6 +115,21 @@ it('answers with nothing, and cleanly, when there are no releases yet', function ->and(trim($process->getOutput()))->toBe('[0]'); }); +it('survives a missing manifest instead of taking the agent down with it', function () { + // Kein storage/app/deployment.json in diesem Wegwerf-Repo — der Zustand + // eines frischen Checkouts vor der ersten Installation. `sed` auf einer + // fehlenden Datei liefert Status 2; die Zeile, die diese Funktion in + // update-agent.sh tatsaechlich verbraucht — eine reine Zuweisung, + // `DEPLOYED_VERSION="$(release_manifest_version)"` — reicht diesen + // Status unter `pipefail` an `set -e` weiter. Ohne Absicherung stirbt der + // Agent bei JEDEM Tick, bevor er je eine Statusdatei schreibt — dieselbe + // Fehlerklasse wie bei sync_vpn_certificate und einem fehlenden `.env`. + $process = runRelease('DEPLOYED_VERSION="$(release_manifest_version)"; echo "[$?][$DEPLOYED_VERSION]"'); + + expect($process->getExitCode())->toBe(0) + ->and(trim($process->getOutput()))->toBe('[0][]'); +}); + it('orders by version, not alphabetically', function () { // v1.10.0 is newer than v1.9.0 and sorts earlier as a string. Getting this // wrong means a server sitting on 1.9.0 is told it is current.