Der erste Durchlauf der Testinstanz hat neun Bugs zutage gefoerdert, und fast
alle waren dieselbe Sorte Fehler: eine Auskunft, die nicht stimmte.
Am folgenreichsten die Fassung. config/config.php fuehrte app.version als feste
Zeichenkette und stand seit 2.0.0 darauf, waehrend 2.7.0 lief - unbemerkt, weil
die Datei gitignored ist und in keinem Diff auftaucht. Zwei gemeldete Bugs sind
daran fehldiagnostiziert worden ("der Server ist zu alt"). src/bootstrap.php
leitet die Fassung jetzt aus "current" in public/docs/changelog.json ab.
Im Einzelnen:
- #346 Fassung aus dem Changelog statt aus der Konfiguration
- #60 /api/health ueberlebt eine leere Datenbank: eigener Check "schema",
healthy=false mit Begruendung statt HTTP 500
- #54 dc-testkit doctor prueft Mindestfassung (semantisch) und Rechte, statt
sie nur anzuzeigen - dafuer neu: GET /api/tokens/v1/whoami
- #53 dc-testkit.sh unter /testkit/ erreichbar (Route fehlte, der
dokumentierte Bezugsweg hat nie funktioniert) und mit LF ausgeliefert
(deploy.py/deploy_dev.py entfernen CR bei .sh/.bash beim Upload)
- #288 Filter und Formulare werfen nicht mehr aufs Dashboard zurueck: die
offene Ansicht wandert bei GET als "view" in den Query-String, und die
Filter loesen ueber requestSubmit() aus - form.submit() erzeugt kein
submit-Ereignis, weshalb der zentrale Zuhoerer dort nie lief
- #347 /api/bugtracker/v1/roadmap auch ohne .php erreichbar
- #55 Fassungshinweis in TESTUMGEBUNG.md 4.6 (serverseitig war das mit 2.6.0
bereits behoben)
Nicht geprueft: php -l. Auf dem Arbeitsplatz ist kein PHP installiert; die
Abnahme laeuft ueber die Testinstanz.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
126 lines
4.4 KiB
PHP
126 lines
4.4 KiB
PHP
<?php
|
|
/**
|
|
* Deploymentcenter Bootstrap
|
|
*
|
|
* Einziger Einstiegspunkt fuer Autoloading, Konfiguration und Fehlerbehandlung.
|
|
* Jede Datei unter public/ bindet ausschliesslich diese Datei ein.
|
|
*/
|
|
|
|
declare(strict_types=1);
|
|
|
|
if (defined('DC_BOOTSTRAPPED')) {
|
|
return;
|
|
}
|
|
define('DC_BOOTSTRAPPED', true);
|
|
|
|
define('DC_ROOT', dirname(__DIR__));
|
|
define('DC_SRC', DC_ROOT . '/src');
|
|
define('DC_VAR', DC_ROOT . '/var');
|
|
|
|
// --- PSR-4 Autoloader: Deploymentcenter\Foo\Bar -> src/Foo/Bar.php ---
|
|
spl_autoload_register(static function (string $class): void {
|
|
$prefix = 'Deploymentcenter\\';
|
|
$len = strlen($prefix);
|
|
if (strncmp($class, $prefix, $len) !== 0) {
|
|
return;
|
|
}
|
|
$relative = substr($class, $len);
|
|
$path = DC_SRC . '/' . str_replace('\\', '/', $relative) . '.php';
|
|
if (is_file($path)) {
|
|
require_once $path;
|
|
}
|
|
});
|
|
|
|
// --- Konfiguration laden ---
|
|
$dcConfigFile = DC_ROOT . '/config/config.php';
|
|
if (!is_file($dcConfigFile)) {
|
|
http_response_code(500);
|
|
header('Content-Type: text/plain; charset=utf-8');
|
|
echo "Konfiguration fehlt.\n\n"
|
|
. "Bitte config/config.example.php nach config/config.php kopieren und ausfuellen.\n";
|
|
exit(1);
|
|
}
|
|
|
|
/** @var array $dcConfig */
|
|
$dcConfig = require $dcConfigFile;
|
|
if (!is_array($dcConfig)) {
|
|
http_response_code(500);
|
|
header('Content-Type: text/plain; charset=utf-8');
|
|
echo "config/config.php muss ein Array zurueckgeben.\n";
|
|
exit(1);
|
|
}
|
|
|
|
// --- Fassung: aus dem Changelog, nicht aus der Konfiguration ---
|
|
// Die ausgelieferte Fassung ist eine Eigenschaft des Standes, keine
|
|
// Einstellung der Installation. In config/config.php stand sie als
|
|
// Zeichenkette - und blieb dort auf 2.0.0 stehen, waehrend laengst 2.7.0 lief.
|
|
// Das war keine Schoenheitsfrage: /api/health meldete 2.0.0, Fehlermeldungen
|
|
// trugen eine falsche build_version, und wer die Fassung gegen eine
|
|
// Mindestanforderung prueft (dc-testkit doctor), bekam auf einem aktuellen
|
|
// Server eine Absage. public/docs/changelog.json wird bei jedem Release
|
|
// ohnehin gepflegt und ist damit die belastbarere Quelle. Der Wert aus der
|
|
// Konfiguration bleibt Rueckfallebene, falls die Datei fehlt.
|
|
//
|
|
// Gelesen wird nur der Kopf der Datei: sie ist rund 55 KB gross, und dafuer
|
|
// bei jedem Aufruf einen json_decode zu bezahlen, waere fuer eine einzelne
|
|
// Zeichenkette zu teuer. Findet sich der Schluessel dort nicht - etwa weil
|
|
// jemand die Datei umsortiert hat -, wird sie doch vollstaendig gelesen.
|
|
$dcChangelogFile = DC_ROOT . '/public/docs/changelog.json';
|
|
if (is_file($dcChangelogFile)) {
|
|
$dcVersion = null;
|
|
$dcHead = (string)file_get_contents($dcChangelogFile, false, null, 0, 4096);
|
|
|
|
if (preg_match('/"current"\s*:\s*"([^"]+)"/', $dcHead, $dcMatch) === 1) {
|
|
$dcVersion = $dcMatch[1];
|
|
} else {
|
|
$dcMeta = json_decode((string)file_get_contents($dcChangelogFile), true);
|
|
if (is_array($dcMeta) && is_string($dcMeta['current'] ?? null)) {
|
|
$dcVersion = $dcMeta['current'];
|
|
}
|
|
}
|
|
|
|
if (is_string($dcVersion) && $dcVersion !== '') {
|
|
if (!isset($dcConfig['app']) || !is_array($dcConfig['app'])) {
|
|
$dcConfig['app'] = [];
|
|
}
|
|
$dcConfig['app']['version'] = $dcVersion;
|
|
}
|
|
}
|
|
|
|
Deploymentcenter\Core\Config::load($dcConfig);
|
|
|
|
date_default_timezone_set((string)Deploymentcenter\Core\Config::get('app.timezone', 'UTC'));
|
|
|
|
// --- Fehleranzeige: niemals an den Client, immer ins Log ---
|
|
$dcDebug = (bool)Deploymentcenter\Core\Config::get('app.debug', false);
|
|
ini_set('display_errors', $dcDebug ? '1' : '0');
|
|
ini_set('log_errors', '1');
|
|
error_reporting(E_ALL);
|
|
|
|
set_exception_handler(static function (\Throwable $e): void {
|
|
// Http::fail() protokolliert die Exception bereits - hier nur die
|
|
// Selbstmeldung in den eigenen Bugtracker anstossen.
|
|
Deploymentcenter\Core\ErrorReporter::report($e);
|
|
|
|
if (!headers_sent()) {
|
|
http_response_code(500);
|
|
}
|
|
Deploymentcenter\Core\Http::fail(500, 'internal_error', 'Interner Serverfehler.', $e);
|
|
});
|
|
|
|
register_shutdown_function(static function (): void {
|
|
$err = error_get_last();
|
|
if ($err === null) {
|
|
return;
|
|
}
|
|
if (!in_array($err['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR], true)) {
|
|
return;
|
|
}
|
|
Deploymentcenter\Core\Logger::error(
|
|
sprintf('Fatal: %s in %s:%d', $err['message'], $err['file'], $err['line'])
|
|
);
|
|
Deploymentcenter\Core\ErrorReporter::reportFatal($err);
|
|
});
|
|
|
|
unset($dcConfigFile, $dcConfig, $dcDebug);
|