Add gemini extensions link command (#7241)

Co-authored-by: Bryan Morgan <bryanmorgan@google.com>
This commit is contained in:
christine betts
2025-09-02 10:15:42 -07:00
committed by GitHub
parent 997136ae25
commit 6a581a695f
15 changed files with 461 additions and 20 deletions
+59 -2
View File
@@ -217,6 +217,36 @@ describe('loadExtensions', () => {
expect(loadedConfig.mcpServers?.['test-server'].cwd).toBe(expectedCwd);
});
it('should load a linked extension correctly', async () => {
const sourceExtDir = createExtension({
extensionsDir: tempWorkspaceDir,
name: 'my-linked-extension',
version: '1.0.0',
contextFileName: 'context.md',
});
fs.writeFileSync(path.join(sourceExtDir, 'context.md'), 'linked context');
const extensionName = await installExtension({
source: sourceExtDir,
type: 'link',
});
expect(extensionName).toEqual('my-linked-extension');
const extensions = loadExtensions(tempHomeDir);
expect(extensions).toHaveLength(1);
const linkedExt = extensions[0];
expect(linkedExt.config.name).toBe('my-linked-extension');
expect(linkedExt.path).toBe(sourceExtDir);
expect(linkedExt.installMetadata).toEqual({
source: sourceExtDir,
type: 'link',
});
expect(linkedExt.contextFiles).toEqual([
path.join(sourceExtDir, 'context.md'),
]);
});
it('should resolve environment variables in extension configuration', () => {
process.env.TEST_API_KEY = 'test-api-key-123';
process.env.TEST_DB_URL = 'postgresql://localhost:5432/testdb';
@@ -402,12 +432,12 @@ describe('installExtension', () => {
fs.rmSync(userExtensionsDir, { recursive: true, force: true });
fs.mkdirSync(userExtensionsDir, { recursive: true });
vi.mocked(isWorkspaceTrusted).mockReturnValue(true);
vi.mocked(execSync).mockClear();
});
afterEach(() => {
fs.rmSync(tempHomeDir, { recursive: true, force: true });
fs.rmSync(userExtensionsDir, { recursive: true, force: true });
});
it('should install an extension from a local path', async () => {
@@ -487,6 +517,31 @@ describe('installExtension', () => {
});
fs.rmSync(targetExtDir, { recursive: true, force: true });
});
it('should install a linked extension', async () => {
const sourceExtDir = createExtension({
extensionsDir: tempHomeDir,
name: 'my-linked-extension',
version: '1.0.0',
});
const targetExtDir = path.join(userExtensionsDir, 'my-linked-extension');
const metadataPath = path.join(targetExtDir, INSTALL_METADATA_FILENAME);
const configPath = path.join(targetExtDir, EXTENSIONS_CONFIG_FILENAME);
await installExtension({ source: sourceExtDir, type: 'link' });
expect(fs.existsSync(targetExtDir)).toBe(true);
expect(fs.existsSync(metadataPath)).toBe(true);
expect(fs.existsSync(configPath)).toBe(false);
const metadata = JSON.parse(fs.readFileSync(metadataPath, 'utf-8'));
expect(metadata).toEqual({
source: sourceExtDir,
type: 'link',
});
fs.rmSync(targetExtDir, { recursive: true, force: true });
});
});
describe('uninstallExtension', () => {
@@ -701,7 +756,9 @@ function createExtension({
}
if (contextFileName) {
fs.writeFileSync(path.join(extDir, contextFileName), 'context');
const contextPath = path.join(extDir, contextFileName);
fs.mkdirSync(path.dirname(contextPath), { recursive: true });
fs.writeFileSync(contextPath, 'context');
}
return extDir;
}