Defer promotion snapshots to campaign activation

This commit is contained in:
2026-10-06 00:16:43 -04:00
parent d6ff59b129
commit 9fd448339d
15 changed files with 179 additions and 56 deletions
+6 -2
View File
@@ -11,7 +11,7 @@ import { cancelStagedFiles, isFileApplied, queueFileChange, stagedFileChanges }
// pre-multi-script legacy rows.
export class RollbackError extends Error {
constructor(message: string, public readonly kind: 'history-expired' | 'no-such-deployment' | 'not-promote' | 'already-rolled-back') {
constructor(message: string, public readonly kind: 'history-expired' | 'no-such-deployment' | 'not-promote' | 'already-rolled-back' | 'snapshot-pending') {
super(message);
}
}
@@ -42,6 +42,7 @@ interface FileRow {
sha256_after: string | null;
content_before: Buffer | null;
content_after: Buffer | null;
snapshot_pending: number;
}
interface ScriptTargetRow {
@@ -100,7 +101,7 @@ export async function rollbackPromoteDeployment(promoteId: string): Promise<Roll
const fileRows = db()
.prepare(
`SELECT f.id, f.server, f.verb, f.rel_path, f.sha256_before, f.sha256_after, f.content_before, f.content_after
`SELECT f.id, f.server, f.verb, f.rel_path, f.sha256_before, f.sha256_after, f.content_before, f.content_after, f.snapshot_pending
FROM deployment_files f JOIN deployment_servers ds ON ds.deployment_id = f.deployment_id AND ds.server = f.server
JOIN servers s ON s.name = f.server
WHERE f.deployment_id = ? AND ds.server_deleted_at IS NULL AND s.destroyed_at IS NULL ORDER BY f.server, f.rel_path`
@@ -154,6 +155,9 @@ export async function rollbackPromoteDeployment(promoteId: string): Promise<Roll
const preservesBetaSnapshot = staged.some(row => row.server === f.server && row.kind === kind
&& row.rel_path === f.rel_path && row.preserve_before_image);
if (!preservesBetaSnapshot && isFileApplied('campaign', promoteId, f.server, kind, f.rel_path) === false) continue;
if (f.snapshot_pending) {
throw new RollbackError(`${f.server}: rollback snapshot for ${f.rel_path} is awaiting activation confirmation. Reconcile the provisioning operation before rolling back.`, 'snapshot-pending');
}
const arr = perServer.get(f.server);
if (arr) arr.push(f);
else perServer.set(f.server, [f]);