Add simple extensions release flow support (#8498)

This commit is contained in:
christine betts
2025-09-17 18:14:01 -04:00
committed by GitHub
parent 13a65ad94f
commit eddd13d70e
8 changed files with 726 additions and 243 deletions
+1 -114
View File
@@ -13,7 +13,6 @@ import {
INSTALL_METADATA_FILENAME,
annotateActiveExtensions,
checkForAllExtensionUpdates,
checkForExtensionUpdate,
disableExtension,
enableExtension,
installExtension,
@@ -23,7 +22,6 @@ import {
uninstallExtension,
updateExtension,
type Extension,
type ExtensionInstallMetadata,
} from './extension.js';
import {
GEMINI_DIR,
@@ -32,6 +30,7 @@ import {
ClearcutLogger,
type Config,
ExtensionUninstallEvent,
type ExtensionInstallMetadata,
} from '@google/gemini-cli-core';
import { execSync } from 'node:child_process';
import { SettingScope } from './settings.js';
@@ -1140,118 +1139,6 @@ describe('extension tests', () => {
});
});
describe('checkForExtensionUpdate', () => {
it('should return UpdateAvailable for a git extension with updates', async () => {
const extensionDir = createExtension({
extensionsDir: userExtensionsDir,
name: 'test-extension',
version: '1.0.0',
installMetadata: {
source: 'https://some.git/repo',
type: 'git',
},
});
const extension = annotateActiveExtensions(
[
loadExtension({
extensionDir,
workspaceDir: tempWorkspaceDir,
})!,
],
[],
process.cwd(),
)[0];
mockGit.getRemotes.mockResolvedValue([
{ name: 'origin', refs: { fetch: 'https://some.git/repo' } },
]);
mockGit.listRemote.mockResolvedValue('remoteHash HEAD');
mockGit.revparse.mockResolvedValue('localHash');
const result = await checkForExtensionUpdate(extension);
expect(result).toBe(ExtensionUpdateState.UPDATE_AVAILABLE);
});
it('should return UpToDate for a git extension with no updates', async () => {
const extensionDir = createExtension({
extensionsDir: userExtensionsDir,
name: 'test-extension',
version: '1.0.0',
installMetadata: {
source: 'https://some.git/repo',
type: 'git',
},
});
const extension = annotateActiveExtensions(
[
loadExtension({
extensionDir,
workspaceDir: tempWorkspaceDir,
})!,
],
[],
process.cwd(),
)[0];
mockGit.getRemotes.mockResolvedValue([
{ name: 'origin', refs: { fetch: 'https://some.git/repo' } },
]);
mockGit.listRemote.mockResolvedValue('sameHash HEAD');
mockGit.revparse.mockResolvedValue('sameHash');
const result = await checkForExtensionUpdate(extension);
expect(result).toBe(ExtensionUpdateState.UP_TO_DATE);
});
it('should return NotUpdatable for a non-git extension', async () => {
const extensionDir = createExtension({
extensionsDir: userExtensionsDir,
name: 'local-extension',
version: '1.0.0',
});
const extension = annotateActiveExtensions(
[
loadExtension({
extensionDir,
workspaceDir: tempWorkspaceDir,
})!,
],
[],
process.cwd(),
)[0];
const result = await checkForExtensionUpdate(extension);
expect(result).toBe(ExtensionUpdateState.NOT_UPDATABLE);
});
it('should return Error when git check fails', async () => {
const extensionDir = createExtension({
extensionsDir: userExtensionsDir,
name: 'error-extension',
version: '1.0.0',
installMetadata: {
source: 'https://some.git/repo',
type: 'git',
},
});
const extension = annotateActiveExtensions(
[
loadExtension({
extensionDir,
workspaceDir: tempWorkspaceDir,
})!,
],
[],
process.cwd(),
)[0];
mockGit.getRemotes.mockRejectedValue(new Error('Git error'));
const result = await checkForExtensionUpdate(extension);
expect(result).toBe(ExtensionUpdateState.ERROR);
});
});
describe('disableExtension', () => {
it('should disable an extension at the user scope', () => {
disableExtension('my-extension', SettingScope.User);