feat(config): add migration framework
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
import assert from "node:assert/strict";
|
||||
import test from "node:test";
|
||||
import { DEFAULT_ASK_CONFIG } from "../src/config/defaults.ts";
|
||||
import { migrateAskConfig } from "../src/config/migrate.ts";
|
||||
import { CURRENT_ASK_CONFIG_SCHEMA_VERSION } from "../src/config/migrations/index.ts";
|
||||
|
||||
const INVALID_CONFIG_PATTERN = /Config was invalid or unsupported/;
|
||||
|
||||
const currentConfigFile = {
|
||||
schemaVersion: CURRENT_ASK_CONFIG_SCHEMA_VERSION,
|
||||
behaviour: DEFAULT_ASK_CONFIG.behaviour,
|
||||
keymaps: DEFAULT_ASK_CONFIG.keymaps,
|
||||
};
|
||||
|
||||
test("config migration framework accepts the current schema version", () => {
|
||||
const result = migrateAskConfig(currentConfigFile);
|
||||
|
||||
assert.equal(result.migrated, false);
|
||||
assert.deepEqual(result.config, DEFAULT_ASK_CONFIG);
|
||||
});
|
||||
|
||||
test("config migration framework rejects unsupported future schema versions", () => {
|
||||
assert.throws(
|
||||
() =>
|
||||
migrateAskConfig({
|
||||
...currentConfigFile,
|
||||
schemaVersion: CURRENT_ASK_CONFIG_SCHEMA_VERSION + 1,
|
||||
}),
|
||||
INVALID_CONFIG_PATTERN
|
||||
);
|
||||
});
|
||||
|
||||
test("config migration framework rejects unversioned config files", () => {
|
||||
assert.throws(
|
||||
() =>
|
||||
migrateAskConfig({
|
||||
behaviour: DEFAULT_ASK_CONFIG.behaviour,
|
||||
keymaps: DEFAULT_ASK_CONFIG.keymaps,
|
||||
}),
|
||||
INVALID_CONFIG_PATTERN
|
||||
);
|
||||
});
|
||||
@@ -111,13 +111,12 @@ test("config store loads current config version without rewriting", async () =>
|
||||
await rm(dirname(path), { force: true, recursive: true });
|
||||
});
|
||||
|
||||
test("config store migrates the legacy extensions config path", async () => {
|
||||
test("config store migrates the legacy root config path into extensions", async () => {
|
||||
const root = await import("node:fs/promises").then(({ mkdtemp }) =>
|
||||
mkdtemp(join(tmpdir(), "pi-ask-config-legacy-"))
|
||||
);
|
||||
const path = join(root, "eko24ive-pi-ask.json");
|
||||
const legacyPath = join(root, "extensions", "eko24ive-pi-ask.json");
|
||||
await mkdir(dirname(legacyPath), { recursive: true });
|
||||
const path = join(root, "extensions", "eko24ive-pi-ask.json");
|
||||
const legacyPath = join(root, "eko24ive-pi-ask.json");
|
||||
await writeFile(
|
||||
legacyPath,
|
||||
JSON.stringify({
|
||||
@@ -131,7 +130,7 @@ test("config store migrates the legacy extensions config path", async () => {
|
||||
keymaps: DEFAULT_ASK_CONFIG.keymaps,
|
||||
})
|
||||
);
|
||||
const store = new AskConfigStore(path, legacyPath);
|
||||
const store = new AskConfigStore(path, [legacyPath]);
|
||||
|
||||
const result = await store.ensureLoaded();
|
||||
|
||||
@@ -156,6 +155,52 @@ test("config store migrates the legacy extensions config path", async () => {
|
||||
await rm(root, { force: true, recursive: true });
|
||||
});
|
||||
|
||||
test("config store leaves legacy root config when extensions config exists", async () => {
|
||||
const root = await import("node:fs/promises").then(({ mkdtemp }) =>
|
||||
mkdtemp(join(tmpdir(), "pi-ask-config-conflict-"))
|
||||
);
|
||||
const path = join(root, "extensions", "eko24ive-pi-ask.json");
|
||||
const legacyPath = join(root, "eko24ive-pi-ask.json");
|
||||
await mkdir(dirname(path), { recursive: true });
|
||||
await writeFile(
|
||||
path,
|
||||
JSON.stringify({
|
||||
schemaVersion: 1,
|
||||
behaviour: {
|
||||
autoSubmitWhenAnsweredWithoutNotes: false,
|
||||
confirmDismissWhenDirty: true,
|
||||
doublePressReviewShortcuts: true,
|
||||
showFooterHints: true,
|
||||
},
|
||||
keymaps: DEFAULT_ASK_CONFIG.keymaps,
|
||||
})
|
||||
);
|
||||
await writeFile(
|
||||
legacyPath,
|
||||
JSON.stringify({
|
||||
schemaVersion: 1,
|
||||
behaviour: {
|
||||
autoSubmitWhenAnsweredWithoutNotes: true,
|
||||
confirmDismissWhenDirty: true,
|
||||
doublePressReviewShortcuts: true,
|
||||
showFooterHints: false,
|
||||
},
|
||||
keymaps: DEFAULT_ASK_CONFIG.keymaps,
|
||||
})
|
||||
);
|
||||
const store = new AskConfigStore(path, [legacyPath]);
|
||||
|
||||
const result = await store.ensureLoaded();
|
||||
|
||||
assert.equal(
|
||||
result.config.behaviour.autoSubmitWhenAnsweredWithoutNotes,
|
||||
false
|
||||
);
|
||||
assert.equal(result.config.behaviour.showFooterHints, true);
|
||||
assert.ok(await readFile(legacyPath, "utf-8"));
|
||||
await rm(root, { force: true, recursive: true });
|
||||
});
|
||||
|
||||
test("config store falls back only keymaps when configured keymaps are invalid", async () => {
|
||||
const path = await makeTempPath("pi-ask-config-invalid-keymaps-");
|
||||
await mkdir(dirname(path), { recursive: true });
|
||||
|
||||
Reference in New Issue
Block a user