Skip to content

Commit 3ad3644

Browse files
authored
Merge pull request #2542 from github/koesie10/override-extension-directory
Allow overriding the data extensions editor extensions directory
2 parents 77495df + aec5ff3 commit 3ad3644

File tree

3 files changed

+151
-7
lines changed

3 files changed

+151
-7
lines changed

extensions/ql-vscode/src/config.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
EventEmitter,
66
ConfigurationChangeEvent,
77
ConfigurationTarget,
8+
ConfigurationScope,
89
} from "vscode";
910
import { DistributionManager } from "./codeql-cli/distribution";
1011
import { extLogger } from "./common/logging/vscode";
@@ -44,12 +45,12 @@ export class Setting {
4445
}
4546
}
4647

47-
getValue<T>(): T {
48+
getValue<T>(scope?: ConfigurationScope | null): T {
4849
if (this.parent === undefined) {
4950
throw new Error("Cannot get the value of a root setting.");
5051
}
5152
return workspace
52-
.getConfiguration(this.parent.qualifiedName)
53+
.getConfiguration(this.parent.qualifiedName, scope)
5354
.get<T>(this.name)!;
5455
}
5556

@@ -719,6 +720,10 @@ const DISABLE_AUTO_NAME_EXTENSION_PACK = new Setting(
719720
"disableAutoNameExtensionPack",
720721
DATA_EXTENSIONS,
721722
);
723+
const EXTENSIONS_DIRECTORY = new Setting(
724+
"extensionsDirectory",
725+
DATA_EXTENSIONS,
726+
);
722727

723728
export function showLlmGeneration(): boolean {
724729
return !!LLM_GENERATION.getValue<boolean>();
@@ -731,3 +736,9 @@ export function enableFrameworkMode(): boolean {
731736
export function disableAutoNameExtensionPack(): boolean {
732737
return !!DISABLE_AUTO_NAME_EXTENSION_PACK.getValue<boolean>();
733738
}
739+
740+
export function getExtensionsDirectory(languageId: string): string | undefined {
741+
return EXTENSIONS_DIRECTORY.getValue<string>({
742+
languageId,
743+
});
744+
}

extensions/ql-vscode/src/data-extensions-editor/extension-pack-picker.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { join } from "path";
22
import { outputFile, pathExists, readFile } from "fs-extra";
33
import { dump as dumpYaml, load as loadYaml } from "js-yaml";
4-
import { CancellationToken, window } from "vscode";
4+
import { CancellationToken, Uri, window } from "vscode";
55
import { CodeQLCliServer, QlpacksInfo } from "../codeql-cli/cli";
66
import { getOnDiskWorkspaceFolders } from "../common/vscode/workspace-folders";
77
import { ProgressCallback } from "../common/vscode/progress";
@@ -10,7 +10,10 @@ import { getQlPackPath, QLPACK_FILENAMES } from "../common/ql";
1010
import { getErrorMessage } from "../common/helpers-pure";
1111
import { ExtensionPack } from "./shared/extension-pack";
1212
import { NotificationLogger, showAndLogErrorMessage } from "../common/logging";
13-
import { disableAutoNameExtensionPack } from "../config";
13+
import {
14+
disableAutoNameExtensionPack,
15+
getExtensionsDirectory,
16+
} from "../config";
1417
import {
1518
autoNameExtensionPack,
1619
ExtensionPackName,
@@ -219,8 +222,14 @@ async function autoCreateExtensionPack(
219222
extensionPacksInfo: QlpacksInfo,
220223
logger: NotificationLogger,
221224
): Promise<ExtensionPack | undefined> {
222-
// Get the extensions directory to create the extension pack in
223-
const extensionsDirectory = await autoPickExtensionsDirectory();
225+
// Get the `codeQL.dataExtensions.extensionsDirectory` setting for the language
226+
const userExtensionsDirectory = getExtensionsDirectory(language);
227+
228+
// If the setting is not set, automatically pick a suitable directory
229+
const extensionsDirectory = userExtensionsDirectory
230+
? Uri.file(userExtensionsDirectory)
231+
: await autoPickExtensionsDirectory();
232+
224233
if (!extensionsDirectory) {
225234
return undefined;
226235
}

extensions/ql-vscode/test/vscode-tests/no-workspace/data-extensions-editor/extension-pack-picker.test.ts

Lines changed: 125 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import {
22
CancellationTokenSource,
3+
ConfigurationScope,
34
QuickPickItem,
45
Uri,
56
window,
67
workspace,
8+
WorkspaceConfiguration as VSCodeWorkspaceConfiguration,
79
WorkspaceFolder,
810
} from "vscode";
911
import { dump as dumpYaml, load as loadYaml } from "js-yaml";
@@ -17,6 +19,7 @@ import * as config from "../../../../src/config";
1719
import { pickExtensionPack } from "../../../../src/data-extensions-editor/extension-pack-picker";
1820
import { ExtensionPack } from "../../../../src/data-extensions-editor/shared/extension-pack";
1921
import { createMockLogger } from "../../../__mocks__/loggerMock";
22+
import { vscodeGetConfigurationMock } from "../../test-config";
2023

2124
describe("pickExtensionPack", () => {
2225
let tmpDir: string;
@@ -153,6 +156,31 @@ describe("pickExtensionPack", () => {
153156

154157
it("automatically selects an extension pack", async () => {
155158
disableAutoNameExtensionPackSpy.mockReturnValue(false);
159+
vscodeGetConfigurationMock.mockImplementation(
160+
(
161+
section?: string,
162+
scope?: ConfigurationScope | null,
163+
): VSCodeWorkspaceConfiguration => {
164+
expect(section).toEqual("codeQL.dataExtensions");
165+
expect((scope as any)?.languageId).toEqual("java");
166+
167+
return {
168+
get: (key: string) => {
169+
expect(key).toEqual("extensionsDirectory");
170+
return undefined;
171+
},
172+
has: (key: string) => {
173+
return key === "extensionsDirectory";
174+
},
175+
inspect: () => {
176+
throw new Error("inspect not implemented");
177+
},
178+
update: () => {
179+
throw new Error("update not implemented");
180+
},
181+
};
182+
},
183+
);
156184

157185
const cliServer = mockCliServer(qlPacks);
158186

@@ -167,8 +195,33 @@ describe("pickExtensionPack", () => {
167195
);
168196
});
169197

170-
it("automatically creates an extension pack", async () => {
198+
it("automatically creates an extension pack and selects an extensions directory", async () => {
171199
disableAutoNameExtensionPackSpy.mockReturnValue(false);
200+
vscodeGetConfigurationMock.mockImplementation(
201+
(
202+
section?: string,
203+
scope?: ConfigurationScope | null,
204+
): VSCodeWorkspaceConfiguration => {
205+
expect(section).toEqual("codeQL.dataExtensions");
206+
expect((scope as any)?.languageId).toEqual("java");
207+
208+
return {
209+
get: (key: string) => {
210+
expect(key).toEqual("extensionsDirectory");
211+
return undefined;
212+
},
213+
has: (key: string) => {
214+
return key === "extensionsDirectory";
215+
},
216+
inspect: () => {
217+
throw new Error("inspect not implemented");
218+
},
219+
update: () => {
220+
throw new Error("update not implemented");
221+
},
222+
};
223+
},
224+
);
172225

173226
const tmpDir = await dir({
174227
unsafeCleanup: true,
@@ -237,6 +290,77 @@ describe("pickExtensionPack", () => {
237290
});
238291
});
239292

293+
it("automatically creates an extension pack when extensions directory is set in config", async () => {
294+
disableAutoNameExtensionPackSpy.mockReturnValue(false);
295+
296+
const tmpDir = await dir({
297+
unsafeCleanup: true,
298+
});
299+
300+
const configExtensionsDir = join(
301+
Uri.file(tmpDir.path).fsPath,
302+
"my-custom-extensions-directory",
303+
);
304+
305+
vscodeGetConfigurationMock.mockImplementation(
306+
(
307+
section?: string,
308+
scope?: ConfigurationScope | null,
309+
): VSCodeWorkspaceConfiguration => {
310+
expect(section).toEqual("codeQL.dataExtensions");
311+
expect((scope as any)?.languageId).toEqual("java");
312+
313+
return {
314+
get: (key: string) => {
315+
expect(key).toEqual("extensionsDirectory");
316+
return configExtensionsDir;
317+
},
318+
has: (key: string) => {
319+
return key === "extensionsDirectory";
320+
},
321+
inspect: () => {
322+
throw new Error("inspect not implemented");
323+
},
324+
update: () => {
325+
throw new Error("update not implemented");
326+
},
327+
};
328+
},
329+
);
330+
331+
const newPackDir = join(configExtensionsDir, "vscode-codeql-java");
332+
333+
const cliServer = mockCliServer({});
334+
335+
expect(
336+
await pickExtensionPack(cliServer, databaseItem, logger, progress, token),
337+
).toEqual({
338+
path: newPackDir,
339+
yamlPath: join(newPackDir, "codeql-pack.yml"),
340+
name: "github/vscode-codeql-java",
341+
version: "0.0.0",
342+
extensionTargets: {
343+
"codeql/java-all": "*",
344+
},
345+
dataExtensions: ["models/**/*.yml"],
346+
});
347+
expect(showQuickPickSpy).not.toHaveBeenCalled();
348+
expect(showInputBoxSpy).not.toHaveBeenCalled();
349+
expect(cliServer.resolveQlpacks).toHaveBeenCalled();
350+
351+
expect(
352+
loadYaml(await readFile(join(newPackDir, "codeql-pack.yml"), "utf8")),
353+
).toEqual({
354+
name: "github/vscode-codeql-java",
355+
version: "0.0.0",
356+
library: true,
357+
extensionTargets: {
358+
"codeql/java-all": "*",
359+
},
360+
dataExtensions: ["models/**/*.yml"],
361+
});
362+
});
363+
240364
it("allows cancelling the prompt", async () => {
241365
const cliServer = mockCliServer(qlPacks);
242366

0 commit comments

Comments
 (0)