feat(docs): Changelog mit "was ist seit meiner Fassung neu"
Bisher musste ein Agent, der eine Anbindung aktualisiert, die gesamte Historie lesen - oder er las gar nichts und uebersah eine brechende Aenderung. Beides schlecht. - public/docs/changelog.json ist die einzige Quelle. Je Fassung eine Zusammenfassung, je Aenderung Bereich, ein "breaking"-Kennzeichen und vor allem ein Feld "action" mit dem, was konkret zu tun ist. Steht dort null, ist nichts zu tun - das ist die haeufigste und nuetzlichste Antwort. - GET /api/updateservice/v1/changelog?since=2.2.0 liefert nur die neueren Fassungen, dazu die Anzahl der Punkte mit Handlungsbedarf und der brechenden Aenderungen. count:0 heisst "du bist auf Stand" - dann muss gar nichts gelesen werden. Optional nach Bereich filterbar (?area=packager). - /docs/changelog.php rendert dieselbe Datei fuer Menschen, mit Eingabefeld fuer die eigene Fassung. Bewusst dieselbe Quelle: zwei Fassungen zu pflegen hiesse, sie auseinanderlaufen zu lassen. - DeploymentcenterSdk.Version im SDK ist der Bezugspunkt. Damit muss die Fassung nicht abgetippt werden. - AGENT_PROMPT_TEMPLATE.md verpflichtet dazu, sie in der AGENTS.md des Projekts festzuhalten und vor jeder Aenderung an der Anbindung den Unterschied abzufragen. Auch in der Kurzfassung fuer knappe Prompt-Budgets. Die Historie ist rueckwirkend bis 2.0.0 gefuellt: 6 Fassungen, 25 Punkte mit Handlungsbedarf, 13 brechende Aenderungen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
1967b49ad7
commit
a8b9f6f7c9
@@ -108,6 +108,90 @@ switch ($action) {
|
||||
);
|
||||
Http::ok(['count' => count($releases), 'releases' => $releases]);
|
||||
|
||||
case 'changelog':
|
||||
// Was hat sich seit einer bestimmten Fassung geaendert?
|
||||
//
|
||||
// Damit muss ein Agent, der eine Anbindung aktualisiert, nicht die
|
||||
// gesamte Historie lesen. Er merkt sich die Fassung, gegen die er
|
||||
// integriert hat, und fragt spaeter nur nach dem Unterschied.
|
||||
$changelogPath = dirname(__DIR__, 3) . '/docs/changelog.json';
|
||||
|
||||
if (!is_file($changelogPath)) {
|
||||
Http::fail(404, 'no_changelog', 'Es ist kein Changelog hinterlegt.');
|
||||
}
|
||||
|
||||
$raw = (string)file_get_contents($changelogPath);
|
||||
// Windows-Werkzeuge stellen gern ein BOM voran; json_decode scheitert daran.
|
||||
$raw = preg_replace('/^\xEF\xBB\xBF/', '', $raw) ?? $raw;
|
||||
|
||||
$changelog = json_decode($raw, true);
|
||||
|
||||
if (!is_array($changelog) || !isset($changelog['versions']) || !is_array($changelog['versions'])) {
|
||||
Http::fail(500, 'invalid_changelog', 'Der hinterlegte Changelog ist nicht lesbar.');
|
||||
}
|
||||
|
||||
$since = Http::str('since');
|
||||
$area = Http::str('area');
|
||||
|
||||
$entries = [];
|
||||
$actionItems = 0;
|
||||
$breaking = 0;
|
||||
|
||||
foreach ($changelog['versions'] as $entry) {
|
||||
if (!is_array($entry) || !isset($entry['version'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Nur echt neuere Fassungen. Wer auf 2.1.0 sitzt, will nicht
|
||||
// wieder ueber 2.1.0 lesen.
|
||||
if ($since !== null && $since !== ''
|
||||
&& !Version::isNewer((string)$entry['version'], $since)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($area !== null && $area !== '') {
|
||||
$entry['changes'] = array_values(array_filter(
|
||||
$entry['changes'] ?? [],
|
||||
static fn(array $c): bool => ($c['area'] ?? '') === $area
|
||||
));
|
||||
|
||||
if ($entry['changes'] === []) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($entry['changes'] ?? [] as $change) {
|
||||
if (!empty($change['action'])) { $actionItems++; }
|
||||
if (!empty($change['breaking'])) { $breaking++; }
|
||||
}
|
||||
|
||||
$entries[] = $entry;
|
||||
}
|
||||
|
||||
// Absteigend: das Neueste zuerst.
|
||||
usort($entries, static fn(array $a, array $b): int
|
||||
=> Version::compare((string)$b['version'], (string)$a['version']));
|
||||
|
||||
Http::ok([
|
||||
'current' => $changelog['current'] ?? null,
|
||||
'since' => $since,
|
||||
'count' => count($entries),
|
||||
'action_items' => $actionItems,
|
||||
'breaking' => $breaking,
|
||||
'versions' => $entries,
|
||||
'message' => $entries === []
|
||||
? ($since !== null && $since !== ''
|
||||
? sprintf('Seit %s hat sich nichts geaendert.', $since)
|
||||
: 'Es ist nichts hinterlegt.')
|
||||
: sprintf(
|
||||
'%d Fassung(en) neuer als %s, davon %d mit Handlungsbedarf und %d mit Bruch.',
|
||||
count($entries),
|
||||
$since !== null && $since !== '' ? $since : 'Anbeginn',
|
||||
$actionItems,
|
||||
$breaking
|
||||
),
|
||||
]);
|
||||
|
||||
case 'pubkey':
|
||||
// Oeffentlicher Schluessel zum Pruefen der Release-Signaturen.
|
||||
// Bewusst ohne Token: er ist oeffentlich, und der Agent braucht ihn,
|
||||
@@ -393,7 +477,8 @@ function resolveUpdateAction(): string
|
||||
$last = strtolower((string)end($segments));
|
||||
|
||||
return match ($last) {
|
||||
'check', 'latest', 'releases', 'pubkey', 'publish', 'update', 'edit', 'delete' => $last === 'edit' ? 'update' : $last,
|
||||
'check', 'latest', 'releases', 'pubkey', 'changelog', 'publish', 'update', 'edit', 'delete'
|
||||
=> $last === 'edit' ? 'update' : $last,
|
||||
'publish_release' => 'publish',
|
||||
default => 'check',
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user