Merge pull request #2542 from github/koesie10/override-extension-directory

Allow overriding the data extensions editor extensions directory
This commit is contained in:
Koen Vlaswinkel
2023-06-27 15:13:59 +02:00
committed by GitHub
3 changed files with 151 additions and 7 deletions

View File

@@ -5,6 +5,7 @@ import {
EventEmitter,
ConfigurationChangeEvent,
ConfigurationTarget,
ConfigurationScope,
} from "vscode";
import { DistributionManager } from "./codeql-cli/distribution";
import { extLogger } from "./common/logging/vscode";
@@ -44,12 +45,12 @@ export class Setting {
}
}
getValue<T>(): T {
getValue<T>(scope?: ConfigurationScope | null): T {
if (this.parent === undefined) {
throw new Error("Cannot get the value of a root setting.");
}
return workspace
.getConfiguration(this.parent.qualifiedName)
.getConfiguration(this.parent.qualifiedName, scope)
.get<T>(this.name)!;
}
@@ -719,6 +720,10 @@ const DISABLE_AUTO_NAME_EXTENSION_PACK = new Setting(
"disableAutoNameExtensionPack",
DATA_EXTENSIONS,
);
const EXTENSIONS_DIRECTORY = new Setting(
"extensionsDirectory",
DATA_EXTENSIONS,
);
export function showLlmGeneration(): boolean {
return !!LLM_GENERATION.getValue<boolean>();
@@ -731,3 +736,9 @@ export function enableFrameworkMode(): boolean {
export function disableAutoNameExtensionPack(): boolean {
return !!DISABLE_AUTO_NAME_EXTENSION_PACK.getValue<boolean>();
}
export function getExtensionsDirectory(languageId: string): string | undefined {
return EXTENSIONS_DIRECTORY.getValue<string>({
languageId,
});
}

View File

@@ -1,7 +1,7 @@
import { join } from "path";
import { outputFile, pathExists, readFile } from "fs-extra";
import { dump as dumpYaml, load as loadYaml } from "js-yaml";
import { CancellationToken, window } from "vscode";
import { CancellationToken, Uri, window } from "vscode";
import { CodeQLCliServer, QlpacksInfo } from "../codeql-cli/cli";
import { getOnDiskWorkspaceFolders } from "../common/vscode/workspace-folders";
import { ProgressCallback } from "../common/vscode/progress";
@@ -10,7 +10,10 @@ import { getQlPackPath, QLPACK_FILENAMES } from "../common/ql";
import { getErrorMessage } from "../common/helpers-pure";
import { ExtensionPack } from "./shared/extension-pack";
import { NotificationLogger, showAndLogErrorMessage } from "../common/logging";
import { disableAutoNameExtensionPack } from "../config";
import {
disableAutoNameExtensionPack,
getExtensionsDirectory,
} from "../config";
import {
autoNameExtensionPack,
ExtensionPackName,
@@ -219,8 +222,14 @@ async function autoCreateExtensionPack(
extensionPacksInfo: QlpacksInfo,
logger: NotificationLogger,
): Promise<ExtensionPack | undefined> {
// Get the extensions directory to create the extension pack in
const extensionsDirectory = await autoPickExtensionsDirectory();
// Get the `codeQL.dataExtensions.extensionsDirectory` setting for the language
const userExtensionsDirectory = getExtensionsDirectory(language);
// If the setting is not set, automatically pick a suitable directory
const extensionsDirectory = userExtensionsDirectory
? Uri.file(userExtensionsDirectory)
: await autoPickExtensionsDirectory();
if (!extensionsDirectory) {
return undefined;
}

View File

@@ -1,9 +1,11 @@
import {
CancellationTokenSource,
ConfigurationScope,
QuickPickItem,
Uri,
window,
workspace,
WorkspaceConfiguration as VSCodeWorkspaceConfiguration,
WorkspaceFolder,
} from "vscode";
import { dump as dumpYaml, load as loadYaml } from "js-yaml";
@@ -17,6 +19,7 @@ import * as config from "../../../../src/config";
import { pickExtensionPack } from "../../../../src/data-extensions-editor/extension-pack-picker";
import { ExtensionPack } from "../../../../src/data-extensions-editor/shared/extension-pack";
import { createMockLogger } from "../../../__mocks__/loggerMock";
import { vscodeGetConfigurationMock } from "../../test-config";
describe("pickExtensionPack", () => {
let tmpDir: string;
@@ -153,6 +156,31 @@ describe("pickExtensionPack", () => {
it("automatically selects an extension pack", async () => {
disableAutoNameExtensionPackSpy.mockReturnValue(false);
vscodeGetConfigurationMock.mockImplementation(
(
section?: string,
scope?: ConfigurationScope | null,
): VSCodeWorkspaceConfiguration => {
expect(section).toEqual("codeQL.dataExtensions");
expect((scope as any)?.languageId).toEqual("java");
return {
get: (key: string) => {
expect(key).toEqual("extensionsDirectory");
return undefined;
},
has: (key: string) => {
return key === "extensionsDirectory";
},
inspect: () => {
throw new Error("inspect not implemented");
},
update: () => {
throw new Error("update not implemented");
},
};
},
);
const cliServer = mockCliServer(qlPacks);
@@ -167,8 +195,33 @@ describe("pickExtensionPack", () => {
);
});
it("automatically creates an extension pack", async () => {
it("automatically creates an extension pack and selects an extensions directory", async () => {
disableAutoNameExtensionPackSpy.mockReturnValue(false);
vscodeGetConfigurationMock.mockImplementation(
(
section?: string,
scope?: ConfigurationScope | null,
): VSCodeWorkspaceConfiguration => {
expect(section).toEqual("codeQL.dataExtensions");
expect((scope as any)?.languageId).toEqual("java");
return {
get: (key: string) => {
expect(key).toEqual("extensionsDirectory");
return undefined;
},
has: (key: string) => {
return key === "extensionsDirectory";
},
inspect: () => {
throw new Error("inspect not implemented");
},
update: () => {
throw new Error("update not implemented");
},
};
},
);
const tmpDir = await dir({
unsafeCleanup: true,
@@ -237,6 +290,77 @@ describe("pickExtensionPack", () => {
});
});
it("automatically creates an extension pack when extensions directory is set in config", async () => {
disableAutoNameExtensionPackSpy.mockReturnValue(false);
const tmpDir = await dir({
unsafeCleanup: true,
});
const configExtensionsDir = join(
Uri.file(tmpDir.path).fsPath,
"my-custom-extensions-directory",
);
vscodeGetConfigurationMock.mockImplementation(
(
section?: string,
scope?: ConfigurationScope | null,
): VSCodeWorkspaceConfiguration => {
expect(section).toEqual("codeQL.dataExtensions");
expect((scope as any)?.languageId).toEqual("java");
return {
get: (key: string) => {
expect(key).toEqual("extensionsDirectory");
return configExtensionsDir;
},
has: (key: string) => {
return key === "extensionsDirectory";
},
inspect: () => {
throw new Error("inspect not implemented");
},
update: () => {
throw new Error("update not implemented");
},
};
},
);
const newPackDir = join(configExtensionsDir, "vscode-codeql-java");
const cliServer = mockCliServer({});
expect(
await pickExtensionPack(cliServer, databaseItem, logger, progress, token),
).toEqual({
path: newPackDir,
yamlPath: join(newPackDir, "codeql-pack.yml"),
name: "github/vscode-codeql-java",
version: "0.0.0",
extensionTargets: {
"codeql/java-all": "*",
},
dataExtensions: ["models/**/*.yml"],
});
expect(showQuickPickSpy).not.toHaveBeenCalled();
expect(showInputBoxSpy).not.toHaveBeenCalled();
expect(cliServer.resolveQlpacks).toHaveBeenCalled();
expect(
loadYaml(await readFile(join(newPackDir, "codeql-pack.yml"), "utf8")),
).toEqual({
name: "github/vscode-codeql-java",
version: "0.0.0",
library: true,
extensionTargets: {
"codeql/java-all": "*",
},
dataExtensions: ["models/**/*.yml"],
});
});
it("allows cancelling the prompt", async () => {
const cliServer = mockCliServer(qlPacks);