Zuweisen mit Umzug und Nachtragen der Pushes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
405b2a0485
commit
a960701d48
2 files changed
+263
No files matched your search
@@ -0,0 +1,106 @@
|
||||
import { config } from '../config.js'
|
||||
import { moveRepoToOrg, WARN } from './repoMove.js'
|
||||
import { listRecentPushes } from './pushHistory.js'
|
||||
import { createGitPushWorksheet, isSystemPusher } from './gitWorksheet.js'
|
||||
import { withLocks } from './keyedLock.js'
|
||||
import { ensureProjectTicket } from './ticketAdmin.js'
|
||||
import { getDocument, updateDocument } from './appwriteAdmin.js'
|
||||
|
||||
/**
|
||||
* Commit-Nachrichten (erste Zeile), die frueher das System mit Kensos Schluessel geschrieben hat
|
||||
* (Preview-Config, automatisch erstellte Preview-Seite) - siehe Plan, Abschnitt "Global
|
||||
* Constraints". Beim Nachtragen zaehlt ein Push nicht, wenn die erste Zeile JEDER seiner
|
||||
* Commit-Nachrichten hier steht - unabhaengig vom Pusher, denn diese alten Commits tragen oft
|
||||
* "knso" als Pusher, nicht das heutige System-Konto (siehe `isSystemPusher`, das dafuer allein
|
||||
* NICHT greift).
|
||||
*/
|
||||
export const SYSTEM_COMMIT_MESSAGES = ['Update preview config from ticket system', 'Automatisch erstellte Preview-Seite']
|
||||
|
||||
function firstLine(message) {
|
||||
return String(message || '').split('\n')[0]
|
||||
}
|
||||
|
||||
/** true, wenn jede Commit-Nachricht des Pushes (erste Zeile) ein alter System-Commit ist. */
|
||||
function isOldSystemCommitPush(push) {
|
||||
const commits = push.commits || []
|
||||
if (commits.length === 0) return false
|
||||
return commits.every((commit) => SYSTEM_COMMIT_MESSAGES.includes(firstLine(commit.message)))
|
||||
}
|
||||
|
||||
/**
|
||||
* Traegt die Pushes der letzten `GITEA_BACKFILL_DAYS` Tage eines Repos als Git-Arbeitsblaetter
|
||||
* nach (fuer neu zugewiesene Projekte, deren bisherige Pushes noch nicht abgerechnet sind).
|
||||
* Ueberspringt Systempushes: das aktuelle System-Konto (`isSystemPusher`) und alte, mit Kensos
|
||||
* Schluessel gemachte System-Commits (`SYSTEM_COMMIT_MESSAGES`). Legt bei Bedarf automatisch ein
|
||||
* Ticket an - aber erst, nachdem feststeht, dass tatsaechlich etwas nachzutragen ist, damit ein
|
||||
* Projekt ohne (relevante) Pushes kein Ticket aufgedraengt bekommt. Wirft nie wegen eines
|
||||
* Gitea-Problems (siehe `reconcileProject`, das sich - wie `moveRepoToOrg` - darauf verlaesst,
|
||||
* dass eine Zuweisung in jedem Fall bestehen bleibt).
|
||||
*/
|
||||
export async function backfillPushes(project, { now = new Date() } = {}) {
|
||||
let pushes
|
||||
try {
|
||||
pushes = await listRecentPushes(project.repoFullName, { now })
|
||||
} catch (err) {
|
||||
return { backfilled: 0, warnings: [WARN.giteaDown(err.message)] }
|
||||
}
|
||||
|
||||
const relevant = pushes.filter((push) => !isSystemPusher(push.pusher) && !isOldSystemCommitPush(push))
|
||||
if (relevant.length === 0) return { backfilled: 0, warnings: [] }
|
||||
|
||||
const ticketId = project.ticketId || (await ensureProjectTicket(project, { repoFullName: project.repoFullName }))
|
||||
if (!ticketId) return { backfilled: 0, warnings: [] }
|
||||
|
||||
let backfilled = 0
|
||||
// Aelteste zuerst (siehe `listRecentPushes`), damit die Arbeitsblaetter in derselben
|
||||
// Reihenfolge entstehen, in der die Pushes tatsaechlich passiert sind.
|
||||
for (const push of relevant) {
|
||||
const result = await createGitPushWorksheet({ ticketId, repoFullName: project.repoFullName, ...push })
|
||||
if (result?.created) backfilled += 1
|
||||
}
|
||||
return { backfilled, warnings: [] }
|
||||
}
|
||||
|
||||
/**
|
||||
* Liest das Projekt, verschiebt sein Repo bei Bedarf nach `GITEA_ORG` und traegt danach dessen
|
||||
* Pushes nach - alles unter der Projekt-Sperre, damit ein Doppelklick auf "Zuweisen" (oder ein
|
||||
* gleichzeitiger Aufruf ueber die Migration, Task 9) nicht zweimal umzieht oder doppelte
|
||||
* Arbeitsblaetter erzeugt (Review Focus 3, Plan). Das Projektdokument wird ERST innerhalb der
|
||||
* Sperre gelesen, damit ein zweiter, gleichzeitiger Aufruf nie mit einem inzwischen veralteten
|
||||
* Objekt arbeitet.
|
||||
*/
|
||||
export async function reconcileProject(projectId, { now } = {}) {
|
||||
return withLocks(['project:' + projectId], async () => {
|
||||
let project = await getDocument(config.collections.websiteProjects, projectId)
|
||||
const { moved, warnings: moveWarnings } = await moveRepoToOrg(project)
|
||||
|
||||
// Immer neu lesen, nicht nur wenn `moved` gesetzt ist: der Selbstheilungs-Zweig in
|
||||
// `moveRepoToOrg` (von Hand verschobenes/umbenanntes Repo) kann das Dokument umbenennen und
|
||||
// dabei trotzdem `moved: null` liefern (Controller-Ruling R13).
|
||||
project = await getDocument(config.collections.websiteProjects, projectId)
|
||||
|
||||
const { backfilled, warnings: backfillWarnings } = await backfillPushes(project, { now })
|
||||
|
||||
return { project, moved, backfilled, warnings: [...moveWarnings, ...backfillWarnings] }
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Weist ein Projekt einem Kunden/Ticket zu und stoesst danach Umzug + Nachtragen an. Die
|
||||
* Zuweisung selbst wird ZUERST und ausserhalb der Projekt-Sperre gespeichert (reines Appwrite,
|
||||
* ohne Gitea) - sie bleibt deshalb bestehen, selbst wenn Gitea gerade nicht erreichbar ist
|
||||
* (siehe `reconcileProject`/`moveRepoToOrg`, die deshalb nie wegen Gitea werfen duerfen).
|
||||
*/
|
||||
export async function assignProject(projectId, { customerId = '', ticketId = '' }, { now } = {}) {
|
||||
// 404 fuer ein unbekanntes Projekt, bevor ueberhaupt geschrieben wird.
|
||||
await getDocument(config.collections.websiteProjects, projectId)
|
||||
|
||||
await updateDocument(config.collections.websiteProjects, projectId, {
|
||||
customerId,
|
||||
ticketId,
|
||||
updatedAt: new Date().toISOString(),
|
||||
})
|
||||
|
||||
const { project, moved, backfilled, warnings } = await reconcileProject(projectId, { now })
|
||||
return { ok: true, project, moved, backfilled, warnings }
|
||||
}
|
||||
Reference in new issue
Block a user