diff --git a/README.md b/README.md index 68bda0d..204ad26 100644 --- a/README.md +++ b/README.md @@ -249,6 +249,7 @@ Limitations of the free hosted service: - Records created by a PR will be deleted after 30 days. - Records in branches without activity (new commits) will be deleted after 180 days. +- After 90 days only the latest record per day will be kept. More limitations may be added in the future as more and more projects use the free hosted service. diff --git a/service/scripts/deleteOldRecords.ts b/service/scripts/deleteOldRecords.ts new file mode 100644 index 0000000..907f41e --- /dev/null +++ b/service/scripts/deleteOldRecords.ts @@ -0,0 +1,116 @@ +// Keep the latest record per day after AGGREGATE_RECORDS_OLDER_THAN_DAYS days + +import { closeMongoClient } from '@/framework/mongo/client'; +import { getCommitRecordsCollection } from '@/framework/mongo/commitRecords'; +import { ObjectId } from 'mongodb'; + +const AGGREGATE_RECORDS_OLDER_THAN_DAYS = 90; + +(async () => { + try { + console.log('Fetch records...'); + const commitRecordsCollection = await getCommitRecordsCollection(); + const agg = await commitRecordsCollection + .aggregate<{ + projectId: string; + subProject?: string; + branch: string; + aggDate: string; + idsToDelete: string[]; + }>([ + { + $sort: { + creationDate: -1, + }, + }, + { + $match: { + creationDate: { + $lt: new Date(new Date().setDate(new Date().getDate() - AGGREGATE_RECORDS_OLDER_THAN_DAYS)), + }, + }, + }, + { + $group: { + _id: { + projectId: '$projectId', + subProject: '$subProject', + branch: '$branch', + aggDate: { + $dateToString: { + format: '%Y-%m-%d', + date: '$creationDate', + }, + }, + }, + records: { + $push: '$_id', + }, + }, + }, + { + // check that the records has at least 2 records + $match: { + 'records.1': { + $exists: true, + }, + }, + }, + { + $project: { + projectId: '$_id.projectId', + subProject: '$_id.subProject', + branch: '$_id.branch', + aggDate: '$_id.aggDate', + // the first id is the last record per that period, so we keep it + idsToDelete: { + $slice: [ + '$records', + 1, + { + $subtract: [ + { + $size: '$records', + }, + 1, + ], + }, + ], + }, + }, + }, + { + $unset: '_id', + }, + ]) + .toArray(); + + const idsToDelete = agg.map((x) => x.idsToDelete).flat(); + + console.log(`Total records to delete: ${idsToDelete.length}`); + + console.log('Are you sure you want to delete all these records? (y/n)'); + const answer = await new Promise((resolve) => { + process.stdin.on('data', (data) => { + resolve(data.toString().trim()); + }); + }); + + if (answer !== 'y') { + console.log('Abort'); + process.exit(0); + } + + console.log('Deleting records...'); + + const result = await commitRecordsCollection.deleteMany({ + _id: { $in: idsToDelete.map((id) => new ObjectId(id)) }, + }); + + console.log(`Deleted records: ${result.deletedCount}`); + + process.exit(0); + } finally { + await closeMongoClient(); + } +})();