Files
Webklar-Kundenbereich/server/services/pushHistory.js
T

100 lines
3.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { config } from '../config.js'
import { giteaFetch, splitRepo } from './giteaClient.js'
const DAY_MS = 24 * 60 * 60 * 1000
// Sicherheitsnetz fuer listRecentPushes: sollte Gitea "page" ignorieren und immer dieselbe
// volle, noch im Fenster liegende Seite liefern, blaettert die Schleife nicht endlos weiter
// (40 x 50 = 2000 Eintraege).
const MAX_FEED_PAGES = 40
/**
* Baut aus Gitea-1.25-Aktivitaeten-Feed-Eintraegen (`GET .../activities/feeds`) Push-Objekte
* im selben Zuschnitt wie der Push-Webhook (siehe `server/routes/webhook/gitea.js` und
* `createGitPushWorksheet`). Nur `op_type === 'commit_repo'`-Eintraege ab `since` mit
* mindestens einem Commit zaehlen. Der erste Push auf einen neuen Branch (Eintrag mit leerem
* `content`) und andere Aktivitaeten (z. B. `create_repo`) werden uebersprungen; ein nicht
* parsbarer `content` ebenso. Ergebnis aufsteigend nach `pushedAt` sortiert (aelteste
* zuerst), unabhaengig von der Reihenfolge im Feed.
*
* @param {object[]} feed Feed-Eintraege wie von Gitea geliefert.
* @param {{since: Date}} options
* @returns {Array<{branch: string, commitSha: string, pushedAt: Date,
* pusher: {login: string, username: string, full_name: string},
* commits: Array<{id: string, message: string, author: {name: string}}>}>}
*/
export function pushesFromFeed(feed, { since } = {}) {
const pushes = []
for (const entry of feed || []) {
if (entry?.op_type !== 'commit_repo') continue
if (!(new Date(entry.created) >= since)) continue
let parsed
try {
parsed = JSON.parse(entry.content)
} catch {
continue
}
const rawCommits = parsed?.Commits
if (!Array.isArray(rawCommits) || rawCommits.length === 0) continue
const actUser = entry.act_user || {}
pushes.push({
branch: String(entry.ref_name || '').replace('refs/heads/', ''),
commitSha: parsed.HeadCommit?.Sha1 || rawCommits[0].Sha1,
pushedAt: new Date(entry.created),
pusher: {
login: actUser.login,
username: actUser.login,
full_name: actUser.full_name || '',
},
commits: rawCommits.map((c) => ({
id: c.Sha1,
message: c.Message,
author: { name: c.AuthorName },
})),
})
}
return pushes.sort((a, b) => a.pushedAt - b.pushedAt)
}
/**
* Liest die Push-Historie eines Repos der letzten `days` Tage aus dem Gitea-Aktivitaeten-Feed
* (`GET /repos/{owner}/{repo}/activities/feeds`, seitenweise mit 50 pro Seite, neueste zuerst).
* Blaettert nur so weit wie noetig: stoppt bei einer leeren Seite, einer Seite mit weniger als
* 50 Eintraegen, oder sobald der aelteste Eintrag einer Seite vor `since` liegt. Bricht
* zusaetzlich nach `MAX_FEED_PAGES` Seiten ab (mit einer Konsolen-Warnung), falls keine dieser
* Bedingungen je eintritt.
*
* @param {string} repoFullName "owner/repo"
* @param {{days?: number, now?: Date}} [options]
* @returns {Promise<ReturnType<typeof pushesFromFeed>>}
*/
export async function listRecentPushes(repoFullName, { days = config.gitea.backfillDays, now = new Date() } = {}) {
const [owner, repo] = splitRepo(repoFullName)
const since = new Date(now - days * DAY_MS)
const limit = 50
const collected = []
let page = 1
while (true) {
const items = await giteaFetch(`/repos/${owner}/${repo}/activities/feeds?limit=${limit}&page=${page}`)
if (!Array.isArray(items) || items.length === 0) break
collected.push(...items)
if (items.length < limit) break
if (new Date(items[items.length - 1].created) < since) break
if (page >= MAX_FEED_PAGES) {
console.warn(
`[pushHistory] ${repoFullName}: mehr als ${MAX_FEED_PAGES} Seiten Aktivitäten – ältere Pushes im Zeitraum werden nicht nachgetragen`
)
break
}
page += 1
}
return pushesFromFeed(collected, { since })
}