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:
Shardul Natu
2025-11-12 08:33:28 -08:00
committed by GitHub
parent 570ccc7da0
commit 1ffb9c4188
2 changed files with 58 additions and 6 deletions

View File

@@ -4,6 +4,7 @@
* SPDX-License-Identifier: Apache-2.0
*/
import * as glob from 'glob';
import * as path from 'node:path';
import type { Config } 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', () => {
const signal: AbortSignal = new AbortController().signal;
beforeEach(() => {
beforeEach(async () => {
vi.clearAllMocks();
const { glob: actualGlob } =
await vi.importActual<typeof import('glob')>('glob');
vi.mocked(glob.glob).mockImplementation(actualGlob);
mockShellProcess.mockImplementation(
(prompt: PromptPipelineContent, context: CommandContext) => {
const userArgsRaw = context?.invocation?.args || '';
@@ -1288,4 +1296,45 @@ describe('FileCommandLoader', () => {
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();
});
});
});

View File

@@ -85,6 +85,10 @@ export class FileCommandLoader implements ICommandLoader {
* @returns A promise that resolves to an array of all loaded SlashCommands.
*/
async loadCommands(signal: AbortSignal): Promise<SlashCommand[]> {
if (this.folderTrustEnabled && !this.isTrustedFolder) {
return [];
}
const allCommands: SlashCommand[] = [];
const globOptions = {
nodir: true,
@@ -102,10 +106,6 @@ export class FileCommandLoader implements ICommandLoader {
cwd: dirInfo.path,
});
if (this.folderTrustEnabled && !this.isTrustedFolder) {
return [];
}
const commandPromises = files.map((file) =>
this.parseAndAdaptFile(
path.join(dirInfo.path, file),
@@ -122,7 +122,10 @@ export class FileCommandLoader implements ICommandLoader {
// Add all commands without deduplication
allCommands.push(...commands);
} catch (error) {
if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {
if (
!signal.aborted &&
(error as { code?: string })?.code !== 'ENOENT'
) {
console.error(
`[FileCommandLoader] Error loading commands from ${dirInfo.path}:`,
error,