fix(vscode-ide-companion): add missing activate() Disposables#27936
fix(vscode-ide-companion): add missing activate() Disposables#27936parveshsaini wants to merge 2 commits into
Conversation
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request addresses a bug in the VS Code companion extension where certain command and workspace event registrations were failing to be disposed of properly due to incorrect syntax. By removing unintended comma expressions, the extension now correctly tracks these Disposables, preventing memory leaks and command registration conflicts during extension reloads. Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. Footnotes
|
|
📊 PR Size: size/M
|
There was a problem hiding this comment.
Code Review
This pull request cleans up redundant parentheses in the VS Code extension activation code and updates the test suite to verify that registered disposables are correctly added to the context subscriptions. Feedback on the changes highlights a resource leak in the tests, where calling activate(context) starts an Express server that is never cleaned up, and recommends adding a deactivate() call in afterEach to prevent hanging test processes.
| expect(vscode.workspace.onDidGrantWorkspaceTrust).toHaveBeenCalled(); | ||
| }); | ||
|
|
||
| it('adds every registered disposable to context.subscriptions', async () => { |
There was a problem hiding this comment.
Resource Leak in Tests
Calling activate(context) starts an Express server on a random port via ideServer.start(context). Because deactivate() is never called in afterEach (or within the tests), these HTTP servers and their associated sockets are leaked for every test that executes activate(context). This can lead to port exhaustion, memory leaks, and hanging test processes, especially in CI or watch mode.
To resolve this, please import deactivate from ./extension.js and call it in afterEach to ensure proper cleanup:
import { activate, deactivate } from './extension.js';
// ...
afterEach(async () => {
await deactivate();
vi.restoreAllMocks();
});There was a problem hiding this comment.
Added deactivate() to afterEach to tear down the IDE server, plus a dispose mock on the output channel so cleanup doesn't throw. All 12 tests still pass ✅
Summary
activate()in the VS Code companion extension wraps two groups ofregistrations in an extra pair of parentheses, which turns each group into a
JavaScript comma expression instead of separate arguments to
context.subscriptions.push(...). A comma expression evaluates both operandsbut yields only the last one, so the first registration in each group runs
but its
Disposableis never pushed ontocontext.subscriptions— and istherefore never disposed on deactivation.
Two Disposables leak today:
gemini.diff.acceptcommand, andonDidChangeWorkspaceFolderslistener.Impact:
update),
gemini.diff.acceptstays registered. Re-activation then throwscommand 'gemini.diff.accept' already exists.onDidChangeWorkspaceFolderslistener is never torn down, so a stalelistener keeps calling
ideServer.syncEnvVars()against anIDEServerthathas already been stopped.
Details
The two offending groups in
packages/vscode-ide-companion/src/extension.ts:The surrounding registrations in the same two
push()calls already use theflat one-argument-per-Disposable style, which is what makes the two
parenthesized groups stand out as unintended. The fix removes the stray
(/)around each group so every registration is its own argument to
push().This is a platform-independent defect (JavaScript comma-operator semantics),
present since the companion extension was introduced.
Related Issues
Closes #27790
How to Validate
This PR adds a regression test,
adds every registered disposable to context.subscriptions, toextension.test.ts. The existingvscodemockreturned
undefinedfromregisterCommand/ the workspace listeners, which iswhy the leak was invisible to the suite; the mock now returns a tagged
Disposableso the test can assert what actually lands incontext.subscriptions.context.subscriptionsis missinggemini.diff.acceptandonDidChangeWorkspaceFolders(
expected [ 'onDidCloseTextDocument', …(5) ] to include 'gemini.diff.accept');the suite reports
1 failed | 11 passed.gemini.diff.accept,gemini.diff.cancel,onDidChangeWorkspaceFolders,onDidGrantWorkspaceTrust) are present and the suite reports12 passed.Pre-Merge Checklist