Skip to content

Commit bf95ff6

Browse files
committed
Extension integration testing improvements
- Include vscode-codeql workspace storage in CODEQL_DATABASES_BASE_DIRS alongside global storage (picks up databases from current workspace) - Add settings: additionalDatabaseDirs, additionalQueryRunResultsDirs, additionalMrvaRunResultsDirs for user-appended discovery directories - Add .gitignore for extension build artifacts (dist/, server/, *.vsix) - Update clean script to remove server/ and *.vsix - Fix launch.json: use npx for vitest (hoisted node_modules), add 5 debug configs (run ext, host tests, unit tests, current file, server) - Export environmentBuilder and serverManager from extension API - Add Extension Host integration tests: bridge env var path validation, MCP server definition tests - Add unit tests: storage paths workspace methods, env var multi-path assembly, user-configured dir appending, discovery var passthrough - Add extension host integration tests for common workspace states: - empty (no folders) vscode workspace; - single-root folder vscode workspace; - multi-root folder vscode workspace.
1 parent 27c26da commit bf95ff6

File tree

25 files changed

+951
-25
lines changed

25 files changed

+951
-25
lines changed

.vscode/launch.json

Lines changed: 74 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,33 +2,98 @@
22
"version": "0.2.0",
33
"configurations": [
44
{
5-
"name": "Run Extension",
5+
"name": "Run Extension (vscode-codeql-development-mcp-server)",
66
"type": "extensionHost",
77
"request": "launch",
88
"args": [
9-
"--extensionDevelopmentPath=${workspaceFolder}/extensions/vscode"
9+
"--extensionDevelopmentPath=${workspaceFolder:codeql-development-mcp-server}/extensions/vscode"
1010
],
1111
"outFiles": [
12-
"${workspaceFolder}/extensions/vscode/dist/**/*.js",
13-
"${workspaceFolder}/extensions/vscode/dist/**/*.cjs"
12+
"${workspaceFolder:codeql-development-mcp-server}/extensions/vscode/dist/**/*.js",
13+
"${workspaceFolder:codeql-development-mcp-server}/extensions/vscode/dist/**/*.cjs"
1414
],
1515
"preLaunchTask": "npm: bundle - extensions/vscode",
1616
"sourceMaps": true
1717
},
1818
{
19-
"name": "Extension Tests",
19+
"name": "Extension Host Tests - No Workspace (vscode-codeql-development-mcp-server)",
2020
"type": "extensionHost",
2121
"request": "launch",
2222
"args": [
23-
"--extensionDevelopmentPath=${workspaceFolder}/extensions/vscode",
24-
"--extensionTestsPath=${workspaceFolder}/extensions/vscode/dist/test/suite/index.cjs"
23+
"--extensionDevelopmentPath=${workspaceFolder:codeql-development-mcp-server}/extensions/vscode",
24+
"--extensionTestsPath=${workspaceFolder:codeql-development-mcp-server}/extensions/vscode/dist/test/suite/index.cjs"
2525
],
2626
"outFiles": [
27-
"${workspaceFolder}/extensions/vscode/dist/**/*.js",
28-
"${workspaceFolder}/extensions/vscode/dist/**/*.cjs"
27+
"${workspaceFolder:codeql-development-mcp-server}/extensions/vscode/dist/**/*.js",
28+
"${workspaceFolder:codeql-development-mcp-server}/extensions/vscode/dist/**/*.cjs"
2929
],
3030
"preLaunchTask": "npm: bundle - extensions/vscode",
3131
"sourceMaps": true
32+
},
33+
{
34+
"name": "Extension Host Tests - Single Folder (vscode-codeql-development-mcp-server)",
35+
"type": "extensionHost",
36+
"request": "launch",
37+
"args": [
38+
"--extensionDevelopmentPath=${workspaceFolder:codeql-development-mcp-server}/extensions/vscode",
39+
"--extensionTestsPath=${workspaceFolder:codeql-development-mcp-server}/extensions/vscode/dist/test/suite/index.cjs",
40+
"${workspaceFolder:codeql-development-mcp-server}/extensions/vscode/test/fixtures/single-folder-workspace"
41+
],
42+
"outFiles": [
43+
"${workspaceFolder:codeql-development-mcp-server}/extensions/vscode/dist/**/*.js",
44+
"${workspaceFolder:codeql-development-mcp-server}/extensions/vscode/dist/**/*.cjs"
45+
],
46+
"preLaunchTask": "npm: bundle - extensions/vscode",
47+
"sourceMaps": true
48+
},
49+
{
50+
"name": "Extension Host Tests - Multi-Root (vscode-codeql-development-mcp-server)",
51+
"type": "extensionHost",
52+
"request": "launch",
53+
"args": [
54+
"--extensionDevelopmentPath=${workspaceFolder:codeql-development-mcp-server}/extensions/vscode",
55+
"--extensionTestsPath=${workspaceFolder:codeql-development-mcp-server}/extensions/vscode/dist/test/suite/index.cjs",
56+
"${workspaceFolder:codeql-development-mcp-server}/extensions/vscode/test/fixtures/multi-root-workspace/test.code-workspace"
57+
],
58+
"outFiles": [
59+
"${workspaceFolder:codeql-development-mcp-server}/extensions/vscode/dist/**/*.js",
60+
"${workspaceFolder:codeql-development-mcp-server}/extensions/vscode/dist/**/*.cjs"
61+
],
62+
"preLaunchTask": "npm: bundle - extensions/vscode",
63+
"sourceMaps": true
64+
},
65+
{
66+
"name": "Unit Tests (vscode-codeql-development-mcp-server)",
67+
"type": "node",
68+
"request": "launch",
69+
"runtimeExecutable": "npx",
70+
"runtimeArgs": ["vitest", "--run"],
71+
"cwd": "${workspaceFolder:codeql-development-mcp-server}/extensions/vscode",
72+
"sourceMaps": true,
73+
"console": "integratedTerminal",
74+
"internalConsoleOptions": "neverOpen"
75+
},
76+
{
77+
"name": "Unit Test - Current File (vscode-codeql-development-mcp-server)",
78+
"type": "node",
79+
"request": "launch",
80+
"runtimeExecutable": "npx",
81+
"runtimeArgs": ["vitest", "--run", "${relativeFile}"],
82+
"cwd": "${workspaceFolder:codeql-development-mcp-server}/extensions/vscode",
83+
"sourceMaps": true,
84+
"console": "integratedTerminal",
85+
"internalConsoleOptions": "neverOpen"
86+
},
87+
{
88+
"name": "Server Unit Tests (vscode-codeql-development-mcp-server)",
89+
"type": "node",
90+
"request": "launch",
91+
"runtimeExecutable": "npx",
92+
"runtimeArgs": ["vitest", "--run"],
93+
"cwd": "${workspaceFolder:codeql-development-mcp-server}/server",
94+
"sourceMaps": true,
95+
"console": "integratedTerminal",
96+
"internalConsoleOptions": "neverOpen"
3297
}
3398
]
3499
}

