From 89ccd70752a0c99be20b6eaf10a3c3037f61e66a Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Fri, 20 Oct 2023 16:43:53 +0200 Subject: [PATCH] Show error message for no workspace folders with model editor It is possible to open the model editor without opening a folder, but this gave an unhelpful error message. This commit adds a more helpful error message. --- .../src/model-editor/extension-pack-picker.ts | 2 +- .../extensions-workspace-folder.ts | 14 +++++- .../extensions-workspace-folder.test.ts | 45 ++++++++++++++++--- 3 files changed, 52 insertions(+), 9 deletions(-) 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 c970002d0..7f3becb0e 100644 --- a/extensions/ql-vscode/src/model-editor/extension-pack-picker.ts +++ b/extensions/ql-vscode/src/model-editor/extension-pack-picker.ts @@ -64,7 +64,7 @@ export async function pickExtensionPack( // If the setting is not set, automatically pick a suitable directory const extensionsDirectory = userExtensionsDirectory ? Uri.file(userExtensionsDirectory) - : await autoPickExtensionsDirectory(); + : await autoPickExtensionsDirectory(logger); if (!extensionsDirectory) { return undefined; 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 729bf0b52..65c4e1a07 100644 --- a/extensions/ql-vscode/src/model-editor/extensions-workspace-folder.ts +++ b/extensions/ql-vscode/src/model-editor/extensions-workspace-folder.ts @@ -2,6 +2,7 @@ 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"; +import { NotificationLogger, showAndLogErrorMessage } from "../common/logging"; /** * Returns the ancestors of this path in order from furthest to closest (i.e. root of filesystem to parent directory) @@ -143,9 +144,20 @@ async function findGitFolder( * for which the .git directory is closest to a workspace folder * 6. If none of the above apply, return `undefined` */ -export async function autoPickExtensionsDirectory(): Promise { +export async function autoPickExtensionsDirectory( + logger: NotificationLogger, +): Promise { const workspaceFolders = getOnDiskWorkspaceFoldersObjects(); + // If there are no on-disk workspace folders, we can't do anything + if (workspaceFolders.length === 0) { + void showAndLogErrorMessage( + logger, + `Could not find any on-disk workspace folders. Please ensure that you have opened a folder or workspace.`, + ); + return undefined; + } + // If there's only 1 workspace folder, use the `.github/codeql/extensions` directory in that folder if (workspaceFolders.length === 1) { return Uri.joinPath( diff --git a/extensions/ql-vscode/test/vscode-tests/no-workspace/model-editor/extensions-workspace-folder.test.ts b/extensions/ql-vscode/test/vscode-tests/no-workspace/model-editor/extensions-workspace-folder.test.ts index 279100b82..34feb3d29 100644 --- a/extensions/ql-vscode/test/vscode-tests/no-workspace/model-editor/extensions-workspace-folder.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/no-workspace/model-editor/extensions-workspace-folder.test.ts @@ -4,6 +4,8 @@ import { join } from "path"; import { autoPickExtensionsDirectory } from "../../../../src/model-editor/extensions-workspace-folder"; import * as files from "../../../../src/common/files"; import { mkdirp } from "fs-extra"; +import { NotificationLogger } from "../../../../src/common/logging"; +import { createMockLogger } from "../../../__mocks__/loggerMock"; describe("autoPickExtensionsDirectory", () => { let tmpDir: DirectoryResult; @@ -19,6 +21,7 @@ describe("autoPickExtensionsDirectory", () => { typeof workspace.updateWorkspaceFolders >; let mockedTmpDirUri: Uri; + let logger: NotificationLogger; beforeEach(async () => { tmpDir = await dir({ @@ -47,6 +50,8 @@ describe("autoPickExtensionsDirectory", () => { .mockReturnValue(true); jest.spyOn(files, "tmpdir").mockReturnValue(mockedTmpDir); + + logger = createMockLogger(); }); afterEach(async () => { @@ -72,7 +77,9 @@ describe("autoPickExtensionsDirectory", () => { }, ]); - expect(await autoPickExtensionsDirectory()).toEqual(extensionsDirectory); + expect(await autoPickExtensionsDirectory(logger)).toEqual( + extensionsDirectory, + ); expect(updateWorkspaceFoldersSpy).not.toHaveBeenCalled(); }); @@ -94,7 +101,9 @@ describe("autoPickExtensionsDirectory", () => { Uri.joinPath(rootDirectory, "workspace.code-workspace"), ); - expect(await autoPickExtensionsDirectory()).toEqual(extensionsDirectory); + expect(await autoPickExtensionsDirectory(logger)).toEqual( + extensionsDirectory, + ); expect(updateWorkspaceFoldersSpy).toHaveBeenCalledWith(2, 0, { name: "CodeQL Extension Packs", uri: extensionsDirectory, @@ -121,7 +130,7 @@ describe("autoPickExtensionsDirectory", () => { Uri.joinPath(rootDirectory, "workspace.code-workspace"), ); - expect(await autoPickExtensionsDirectory()).toEqual(undefined); + expect(await autoPickExtensionsDirectory(logger)).toEqual(undefined); }); it("when a workspace file does not exist and there is a common root directory", async () => { @@ -138,7 +147,9 @@ describe("autoPickExtensionsDirectory", () => { }, ]); - expect(await autoPickExtensionsDirectory()).toEqual(extensionsDirectory); + expect(await autoPickExtensionsDirectory(logger)).toEqual( + extensionsDirectory, + ); expect(updateWorkspaceFoldersSpy).toHaveBeenCalledWith(2, 0, { name: "CodeQL Extension Packs", uri: extensionsDirectory, @@ -164,7 +175,9 @@ describe("autoPickExtensionsDirectory", () => { }, ]); - expect(await autoPickExtensionsDirectory()).toEqual(extensionsDirectory); + expect(await autoPickExtensionsDirectory(logger)).toEqual( + extensionsDirectory, + ); expect(updateWorkspaceFoldersSpy).toHaveBeenCalledWith(3, 0, { name: "CodeQL Extension Packs", uri: extensionsDirectory, @@ -185,7 +198,7 @@ describe("autoPickExtensionsDirectory", () => { }, ]); - expect(await autoPickExtensionsDirectory()).toEqual(undefined); + expect(await autoPickExtensionsDirectory(logger)).toEqual(undefined); expect(updateWorkspaceFoldersSpy).not.toHaveBeenCalled(); }); @@ -205,10 +218,28 @@ describe("autoPickExtensionsDirectory", () => { }, ]); - expect(await autoPickExtensionsDirectory()).toEqual(extensionsDirectory); + expect(await autoPickExtensionsDirectory(logger)).toEqual( + extensionsDirectory, + ); expect(updateWorkspaceFoldersSpy).toHaveBeenCalledWith(2, 0, { name: "CodeQL Extension Packs", uri: extensionsDirectory, }); }); + + it("when there is no on-disk workspace folder", async () => { + workspaceFoldersSpy.mockReturnValue([ + { + uri: Uri.parse("codeql-zip-archive://codeql_db"), + name: "my-db", + index: 0, + }, + ]); + + expect(await autoPickExtensionsDirectory(logger)).toEqual(undefined); + expect(updateWorkspaceFoldersSpy).not.toHaveBeenCalled(); + expect(logger.showErrorMessage).toHaveBeenCalledWith( + "Could not find any on-disk workspace folders. Please ensure that you have opened a folder or workspace.", + ); + }); });