|
|
@@ -28,7 +28,13 @@ type SpawnResult = {
|
|
|
proc: never;
|
|
|
};
|
|
|
|
|
|
-const crossSpawnMock = mock((_command: string[]) => createSpawnResult());
|
|
|
+type SpawnOptions = {
|
|
|
+ cwd?: string;
|
|
|
+};
|
|
|
+
|
|
|
+const crossSpawnMock = mock((_command: string[], _options?: SpawnOptions) =>
|
|
|
+ createSpawnResult(),
|
|
|
+);
|
|
|
|
|
|
mock.module('../utils/compat', () => ({
|
|
|
crossSpawn: crossSpawnMock,
|
|
|
@@ -57,8 +63,11 @@ describe('warmOpenCodePluginCache', () => {
|
|
|
|
|
|
beforeEach(() => {
|
|
|
crossSpawnMock.mockReset();
|
|
|
- crossSpawnMock.mockImplementation((_command: string[]) =>
|
|
|
- createSpawnResult(),
|
|
|
+ crossSpawnMock.mockImplementation(
|
|
|
+ (_command: string[], options?: SpawnOptions) => {
|
|
|
+ writeCachedPluginPackage(options?.cwd);
|
|
|
+ return createSpawnResult();
|
|
|
+ },
|
|
|
);
|
|
|
delete process.env.XDG_CACHE_HOME;
|
|
|
});
|
|
|
@@ -103,7 +112,11 @@ describe('warmOpenCodePluginCache', () => {
|
|
|
expect(result?.success).toBe(true);
|
|
|
expect(result?.configPath).toBe(expectedCacheDir);
|
|
|
expect(crossSpawnMock).toHaveBeenCalledTimes(1);
|
|
|
- expect(crossSpawnMock.mock.calls[0][0]).toEqual(['bun', 'install']);
|
|
|
+ expect(crossSpawnMock.mock.calls[0][0]).toEqual([
|
|
|
+ 'bun',
|
|
|
+ 'install',
|
|
|
+ '--ignore-scripts',
|
|
|
+ ]);
|
|
|
expect(crossSpawnMock.mock.calls[0][1]).toEqual(
|
|
|
expect.objectContaining({ cwd: expectedCacheDir }),
|
|
|
);
|
|
|
@@ -120,6 +133,140 @@ describe('warmOpenCodePluginCache', () => {
|
|
|
rmSync(tmpDir, { recursive: true, force: true });
|
|
|
});
|
|
|
|
|
|
+ test('repairs a stale OpenCode cache manifest', async () => {
|
|
|
+ const tmpDir = mkdirTemp();
|
|
|
+ const cacheHome = join(tmpDir, 'cache');
|
|
|
+ process.env.XDG_CACHE_HOME = cacheHome;
|
|
|
+
|
|
|
+ const packageRoot = join(
|
|
|
+ tmpDir,
|
|
|
+ 'bunx-1000-oh-my-opencode-slim@latest',
|
|
|
+ 'node_modules',
|
|
|
+ 'oh-my-opencode-slim',
|
|
|
+ );
|
|
|
+ mkdirSync(join(packageRoot, 'dist', 'cli'), { recursive: true });
|
|
|
+ writeFileSync(
|
|
|
+ join(packageRoot, 'package.json'),
|
|
|
+ JSON.stringify({ name: 'oh-my-opencode-slim' }),
|
|
|
+ );
|
|
|
+ process.argv[1] = join(packageRoot, 'dist', 'cli', 'index.js');
|
|
|
+
|
|
|
+ const expectedCacheDir = join(
|
|
|
+ cacheHome,
|
|
|
+ 'opencode',
|
|
|
+ 'packages',
|
|
|
+ 'oh-my-opencode-slim@latest',
|
|
|
+ );
|
|
|
+ mkdirSync(expectedCacheDir, { recursive: true });
|
|
|
+ writeFileSync(
|
|
|
+ join(expectedCacheDir, 'package.json'),
|
|
|
+ JSON.stringify({
|
|
|
+ name: 'stale-cache',
|
|
|
+ scripts: { postinstall: 'should-not-run' },
|
|
|
+ dependencies: { other: '1.0.0' },
|
|
|
+ }),
|
|
|
+ );
|
|
|
+
|
|
|
+ const { warmOpenCodePluginCache } = await importFreshConfigIo();
|
|
|
+ const result = await warmOpenCodePluginCache();
|
|
|
+
|
|
|
+ expect(result?.success).toBe(true);
|
|
|
+ expect(
|
|
|
+ JSON.parse(readFileSync(join(expectedCacheDir, 'package.json'), 'utf-8')),
|
|
|
+ ).toEqual({
|
|
|
+ name: 'oh-my-opencode-slim-cache',
|
|
|
+ private: true,
|
|
|
+ dependencies: {
|
|
|
+ 'oh-my-opencode-slim': 'latest',
|
|
|
+ },
|
|
|
+ });
|
|
|
+
|
|
|
+ rmSync(tmpDir, { recursive: true, force: true });
|
|
|
+ });
|
|
|
+
|
|
|
+ test('fails when bun install does not create the cached plugin package', async () => {
|
|
|
+ const tmpDir = mkdirTemp();
|
|
|
+ const cacheHome = join(tmpDir, 'cache');
|
|
|
+ process.env.XDG_CACHE_HOME = cacheHome;
|
|
|
+
|
|
|
+ const packageRoot = join(
|
|
|
+ tmpDir,
|
|
|
+ 'bunx-1000-oh-my-opencode-slim@latest',
|
|
|
+ 'node_modules',
|
|
|
+ 'oh-my-opencode-slim',
|
|
|
+ );
|
|
|
+ mkdirSync(join(packageRoot, 'dist', 'cli'), { recursive: true });
|
|
|
+ writeFileSync(
|
|
|
+ join(packageRoot, 'package.json'),
|
|
|
+ JSON.stringify({ name: 'oh-my-opencode-slim' }),
|
|
|
+ );
|
|
|
+ process.argv[1] = join(packageRoot, 'dist', 'cli', 'index.js');
|
|
|
+ crossSpawnMock.mockImplementation(() => createSpawnResult());
|
|
|
+
|
|
|
+ const { warmOpenCodePluginCache } = await importFreshConfigIo();
|
|
|
+ const result = await warmOpenCodePluginCache();
|
|
|
+
|
|
|
+ expect(result).toEqual({
|
|
|
+ success: false,
|
|
|
+ configPath: join(
|
|
|
+ cacheHome,
|
|
|
+ 'opencode',
|
|
|
+ 'packages',
|
|
|
+ 'oh-my-opencode-slim@latest',
|
|
|
+ ),
|
|
|
+ error: `Cached plugin package not found at ${join(
|
|
|
+ cacheHome,
|
|
|
+ 'opencode',
|
|
|
+ 'packages',
|
|
|
+ 'oh-my-opencode-slim@latest',
|
|
|
+ 'node_modules',
|
|
|
+ 'oh-my-opencode-slim',
|
|
|
+ 'package.json',
|
|
|
+ )}`,
|
|
|
+ });
|
|
|
+
|
|
|
+ rmSync(tmpDir, { recursive: true, force: true });
|
|
|
+ });
|
|
|
+
|
|
|
+ test('returns a failed result when bun install fails', async () => {
|
|
|
+ const tmpDir = mkdirTemp();
|
|
|
+ const cacheHome = join(tmpDir, 'cache');
|
|
|
+ process.env.XDG_CACHE_HOME = cacheHome;
|
|
|
+
|
|
|
+ const packageRoot = join(
|
|
|
+ tmpDir,
|
|
|
+ 'bunx-1000-oh-my-opencode-slim@latest',
|
|
|
+ 'node_modules',
|
|
|
+ 'oh-my-opencode-slim',
|
|
|
+ );
|
|
|
+ mkdirSync(join(packageRoot, 'dist', 'cli'), { recursive: true });
|
|
|
+ writeFileSync(
|
|
|
+ join(packageRoot, 'package.json'),
|
|
|
+ JSON.stringify({ name: 'oh-my-opencode-slim' }),
|
|
|
+ );
|
|
|
+ process.argv[1] = join(packageRoot, 'dist', 'cli', 'index.js');
|
|
|
+ crossSpawnMock.mockImplementation(() => ({
|
|
|
+ ...createSpawnResult(1),
|
|
|
+ stderr: () => Promise.resolve('registry unavailable'),
|
|
|
+ }));
|
|
|
+
|
|
|
+ const { warmOpenCodePluginCache } = await importFreshConfigIo();
|
|
|
+ const result = await warmOpenCodePluginCache();
|
|
|
+
|
|
|
+ expect(result).toEqual({
|
|
|
+ success: false,
|
|
|
+ configPath: join(
|
|
|
+ cacheHome,
|
|
|
+ 'opencode',
|
|
|
+ 'packages',
|
|
|
+ 'oh-my-opencode-slim@latest',
|
|
|
+ ),
|
|
|
+ error: 'registry unavailable',
|
|
|
+ });
|
|
|
+
|
|
|
+ rmSync(tmpDir, { recursive: true, force: true });
|
|
|
+ });
|
|
|
+
|
|
|
test('returns a failed result when cache package.json cannot be written', async () => {
|
|
|
const tmpDir = mkdirTemp();
|
|
|
const cacheHome = join(tmpDir, 'cache');
|
|
|
@@ -196,3 +343,14 @@ describe('warmOpenCodePluginCache', () => {
|
|
|
function mkdirTemp(): string {
|
|
|
return mkdtempSync(join(tmpdir(), 'opencode-cache-test-'));
|
|
|
}
|
|
|
+
|
|
|
+function writeCachedPluginPackage(cacheDir?: string): void {
|
|
|
+ if (!cacheDir) return;
|
|
|
+
|
|
|
+ const pluginRoot = join(cacheDir, 'node_modules', 'oh-my-opencode-slim');
|
|
|
+ mkdirSync(pluginRoot, { recursive: true });
|
|
|
+ writeFileSync(
|
|
|
+ join(pluginRoot, 'package.json'),
|
|
|
+ JSON.stringify({ name: 'oh-my-opencode-slim' }),
|
|
|
+ );
|
|
|
+}
|