Gesamtprüfung: Zeitlimit für Gitea, Aufräumen ohne Weiterleitung
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
febac3c2a3
commit
d5c70a5bd6
7 files changed
+233
-11
No files matched your search
@@ -142,6 +142,74 @@ async function deletePortalHooks(repoFullName) {
|
||||
return warnings
|
||||
}
|
||||
|
||||
/**
|
||||
* Wie `deletePortalHooks`, aber fuer Schritt 1 (isOrgRepo(from)-Zweig): LIST und DELETE laufen mit
|
||||
* `redirect: 'manual'`, damit ein von Hand AUS der Organisation herausbewegtes Repo (der Name
|
||||
* `repoFullName` sieht per Owner noch wie WEBklar aus, Gitea antwortet aber mit einer
|
||||
* Weiterleitung) nicht angefasst wird - eine ganz normale (Folge-)Anfrage wuerde sonst den
|
||||
* Portal-Webhook eines inzwischen fremden Repos loeschen (final-fix Punkt 2). Eine 3xx- oder
|
||||
* 404-Antwort der LIST gilt als "hier nicht (mehr) zu finden" (`{ redirected: true }`); die
|
||||
* Aufloesung des tatsaechlichen aktuellen Namens ist Sache des Aufrufers.
|
||||
*/
|
||||
async function deletePortalHooksStrict(repoFullName) {
|
||||
const portalUrl = portalWebhookUrl()
|
||||
let hooks
|
||||
try {
|
||||
hooks = await giteaFetch(`/repos/${repoFullName}/hooks`, { redirect: 'manual' })
|
||||
} catch (err) {
|
||||
if (err.status === 404 || (err.status >= 300 && err.status < 400)) return { redirected: true }
|
||||
console.error(`[repoMove] Webhooks von ${repoFullName} konnten nicht gelesen werden:`, err.message)
|
||||
return { redirected: false, warnings: [] }
|
||||
}
|
||||
|
||||
const warnings = []
|
||||
for (const hook of hooks || []) {
|
||||
if (!hookUrl(hook).startsWith(portalUrl)) continue
|
||||
try {
|
||||
await giteaFetch(`/repos/${repoFullName}/hooks/${hook.id}`, { method: 'DELETE', redirect: 'manual' })
|
||||
} catch (err) {
|
||||
console.error(`[repoMove] Webhook ${hook.id} bei ${repoFullName} konnte nicht geloescht werden:`, err.message)
|
||||
warnings.push(WARN.hookNotRemoved(err.message))
|
||||
}
|
||||
}
|
||||
return { redirected: false, warnings }
|
||||
}
|
||||
|
||||
/**
|
||||
* Schritt 1 selbst, wenn `deletePortalHooksStrict` eine Weiterleitung meldet: den kanonischen
|
||||
* Namen normal (mit Redirect-Folge) aufloesen. Liegt er AUSSERHALB von WEBklar, wurde das Repo von
|
||||
* Hand herausverschoben - nur das Projektdokument wird nachgezogen, OHNE es automatisch
|
||||
* zurueckzuholen (final-fix Punkt 2). Liegt er weiterhin in WEBklar (z. B. nur umbenannt), wird
|
||||
* dort ganz normal aufgeraeumt.
|
||||
*/
|
||||
async function resolveRedirectedOrgRepo(project, from) {
|
||||
let canonical
|
||||
try {
|
||||
canonical = (await giteaFetch(`/repos/${from}`)).full_name
|
||||
} catch (err) {
|
||||
return classifyGiteaError(err)
|
||||
}
|
||||
|
||||
if (!isOrgRepo(canonical)) {
|
||||
try {
|
||||
await updateProjectDocument(project, canonical)
|
||||
} catch (err) {
|
||||
return { moved: null, warnings: [WARN.docNotUpdated(err.message)] }
|
||||
}
|
||||
return { moved: null, warnings: [] }
|
||||
}
|
||||
|
||||
const warnings = await deletePortalHooks(canonical)
|
||||
if (!sameRepoFullName(canonical, from)) {
|
||||
try {
|
||||
await updateProjectDocument(project, canonical)
|
||||
} catch (err) {
|
||||
warnings.push(WARN.docNotUpdated(err.message))
|
||||
}
|
||||
}
|
||||
return { moved: null, warnings }
|
||||
}
|
||||
|
||||
/**
|
||||
* Schritte 7-9, idempotent: Cache fuer alten und neuen Namen verwerfen, alte Portal-Webhooks am
|
||||
* neuen Ort loeschen, Preview-Arbeitsverzeichnis des alten Namens aufraeumen. Laeuft unabhaengig
|
||||
@@ -207,6 +275,11 @@ async function moveViaTransfer(project, from) {
|
||||
}
|
||||
|
||||
const confirmedTo = transferResult.full_name
|
||||
// Ein-Zeiler-Absicherung (final-fix Punkt 3): Gitea kann 2xx melden, ohne das Repo tatsaechlich
|
||||
// verschoben zu haben (z. B. Teil-Fehlschlag). Erst wenn der bestaetigte Name wirklich in
|
||||
// WEBklar liegt, gilt der Transfer als geglueckt - sonst kein Dokument-Update, kein Aufraeumen.
|
||||
if (!isOrgRepo(confirmedTo)) return { failed: 'notMoved' }
|
||||
|
||||
let docErr = null
|
||||
try {
|
||||
await updateProjectDocument(project, confirmedTo)
|
||||
@@ -217,6 +290,9 @@ async function moveViaTransfer(project, from) {
|
||||
})
|
||||
|
||||
if (outcome.failed === 'gitea') return classifyGiteaError(outcome.err)
|
||||
if (outcome.failed === 'notMoved') {
|
||||
return { moved: null, warnings: ['Umzug nach WEBklar nicht möglich (Übertragung nicht abgeschlossen).'] }
|
||||
}
|
||||
|
||||
const confirmedTo = outcome.to
|
||||
// Das Aufraeumen (Cache, alter Webhook, Preview-Verzeichnis) haengt nicht am Dokument-Update -
|
||||
@@ -238,10 +314,12 @@ export async function moveRepoToOrg(project) {
|
||||
const from = project.repoFullName
|
||||
|
||||
// Schritt 1: schon in der Organisation - nur noch nach einem liegen gebliebenen Einzel-Webhook
|
||||
// schauen (R11), damit "Pushes nachtragen" auch das noch nachholen kann.
|
||||
// schauen (R11), damit "Pushes nachtragen" auch das noch nachholen kann. Ohne Redirect-Folge
|
||||
// (final-fix Punkt 2), damit ein von Hand herausverschobenes Repo nicht angefasst wird.
|
||||
if (isOrgRepo(from)) {
|
||||
const warnings = await deletePortalHooks(from)
|
||||
return { moved: null, warnings }
|
||||
const result = await deletePortalHooksStrict(from)
|
||||
if (result.redirected) return resolveRedirectedOrgRepo(project, from)
|
||||
return { moved: null, warnings: result.warnings }
|
||||
}
|
||||
|
||||
// Schritt 2: aktuellen Stand holen (fetch folgt Giteas 301-Weiterleitung von Hand verschobener
|
||||
|
||||
Reference in new issue
Block a user