mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-11-14 02:29:33 +01:00
fix(config-backup): reuse the newest backup as the undo copy when nothing changed
Merge-time fix for #661. The pre-restore copy was forced, so a restore made while the live files equalled the newest backup spent a retention slot on a duplicate. It now goes through the normal change check: when nothing changed since the newest backup, no copy is made and safetySnapshot names that backup. Two tests that relied on the forced copy now change a file before the restore; a new one pins the reuse. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
8a216df12f
commit
ebb50ef53a
5 files changed
+36
-12
No files matched your search
@@ -51,6 +51,7 @@ describe('configBackupOrigin', () => {
|
||||
host.name = 'container-b'; // the container was recreated
|
||||
const origin = configBackupOrigin(data);
|
||||
expect(listConfigBackups(backups, origin)).toHaveLength(2);
|
||||
writeFileSync(join(data, 'settings.json'), '{"a":2}'); // a change, so the restore takes a pre-restore copy
|
||||
expect(() => restoreConfigBackup({ dataDir: data, backupDir: backups, id: made.id })).not.toThrow();
|
||||
const removed = pruneConfigBackups(backups, { keepCount: 1, keepDays: 0, origin });
|
||||
expect(removed).toHaveLength(2); // 3 now: the restore took a pre-restore copy
|
||||
|
||||
@@ -346,6 +346,19 @@ describe('restoreConfigBackup', () => {
|
||||
}
|
||||
});
|
||||
|
||||
it('reuses the newest backup as the undo copy when the live files already equal it', () => {
|
||||
put('settings.json', '{"a":1}');
|
||||
const first = createConfigBackup({ dataDir: data, backupDir: backups, reason: 'auto', now: T0 }) as { id: string };
|
||||
put('settings.json', '{"a":2}');
|
||||
const newest = createConfigBackup({ dataDir: data, backupDir: backups, reason: 'auto', now: T0 + DAY }) as {
|
||||
id: string;
|
||||
};
|
||||
const r = restoreConfigBackup({ dataDir: data, backupDir: backups, id: first.id, now: T0 + 2 * DAY });
|
||||
expect(r.safetySnapshot).toBe(newest.id);
|
||||
expect(listConfigBackups(backups).map((b) => b.id)).toEqual([newest.id, first.id]); // no duplicate
|
||||
expect(readFileSync(join(data, 'settings.json'), 'utf8')).toBe('{"a":1}');
|
||||
});
|
||||
|
||||
it('a file it cannot write does not stop the others, and the error names both lists', () => {
|
||||
put('settings.json', '{"good":true}');
|
||||
put('clis.json', '{"clis":{}}');
|
||||
@@ -644,9 +657,12 @@ describe('restore trusts only what this module wrote', () => {
|
||||
const origin = configBackupOrigin(data);
|
||||
expect(latestBackupRetention(backups, origin)).toEqual({ keepCount: 100, keepDays: 0 });
|
||||
const id = listConfigBackups(backups, origin).at(-1)!.id;
|
||||
// A change since the newest backup, so the restore makes a pre-restore copy rather than reusing it.
|
||||
put('settings.json', '{"a":3}');
|
||||
const r = restoreConfigBackup({ dataDir: data, backupDir: backups, id, now: T0 + 2000 });
|
||||
expect(r.safetySnapshot).toBeTruthy();
|
||||
const pre = listConfigBackups(backups, origin).find((b) => b.id === r.safetySnapshot)!;
|
||||
expect(pre.reason).toBe('pre-restore');
|
||||
expect(JSON.parse(readFileSync(join(backups, pre.id, 'manifest.json'), 'utf8'))).toMatchObject({
|
||||
keepCount: 100,
|
||||
keepDays: 0,
|
||||
|
||||
Reference in new issue
Block a user