mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-05-15 06:12:50 -07:00
fix(cli): return proper errors from loadExtensionConfig (#8909)
Co-authored-by: Taneja Hriday <hridayt@google.com>
This commit is contained in:
@@ -373,6 +373,70 @@ describe('extension tests', () => {
|
||||
expect(serverConfig.env!.MISSING_VAR_BRACES).toBe('${ALSO_UNDEFINED}');
|
||||
});
|
||||
|
||||
it('should skip extensions with invalid JSON and log a warning', () => {
|
||||
const consoleSpy = vi
|
||||
.spyOn(console, 'error')
|
||||
.mockImplementation(() => {});
|
||||
|
||||
// Good extension
|
||||
createExtension({
|
||||
extensionsDir: userExtensionsDir,
|
||||
name: 'good-ext',
|
||||
version: '1.0.0',
|
||||
});
|
||||
|
||||
// Bad extension
|
||||
const badExtDir = path.join(userExtensionsDir, 'bad-ext');
|
||||
fs.mkdirSync(badExtDir);
|
||||
const badConfigPath = path.join(badExtDir, EXTENSIONS_CONFIG_FILENAME);
|
||||
fs.writeFileSync(badConfigPath, '{ "name": "bad-ext"'); // Malformed
|
||||
|
||||
const extensions = loadExtensions();
|
||||
|
||||
expect(extensions).toHaveLength(1);
|
||||
expect(extensions[0].config.name).toBe('good-ext');
|
||||
expect(consoleSpy).toHaveBeenCalledOnce();
|
||||
expect(consoleSpy).toHaveBeenCalledWith(
|
||||
expect.stringContaining(
|
||||
`Warning: Skipping extension in ${badExtDir}: Failed to load extension config from ${badConfigPath}`,
|
||||
),
|
||||
);
|
||||
|
||||
consoleSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('should skip extensions with missing name and log a warning', () => {
|
||||
const consoleSpy = vi
|
||||
.spyOn(console, 'error')
|
||||
.mockImplementation(() => {});
|
||||
|
||||
// Good extension
|
||||
createExtension({
|
||||
extensionsDir: userExtensionsDir,
|
||||
name: 'good-ext',
|
||||
version: '1.0.0',
|
||||
});
|
||||
|
||||
// Bad extension
|
||||
const badExtDir = path.join(userExtensionsDir, 'bad-ext-no-name');
|
||||
fs.mkdirSync(badExtDir);
|
||||
const badConfigPath = path.join(badExtDir, EXTENSIONS_CONFIG_FILENAME);
|
||||
fs.writeFileSync(badConfigPath, JSON.stringify({ version: '1.0.0' }));
|
||||
|
||||
const extensions = loadExtensions();
|
||||
|
||||
expect(extensions).toHaveLength(1);
|
||||
expect(extensions[0].config.name).toBe('good-ext');
|
||||
expect(consoleSpy).toHaveBeenCalledOnce();
|
||||
expect(consoleSpy).toHaveBeenCalledWith(
|
||||
expect.stringContaining(
|
||||
`Warning: Skipping extension in ${badExtDir}: Failed to load extension config from ${badConfigPath}: Invalid configuration in ${badConfigPath}: missing "name"`,
|
||||
),
|
||||
);
|
||||
|
||||
consoleSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('should filter trust out of mcp servers', () => {
|
||||
createExtension({
|
||||
extensionsDir: userExtensionsDir,
|
||||
@@ -591,15 +655,49 @@ describe('extension tests', () => {
|
||||
it('should throw an error and cleanup if gemini-extension.json is missing', async () => {
|
||||
const sourceExtDir = path.join(tempHomeDir, 'bad-extension');
|
||||
fs.mkdirSync(sourceExtDir, { recursive: true });
|
||||
const configPath = path.join(sourceExtDir, EXTENSIONS_CONFIG_FILENAME);
|
||||
|
||||
await expect(
|
||||
installExtension({ source: sourceExtDir, type: 'local' }),
|
||||
).rejects.toThrow(`Configuration file not found at ${configPath}`);
|
||||
|
||||
const targetExtDir = path.join(userExtensionsDir, 'bad-extension');
|
||||
expect(fs.existsSync(targetExtDir)).toBe(false);
|
||||
});
|
||||
|
||||
it('should throw an error for invalid JSON in gemini-extension.json', async () => {
|
||||
const sourceExtDir = path.join(tempHomeDir, 'bad-json-ext');
|
||||
fs.mkdirSync(sourceExtDir, { recursive: true });
|
||||
const configPath = path.join(sourceExtDir, EXTENSIONS_CONFIG_FILENAME);
|
||||
fs.writeFileSync(configPath, '{ "name": "bad-json", "version": "1.0.0"'); // Malformed JSON
|
||||
|
||||
await expect(
|
||||
installExtension({ source: sourceExtDir, type: 'local' }),
|
||||
).rejects.toThrow(
|
||||
`Invalid extension at ${sourceExtDir}. Please make sure it has a valid gemini-extension.json file.`,
|
||||
new RegExp(
|
||||
`^Failed to load extension config from ${configPath.replace(
|
||||
/\\/g,
|
||||
'\\\\',
|
||||
)}`,
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
const targetExtDir = path.join(userExtensionsDir, 'bad-extension');
|
||||
expect(fs.existsSync(targetExtDir)).toBe(false);
|
||||
it('should throw an error for missing name in gemini-extension.json', async () => {
|
||||
const sourceExtDir = createExtension({
|
||||
extensionsDir: tempHomeDir,
|
||||
name: 'missing-name-ext',
|
||||
version: '1.0.0',
|
||||
});
|
||||
const configPath = path.join(sourceExtDir, EXTENSIONS_CONFIG_FILENAME);
|
||||
// Overwrite with invalid config
|
||||
fs.writeFileSync(configPath, JSON.stringify({ version: '1.0.0' }));
|
||||
|
||||
await expect(
|
||||
installExtension({ source: sourceExtDir, type: 'local' }),
|
||||
).rejects.toThrow(
|
||||
`Invalid configuration in ${configPath}: missing "name"`,
|
||||
);
|
||||
});
|
||||
|
||||
it('should install an extension from a git URL', async () => {
|
||||
|
||||
Reference in New Issue
Block a user