diff --git a/tools/select-manifest.mjs b/tools/select-manifest.mjs index 62036ad..1cab274 100644 --- a/tools/select-manifest.mjs +++ b/tools/select-manifest.mjs @@ -33,8 +33,10 @@ export async function archiveManifest({ root = process.cwd(), network, now = new try { await operations.rm(source); } catch (error) { - await operations.rm(target, { force: true }).catch(() => {}); - throw error; + throw new Error( + `archive created at ${target}, but source ${source} could not be removed; both paths were preserved: ${error.message}`, + { cause: error }, + ); } return { source, path: target }; } diff --git a/tools/test-base-config.sh b/tools/test-base-config.sh index f8a940a..fca7dca 100755 --- a/tools/test-base-config.sh +++ b/tools/test-base-config.sh @@ -231,6 +231,28 @@ try { ); assert.deepEqual(await readFile(canonicalPath), canonicalBytes); assert.deepEqual(await readFile(boundaryPath), boundaryBytes); + + const unlinkFailureDate = new Date("2026-08-21T12:37:56.789Z"); + const unlinkFailurePath = join(deployments, "base-sepolia.20260821T123756789Z.json"); + await assert.rejects( + () => archiveManifest({ + root, + network: "baseSepolia", + now: unlinkFailureDate, + io: { + rm: async (path, options) => { + if (path === canonicalPath) { + assert.deepEqual(await readFile(unlinkFailurePath), canonicalBytes); + throw new Error("source unlink failed"); + } + return rm(path, options); + }, + }, + }), + /source unlink failed/, + ); + assert.deepEqual(await readFile(canonicalPath), canonicalBytes); + assert.deepEqual(await readFile(unlinkFailurePath), canonicalBytes); await assert.rejects(() => archiveManifest({ root, network: "anvil" }), /baseSepolia/); } finally { await rm(root, { recursive: true, force: true });