mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-30 06:54:15 -07:00
Pass whole extensions rather than just context files (#10910)
Co-authored-by: Jake Macdonald <jakemac@google.com>
This commit is contained in:
@@ -22,6 +22,7 @@ import * as path from 'node:path';
|
||||
import * as tar from 'tar';
|
||||
import * as archiver from 'archiver';
|
||||
import type { GeminiCLIExtension } from '@google/gemini-cli-core';
|
||||
import { ExtensionEnablementManager } from './extensionEnablement.js';
|
||||
|
||||
const mockPlatform = vi.hoisted(() => vi.fn());
|
||||
const mockArch = vi.hoisted(() => vi.fn());
|
||||
@@ -149,7 +150,10 @@ describe('git extension helpers', () => {
|
||||
},
|
||||
contextFiles: [],
|
||||
};
|
||||
const result = await checkForExtensionUpdate(extension);
|
||||
const result = await checkForExtensionUpdate(
|
||||
extension,
|
||||
new ExtensionEnablementManager(),
|
||||
);
|
||||
expect(result).toBe(ExtensionUpdateState.NOT_UPDATABLE);
|
||||
});
|
||||
|
||||
@@ -166,7 +170,10 @@ describe('git extension helpers', () => {
|
||||
contextFiles: [],
|
||||
};
|
||||
mockGit.getRemotes.mockResolvedValue([]);
|
||||
const result = await checkForExtensionUpdate(extension);
|
||||
const result = await checkForExtensionUpdate(
|
||||
extension,
|
||||
new ExtensionEnablementManager(),
|
||||
);
|
||||
expect(result).toBe(ExtensionUpdateState.ERROR);
|
||||
});
|
||||
|
||||
@@ -188,7 +195,10 @@ describe('git extension helpers', () => {
|
||||
mockGit.listRemote.mockResolvedValue('remote-hash\tHEAD');
|
||||
mockGit.revparse.mockResolvedValue('local-hash');
|
||||
|
||||
const result = await checkForExtensionUpdate(extension);
|
||||
const result = await checkForExtensionUpdate(
|
||||
extension,
|
||||
new ExtensionEnablementManager(),
|
||||
);
|
||||
expect(result).toBe(ExtensionUpdateState.UPDATE_AVAILABLE);
|
||||
});
|
||||
|
||||
@@ -210,7 +220,10 @@ describe('git extension helpers', () => {
|
||||
mockGit.listRemote.mockResolvedValue('same-hash\tHEAD');
|
||||
mockGit.revparse.mockResolvedValue('same-hash');
|
||||
|
||||
const result = await checkForExtensionUpdate(extension);
|
||||
const result = await checkForExtensionUpdate(
|
||||
extension,
|
||||
new ExtensionEnablementManager(),
|
||||
);
|
||||
expect(result).toBe(ExtensionUpdateState.UP_TO_DATE);
|
||||
});
|
||||
|
||||
@@ -228,7 +241,10 @@ describe('git extension helpers', () => {
|
||||
};
|
||||
mockGit.getRemotes.mockRejectedValue(new Error('git error'));
|
||||
|
||||
const result = await checkForExtensionUpdate(extension);
|
||||
const result = await checkForExtensionUpdate(
|
||||
extension,
|
||||
new ExtensionEnablementManager(),
|
||||
);
|
||||
expect(result).toBe(ExtensionUpdateState.ERROR);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -20,6 +20,7 @@ import { EXTENSIONS_CONFIG_FILENAME, loadExtension } from '../extension.js';
|
||||
import * as tar from 'tar';
|
||||
import extract from 'extract-zip';
|
||||
import { fetchJson, getGitHubToken } from './github_fetch.js';
|
||||
import { type ExtensionEnablementManager } from './extensionEnablement.js';
|
||||
|
||||
/**
|
||||
* Clones a Git repository to a specified local path.
|
||||
@@ -152,6 +153,7 @@ export async function fetchReleaseFromGithub(
|
||||
|
||||
export async function checkForExtensionUpdate(
|
||||
extension: GeminiCLIExtension,
|
||||
extensionEnablementManager: ExtensionEnablementManager,
|
||||
cwd: string = process.cwd(),
|
||||
): Promise<ExtensionUpdateState> {
|
||||
const installMetadata = extension.installMetadata;
|
||||
@@ -159,6 +161,7 @@ export async function checkForExtensionUpdate(
|
||||
const newExtension = loadExtension({
|
||||
extensionDir: installMetadata.source,
|
||||
workspaceDir: cwd,
|
||||
extensionEnablementManager,
|
||||
});
|
||||
if (!newExtension) {
|
||||
debugLogger.error(
|
||||
|
||||
@@ -11,7 +11,6 @@ import * as path from 'node:path';
|
||||
import {
|
||||
EXTENSIONS_CONFIG_FILENAME,
|
||||
INSTALL_METADATA_FILENAME,
|
||||
annotateActiveExtensions,
|
||||
loadExtension,
|
||||
} from '../extension.js';
|
||||
import { checkForAllExtensionUpdates, updateExtension } from './update.js';
|
||||
@@ -128,18 +127,15 @@ describe('update tests', () => {
|
||||
);
|
||||
});
|
||||
mockGit.getRemotes.mockResolvedValue([{ name: 'origin' }]);
|
||||
const extension = annotateActiveExtensions(
|
||||
[
|
||||
loadExtension({
|
||||
extensionDir: targetExtDir,
|
||||
workspaceDir: tempWorkspaceDir,
|
||||
})!,
|
||||
],
|
||||
process.cwd(),
|
||||
new ExtensionEnablementManager(),
|
||||
)[0];
|
||||
const extensionEnablementManager = new ExtensionEnablementManager();
|
||||
const extension = loadExtension({
|
||||
extensionDir: targetExtDir,
|
||||
workspaceDir: tempWorkspaceDir,
|
||||
extensionEnablementManager,
|
||||
})!;
|
||||
const updateInfo = await updateExtension(
|
||||
extension,
|
||||
extensionEnablementManager,
|
||||
tempHomeDir,
|
||||
async (_) => true,
|
||||
ExtensionUpdateState.UPDATE_AVAILABLE,
|
||||
@@ -185,18 +181,15 @@ describe('update tests', () => {
|
||||
mockGit.getRemotes.mockResolvedValue([{ name: 'origin' }]);
|
||||
|
||||
const dispatch = vi.fn();
|
||||
const extension = annotateActiveExtensions(
|
||||
[
|
||||
loadExtension({
|
||||
extensionDir,
|
||||
workspaceDir: tempWorkspaceDir,
|
||||
})!,
|
||||
],
|
||||
process.cwd(),
|
||||
new ExtensionEnablementManager(),
|
||||
)[0];
|
||||
const extensionEnablementManager = new ExtensionEnablementManager();
|
||||
const extension = loadExtension({
|
||||
extensionDir,
|
||||
workspaceDir: tempWorkspaceDir,
|
||||
extensionEnablementManager,
|
||||
})!;
|
||||
await updateExtension(
|
||||
extension,
|
||||
extensionEnablementManager,
|
||||
tempHomeDir,
|
||||
async (_) => true,
|
||||
ExtensionUpdateState.UPDATE_AVAILABLE,
|
||||
@@ -235,19 +228,16 @@ describe('update tests', () => {
|
||||
mockGit.getRemotes.mockResolvedValue([{ name: 'origin' }]);
|
||||
|
||||
const dispatch = vi.fn();
|
||||
const extension = annotateActiveExtensions(
|
||||
[
|
||||
loadExtension({
|
||||
extensionDir,
|
||||
workspaceDir: tempWorkspaceDir,
|
||||
})!,
|
||||
],
|
||||
process.cwd(),
|
||||
new ExtensionEnablementManager(),
|
||||
)[0];
|
||||
const extensionEnablementManager = new ExtensionEnablementManager();
|
||||
const extension = loadExtension({
|
||||
extensionDir,
|
||||
workspaceDir: tempWorkspaceDir,
|
||||
extensionEnablementManager,
|
||||
})!;
|
||||
await expect(
|
||||
updateExtension(
|
||||
extension,
|
||||
extensionEnablementManager,
|
||||
tempHomeDir,
|
||||
async (_) => true,
|
||||
ExtensionUpdateState.UPDATE_AVAILABLE,
|
||||
@@ -283,16 +273,12 @@ describe('update tests', () => {
|
||||
type: 'git',
|
||||
},
|
||||
});
|
||||
const extension = annotateActiveExtensions(
|
||||
[
|
||||
loadExtension({
|
||||
extensionDir,
|
||||
workspaceDir: tempWorkspaceDir,
|
||||
})!,
|
||||
],
|
||||
process.cwd(),
|
||||
new ExtensionEnablementManager(),
|
||||
)[0];
|
||||
const extensionEnablementManager = new ExtensionEnablementManager();
|
||||
const extension = loadExtension({
|
||||
extensionDir,
|
||||
workspaceDir: tempWorkspaceDir,
|
||||
extensionEnablementManager,
|
||||
})!;
|
||||
|
||||
mockGit.getRemotes.mockResolvedValue([
|
||||
{ name: 'origin', refs: { fetch: 'https://some.git/repo' } },
|
||||
@@ -303,6 +289,7 @@ describe('update tests', () => {
|
||||
const dispatch = vi.fn();
|
||||
await checkForAllExtensionUpdates(
|
||||
[extension],
|
||||
extensionEnablementManager,
|
||||
dispatch,
|
||||
tempWorkspaceDir,
|
||||
);
|
||||
@@ -325,16 +312,12 @@ describe('update tests', () => {
|
||||
type: 'git',
|
||||
},
|
||||
});
|
||||
const extension = annotateActiveExtensions(
|
||||
[
|
||||
loadExtension({
|
||||
extensionDir,
|
||||
workspaceDir: tempWorkspaceDir,
|
||||
})!,
|
||||
],
|
||||
process.cwd(),
|
||||
new ExtensionEnablementManager(),
|
||||
)[0];
|
||||
const extensionEnablementManager = new ExtensionEnablementManager();
|
||||
const extension = loadExtension({
|
||||
extensionDir,
|
||||
workspaceDir: tempWorkspaceDir,
|
||||
extensionEnablementManager,
|
||||
})!;
|
||||
|
||||
mockGit.getRemotes.mockResolvedValue([
|
||||
{ name: 'origin', refs: { fetch: 'https://some.git/repo' } },
|
||||
@@ -345,6 +328,7 @@ describe('update tests', () => {
|
||||
const dispatch = vi.fn();
|
||||
await checkForAllExtensionUpdates(
|
||||
[extension],
|
||||
extensionEnablementManager,
|
||||
dispatch,
|
||||
tempWorkspaceDir,
|
||||
);
|
||||
@@ -371,19 +355,16 @@ describe('update tests', () => {
|
||||
version: '1.0.0',
|
||||
installMetadata: { source: sourceExtensionDir, type: 'local' },
|
||||
});
|
||||
const extension = annotateActiveExtensions(
|
||||
[
|
||||
loadExtension({
|
||||
extensionDir: installedExtensionDir,
|
||||
workspaceDir: tempWorkspaceDir,
|
||||
})!,
|
||||
],
|
||||
process.cwd(),
|
||||
new ExtensionEnablementManager(),
|
||||
)[0];
|
||||
const extensionEnablementManager = new ExtensionEnablementManager();
|
||||
const extension = loadExtension({
|
||||
extensionDir: installedExtensionDir,
|
||||
workspaceDir: tempWorkspaceDir,
|
||||
extensionEnablementManager,
|
||||
})!;
|
||||
const dispatch = vi.fn();
|
||||
await checkForAllExtensionUpdates(
|
||||
[extension],
|
||||
extensionEnablementManager,
|
||||
dispatch,
|
||||
tempWorkspaceDir,
|
||||
);
|
||||
@@ -410,19 +391,16 @@ describe('update tests', () => {
|
||||
version: '1.0.0',
|
||||
installMetadata: { source: sourceExtensionDir, type: 'local' },
|
||||
});
|
||||
const extension = annotateActiveExtensions(
|
||||
[
|
||||
loadExtension({
|
||||
extensionDir: installedExtensionDir,
|
||||
workspaceDir: tempWorkspaceDir,
|
||||
})!,
|
||||
],
|
||||
process.cwd(),
|
||||
new ExtensionEnablementManager(),
|
||||
)[0];
|
||||
const extensionEnablementManager = new ExtensionEnablementManager();
|
||||
const extension = loadExtension({
|
||||
extensionDir: installedExtensionDir,
|
||||
workspaceDir: tempWorkspaceDir,
|
||||
extensionEnablementManager,
|
||||
})!;
|
||||
const dispatch = vi.fn();
|
||||
await checkForAllExtensionUpdates(
|
||||
[extension],
|
||||
extensionEnablementManager,
|
||||
dispatch,
|
||||
tempWorkspaceDir,
|
||||
);
|
||||
@@ -445,22 +423,19 @@ describe('update tests', () => {
|
||||
type: 'git',
|
||||
},
|
||||
});
|
||||
const extension = annotateActiveExtensions(
|
||||
[
|
||||
loadExtension({
|
||||
extensionDir,
|
||||
workspaceDir: tempWorkspaceDir,
|
||||
})!,
|
||||
],
|
||||
process.cwd(),
|
||||
new ExtensionEnablementManager(),
|
||||
)[0];
|
||||
const extensionEnablementManager = new ExtensionEnablementManager();
|
||||
const extension = loadExtension({
|
||||
extensionDir,
|
||||
workspaceDir: tempWorkspaceDir,
|
||||
extensionEnablementManager,
|
||||
})!;
|
||||
|
||||
mockGit.getRemotes.mockRejectedValue(new Error('Git error'));
|
||||
|
||||
const dispatch = vi.fn();
|
||||
await checkForAllExtensionUpdates(
|
||||
[extension],
|
||||
extensionEnablementManager,
|
||||
dispatch,
|
||||
tempWorkspaceDir,
|
||||
);
|
||||
|
||||
@@ -21,6 +21,7 @@ import { checkForExtensionUpdate } from './github.js';
|
||||
import { debugLogger, type GeminiCLIExtension } from '@google/gemini-cli-core';
|
||||
import * as fs from 'node:fs';
|
||||
import { getErrorMessage } from '../../utils/errors.js';
|
||||
import { type ExtensionEnablementManager } from './extensionEnablement.js';
|
||||
|
||||
export interface ExtensionUpdateInfo {
|
||||
name: string;
|
||||
@@ -30,6 +31,7 @@ export interface ExtensionUpdateInfo {
|
||||
|
||||
export async function updateExtension(
|
||||
extension: GeminiCLIExtension,
|
||||
extensionEnablementManager: ExtensionEnablementManager,
|
||||
cwd: string = process.cwd(),
|
||||
requestConsent: (consent: string) => Promise<boolean>,
|
||||
currentState: ExtensionUpdateState,
|
||||
@@ -67,6 +69,7 @@ export async function updateExtension(
|
||||
const previousExtensionConfig = await loadExtensionConfig({
|
||||
extensionDir: extension.path,
|
||||
workspaceDir: cwd,
|
||||
extensionEnablementManager,
|
||||
});
|
||||
await installOrUpdateExtension(
|
||||
installMetadata,
|
||||
@@ -79,6 +82,7 @@ export async function updateExtension(
|
||||
const updatedExtension = loadExtension({
|
||||
extensionDir: updatedExtensionStorage.getExtensionDir(),
|
||||
workspaceDir: cwd,
|
||||
extensionEnablementManager,
|
||||
});
|
||||
if (!updatedExtension) {
|
||||
dispatchExtensionStateUpdate({
|
||||
@@ -120,6 +124,7 @@ export async function updateAllUpdatableExtensions(
|
||||
requestConsent: (consent: string) => Promise<boolean>,
|
||||
extensions: GeminiCLIExtension[],
|
||||
extensionsState: Map<string, ExtensionUpdateStatus>,
|
||||
extensionEnablementManager: ExtensionEnablementManager,
|
||||
dispatch: (action: ExtensionUpdateAction) => void,
|
||||
): Promise<ExtensionUpdateInfo[]> {
|
||||
return (
|
||||
@@ -133,6 +138,7 @@ export async function updateAllUpdatableExtensions(
|
||||
.map((extension) =>
|
||||
updateExtension(
|
||||
extension,
|
||||
extensionEnablementManager,
|
||||
cwd,
|
||||
requestConsent,
|
||||
extensionsState.get(extension.name)!.status,
|
||||
@@ -150,6 +156,7 @@ export interface ExtensionUpdateCheckResult {
|
||||
|
||||
export async function checkForAllExtensionUpdates(
|
||||
extensions: GeminiCLIExtension[],
|
||||
extensionEnablementManager: ExtensionEnablementManager,
|
||||
dispatch: (action: ExtensionUpdateAction) => void,
|
||||
cwd: string = process.cwd(),
|
||||
): Promise<void> {
|
||||
@@ -174,11 +181,12 @@ export async function checkForAllExtensionUpdates(
|
||||
},
|
||||
});
|
||||
promises.push(
|
||||
checkForExtensionUpdate(extension, cwd).then((state) =>
|
||||
dispatch({
|
||||
type: 'SET_STATE',
|
||||
payload: { name: extension.name, state },
|
||||
}),
|
||||
checkForExtensionUpdate(extension, extensionEnablementManager, cwd).then(
|
||||
(state) =>
|
||||
dispatch({
|
||||
type: 'SET_STATE',
|
||||
payload: { name: extension.name, state },
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import type { ExtensionEnablementManager } from './extensionEnablement.js';
|
||||
|
||||
export interface VariableDefinition {
|
||||
type: 'string';
|
||||
description: string;
|
||||
@@ -18,6 +20,7 @@ export interface VariableSchema {
|
||||
export interface LoadExtensionContext {
|
||||
extensionDir: string;
|
||||
workspaceDir: string;
|
||||
extensionEnablementManager: ExtensionEnablementManager;
|
||||
}
|
||||
|
||||
const PATH_SEPARATOR_DEFINITION = {
|
||||
|
||||
Reference in New Issue
Block a user