mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-05-12 12:54:07 -07:00
fix(FileCommandLoader): Remove error logs if the operation was aborted (#12927)
Co-authored-by: Shnatu <snatu@google.com> Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
This commit is contained in:
@@ -4,6 +4,7 @@
|
|||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import * as glob from 'glob';
|
||||||
import * as path from 'node:path';
|
import * as path from 'node:path';
|
||||||
import type { Config } from '@google/gemini-cli-core';
|
import type { Config } from '@google/gemini-cli-core';
|
||||||
import { GEMINI_DIR, Storage } from '@google/gemini-cli-core';
|
import { GEMINI_DIR, Storage } from '@google/gemini-cli-core';
|
||||||
@@ -70,11 +71,18 @@ vi.mock('@google/gemini-cli-core', async (importOriginal) => {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
vi.mock('glob', () => ({
|
||||||
|
glob: vi.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
describe('FileCommandLoader', () => {
|
describe('FileCommandLoader', () => {
|
||||||
const signal: AbortSignal = new AbortController().signal;
|
const signal: AbortSignal = new AbortController().signal;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(async () => {
|
||||||
vi.clearAllMocks();
|
vi.clearAllMocks();
|
||||||
|
const { glob: actualGlob } =
|
||||||
|
await vi.importActual<typeof import('glob')>('glob');
|
||||||
|
vi.mocked(glob.glob).mockImplementation(actualGlob);
|
||||||
mockShellProcess.mockImplementation(
|
mockShellProcess.mockImplementation(
|
||||||
(prompt: PromptPipelineContent, context: CommandContext) => {
|
(prompt: PromptPipelineContent, context: CommandContext) => {
|
||||||
const userArgsRaw = context?.invocation?.args || '';
|
const userArgsRaw = context?.invocation?.args || '';
|
||||||
@@ -1288,4 +1296,45 @@ describe('FileCommandLoader', () => {
|
|||||||
expect(commands).toHaveLength(0);
|
expect(commands).toHaveLength(0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('Aborted signal', () => {
|
||||||
|
it('does not log errors if the signal is aborted', async () => {
|
||||||
|
const controller = new AbortController();
|
||||||
|
const abortSignal = controller.signal;
|
||||||
|
|
||||||
|
const consoleErrorSpy = vi
|
||||||
|
.spyOn(console, 'error')
|
||||||
|
.mockImplementation(() => {});
|
||||||
|
|
||||||
|
const mockConfig = {
|
||||||
|
getProjectRoot: vi.fn(() => '/path/to/project'),
|
||||||
|
getExtensions: vi.fn(() => []),
|
||||||
|
getFolderTrust: vi.fn(() => false),
|
||||||
|
isTrustedFolder: vi.fn(() => false),
|
||||||
|
} as unknown as Config;
|
||||||
|
|
||||||
|
// Set up mock-fs so that the loader attempts to read a directory.
|
||||||
|
const userCommandsDir = Storage.getUserCommandsDir();
|
||||||
|
mock({
|
||||||
|
[userCommandsDir]: {
|
||||||
|
'test1.toml': 'prompt = "Prompt 1"',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const loader = new FileCommandLoader(mockConfig);
|
||||||
|
|
||||||
|
// Mock glob to throw an AbortError
|
||||||
|
const abortError = new DOMException('Aborted', 'AbortError');
|
||||||
|
vi.mocked(glob.glob).mockImplementation(async () => {
|
||||||
|
controller.abort(); // Ensure the signal is aborted when the service checks
|
||||||
|
throw abortError;
|
||||||
|
});
|
||||||
|
|
||||||
|
await loader.loadCommands(abortSignal);
|
||||||
|
|
||||||
|
expect(consoleErrorSpy).not.toHaveBeenCalled();
|
||||||
|
|
||||||
|
consoleErrorSpy.mockRestore();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -85,6 +85,10 @@ export class FileCommandLoader implements ICommandLoader {
|
|||||||
* @returns A promise that resolves to an array of all loaded SlashCommands.
|
* @returns A promise that resolves to an array of all loaded SlashCommands.
|
||||||
*/
|
*/
|
||||||
async loadCommands(signal: AbortSignal): Promise<SlashCommand[]> {
|
async loadCommands(signal: AbortSignal): Promise<SlashCommand[]> {
|
||||||
|
if (this.folderTrustEnabled && !this.isTrustedFolder) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
const allCommands: SlashCommand[] = [];
|
const allCommands: SlashCommand[] = [];
|
||||||
const globOptions = {
|
const globOptions = {
|
||||||
nodir: true,
|
nodir: true,
|
||||||
@@ -102,10 +106,6 @@ export class FileCommandLoader implements ICommandLoader {
|
|||||||
cwd: dirInfo.path,
|
cwd: dirInfo.path,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this.folderTrustEnabled && !this.isTrustedFolder) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
const commandPromises = files.map((file) =>
|
const commandPromises = files.map((file) =>
|
||||||
this.parseAndAdaptFile(
|
this.parseAndAdaptFile(
|
||||||
path.join(dirInfo.path, file),
|
path.join(dirInfo.path, file),
|
||||||
@@ -122,7 +122,10 @@ export class FileCommandLoader implements ICommandLoader {
|
|||||||
// Add all commands without deduplication
|
// Add all commands without deduplication
|
||||||
allCommands.push(...commands);
|
allCommands.push(...commands);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {
|
if (
|
||||||
|
!signal.aborted &&
|
||||||
|
(error as { code?: string })?.code !== 'ENOENT'
|
||||||
|
) {
|
||||||
console.error(
|
console.error(
|
||||||
`[FileCommandLoader] Error loading commands from ${dirInfo.path}:`,
|
`[FileCommandLoader] Error loading commands from ${dirInfo.path}:`,
|
||||||
error,
|
error,
|
||||||
|
|||||||
Reference in New Issue
Block a user