Fully detach autoupgrade process (#14595)

This commit is contained in:
Tommaso Sciortino
2025-12-05 14:12:54 -08:00
committed by GitHub
parent 04cbae5b5f
commit bdd15e8911
2 changed files with 14 additions and 20 deletions
@@ -11,6 +11,7 @@ import { updateEventEmitter } from './updateEventEmitter.js';
import type { UpdateObject } from '../ui/utils/updateCheck.js'; import type { UpdateObject } from '../ui/utils/updateCheck.js';
import type { LoadedSettings } from '../config/settings.js'; import type { LoadedSettings } from '../config/settings.js';
import EventEmitter from 'node:events'; import EventEmitter from 'node:events';
import type { ChildProcess } from 'node:child_process';
import { handleAutoUpdate, setUpdateHandler } from './handleAutoUpdate.js'; import { handleAutoUpdate, setUpdateHandler } from './handleAutoUpdate.js';
import { MessageType } from '../ui/types.js'; import { MessageType } from '../ui/types.js';
@@ -26,22 +27,13 @@ vi.mock('./updateEventEmitter.js', async (importOriginal) =>
importOriginal<typeof import('./updateEventEmitter.js')>(), importOriginal<typeof import('./updateEventEmitter.js')>(),
); );
interface MockChildProcess extends EventEmitter {
stdin: EventEmitter & {
write: Mock;
end: Mock;
};
stderr: EventEmitter;
}
const mockGetInstallationInfo = vi.mocked(getInstallationInfo); const mockGetInstallationInfo = vi.mocked(getInstallationInfo);
// updateEventEmitter is now real, but we will spy on it
describe('handleAutoUpdate', () => { describe('handleAutoUpdate', () => {
let mockSpawn: Mock; let mockSpawn: Mock;
let mockUpdateInfo: UpdateObject; let mockUpdateInfo: UpdateObject;
let mockSettings: LoadedSettings; let mockSettings: LoadedSettings;
let mockChildProcess: MockChildProcess; let mockChildProcess: ChildProcess;
beforeEach(() => { beforeEach(() => {
mockSpawn = vi.fn(); mockSpawn = vi.fn();
@@ -70,8 +62,8 @@ describe('handleAutoUpdate', () => {
write: vi.fn(), write: vi.fn(),
end: vi.fn(), end: vi.fn(),
}), }),
stderr: new EventEmitter(), unref: vi.fn(),
}) as MockChildProcess; }) as unknown as ChildProcess;
mockSpawn.mockReturnValue( mockSpawn.mockReturnValue(
mockChildProcess as unknown as ReturnType<typeof mockSpawn>, mockChildProcess as unknown as ReturnType<typeof mockSpawn>,
@@ -194,7 +186,6 @@ describe('handleAutoUpdate', () => {
// Simulate failed execution // Simulate failed execution
setTimeout(() => { setTimeout(() => {
mockChildProcess.stderr.emit('data', 'An error occurred');
mockChildProcess.emit('close', 1); mockChildProcess.emit('close', 1);
resolve(); resolve();
}, 0); }, 0);
@@ -204,7 +195,7 @@ describe('handleAutoUpdate', () => {
expect(updateEventEmitter.emit).toHaveBeenCalledWith('update-failed', { expect(updateEventEmitter.emit).toHaveBeenCalledWith('update-failed', {
message: message:
'Automatic update failed. Please try updating manually. (command: npm i -g @google/gemini-cli@2.0.0, stderr: An error occurred)', 'Automatic update failed. Please try updating manually. (command: npm i -g @google/gemini-cli@2.0.0)',
}); });
}); });
@@ -253,7 +244,8 @@ describe('handleAutoUpdate', () => {
'npm i -g @google/gemini-cli@nightly', 'npm i -g @google/gemini-cli@nightly',
{ {
shell: true, shell: true,
stdio: 'pipe', stdio: 'ignore',
detached: true,
}, },
); );
}); });
+7 -5
View File
@@ -68,11 +68,13 @@ export function handleAutoUpdate(
'@latest', '@latest',
isNightly ? '@nightly' : `@${info.update.latest}`, isNightly ? '@nightly' : `@${info.update.latest}`,
); );
const updateProcess = spawnFn(updateCommand, { stdio: 'pipe', shell: true }); const updateProcess = spawnFn(updateCommand, {
let errorOutput = ''; stdio: 'ignore',
updateProcess.stderr.on('data', (data) => { shell: true,
errorOutput += data.toString(); detached: true,
}); });
// Un-reference the child process to allow the parent to exit independently.
updateProcess.unref();
updateProcess.on('close', (code) => { updateProcess.on('close', (code) => {
if (code === 0) { if (code === 0) {
@@ -82,7 +84,7 @@ export function handleAutoUpdate(
}); });
} else { } else {
updateEventEmitter.emit('update-failed', { updateEventEmitter.emit('update-failed', {
message: `Automatic update failed. Please try updating manually. (command: ${updateCommand}, stderr: ${errorOutput.trim()})`, message: `Automatic update failed. Please try updating manually. (command: ${updateCommand})`,
}); });
} }
}); });