mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-05-13 05:12:55 -07:00
fix(cli): uninstall extensions using their source URL (#8692)
Co-authored-by: Taneja Hriday <hridayt@google.com>
This commit is contained in:
@@ -9,7 +9,7 @@ import { uninstallExtension } from '../../config/extension.js';
|
|||||||
import { getErrorMessage } from '../../utils/errors.js';
|
import { getErrorMessage } from '../../utils/errors.js';
|
||||||
|
|
||||||
interface UninstallArgs {
|
interface UninstallArgs {
|
||||||
name: string;
|
name: string; // can be extension name or source URL.
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function handleUninstall(args: UninstallArgs) {
|
export async function handleUninstall(args: UninstallArgs) {
|
||||||
@@ -28,7 +28,7 @@ export const uninstallCommand: CommandModule = {
|
|||||||
builder: (yargs) =>
|
builder: (yargs) =>
|
||||||
yargs
|
yargs
|
||||||
.positional('name', {
|
.positional('name', {
|
||||||
describe: 'The name of the extension to uninstall.',
|
describe: 'The name or source path of the extension to uninstall.',
|
||||||
type: 'string',
|
type: 'string',
|
||||||
})
|
})
|
||||||
.check((argv) => {
|
.check((argv) => {
|
||||||
|
|||||||
@@ -715,7 +715,7 @@ describe('extension tests', () => {
|
|||||||
|
|
||||||
it('should throw an error if the extension does not exist', async () => {
|
it('should throw an error if the extension does not exist', async () => {
|
||||||
await expect(uninstallExtension('nonexistent-extension')).rejects.toThrow(
|
await expect(uninstallExtension('nonexistent-extension')).rejects.toThrow(
|
||||||
'Extension "nonexistent-extension" not found.',
|
'Extension not found.',
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -733,6 +733,40 @@ describe('extension tests', () => {
|
|||||||
new ExtensionUninstallEvent('my-local-extension', 'success'),
|
new ExtensionUninstallEvent('my-local-extension', 'success'),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should uninstall an extension by its source URL', async () => {
|
||||||
|
const gitUrl = 'https://github.com/google/gemini-sql-extension.git';
|
||||||
|
const sourceExtDir = createExtension({
|
||||||
|
extensionsDir: userExtensionsDir,
|
||||||
|
name: 'gemini-sql-extension',
|
||||||
|
version: '1.0.0',
|
||||||
|
installMetadata: {
|
||||||
|
source: gitUrl,
|
||||||
|
type: 'git',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await uninstallExtension(gitUrl);
|
||||||
|
|
||||||
|
expect(fs.existsSync(sourceExtDir)).toBe(false);
|
||||||
|
const logger = ClearcutLogger.getInstance({} as Config);
|
||||||
|
expect(logger?.logExtensionUninstallEvent).toHaveBeenCalledWith(
|
||||||
|
new ExtensionUninstallEvent('gemini-sql-extension', 'success'),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fail to uninstall by URL if an extension has no install metadata', async () => {
|
||||||
|
createExtension({
|
||||||
|
extensionsDir: userExtensionsDir,
|
||||||
|
name: 'no-metadata-extension',
|
||||||
|
version: '1.0.0',
|
||||||
|
// No installMetadata provided
|
||||||
|
});
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
uninstallExtension('https://github.com/google/no-metadata-extension'),
|
||||||
|
).rejects.toThrow('Extension not found.');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('performWorkspaceExtensionMigration', () => {
|
describe('performWorkspaceExtensionMigration', () => {
|
||||||
|
|||||||
@@ -573,17 +573,20 @@ export async function loadExtensionConfig(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function uninstallExtension(
|
export async function uninstallExtension(
|
||||||
extensionName: string,
|
extensionIdentifier: string,
|
||||||
cwd: string = process.cwd(),
|
cwd: string = process.cwd(),
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const logger = getClearcutLogger(cwd);
|
const logger = getClearcutLogger(cwd);
|
||||||
const installedExtensions = loadUserExtensions();
|
const installedExtensions = loadUserExtensions();
|
||||||
if (
|
const extensionName = installedExtensions.find(
|
||||||
!installedExtensions.some(
|
(installed) =>
|
||||||
(installed) => installed.config.name === extensionName,
|
installed.config.name.toLowerCase() ===
|
||||||
)
|
extensionIdentifier.toLowerCase() ||
|
||||||
) {
|
installed.installMetadata?.source.toLowerCase() ===
|
||||||
throw new Error(`Extension "${extensionName}" not found.`);
|
extensionIdentifier.toLowerCase(),
|
||||||
|
)?.config.name;
|
||||||
|
if (!extensionName) {
|
||||||
|
throw new Error(`Extension not found.`);
|
||||||
}
|
}
|
||||||
const manager = new ExtensionEnablementManager(
|
const manager = new ExtensionEnablementManager(
|
||||||
ExtensionStorage.getUserExtensionsDir(),
|
ExtensionStorage.getUserExtensionsDir(),
|
||||||
|
|||||||
Reference in New Issue
Block a user