Fassung 1.4.6: das Update schreibt mit, und die Ergebnisseite ist nachsichtig
CMS quality / php (8.2) (push) Canceled after 0s
CMS quality / php (8.4) (push) Canceled after 0s
CMS quality / browser (push) Canceled after 0s
CMS quality / mysql (push) Canceled after 0s

Zwei Nachtraege zu 1.4.5, beide aus der Generalprobe.

- Jeder Schritt des Archiv-Updaters geht sofort nach var/updates.log,
  waehrend des Laufs und nicht am Ende. Auf Umuts Hosting war die
  Ergebnisseite tot, und damit war auch verloren, was der Updater
  berichtet hatte. Genau so wurde der naechste Fehlschlag dann doch
  lesbar: "bin liess sich nicht beiseitelegen - der alte Stand wurde
  zurueckgeschoben" (ein Windows-Artefakt der Testumgebung, und
  zugleich der Beweis, dass der Rueckweg funktioniert).
- Die Ergebnisseite versteht auch die Schreibweise bis 1.4.4. Das ist
  kein Nachgeben, sondern noetig: Beim Update schreibt der alte Code
  die Schritte in die Sitzung und der neue zeigt sie an. Eine Fassung,
  die nur die neue Schreibweise kennt, koennte das Update, das sie
  selbst einspielt, nicht berichten.

Nachgestellt mit einer echten Installation aus dem Releasearchiv, die
ueber die Oberflaeche aktualisiert wurde - nicht ueber die Konsole.

Geprueft: 434 Tests auf PHP 8.2 und 8.4.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
kantarciandClaude Opus 5 committed 2026-09-14 00:04:37 +02:00
1 parent d295757ce0
commit af5a2cef86
5 files changed
+51 -4

No files matched your search

+26 -1
View File
@@ -38,6 +38,9 @@ final class ArchiveUpdate
*/
private const MARKE = 'var/update/offen.json';
/** Das Protokoll - dieselbe Datei, in die auch der Updater über Git schreibt. */
private const PROTOKOLL = 'var/updates.log';
public function __construct(
private string $root,
private Updater $updater,
@@ -96,11 +99,19 @@ final class ArchiveUpdate
public function run(?string $version = null): array
{
$schritte = [];
$melden = static function (array &$schritte, string $schritt, bool $ok, string $detail = ''): bool {
// Jeder Schritt geht sofort ins Protokoll, nicht erst am Ende.
//
// Der Grund steht in ADR 071: Wenn die Seite, die das Ergebnis anzeigt, nicht erscheint -
// aus welchem Grund auch immer -, weiß niemand mehr, was passiert ist. Eine Zeile in
// einer Datei überlebt das, und auf einem Hosting ohne Konsole ist sie manchmal das
// Einzige, was von einem gescheiterten Update übrig bleibt.
$melden = function (array &$schritte, string $schritt, bool $ok, string $detail = ''): bool {
$schritte[] = ['step' => $schritt, 'ok' => $ok, 'detail' => $detail];
$this->protokoll(sprintf('%s %s: %s', $ok ? 'ok ' : 'FEHLER', $schritt, $detail));
return $ok;
};
$this->protokoll(sprintf('--- Update aus dem Archiv, %s UTC', gmdate('Y-m-d H:i:s')));
$neueste = $this->latest();
if (null === $neueste) {
@@ -259,6 +270,7 @@ final class ArchiveUpdate
public function finish(Installation $installation): array
{
$schritte = [];
$this->protokoll(sprintf('--- Migrationen nach dem Update, %s UTC', gmdate('Y-m-d H:i:s')));
try {
$namen = $installation->migrate();
$schritte[] = ['step' => 'Migrationen', 'ok' => true, 'detail' => [] === $namen
@@ -266,12 +278,14 @@ final class ArchiveUpdate
: sprintf('%d ausgeführt: %s.', count($namen), implode(', ', $namen))];
} catch (\Throwable $fehler) {
$schritte[] = ['step' => 'Migrationen', 'ok' => false, 'detail' => $fehler->getMessage().' Die Website bleibt im Wartungszustand, bis das geklärt ist.'];
$this->protokoll('FEHLER Migrationen: '.$fehler->getMessage());
return ['ok' => false, 'steps' => $schritte];
}
@unlink($this->root.'/'.self::MARKE);
$this->updater->maintenance(false);
$this->protokoll('ok Migrationen: '.$schritte[0]['detail']);
$schritte[] = ['step' => 'Fertig', 'ok' => true, 'detail' => sprintf(
'Fassung %s läuft. Der vorherige Stand liegt unter var/update/, bis du ihn löschst.',
$this->updater->version(),
@@ -280,6 +294,17 @@ final class ArchiveUpdate
return ['ok' => true, 'steps' => $schritte];
}
/**
* Eine Zeile ins Protokoll, und zwar sofort.
*
* Ohne Ausnahme bei Fehlschlag: Ein Update, das daran scheitert, dass sein Protokoll nicht
* schreibbar ist, wäre absurd.
*/
private function protokoll(string $zeile): void
{
@file_put_contents($this->root.'/'.self::PROTOKOLL, $zeile.PHP_EOL, FILE_APPEND);
}
/** Kopiert das neue public/ über das alte, ohne das zu berühren, was dort entstanden ist. */
private function mergePublic(string $von, string $nach): void
{