diff --git a/extensions/ql-vscode/src/config.ts b/extensions/ql-vscode/src/config.ts index f663d6fcc..070f17d54 100644 --- a/extensions/ql-vscode/src/config.ts +++ b/extensions/ql-vscode/src/config.ts @@ -707,20 +707,12 @@ export function showQueriesPanel(): boolean { const MODEL_SETTING = new Setting("model", ROOT_SETTING); const LLM_GENERATION = new Setting("llmGeneration", MODEL_SETTING); -const DISABLE_AUTO_NAME_EXTENSION_PACK = new Setting( - "disableAutoNameExtensionPack", - MODEL_SETTING, -); const EXTENSIONS_DIRECTORY = new Setting("extensionsDirectory", MODEL_SETTING); export function showLlmGeneration(): boolean { return !!LLM_GENERATION.getValue(); } -export function disableAutoNameExtensionPack(): boolean { - return !!DISABLE_AUTO_NAME_EXTENSION_PACK.getValue(); -} - export function getExtensionsDirectory(languageId: string): string | undefined { return EXTENSIONS_DIRECTORY.getValue({ languageId, diff --git a/extensions/ql-vscode/src/model-editor/extension-pack-picker.ts b/extensions/ql-vscode/src/model-editor/extension-pack-picker.ts index 133000334..4e87cfe15 100644 --- a/extensions/ql-vscode/src/model-editor/extension-pack-picker.ts +++ b/extensions/ql-vscode/src/model-editor/extension-pack-picker.ts @@ -1,8 +1,8 @@ import { join } from "path"; import { outputFile, pathExists, readFile } from "fs-extra"; import { dump as dumpYaml, load as loadYaml } from "js-yaml"; -import { CancellationToken, Uri, window } from "vscode"; -import { CodeQLCliServer, QlpacksInfo } from "../codeql-cli/cli"; +import { Uri } from "vscode"; +import { CodeQLCliServer } from "../codeql-cli/cli"; import { getOnDiskWorkspaceFolders } from "../common/vscode/workspace-folders"; import { ProgressCallback } from "../common/vscode/progress"; import { DatabaseItem } from "../databases/local-databases"; @@ -10,21 +10,13 @@ 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, - getExtensionsDirectory, -} from "../config"; +import { getExtensionsDirectory } from "../config"; import { autoNameExtensionPack, ExtensionPackName, formatPackName, - parsePackName, - validatePackName, } from "./extension-pack-name"; -import { - askForWorkspaceFolder, - autoPickExtensionsDirectory, -} from "./extensions-workspace-folder"; +import { autoPickExtensionsDirectory } from "./extensions-workspace-folder"; const maxStep = 3; @@ -33,7 +25,6 @@ export async function pickExtensionPack( databaseItem: Pick, logger: NotificationLogger, progress: ProgressCallback, - token: CancellationToken, ): Promise { progress({ message: "Resolving extension packs...", @@ -52,182 +43,14 @@ export async function pickExtensionPack( true, ); - if (!disableAutoNameExtensionPack()) { - progress({ - message: "Creating extension pack...", - step: 2, - maxStep, - }); - - return autoCreateExtensionPack( - databaseItem.name, - databaseItem.language, - extensionPacksInfo, - logger, - ); - } - - if (Object.keys(extensionPacksInfo).length === 0) { - return pickNewExtensionPack(databaseItem, token); - } - - const extensionPacks = ( - await Promise.all( - Object.entries(extensionPacksInfo).map(async ([name, paths]) => { - if (paths.length !== 1) { - void showAndLogErrorMessage( - logger, - `Extension pack ${name} resolves to multiple paths`, - { - fullMessage: `Extension pack ${name} resolves to multiple paths: ${paths.join( - ", ", - )}`, - }, - ); - - return undefined; - } - - const path = paths[0]; - - let extensionPack: ExtensionPack; - try { - extensionPack = await readExtensionPack(path, databaseItem.language); - } catch (e: unknown) { - void showAndLogErrorMessage( - logger, - `Could not read extension pack ${name}`, - { - fullMessage: `Could not read extension pack ${name} at ${path}: ${getErrorMessage( - e, - )}`, - }, - ); - - return undefined; - } - - return extensionPack; - }), - ) - ).filter((info): info is ExtensionPack => info !== undefined); - - const extensionPacksForLanguage = extensionPacks.filter( - (pack) => - pack.extensionTargets[`codeql/${databaseItem.language}-all`] !== - undefined, - ); - - const options: Array<{ - label: string; - description: string | undefined; - detail: string | undefined; - extensionPack: ExtensionPack | null; - }> = extensionPacksForLanguage.map((pack) => ({ - label: pack.name, - description: pack.version, - detail: pack.path, - extensionPack: pack, - })); - options.push({ - label: "Create new extension pack", - description: undefined, - detail: undefined, - extensionPack: null, - }); - progress({ - message: "Choosing extension pack...", + message: "Creating extension pack...", step: 2, maxStep, }); - const extensionPackOption = await window.showQuickPick( - options, - { - title: "Select extension pack to use", - }, - token, - ); - if (!extensionPackOption) { - return undefined; - } - - if (!extensionPackOption.extensionPack) { - return pickNewExtensionPack(databaseItem, token); - } - - return extensionPackOption.extensionPack; -} - -async function pickNewExtensionPack( - databaseItem: Pick, - token: CancellationToken, -): Promise { - const workspaceFolder = await askForWorkspaceFolder(); - if (!workspaceFolder) { - return undefined; - } - - const examplePackName = autoNameExtensionPack( - databaseItem.name, - databaseItem.language, - ); - - const name = await window.showInputBox( - { - title: "Create new extension pack", - prompt: "Enter name of extension pack", - placeHolder: examplePackName - ? `e.g. ${formatPackName(examplePackName)}` - : "", - validateInput: async (value: string): Promise => { - const message = validatePackName(value); - if (message) { - return message; - } - - const packName = parsePackName(value); - if (!packName) { - return "Invalid pack name"; - } - - const packPath = join(workspaceFolder.uri.fsPath, packName.name); - if (await pathExists(packPath)) { - return `A pack already exists at ${packPath}`; - } - - return undefined; - }, - }, - token, - ); - if (!name) { - return undefined; - } - - const packName = parsePackName(name); - if (!packName) { - return undefined; - } - - const packPath = join(workspaceFolder.uri.fsPath, packName.name); - - if (await pathExists(packPath)) { - return undefined; - } - - return writeExtensionPack(packPath, packName, databaseItem.language); -} - -async function autoCreateExtensionPack( - name: string, - language: string, - extensionPacksInfo: QlpacksInfo, - logger: NotificationLogger, -): Promise { // Get the `codeQL.model.extensionsDirectory` setting for the language - const userExtensionsDirectory = getExtensionsDirectory(language); + const userExtensionsDirectory = getExtensionsDirectory(databaseItem.language); // If the setting is not set, automatically pick a suitable directory const extensionsDirectory = userExtensionsDirectory @@ -239,11 +62,14 @@ async function autoCreateExtensionPack( } // Generate the name of the extension pack - const packName = autoNameExtensionPack(name, language); + const packName = autoNameExtensionPack( + databaseItem.name, + databaseItem.language, + ); if (!packName) { void showAndLogErrorMessage( logger, - `Could not automatically name extension pack for database ${name}`, + `Could not automatically name extension pack for database ${databaseItem.name}`, ); return undefined; @@ -259,7 +85,7 @@ async function autoCreateExtensionPack( try { extensionPack = await readExtensionPack( existingExtensionPackPaths[0], - language, + databaseItem.language, ); } catch (e: unknown) { void showAndLogErrorMessage( @@ -309,7 +135,7 @@ async function autoCreateExtensionPack( return undefined; } - return writeExtensionPack(packPath, packName, language); + return writeExtensionPack(packPath, packName, databaseItem.language); } async function writeExtensionPack( diff --git a/extensions/ql-vscode/src/model-editor/extensions-workspace-folder.ts b/extensions/ql-vscode/src/model-editor/extensions-workspace-folder.ts index ef09aa161..729bf0b52 100644 --- a/extensions/ql-vscode/src/model-editor/extensions-workspace-folder.ts +++ b/extensions/ql-vscode/src/model-editor/extensions-workspace-folder.ts @@ -1,4 +1,4 @@ -import { FileType, Uri, window, workspace, WorkspaceFolder } from "vscode"; +import { FileType, Uri, workspace, WorkspaceFolder } from "vscode"; import { getOnDiskWorkspaceFoldersObjects } from "../common/vscode/workspace-folders"; import { extLogger } from "../common/logging/vscode"; import { tmpdir } from "../common/files"; @@ -200,25 +200,3 @@ export async function autoPickExtensionsDirectory(): Promise { return extensionsUri; } - -export async function askForWorkspaceFolder(): Promise< - WorkspaceFolder | undefined -> { - const workspaceFolders = getOnDiskWorkspaceFoldersObjects(); - const workspaceFolderOptions = workspaceFolders.map((folder) => ({ - label: folder.name, - detail: folder.uri.fsPath, - folder, - })); - - // We're not using window.showWorkspaceFolderPick because that also includes the database source folders while - // we only want to include on-disk workspace folders. - const workspaceFolder = await window.showQuickPick(workspaceFolderOptions, { - title: "Select workspace folder to create extension pack in", - }); - if (!workspaceFolder) { - return undefined; - } - - return workspaceFolder.folder; -} diff --git a/extensions/ql-vscode/src/model-editor/model-editor-module.ts b/extensions/ql-vscode/src/model-editor/model-editor-module.ts index 639496b87..d2630d9c3 100644 --- a/extensions/ql-vscode/src/model-editor/model-editor-module.ts +++ b/extensions/ql-vscode/src/model-editor/model-editor-module.ts @@ -101,7 +101,7 @@ export class ModelEditorModule extends DisposableObject { } return withProgress( - async (progress, token) => { + async (progress) => { if (!(await this.cliServer.cliConstraints.supportsQlpacksKind())) { void showAndLogErrorMessage( this.app.logger, @@ -125,7 +125,6 @@ export class ModelEditorModule extends DisposableObject { db, this.app.logger, progress, - token, ); if (!modelFile) { return; diff --git a/extensions/ql-vscode/src/model-editor/model-editor-view.ts b/extensions/ql-vscode/src/model-editor/model-editor-view.ts index d56f816b1..ceaad33c3 100644 --- a/extensions/ql-vscode/src/model-editor/model-editor-view.ts +++ b/extensions/ql-vscode/src/model-editor/model-editor-view.ts @@ -483,7 +483,6 @@ export class ModelEditorView extends AbstractWebview< addedDatabase, this.app.logger, progress, - token, ); if (!modelFile) { return; diff --git a/extensions/ql-vscode/test/vscode-tests/no-workspace/model-editor/extension-pack-picker.test.ts b/extensions/ql-vscode/test/vscode-tests/no-workspace/model-editor/extension-pack-picker.test.ts index 191ac7aec..6b561ac37 100644 --- a/extensions/ql-vscode/test/vscode-tests/no-workspace/model-editor/extension-pack-picker.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/no-workspace/model-editor/extension-pack-picker.test.ts @@ -1,9 +1,6 @@ import { - CancellationTokenSource, ConfigurationScope, - QuickPickItem, Uri, - window, workspace, WorkspaceConfiguration as VSCodeWorkspaceConfiguration, WorkspaceFolder, @@ -14,8 +11,6 @@ import { join } from "path"; import { dir } from "tmp-promise"; import { QlpacksInfo } from "../../../../src/codeql-cli/cli"; -import * as config from "../../../../src/config"; - import { pickExtensionPack } from "../../../../src/model-editor/extension-pack-picker"; import { ExtensionPack } from "../../../../src/model-editor/shared/extension-pack"; import { createMockLogger } from "../../../__mocks__/loggerMock"; @@ -23,11 +18,8 @@ import { vscodeGetConfigurationMock } from "../../test-config"; describe("pickExtensionPack", () => { let tmpDir: string; - let extensionPackPath: string; - let anotherExtensionPackPath: string; + const autoExtensionPackName = "github/vscode-codeql-java"; let autoExtensionPackPath: string; - let extensionPack: ExtensionPack; - let anotherExtensionPack: ExtensionPack; let autoExtensionPack: ExtensionPack; let qlPacks: QlpacksInfo; @@ -36,15 +28,7 @@ describe("pickExtensionPack", () => { language: "java", }; - const cancellationTokenSource = new CancellationTokenSource(); - const token = cancellationTokenSource.token; - const progress = jest.fn(); - let showQuickPickSpy: jest.SpiedFunction; - let showInputBoxSpy: jest.SpiedFunction; - let disableAutoNameExtensionPackSpy: jest.SpiedFunction< - typeof config.disableAutoNameExtensionPack - >; let workspaceFoldersSpy: jest.SpyInstance; let additionalPacks: string[]; let workspaceFolder: WorkspaceFolder; @@ -59,41 +43,17 @@ describe("pickExtensionPack", () => { ).path; // Uri.file(...).fsPath normalizes the filenames so we can properly compare them on Windows - extensionPackPath = Uri.file(join(tmpDir, "my-extension-pack")).fsPath; - anotherExtensionPackPath = Uri.file( - join(tmpDir, "another-extension-pack"), - ).fsPath; autoExtensionPackPath = Uri.file(join(tmpDir, "vscode-codeql-java")).fsPath; qlPacks = { - "my-extension-pack": [extensionPackPath], - "another-extension-pack": [anotherExtensionPackPath], "github/vscode-codeql-java": [autoExtensionPackPath], }; - extensionPack = await createMockExtensionPack( - extensionPackPath, - "my-extension-pack", - ); - anotherExtensionPack = await createMockExtensionPack( - anotherExtensionPackPath, - "another-extension-pack", - ); autoExtensionPack = await createMockExtensionPack( autoExtensionPackPath, - "github/vscode-codeql-java", + autoExtensionPackName, ); - showQuickPickSpy = jest - .spyOn(window, "showQuickPick") - .mockRejectedValue(new Error("Unexpected call to showQuickPick")); - showInputBoxSpy = jest - .spyOn(window, "showInputBox") - .mockRejectedValue(new Error("Unexpected call to showInputBox")); - disableAutoNameExtensionPackSpy = jest - .spyOn(config, "disableAutoNameExtensionPack") - .mockReturnValue(true); - workspaceFolder = { uri: Uri.file(tmpDir), name: "codeql-custom-queries-java", @@ -108,57 +68,7 @@ describe("pickExtensionPack", () => { .mockReturnValue([workspaceFolder]); }); - it("allows choosing an existing extension pack", async () => { - const cliServer = mockCliServer(qlPacks); - - showQuickPickSpy.mockResolvedValueOnce({ - label: "my-extension-pack", - extensionPack, - } as QuickPickItem); - - expect( - await pickExtensionPack(cliServer, databaseItem, logger, progress, token), - ).toEqual(extensionPack); - expect(showQuickPickSpy).toHaveBeenCalledTimes(1); - expect(showQuickPickSpy).toHaveBeenCalledWith( - [ - { - label: "my-extension-pack", - description: "0.0.0", - detail: extensionPackPath, - extensionPack, - }, - { - label: "another-extension-pack", - description: "0.0.0", - detail: anotherExtensionPackPath, - extensionPack: anotherExtensionPack, - }, - { - label: "github/vscode-codeql-java", - description: "0.0.0", - detail: autoExtensionPackPath, - extensionPack: autoExtensionPack, - }, - { - label: expect.stringMatching(/create/i), - extensionPack: null, - }, - ], - { - title: expect.any(String), - }, - token, - ); - expect(cliServer.resolveQlpacks).toHaveBeenCalledTimes(1); - expect(cliServer.resolveQlpacks).toHaveBeenCalledWith( - additionalPacks, - true, - ); - }); - - it("automatically selects an extension pack", async () => { - disableAutoNameExtensionPackSpy.mockReturnValue(false); + it("selects an existing extension pack", async () => { vscodeGetConfigurationMock.mockImplementation( ( section?: string, @@ -188,9 +98,8 @@ describe("pickExtensionPack", () => { const cliServer = mockCliServer(qlPacks); expect( - await pickExtensionPack(cliServer, databaseItem, logger, progress, token), + await pickExtensionPack(cliServer, databaseItem, logger, progress), ).toEqual(autoExtensionPack); - expect(showQuickPickSpy).not.toHaveBeenCalled(); expect(cliServer.resolveQlpacks).toHaveBeenCalledTimes(1); expect(cliServer.resolveQlpacks).toHaveBeenCalledWith( additionalPacks, @@ -198,8 +107,7 @@ describe("pickExtensionPack", () => { ); }); - it("automatically creates an extension pack and selects an extensions directory", async () => { - disableAutoNameExtensionPackSpy.mockReturnValue(false); + it("creates a new extension pack using default extensions directory", async () => { vscodeGetConfigurationMock.mockImplementation( ( section?: string, @@ -265,11 +173,11 @@ describe("pickExtensionPack", () => { const cliServer = mockCliServer({}); expect( - await pickExtensionPack(cliServer, databaseItem, logger, progress, token), + await pickExtensionPack(cliServer, databaseItem, logger, progress), ).toEqual({ path: newPackDir, yamlPath: join(newPackDir, "codeql-pack.yml"), - name: "github/vscode-codeql-java", + name: autoExtensionPackName, version: "0.0.0", language: "java", extensionTargets: { @@ -277,14 +185,12 @@ describe("pickExtensionPack", () => { }, 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", + name: autoExtensionPackName, version: "0.0.0", library: true, extensionTargets: { @@ -294,9 +200,7 @@ describe("pickExtensionPack", () => { }); }); - it("automatically creates an extension pack when extensions directory is set in config", async () => { - disableAutoNameExtensionPackSpy.mockReturnValue(false); - + it("creates a new extension pack when extensions directory is set in config", async () => { const tmpDir = await dir({ unsafeCleanup: true, }); @@ -337,11 +241,11 @@ describe("pickExtensionPack", () => { const cliServer = mockCliServer({}); expect( - await pickExtensionPack(cliServer, databaseItem, logger, progress, token), + await pickExtensionPack(cliServer, databaseItem, logger, progress), ).toEqual({ path: newPackDir, yamlPath: join(newPackDir, "codeql-pack.yml"), - name: "github/vscode-codeql-java", + name: autoExtensionPackName, version: "0.0.0", language: "java", extensionTargets: { @@ -349,14 +253,12 @@ describe("pickExtensionPack", () => { }, 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", + name: autoExtensionPackName, version: "0.0.0", library: true, extensionTargets: { @@ -366,208 +268,21 @@ describe("pickExtensionPack", () => { }); }); - it("allows cancelling the prompt", async () => { - const cliServer = mockCliServer(qlPacks); - - showQuickPickSpy.mockResolvedValueOnce(undefined); - - expect( - await pickExtensionPack(cliServer, databaseItem, logger, progress, token), - ).toEqual(undefined); - expect(cliServer.resolveQlpacks).toHaveBeenCalled(); - }); - - it("allows user to create an extension pack when there are no extension packs", async () => { - const cliServer = mockCliServer({}); - - const tmpDir = await dir({ - unsafeCleanup: true, - }); - - const newPackDir = join(Uri.file(tmpDir.path).fsPath, "new-extension-pack"); - - showQuickPickSpy.mockResolvedValueOnce({ - label: "codeql-custom-queries-java", - folder: { - uri: Uri.file(tmpDir.path), - name: "codeql-custom-queries-java", - index: 0, - }, - } as QuickPickItem); - showInputBoxSpy.mockResolvedValueOnce("pack/new-extension-pack"); - showInputBoxSpy.mockResolvedValue("models/my-model.yml"); - - expect( - await pickExtensionPack(cliServer, databaseItem, logger, progress, token), - ).toEqual({ - path: newPackDir, - yamlPath: join(newPackDir, "codeql-pack.yml"), - name: "pack/new-extension-pack", - version: "0.0.0", - language: "java", - extensionTargets: { - "codeql/java-all": "*", - }, - dataExtensions: ["models/**/*.yml"], - }); - expect(showQuickPickSpy).toHaveBeenCalledTimes(1); - expect(showInputBoxSpy).toHaveBeenCalledTimes(1); - expect(showInputBoxSpy).toHaveBeenCalledWith( - { - title: expect.stringMatching(/extension pack/i), - prompt: expect.stringMatching(/extension pack/i), - placeHolder: expect.stringMatching(/github\/vscode-codeql-java/), - validateInput: expect.any(Function), - }, - token, - ); - expect(cliServer.resolveQlpacks).toHaveBeenCalled(); - - expect( - loadYaml(await readFile(join(newPackDir, "codeql-pack.yml"), "utf8")), - ).toEqual({ - name: "pack/new-extension-pack", - version: "0.0.0", - library: true, - extensionTargets: { - "codeql/java-all": "*", - }, - dataExtensions: ["models/**/*.yml"], - }); - }); - - it("allows user to create an extension pack when there are no extension packs with a different language", async () => { - const cliServer = mockCliServer({}); - - const tmpDir = await dir({ - unsafeCleanup: true, - }); - - const newPackDir = join(Uri.file(tmpDir.path).fsPath, "new-extension-pack"); - - showQuickPickSpy.mockResolvedValueOnce({ - label: "codeql-custom-queries-java", - folder: { - uri: Uri.file(tmpDir.path), - name: "codeql-custom-queries-java", - index: 0, - }, - } as QuickPickItem); - showInputBoxSpy.mockResolvedValueOnce("pack/new-extension-pack"); - showInputBoxSpy.mockResolvedValue("models/my-model.yml"); - - expect( - await pickExtensionPack( - cliServer, - { - ...databaseItem, - language: "csharp", - }, - logger, - progress, - token, - ), - ).toEqual({ - path: newPackDir, - yamlPath: join(newPackDir, "codeql-pack.yml"), - name: "pack/new-extension-pack", - version: "0.0.0", - language: "csharp", - extensionTargets: { - "codeql/csharp-all": "*", - }, - dataExtensions: ["models/**/*.yml"], - }); - expect(showQuickPickSpy).toHaveBeenCalledTimes(1); - expect(showInputBoxSpy).toHaveBeenCalledTimes(1); - expect(showInputBoxSpy).toHaveBeenCalledWith( - { - title: expect.stringMatching(/extension pack/i), - prompt: expect.stringMatching(/extension pack/i), - placeHolder: expect.stringMatching(/github\/vscode-codeql-csharp/), - validateInput: expect.any(Function), - }, - token, - ); - expect(cliServer.resolveQlpacks).toHaveBeenCalled(); - - expect( - loadYaml(await readFile(join(newPackDir, "codeql-pack.yml"), "utf8")), - ).toEqual({ - name: "pack/new-extension-pack", - version: "0.0.0", - library: true, - extensionTargets: { - "codeql/csharp-all": "*", - }, - dataExtensions: ["models/**/*.yml"], - }); - }); - - it("allows cancelling the workspace folder selection", async () => { - const cliServer = mockCliServer({}); - - showQuickPickSpy.mockResolvedValueOnce(undefined); - - expect( - await pickExtensionPack(cliServer, databaseItem, logger, progress, token), - ).toEqual(undefined); - expect(showQuickPickSpy).toHaveBeenCalledTimes(1); - expect(showInputBoxSpy).toHaveBeenCalledTimes(0); - expect(cliServer.resolveQlpacks).toHaveBeenCalled(); - }); - - it("allows cancelling the extension pack name input", async () => { - const cliServer = mockCliServer({}); - - showQuickPickSpy.mockResolvedValueOnce({ - label: "codeql-custom-queries-java", - folder: { - uri: Uri.file("/a/b/c"), - name: "codeql-custom-queries-java", - index: 0, - }, - } as QuickPickItem); - showInputBoxSpy.mockResolvedValueOnce(undefined); - - expect( - await pickExtensionPack(cliServer, databaseItem, logger, progress, token), - ).toEqual(undefined); - expect(showQuickPickSpy).toHaveBeenCalledTimes(1); - expect(showInputBoxSpy).toHaveBeenCalledTimes(1); - expect(cliServer.resolveQlpacks).toHaveBeenCalled(); - }); - it("shows an error when an extension pack resolves to more than 1 location", async () => { const cliServer = mockCliServer({ - "my-extension-pack": [ + "github/vscode-codeql-java": [ "/a/b/c/my-extension-pack", "/a/b/c/my-extension-pack2", ], }); - showQuickPickSpy.mockResolvedValueOnce(undefined); - expect( - await pickExtensionPack(cliServer, databaseItem, logger, progress, token), + await pickExtensionPack(cliServer, databaseItem, logger, progress), ).toEqual(undefined); expect(logger.showErrorMessage).toHaveBeenCalledTimes(1); expect(logger.showErrorMessage).toHaveBeenCalledWith( expect.stringMatching(/resolves to multiple paths/), ); - expect(showQuickPickSpy).toHaveBeenCalledTimes(1); - expect(showQuickPickSpy).toHaveBeenCalledWith( - [ - { - label: expect.stringMatching(/create/i), - extensionPack: null, - }, - ], - { - title: "Select extension pack to use", - }, - token, - ); expect(cliServer.resolveQlpacks).toHaveBeenCalled(); }); @@ -577,31 +292,15 @@ describe("pickExtensionPack", () => { }); const cliServer = mockCliServer({ - "my-extension-pack": [tmpDir.path], + "github/vscode-codeql-java": [tmpDir.path], }); - showQuickPickSpy.mockResolvedValueOnce(undefined); - expect( - await pickExtensionPack(cliServer, databaseItem, logger, progress, token), + await pickExtensionPack(cliServer, databaseItem, logger, progress), ).toEqual(undefined); - expect(showQuickPickSpy).toHaveBeenCalledTimes(1); - expect(showQuickPickSpy).toHaveBeenCalledWith( - [ - { - label: expect.stringMatching(/create/i), - extensionPack: null, - }, - ], - { - title: "Select extension pack to use", - }, - token, - ); - expect(showInputBoxSpy).not.toHaveBeenCalled(); expect(logger.showErrorMessage).toHaveBeenCalledTimes(1); expect(logger.showErrorMessage).toHaveBeenCalledWith( - expect.stringMatching(/my-extension-pack/), + "Could not read extension pack github/vscode-codeql-java", ); expect(cliServer.resolveQlpacks).toHaveBeenCalled(); }); @@ -612,33 +311,17 @@ describe("pickExtensionPack", () => { }); const cliServer = mockCliServer({ - "my-extension-pack": [tmpDir.path], + "github/vscode-codeql-java": [tmpDir.path], }); await outputFile(join(tmpDir.path, "codeql-pack.yml"), dumpYaml("java")); - showQuickPickSpy.mockResolvedValueOnce(undefined); - expect( - await pickExtensionPack(cliServer, databaseItem, logger, progress, token), + await pickExtensionPack(cliServer, databaseItem, logger, progress), ).toEqual(undefined); - expect(showQuickPickSpy).toHaveBeenCalledTimes(1); - expect(showQuickPickSpy).toHaveBeenCalledWith( - [ - { - label: expect.stringMatching(/create/i), - extensionPack: null, - }, - ], - { - title: "Select extension pack to use", - }, - token, - ); - expect(showInputBoxSpy).not.toHaveBeenCalled(); expect(logger.showErrorMessage).toHaveBeenCalledTimes(1); expect(logger.showErrorMessage).toHaveBeenCalledWith( - expect.stringMatching(/my-extension-pack/), + "Could not read extension pack github/vscode-codeql-java", ); expect(cliServer.resolveQlpacks).toHaveBeenCalled(); }); @@ -649,13 +332,13 @@ describe("pickExtensionPack", () => { }); const cliServer = mockCliServer({ - "my-extension-pack": [tmpDir.path], + "github/vscode-codeql-java": [tmpDir.path], }); await outputFile( join(tmpDir.path, "codeql-pack.yml"), dumpYaml({ - name: "my-extension-pack", + name: autoExtensionPackName, version: "0.0.0", library: true, extensionTargets: { @@ -664,28 +347,12 @@ describe("pickExtensionPack", () => { }), ); - showQuickPickSpy.mockResolvedValueOnce(undefined); - expect( - await pickExtensionPack(cliServer, databaseItem, logger, progress, token), + await pickExtensionPack(cliServer, databaseItem, logger, progress), ).toEqual(undefined); - expect(showQuickPickSpy).toHaveBeenCalledTimes(1); - expect(showQuickPickSpy).toHaveBeenCalledWith( - [ - { - label: expect.stringMatching(/create/i), - extensionPack: null, - }, - ], - { - title: "Select extension pack to use", - }, - token, - ); - expect(showInputBoxSpy).not.toHaveBeenCalled(); expect(logger.showErrorMessage).toHaveBeenCalledTimes(1); expect(logger.showErrorMessage).toHaveBeenCalledWith( - expect.stringMatching(/my-extension-pack/), + "Could not read extension pack github/vscode-codeql-java", ); expect(cliServer.resolveQlpacks).toHaveBeenCalled(); }); @@ -696,13 +363,13 @@ describe("pickExtensionPack", () => { }); const cliServer = mockCliServer({ - "my-extension-pack": [tmpDir.path], + "github/vscode-codeql-java": [tmpDir.path], }); await outputFile( join(tmpDir.path, "codeql-pack.yml"), dumpYaml({ - name: "my-extension-pack", + name: autoExtensionPackName, version: "0.0.0", library: true, extensionTargets: { @@ -714,94 +381,30 @@ describe("pickExtensionPack", () => { }), ); - showQuickPickSpy.mockResolvedValueOnce(undefined); - expect( - await pickExtensionPack(cliServer, databaseItem, logger, progress, token), + await pickExtensionPack(cliServer, databaseItem, logger, progress), ).toEqual(undefined); - expect(showQuickPickSpy).toHaveBeenCalledTimes(1); - expect(showQuickPickSpy).toHaveBeenCalledWith( - [ - { - label: expect.stringMatching(/create/i), - extensionPack: null, - }, - ], - { - title: "Select extension pack to use", - }, - token, - ); - expect(showInputBoxSpy).not.toHaveBeenCalled(); expect(logger.showErrorMessage).toHaveBeenCalledTimes(1); expect(logger.showErrorMessage).toHaveBeenCalledWith( - expect.stringMatching(/my-extension-pack/), + "Could not read extension pack github/vscode-codeql-java", ); expect(cliServer.resolveQlpacks).toHaveBeenCalled(); }); - it("validates the pack name input", async () => { - const cliServer = mockCliServer({}); - - showQuickPickSpy.mockResolvedValueOnce({ - label: "a", - folder: { - uri: Uri.file("/a/b/c"), - name: "a", - index: 0, - }, - } as QuickPickItem); - showInputBoxSpy.mockResolvedValue(undefined); - - expect( - await pickExtensionPack(cliServer, databaseItem, logger, progress, token), - ).toEqual(undefined); - - const validateFile = showInputBoxSpy.mock.calls[0][0]?.validateInput; - expect(validateFile).toBeDefined(); - if (!validateFile) { - return; - } - - expect(await validateFile("")).toEqual("Pack name must not be empty"); - expect(await validateFile("a".repeat(129))).toEqual( - "Pack name must be no longer than 128 characters", - ); - expect(await validateFile("github/vscode-codeql/extensions")).toEqual( - "Invalid package name: a pack name must contain only lowercase ASCII letters, ASCII digits, and hyphens", - ); - expect(await validateFile("VSCODE")).toEqual( - "Invalid package name: a pack name must contain a slash to separate the scope from the pack name", - ); - expect(await validateFile("github/")).toEqual( - "Invalid package name: a pack name must contain only lowercase ASCII letters, ASCII digits, and hyphens", - ); - expect(await validateFile("github/VSCODE")).toEqual( - "Invalid package name: a pack name must contain only lowercase ASCII letters, ASCII digits, and hyphens", - ); - expect(await validateFile("github/vscode-codeql-")).toEqual( - "Invalid package name: a pack name must contain only lowercase ASCII letters, ASCII digits, and hyphens", - ); - expect( - await validateFile("github/vscode-codeql-extensions"), - ).toBeUndefined(); - expect(await validateFile("pack/vscode-codeql-extensions")).toBeUndefined(); - }); - it("allows the dataExtensions to be a string", async () => { const tmpDir = await dir({ unsafeCleanup: true, }); const cliServer = mockCliServer({ - "new-extension-pack": [tmpDir.path], + "github/vscode-codeql-java": [tmpDir.path], }); const qlpackPath = join(tmpDir.path, "codeql-pack.yml"); await outputFile( qlpackPath, dumpYaml({ - name: "new-extension-pack", + name: autoExtensionPackName, version: "0.0.0", library: true, extensionTargets: { @@ -820,7 +423,7 @@ describe("pickExtensionPack", () => { const extensionPack = { path: tmpDir.path, yamlPath: qlpackPath, - name: "new-extension-pack", + name: autoExtensionPackName, version: "0.0.0", language: "java", extensionTargets: { @@ -828,75 +431,11 @@ describe("pickExtensionPack", () => { }, dataExtensions: ["models/**/*.yml"], }; - showQuickPickSpy.mockResolvedValueOnce({ - label: "new-extension-pack", - extensionPack, - } as QuickPickItem); - showQuickPickSpy.mockResolvedValueOnce(undefined); - showInputBoxSpy.mockResolvedValue(undefined); expect( - await pickExtensionPack(cliServer, databaseItem, logger, progress, token), + await pickExtensionPack(cliServer, databaseItem, logger, progress), ).toEqual(extensionPack); }); - - it("only shows extension packs for the database language", async () => { - const csharpPack = await createMockExtensionPack( - join(tmpDir, "csharp-extensions"), - "csharp-extension-pack", - { - version: "0.5.3", - language: "csharp", - extensionTargets: { - "codeql/csharp-all": "*", - }, - }, - ); - - const cliServer = mockCliServer({ - ...qlPacks, - "csharp-extension-pack": [csharpPack.path], - }); - - showQuickPickSpy.mockResolvedValueOnce(undefined); - - expect( - await pickExtensionPack( - cliServer, - { - ...databaseItem, - language: "csharp", - }, - logger, - progress, - token, - ), - ).toEqual(undefined); - expect(showQuickPickSpy).toHaveBeenCalledTimes(1); - expect(showQuickPickSpy).toHaveBeenCalledWith( - [ - { - label: "csharp-extension-pack", - description: "0.5.3", - detail: csharpPack.path, - extensionPack: csharpPack, - }, - { - label: expect.stringMatching(/create/i), - extensionPack: null, - }, - ], - { - title: expect.any(String), - }, - token, - ); - expect(cliServer.resolveQlpacks).toHaveBeenCalledTimes(1); - expect(cliServer.resolveQlpacks).toHaveBeenCalledWith( - additionalPacks, - true, - ); - }); }); function mockCliServer(qlpacks: QlpacksInfo) {