1 Commits
Author SHA1 Message Date
christianandClaude Opus 5 a0c3921edd Rank old builds by version, not created_at, when pruning the update package
Gitea returns an empty created_at for generic package files, so sorting by it
left every build equally old and the "keep one previous for rollback" rule
retained whichever the listing happened to return first — the OLDEST build,
with the newest deleted. Rank by the version in the filename instead, numeric
segment by segment so 1.4.34 outranks 1.4.9, and fall back to created_at only
when a name carries no version.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-24 13:27:13 -04:00
+16 -1
View File
@@ -185,9 +185,24 @@ async function giteaPrune(baseUrl, token, keepFile, keepPrevious = 1) {
let files; let files;
try { files = JSON.parse(res.body); } catch (_) { return; } try { files = JSON.parse(res.body); } catch (_) { return; }
if (!Array.isArray(files)) return; if (!Array.isArray(files)) return;
// Rank by the version in the filename, not by created_at: this server returns that field empty,
// which would leave every build "equally old" and quietly retain the OLDEST one as the rollback
// copy instead of the newest.
const verOf = (name) => {
const m = String(name).match(/(\d+(?:\.\d+)+)/);
return m ? m[1].split('.').map(n => parseInt(n, 10) || 0) : [];
};
const newerFirst = (a, b) => {
const pa = verOf(a.name), pb = verOf(b.name);
for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
const x = pa[i] || 0, y = pb[i] || 0;
if (x !== y) return y - x;
}
return new Date(b.created_at || 0) - new Date(a.created_at || 0);
};
const stale = files const stale = files
.filter(f => f && typeof f.name === 'string' && f.name.toLowerCase().endsWith('.exe') && f.name !== keepFile) .filter(f => f && typeof f.name === 'string' && f.name.toLowerCase().endsWith('.exe') && f.name !== keepFile)
.sort((a, b) => new Date(b.created_at || 0) - new Date(a.created_at || 0)) .sort(newerFirst)
.slice(keepPrevious); .slice(keepPrevious);
for (const f of stale) { for (const f of stale) {
const del = await giteaRequest('DELETE', baseUrl.replace(/\/+$/, '') + '/' + encodeURIComponent(f.name), token, null); const del = await giteaRequest('DELETE', baseUrl.replace(/\/+$/, '') + '/' + encodeURIComponent(f.name), token, null);