Release-Ankündigungen + öffentliche Changelog-Seite

- Gitea-Release-Webhook: Releases werden archiviert (releases-Tabelle) und neue
  'published'-Releases als oranges 🚀-Embed mit Buttons angekündigt
- Release-Kanal auf der Setup-Seite wählbar (leer = Feature aus) + Test-Button
- /changelog: öffentliche Seite mit Tag-Chips, Pre-Release-Badge, Release-Notes
- /api/releases öffentlich; Updates/Redeliveries posten nicht doppelt

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-23 10:37:28 +02:00
co-authored by Claude Opus 4.8
parent 5a57108230
commit be1fc227d0
9 changed files with 273 additions and 15 deletions
+38 -2
View File
@@ -8,9 +8,10 @@ import { existsSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';
import { config } from '../config.js';
import { saveCommits } from '../db.js';
import { saveCommits, saveRelease } from '../db.js';
import { commitFeedEnabled, branchAllowed, repoIgnored } from '../runtime-settings.js';
import { postPushEmbed } from '../bot/commit-feed.js';
import { postReleaseEmbed } from '../bot/release-feed.js';
import { registerAuthRoutes } from './auth.js';
import { registerApiRoutes } from './api.js';
import { registerDevlogEndpoint } from './devlog-endpoint.js';
@@ -103,8 +104,43 @@ export async function startWebServer(client) {
return reply.code(401).send({ error: 'invalid signature' });
}
// Andere Events (Tag, Issue, …) freundlich ignorieren
const event = request.headers['x-gitea-event'];
// Release-Events → Ankündigung + Changelog-Archiv
if (event === 'release') {
const payload = request.body;
const repo = payload.repository?.full_name ?? 'unbekannt';
if (repoIgnored(repo) || !payload.release) {
return { ok: true, ignored: `release ${repo}` };
}
const release = {
repo,
tag: payload.release.tag_name ?? 'unbekannt',
name: payload.release.name ?? null,
body: payload.release.body ?? null,
url: payload.release.html_url ?? null,
prerelease: payload.release.prerelease ? 1 : 0,
published_at: payload.release.published_at ?? new Date().toISOString(),
};
const isNew = saveRelease(release);
request.log.info(`Release ${release.tag} in ${repo} (${payload.action}, neu: ${isNew})`);
// Nur neue Releases ankündigen — Updates/Löschungen nur still archivieren
let posted = false;
if (isNew && payload.action === 'published') {
try {
posted = await postReleaseEmbed(client, {
...release,
prerelease: Boolean(release.prerelease),
});
} catch (error) {
request.log.error({ err: error }, 'Release-Embed konnte nicht gepostet werden');
}
}
return { ok: true, release: release.tag, posted };
}
// Andere Events (Tag, Issue, …) freundlich ignorieren
if (event !== 'push') {
return { ok: true, ignored: event };
}