mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-18 01:51:20 -07:00
Re-request consent if necessary when updating extensions (#9517)
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
This commit is contained in:
@@ -153,11 +153,14 @@ describe('extensionsCommand', () => {
|
||||
it('should update a single extension by name', async () => {
|
||||
const extension: GeminiCLIExtension = {
|
||||
name: 'ext-one',
|
||||
type: 'git',
|
||||
version: '1.0.0',
|
||||
isActive: true,
|
||||
path: '/test/dir/ext-one',
|
||||
autoUpdate: false,
|
||||
installMetadata: {
|
||||
type: 'git',
|
||||
autoUpdate: false,
|
||||
source: 'https://github.com/some/extension.git',
|
||||
},
|
||||
};
|
||||
mockUpdateExtension.mockResolvedValue({
|
||||
name: extension.name,
|
||||
@@ -173,6 +176,7 @@ describe('extensionsCommand', () => {
|
||||
expect(mockUpdateExtension).toHaveBeenCalledWith(
|
||||
extension,
|
||||
'/test/dir',
|
||||
expect.any(Function),
|
||||
ExtensionUpdateState.UPDATE_AVAILABLE,
|
||||
expect.any(Function),
|
||||
);
|
||||
@@ -194,19 +198,25 @@ describe('extensionsCommand', () => {
|
||||
it('should update multiple extensions by name', async () => {
|
||||
const extensionOne: GeminiCLIExtension = {
|
||||
name: 'ext-one',
|
||||
type: 'git',
|
||||
version: '1.0.0',
|
||||
isActive: true,
|
||||
path: '/test/dir/ext-one',
|
||||
autoUpdate: false,
|
||||
installMetadata: {
|
||||
type: 'git',
|
||||
autoUpdate: false,
|
||||
source: 'https://github.com/some/extension.git',
|
||||
},
|
||||
};
|
||||
const extensionTwo: GeminiCLIExtension = {
|
||||
name: 'ext-two',
|
||||
type: 'git',
|
||||
version: '1.0.0',
|
||||
isActive: true,
|
||||
path: '/test/dir/ext-two',
|
||||
autoUpdate: false,
|
||||
installMetadata: {
|
||||
type: 'git',
|
||||
autoUpdate: false,
|
||||
source: 'https://github.com/some/extension.git',
|
||||
},
|
||||
};
|
||||
mockGetExtensions.mockReturnValue([extensionOne, extensionTwo]);
|
||||
mockContext.ui.extensionsUpdateState.set(
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { requestConsentInteractive } from '../../config/extension.js';
|
||||
import {
|
||||
updateAllUpdatableExtensions,
|
||||
type ExtensionUpdateInfo,
|
||||
@@ -51,6 +52,9 @@ async function updateAction(context: CommandContext, args: string) {
|
||||
if (all) {
|
||||
updateInfos = await updateAllUpdatableExtensions(
|
||||
context.services.config!.getWorkingDir(),
|
||||
// We don't have the ability to prompt for consent yet in this flow.
|
||||
(description) =>
|
||||
requestConsentInteractive(description, context.ui.addItem),
|
||||
context.services.config!.getExtensions(),
|
||||
context.ui.extensionsUpdateState,
|
||||
context.ui.setExtensionsUpdateState,
|
||||
@@ -75,6 +79,8 @@ async function updateAction(context: CommandContext, args: string) {
|
||||
const updateInfo = await updateExtension(
|
||||
extension,
|
||||
workingDir,
|
||||
(description) =>
|
||||
requestConsentInteractive(description, context.ui.addItem),
|
||||
context.ui.extensionsUpdateState.get(extension.name) ??
|
||||
ExtensionUpdateState.UNKNOWN,
|
||||
(updateState) => {
|
||||
|
||||
@@ -23,8 +23,11 @@ export function WorkspaceMigrationDialog(props: {
|
||||
const [failedExtensions, setFailedExtensions] = useState<string[]>([]);
|
||||
onOpen();
|
||||
const onMigrate = async () => {
|
||||
const failed =
|
||||
await performWorkspaceExtensionMigration(workspaceExtensions);
|
||||
const failed = await performWorkspaceExtensionMigration(
|
||||
workspaceExtensions,
|
||||
// We aren't updating extensions, just moving them around, don't need to ask for consent.
|
||||
async (_) => true,
|
||||
);
|
||||
setFailedExtensions(failed);
|
||||
setMigrationComplete(true);
|
||||
};
|
||||
|
||||
@@ -91,7 +91,7 @@ describe('<ExtensionsList />', () => {
|
||||
},
|
||||
{
|
||||
state: ExtensionUpdateState.ERROR,
|
||||
expectedText: '(error checking for updates)',
|
||||
expectedText: '(error)',
|
||||
},
|
||||
{
|
||||
state: ExtensionUpdateState.UP_TO_DATE,
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
checkForAllExtensionUpdates,
|
||||
updateExtension,
|
||||
} from '../../config/extensions/update.js';
|
||||
import { requestConsentInteractive } from '../../config/extension.js';
|
||||
|
||||
export const useExtensionUpdates = (
|
||||
extensions: GeminiCLIExtension[],
|
||||
@@ -40,13 +41,19 @@ export const useExtensionUpdates = (
|
||||
continue;
|
||||
}
|
||||
if (extension.installMetadata?.autoUpdate) {
|
||||
updateExtension(extension, cwd, currentState, (newState) => {
|
||||
setExtensionsUpdateState((prev) => {
|
||||
const finalState = new Map(prev);
|
||||
finalState.set(extension.name, newState);
|
||||
return finalState;
|
||||
});
|
||||
})
|
||||
updateExtension(
|
||||
extension,
|
||||
cwd,
|
||||
(description) => requestConsentInteractive(description, addItem),
|
||||
currentState,
|
||||
(newState) => {
|
||||
setExtensionsUpdateState((prev) => {
|
||||
const finalState = new Map(prev);
|
||||
finalState.set(extension.name, newState);
|
||||
return finalState;
|
||||
});
|
||||
},
|
||||
)
|
||||
.then((result) => {
|
||||
if (!result) return;
|
||||
addItem(
|
||||
|
||||
@@ -10,7 +10,7 @@ export enum ExtensionUpdateState {
|
||||
UPDATING = 'updating',
|
||||
UPDATE_AVAILABLE = 'update available',
|
||||
UP_TO_DATE = 'up to date',
|
||||
ERROR = 'error checking for updates',
|
||||
ERROR = 'error',
|
||||
NOT_UPDATABLE = 'not updatable',
|
||||
UNKNOWN = 'unknown',
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user