test(opencode): cover legacy upgrade edge cases

This commit is contained in:
haelyra
2026-08-25 12:28:23 -04:00
parent ba280120f1
commit 856733263c
2 changed files with 115 additions and 2 deletions
+69 -2
View File
@@ -62,6 +62,23 @@ function seedLegacyInstall(homeDir, options = {}) {
scaffoldOnly: false,
contentSha256: digest(sourceContent),
};
const operations = [operation];
if (options.includeJsonOperation) {
const configPath = path.join(targetRoot, 'opencode.json');
fs.writeFileSync(configPath, JSON.stringify({ plugin: ['ecc'] }, null, 2) + '\n');
operations.push({
kind: 'merge-json',
moduleId: 'opencode-plugin',
sourceRelativePath: '.opencode/opencode.json',
destinationPath: configPath,
strategy: 'merge-json',
ownership: 'managed',
scaffoldOnly: false,
mergePayload: { plugin: ['ecc'] },
previousExists: false,
previousContent: null,
});
}
const state = createInstallState({
adapter: { id: 'opencode-home', target: 'opencode', kind: 'home' },
targetRoot,
@@ -80,19 +97,20 @@ function seedLegacyInstall(homeDir, options = {}) {
repoCommit: 'legacy-opencode-test',
manifestVersion: require('../../manifests/install-modules.json').version,
},
operations: [operation],
operations,
});
writeInstallState(installStatePath, state);
return { targetRoot, installStatePath, destinationPath };
}
function canonicalPlan(homeDir) {
function canonicalPlan(homeDir, env) {
return createManifestInstallPlan({
sourceRoot: REPO_ROOT,
target: 'opencode',
moduleIds: ['workflow-quality'],
projectRoot: homeDir,
homeDir,
...(env ? { env } : {}),
exemptValidationCodes: ['opencode-plugin-not-built'],
});
}
@@ -182,6 +200,55 @@ test('a canonical install migrates unchanged legacy ownership', () => {
}
});
test('a canonical install migrates legacy ownership when its config root is overridden', () => {
const homeDir = fs.mkdtempSync(path.join(os.tmpdir(), 'opencode-legacy-custom-root-'));
try {
const legacy = seedLegacyInstall(homeDir);
const configRoot = path.join(homeDir, 'custom', 'opencode');
const result = applyInstallPlan(canonicalPlan(homeDir, {
OPENCODE_CONFIG_DIR: configRoot,
}));
assert.ok(result.applied);
assert.ok(fs.existsSync(path.join(configRoot, 'ecc-install-state.json')));
assert.ok(!fs.existsSync(legacy.installStatePath));
assert.ok(!fs.existsSync(legacy.destinationPath));
} finally {
fs.rmSync(homeDir, { recursive: true, force: true });
}
});
test('legacy non-file operations do not block canonical cleanup or repair', () => {
const applyHome = fs.mkdtempSync(path.join(os.tmpdir(), 'opencode-legacy-json-apply-'));
const repairHome = fs.mkdtempSync(path.join(os.tmpdir(), 'opencode-legacy-json-repair-'));
try {
const legacyApply = seedLegacyInstall(applyHome, { includeJsonOperation: true });
applyInstallPlan(canonicalPlan(applyHome));
assert.ok(!fs.existsSync(legacyApply.installStatePath));
assert.ok(fs.existsSync(path.join(legacyApply.targetRoot, 'opencode.json')));
const legacyRepair = seedLegacyInstall(repairHome, { includeJsonOperation: true });
const result = repairInstalledStates({
repoRoot: REPO_ROOT,
homeDir: repairHome,
projectRoot: repairHome,
targets: ['opencode'],
});
const canonicalStatePath = path.join(
repairHome,
'.config',
'opencode',
'ecc-install-state.json'
);
assert.strictEqual(result.summary.errorCount, 0, JSON.stringify(result));
assert.ok(fs.existsSync(canonicalStatePath));
assert.ok(!fs.existsSync(legacyRepair.installStatePath));
assert.ok(fs.existsSync(path.join(legacyRepair.targetRoot, 'opencode.json')));
} finally {
fs.rmSync(applyHome, { recursive: true, force: true });
fs.rmSync(repairHome, { recursive: true, force: true });
}
});
test('repair migrates a legacy install while preserving modified legacy files', () => {
const homeDir = fs.mkdtempSync(path.join(os.tmpdir(), 'opencode-legacy-repair-'));
try {
+46
View File
@@ -502,6 +502,52 @@ function runTests() {
}
})) passed += 1; else failed += 1;
if (test('runAutoUpdate gives legacy-only OpenCode migration guidance', () => {
const homeDir = createTempDir('auto-update-home-');
const projectRoot = createTempDir('auto-update-project-');
const repoRoot = createTempDir('auto-update-repo-');
try {
ensureFakeRepo(repoRoot);
const legacy = {
...makeRecord({
repoRoot,
homeDir,
projectRoot,
adapter: { id: 'opencode-home', target: 'opencode', kind: 'home' },
request: {
profile: null,
modules: ['workflow-quality'],
includeComponents: [],
excludeComponents: [],
legacyLanguages: [],
legacyMode: false,
},
resolution: { selectedModules: ['workflow-quality'], skippedModules: [] },
operations: [],
}),
installStatePath: path.join(homeDir, '.opencode', 'ecc-install-state.json'),
legacy: true,
legacyLayout: 'opencode',
};
const result = runAutoUpdate(
{ homeDir, projectRoot, repoRoot, dryRun: true },
{ discoverInstalledStates: () => [legacy] }
);
assert.deepStrictEqual(result.results, []);
assert.ok(result.warnings.some(warning => warning.includes(
'Run the OpenCode installer once to migrate it to the configured OpenCode directory'
)));
assert.ok(result.warnings.every(warning => !warning.includes('Antigravity')));
} finally {
cleanup(homeDir);
cleanup(projectRoot);
cleanup(repoRoot);
}
})) passed += 1; else failed += 1;
console.log(`\nResults: Passed: ${passed}, Failed: ${failed}`);
process.exit(failed > 0 ? 1 : 0);
}