160 lines
3.9 KiB
JavaScript
160 lines
3.9 KiB
JavaScript
const readline = require("node:readline/promises");
|
|
const { stdin: input, stdout: output } = require("node:process");
|
|
|
|
// Configuration
|
|
const config = {
|
|
GITEA_URL: "https://git.zeldon.ru",
|
|
GITEA_TOKEN: "",
|
|
REPO_OWNER: "",
|
|
REPO_NAME: "",
|
|
KEEP_LAST_N: 10, // Number of latest attachments to keep
|
|
};
|
|
|
|
// Helper function for API calls
|
|
async function fetchApi(endpoint) {
|
|
const response = await fetch(`${config.GITEA_URL}/api/v1${endpoint}`, {
|
|
headers: {
|
|
Authorization: `token ${config.GITEA_TOKEN}`,
|
|
Accept: "application/json",
|
|
},
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(
|
|
`API call failed: ${response.status} ${response.statusText}`
|
|
);
|
|
}
|
|
|
|
return response.json();
|
|
}
|
|
|
|
async function getAllReleases() {
|
|
let page = 1;
|
|
let allReleases = [];
|
|
|
|
while (true) {
|
|
const releases = await fetchApi(
|
|
`/repos/${config.REPO_OWNER}/${config.REPO_NAME}/releases?page=${page}&limit=50`
|
|
);
|
|
if (releases.length === 0) {
|
|
break;
|
|
}
|
|
allReleases = [...allReleases, ...releases];
|
|
page++;
|
|
}
|
|
|
|
return allReleases;
|
|
}
|
|
|
|
async function getAttachmentsToDelete() {
|
|
try {
|
|
// Get all releases using pagination
|
|
const releases = await getAllReleases();
|
|
|
|
// Collect all attachments with their metadata
|
|
const allAttachments = releases.reduce((acc, release) => {
|
|
const attachments = (release.assets || []).map((asset) => ({
|
|
id: asset.id,
|
|
name: asset.name,
|
|
created: new Date(release.created_at),
|
|
releaseId: release.id,
|
|
size: asset.size,
|
|
}));
|
|
return [...acc, ...attachments];
|
|
}, []);
|
|
|
|
// Sort attachments by creation date (newest first)
|
|
allAttachments.sort((a, b) => b.created - a.created);
|
|
|
|
// Get attachments to delete (skip the first KEEP_LAST_N)
|
|
const attachmentsToDelete = allAttachments.slice(config.KEEP_LAST_N);
|
|
|
|
// Calculate total size in MB
|
|
const totalSizeMB = (
|
|
allAttachments.reduce((sum, att) => sum + att.size, 0) /
|
|
(1024 * 1024)
|
|
).toFixed(2);
|
|
const sizeToDeleteMB = (
|
|
attachmentsToDelete.reduce((sum, att) => sum + att.size, 0) /
|
|
(1024 * 1024)
|
|
).toFixed(2);
|
|
const sizeToKeepMB = (totalSizeMB - sizeToDeleteMB).toFixed(2);
|
|
|
|
console.log(
|
|
`Found ${allAttachments.length} total attachments (${totalSizeMB} MB)`
|
|
);
|
|
console.log(
|
|
`Keeping ${config.KEEP_LAST_N} most recent attachments (${sizeToKeepMB} MB)`
|
|
);
|
|
console.log(
|
|
`${attachmentsToDelete.length} attachments will be deleted (${sizeToDeleteMB} MB)`
|
|
);
|
|
|
|
// Return list of attachment IDs to delete
|
|
return attachmentsToDelete.map((att) => ({
|
|
id: att.id,
|
|
name: att.name,
|
|
releaseId: att.releaseId,
|
|
}));
|
|
} catch (error) {
|
|
console.error("Error getting attachments:", error.message);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async function deleteAttachment(releaseId, attachmentId) {
|
|
const response = await fetch(
|
|
`${config.GITEA_URL}/api/v1/repos/${config.REPO_OWNER}/${config.REPO_NAME}/releases/${releaseId}/assets/${attachmentId}`,
|
|
{
|
|
method: "DELETE",
|
|
headers: {
|
|
Authorization: `token ${config.GITEA_TOKEN}`,
|
|
},
|
|
}
|
|
);
|
|
|
|
if (!response.ok) {
|
|
throw new Error(
|
|
`Failed to delete attachment ${attachmentId}: ${response.status} ${response.statusText}`
|
|
);
|
|
}
|
|
}
|
|
|
|
async function main() {
|
|
try {
|
|
const attachments = await getAttachmentsToDelete();
|
|
|
|
const rl = readline.createInterface({ input, output });
|
|
const answer = await rl.question(
|
|
"\nDo you want to proceed with deletion? (y/N) "
|
|
);
|
|
rl.close();
|
|
|
|
if (answer.toLowerCase() === "y") {
|
|
console.log("\nDeleting attachments...");
|
|
let deleted = 0;
|
|
|
|
for (const att of attachments) {
|
|
try {
|
|
await deleteAttachment(att.releaseId, att.id);
|
|
console.log(`Deleted: ${att.name}`);
|
|
deleted++;
|
|
} catch (error) {
|
|
console.error(`Failed to delete ${att.name}:`, error.message);
|
|
}
|
|
}
|
|
|
|
console.log(
|
|
`\nDeletion complete. Successfully deleted ${deleted}/${attachments.length} attachments.`
|
|
);
|
|
} else {
|
|
console.log("Operation cancelled by user.");
|
|
}
|
|
} catch (error) {
|
|
console.error("Script failed:", error);
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
main();
|