extensions/vscode/.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Build artifacts
2+
dist/
3+
server/
4+
coverage/
5+
*.vsix

extensions/vscode/.vscodeignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ src/**
44
test/**
55
scripts/**
66
node_modules/**
7-
.gitignore
87
tsconfig.json
98
test/tsconfig.json
109
vitest.config.ts

extensions/vscode/esbuild.config.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,11 @@ const testSuiteConfig = {
3434
...shared,
3535
entryPoints: [
3636
'test/suite/index.ts',
37+
'test/suite/bridge.integration.test.ts',
3738
'test/suite/extension.integration.test.ts',
39+
'test/suite/mcp-server.integration.test.ts',
40+
'test/suite/mcp-tool-e2e.integration.test.ts',
41+
'test/suite/workspace-scenario.integration.test.ts',
3842
],
3943
outdir: 'dist/test/suite',
4044
outfile: undefined, // outdir and outfile are mutually exclusive

extensions/vscode/package.json

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,24 @@
8181
"additionalProperties": {
8282
"type": "string"
8383
}
84+
},
85+
"codeql-mcp.additionalDatabaseDirs": {
86+
"type": "array",
87+
"items": { "type": "string" },
88+
"default": [],
89+
"description": "Additional directories to search for CodeQL databases. Appended to CODEQL_DATABASES_BASE_DIRS alongside the vscode-codeql storage paths."
90+
},
91+
"codeql-mcp.additionalMrvaRunResultsDirs": {
92+
"type": "array",
93+
"items": { "type": "string" },
94+
"default": [],
95+
"description": "Additional directories containing MRVA run result subdirectories. Appended to CODEQL_MRVA_RUN_RESULTS_DIRS alongside the vscode-codeql variant analysis storage path."
96+
},
97+
"codeql-mcp.additionalQueryRunResultsDirs": {
98+
"type": "array",
99+
"items": { "type": "string" },
100+
"default": [],
101+
"description": "Additional directories containing query run result subdirectories. Appended to CODEQL_QUERY_RUN_RESULTS_DIRS alongside the vscode-codeql query storage path."
84102
}
85103
}
86104
},
@@ -111,7 +129,7 @@
111129
"build": "npm run clean && npm run lint && npm run bundle",
112130
"bundle": "node esbuild.config.js",
113131
"bundle:server": "node scripts/bundle-server.js",
114-
"clean": "rm -rf dist",
132+
"clean": "rm -rf dist server *.vsix",
115133
"lint": "eslint src/ test/",
116134
"lint:fix": "eslint src/ test/ --fix",
117135
"package": "vsce package --out codeql-development-mcp-server.vsix",

extensions/vscode/src/bridge/environment-builder.ts

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ export class EnvironmentBuilder extends DisposableObject {
4242

4343
const env: Record<string, string> = {};
4444

45+
// User configuration
46+
const config = vscode.workspace.getConfiguration('codeql-mcp');
47+
4548
// Transport mode is always stdio when launched from VS Code
4649
env.TRANSPORT_MODE = 'stdio';
4750

@@ -78,17 +81,26 @@ export class EnvironmentBuilder extends DisposableObject {
7881

7982
env.CODEQL_ADDITIONAL_PACKS = additionalPaths.join(':');
8083

81-
// Database discovery directory for list_codeql_databases
82-
env.CODEQL_DATABASES_BASE_DIRS = this.storagePaths.getDatabaseStoragePath();
84+
// Database discovery directories for list_codeql_databases
85+
// Includes: global storage, workspace storage, and user-configured dirs
86+
const dbDirs = [...this.storagePaths.getAllDatabaseStoragePaths()];
87+
const userDbDirs = config.get<string[]>('additionalDatabaseDirs', []);
88+
dbDirs.push(...userDbDirs);
89+
env.CODEQL_DATABASES_BASE_DIRS = dbDirs.join(':');
8390

8491
// MRVA run results directory for variant analysis discovery
85-
env.CODEQL_MRVA_RUN_RESULTS_DIRS = this.storagePaths.getVariantAnalysisStoragePath();
92+
const mrvaDirs = [this.storagePaths.getVariantAnalysisStoragePath()];
93+
const userMrvaDirs = config.get<string[]>('additionalMrvaRunResultsDirs', []);
94+
mrvaDirs.push(...userMrvaDirs);
95+
env.CODEQL_MRVA_RUN_RESULTS_DIRS = mrvaDirs.join(':');
8696

8797
// Query run results directory for query history discovery
88-
env.CODEQL_QUERY_RUN_RESULTS_DIRS = this.storagePaths.getQueryStoragePath();
98+
const queryDirs = [this.storagePaths.getQueryStoragePath()];
99+
const userQueryDirs = config.get<string[]>('additionalQueryRunResultsDirs', []);
100+
queryDirs.push(...userQueryDirs);
101+
env.CODEQL_QUERY_RUN_RESULTS_DIRS = queryDirs.join(':');
89102

90103
// User-configured additional environment variables
91-
const config = vscode.workspace.getConfiguration('codeql-mcp');
92104
const additionalEnv = config.get<Record<string, string>>('additionalEnv', {});
93105
for (const [key, value] of Object.entries(additionalEnv)) {
94106
env[key] = value;

extensions/vscode/src/bridge/storage-paths.ts

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,21 @@ const VSCODE_CODEQL_EXTENSION_ID = 'GitHub.vscode-codeql';
1919
*/
2020
export class StoragePaths extends DisposableObject {
2121
private readonly vsCodeGlobalStorageRoot: string;
22+
private readonly vsCodeWorkspaceStorageRoot: string | undefined;
2223

2324
constructor(private readonly context: vscode.ExtensionContext) {
2425
super();
2526
// Our extension's globalStorageUri is something like:
2627
// .../<vscode-global-storage>/advanced-security.vscode-codeql-development-mcp-server/
2728
// The parent directory is the vscode global storage root.
2829
this.vsCodeGlobalStorageRoot = dirname(context.globalStorageUri.fsPath);
30+
31+
// Our extension's storageUri (workspace-scoped) is something like:
32+
// .../<vscode-workspace-storage>/<workspace-id>/advanced-security.vscode-codeql-development-mcp-server/
33+
// The parent directory is this workspace's storage root.
34+
if (context.storageUri) {
35+
this.vsCodeWorkspaceStorageRoot = dirname(context.storageUri.fsPath);
36+
}
2937
}
3038

3139
/** Global storage directory for the vscode-codeql extension. */
@@ -34,13 +42,36 @@ export class StoragePaths extends DisposableObject {
3442
}
3543

3644
/**
37-
* Directory where vscode-codeql stores downloaded/managed databases.
38-
* Databases are stored directly under the global storage path.
45+
* Directory where vscode-codeql stores downloaded/managed databases
46+
* at the global level (e.g. databases added from GitHub).
3947
*/
4048
getDatabaseStoragePath(): string {
4149
return this.getCodeqlGlobalStoragePath();
4250
}
4351

52+
/**
53+
* Directory where vscode-codeql stores workspace-scoped databases
54+
* (e.g. databases created from repos in the current workspace).
55+
* Returns `undefined` if no workspace is open.
56+
*/
57+
getWorkspaceDatabaseStoragePath(): string | undefined {
58+
if (!this.vsCodeWorkspaceStorageRoot) return undefined;
59+
return join(this.vsCodeWorkspaceStorageRoot, VSCODE_CODEQL_EXTENSION_ID);
60+
}
61+
62+
/**
63+
* All database storage paths: global + workspace-scoped.
64+
* Suitable for colon-joining into `CODEQL_DATABASES_BASE_DIRS`.
65+
*/
66+
getAllDatabaseStoragePaths(): string[] {
67+
const paths = [this.getDatabaseStoragePath()];
68+
const workspacePath = this.getWorkspaceDatabaseStoragePath();
69+
if (workspacePath) {
70+
paths.push(workspacePath);
71+
}
72+
return paths;
73+
}
74+
4475
/**
4576
* Directory where vscode-codeql stores query results.
4677
* Path: `<globalStorageUri>/queries/<queryBasename>-<nanoid>/`

extensions/vscode/src/extension.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ export async function activate(
187187
}
188188

189189
logger.info('CodeQL Development MCP Server extension activated.');
190-
return { mcpProvider };
190+
return { environmentBuilder: envBuilder, mcpProvider, serverManager };
191191
}
192192

193193
export function deactivate(): void {

extensions/vscode/src/server/server-manager.ts

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -129,16 +129,33 @@ export class ServerManager extends DisposableObject {
129129
// ---------------------------------------------------------------------------
130130

131131
/**
132-
* Absolute path to the bundled MCP server entry point inside the extension.
133-
* Returns `undefined` if the bundled server is not present (e.g. dev build
134-
* that hasn't run `vscode:prepublish` yet).
132+
* Absolute path to the MCP server entry point.
133+
*
134+
* Checks two locations:
135+
* 1. **VSIX layout**: `<extensionRoot>/server/dist/codeql-development-mcp-server.js`
136+
* (created by `bundle:server` during `vscode:prepublish`)
137+
* 2. **Monorepo dev layout**: `<extensionRoot>/../../server/dist/codeql-development-mcp-server.js`
138+
* (the adjacent server build when running from Extension Development Host)
139+
*
140+
* Returns `undefined` if neither location exists.
135141
*/
136142
getBundledServerPath(): string | undefined {
137143
const extensionRoot = this.context.extensionUri.fsPath;
138-
const candidate = join(extensionRoot, BUNDLED_SERVER_ENTRY);
144+
145+
// VSIX layout: server files bundled inside the extension
146+
const vsixCandidate = join(extensionRoot, BUNDLED_SERVER_ENTRY);
147+
try {
148+
accessSync(vsixCandidate, constants.R_OK);
149+
return vsixCandidate;
150+
} catch {
151+
// Not in VSIX layout — try monorepo
152+
}
153+
154+
// Monorepo dev layout: extensions/vscode/../../server/dist/...
155+
const monorepoCandidate = join(extensionRoot, '..', '..', BUNDLED_SERVER_ENTRY);
139156
try {
140-
accessSync(candidate, constants.R_OK);
141-
return candidate;
157+
accessSync(monorepoCandidate, constants.R_OK);
158+
return monorepoCandidate;
142159
} catch {
143160
return undefined;
144161
}

0 commit comments

Comments
 (0)