fix: preserve paid hosting deadlines, quotas and review snapshots

This commit is contained in:
Thomas Durieux committed 2026-11-02 21:03:29 +00:00
1 parent 7d7f95506a
commit 036eddfa0e
10 files changed
+116 -27

No files matched your search

+14
View File
@@ -708,6 +708,20 @@ export default class Repository {
logger.info("up to date", { repoId: this._model.repoId });
return;
}
// Admit the pinned replacement before changing or deleting the published snapshot.
if (config.BILLING_ENABLED && this.model.billingManaged) {
const candidateModel = new AnonymizedRepositoryModel(this.model.toObject());
candidateModel.source.commit = newCommit;
const candidate = new Repository(candidateModel);
const files = await candidate.source.getFiles();
try {
await reserveRepository(String(this.model.owner), this.repoId,
files.reduce((sum, file) => sum + (file.size || 0), 0), this.model.conference);
} catch (error) {
if (!opt?.force && error instanceof Error && error.message === "quota_exceeded") return;
throw error;
}
}
this._model.source.commit = newCommit;
const commitInfo = await ghRepo.getCommitInfo(newCommit, {
accessToken: token,
+6 -2
View File
@@ -30,8 +30,12 @@ export async function reserveRepository(owner: string, repoId: string, bytes: nu
if (!await BillingQuota.exists({ _id: limits.scope })) {
const existing = await RepositoryModel.find(limits.scope.startsWith("user:") ? { owner, status: { $nin: ["removed", "expired"] } }
: limits.scope.startsWith("conference:") ? { conference, status: { $nin: ["removed", "expired"] } } : { repoId, status: { $nin: ["removed", "expired"] } })
.select("repoId size").lean();
try { await BillingQuota.create({ _id: limits.scope, allocations: existing.map(r => ({ repoId: r.repoId, bytes: r.size?.storage || 0, createdAt: new Date() })) }); }
.select("repoId size owner conference").lean();
const funded = [];
for (const repository of existing) {
if ((await allowance(String(repository.owner), repository.repoId, repository.conference)).scope === limits.scope) funded.push(repository);
}
try { await BillingQuota.create({ _id: limits.scope, allocations: funded.map(r => ({ repoId: r.repoId, bytes: r.size?.storage || 0, createdAt: new Date() })) }); }
catch (error) { if ((error as { code?: number }).code !== 11000) throw error; }
}
// Only confirmed terminal repositories release capacity. Unknown reservations
+2
View File
@@ -625,6 +625,7 @@ router.post(
"githubAccess.revision": previousAccessRevision || { $exists: false } },
{
$set: {
...(repo.model.billingNeverExpiresUntil ? { billingNeverExpiresUntil: repo.model.billingNeverExpiresUntil } : {}),
settingsSavedAt: new Date(),
options: repo.model.options,
source: repo.model.source,
@@ -632,6 +633,7 @@ router.post(
conference: repo.model.conference,
anonymizeDate: repo.model.anonymizeDate,
},
...(!repo.model.billingNeverExpiresUntil ? { $unset: { billingNeverExpiresUntil: 1 } } : {}),
}
).exec();
if (!saved.matchedCount) throw appError("connection_changed", 409);