From 5b2114ee816ceaf4667a281d79b921a359f96fa2 Mon Sep 17 00:00:00 2001 From: hugosmoreira Date: Sun, 9 Aug 2026 22:59:00 -0700 Subject: [PATCH] Fix Quick Query without a workspace --- extensions/ql-vscode/CHANGELOG.md | 2 + .../src/local-queries/quick-query-dir.ts | 12 +++++ .../src/local-queries/quick-query.ts | 15 +------ .../local-queries/quick-query.test.ts | 45 +++++++++++++++++++ 4 files changed, 61 insertions(+), 13 deletions(-) create mode 100644 extensions/ql-vscode/src/local-queries/quick-query-dir.ts create mode 100644 extensions/ql-vscode/test/unit-tests/local-queries/quick-query.test.ts diff --git a/extensions/ql-vscode/CHANGELOG.md b/extensions/ql-vscode/CHANGELOG.md index 5bfed122e1d..65b69aa463d 100644 --- a/extensions/ql-vscode/CHANGELOG.md +++ b/extensions/ql-vscode/CHANGELOG.md @@ -2,6 +2,8 @@ ## [UNRELEASED] +- Fix Quick Query failing to start when no workspace is open. + ## 1.17.8 - 17 July 2026 - Fix a bug where installing or updating the CodeQL CLI could hang indefinitely while extracting the downloaded archive. Extraction now reports an error if a file cannot be written, and aborts with a clear message if no progress is made within the download timeout (for example due to slow or networked storage, or security software). [#4455](https://github.com/github/vscode-codeql/pull/4455) diff --git a/extensions/ql-vscode/src/local-queries/quick-query-dir.ts b/extensions/ql-vscode/src/local-queries/quick-query-dir.ts new file mode 100644 index 00000000000..b78cc6eecbd --- /dev/null +++ b/extensions/ql-vscode/src/local-queries/quick-query-dir.ts @@ -0,0 +1,12 @@ +import { ensureDir } from "fs-extra"; +import { join } from "path"; +import type { App } from "../common/app"; + +const QUICK_QUERIES_DIR_NAME = "quick-queries"; + +export async function getQuickQueriesDir(app: App): Promise { + const storagePath = app.workspaceStoragePath ?? app.globalStoragePath; + const queriesPath = join(storagePath, QUICK_QUERIES_DIR_NAME); + await ensureDir(queriesPath, { mode: 0o700 }); + return queriesPath; +} diff --git a/extensions/ql-vscode/src/local-queries/quick-query.ts b/extensions/ql-vscode/src/local-queries/quick-query.ts index 8e0c55d885b..88df4591699 100644 --- a/extensions/ql-vscode/src/local-queries/quick-query.ts +++ b/extensions/ql-vscode/src/local-queries/quick-query.ts @@ -1,4 +1,4 @@ -import { ensureDir, writeFile, pathExists, readFile } from "fs-extra"; +import { writeFile, pathExists, readFile } from "fs-extra"; import { dump, load } from "js-yaml"; import { basename, join } from "path"; import { window as Window, workspace, Uri } from "vscode"; @@ -11,11 +11,10 @@ import type { ProgressCallback } from "../common/vscode/progress"; import { UserCancellationException } from "../common/vscode/progress"; import { getErrorMessage } from "../common/helpers-pure"; import { FALLBACK_QLPACK_FILENAME, getQlPackFilePath } from "../common/ql"; -import type { App } from "../common/app"; import type { ExtensionApp } from "../common/vscode/extension-app"; import type { QlPackFile } from "../packaging/qlpack-file"; +import { getQuickQueriesDir } from "./quick-query-dir"; -const QUICK_QUERIES_DIR_NAME = "quick-queries"; const QUICK_QUERY_QUERY_NAME = "quick-query.ql"; const QUICK_QUERY_WORKSPACE_FOLDER_NAME = "Quick Queries"; const QLPACK_FILE_HEADER = "# This is an automatically generated file.\n\n"; @@ -24,16 +23,6 @@ export function isQuickQueryPath(queryPath: string): boolean { return basename(queryPath) === QUICK_QUERY_QUERY_NAME; } -async function getQuickQueriesDir(app: App): Promise { - const storagePath = app.workspaceStoragePath; - if (storagePath === undefined) { - throw new Error("Workspace storage path is undefined"); - } - const queriesPath = join(storagePath, QUICK_QUERIES_DIR_NAME); - await ensureDir(queriesPath, { mode: 0o700 }); - return queriesPath; -} - function updateQuickQueryDir(queriesDir: string, index: number, len: number) { workspace.updateWorkspaceFolders(index, len, { uri: Uri.file(queriesDir), diff --git a/extensions/ql-vscode/test/unit-tests/local-queries/quick-query.test.ts b/extensions/ql-vscode/test/unit-tests/local-queries/quick-query.test.ts new file mode 100644 index 00000000000..4d53b891167 --- /dev/null +++ b/extensions/ql-vscode/test/unit-tests/local-queries/quick-query.test.ts @@ -0,0 +1,45 @@ +import type { DirResult } from "tmp"; +import { dirSync } from "tmp"; +import { pathExists } from "fs-extra"; +import { join } from "path"; +import { createMockApp } from "../../__mocks__/appMock"; +import { getQuickQueriesDir } from "../../../src/local-queries/quick-query-dir"; + +describe("getQuickQueriesDir", () => { + let dir: DirResult; + + beforeEach(() => { + dir = dirSync({ + unsafeCleanup: true, + }); + }); + + afterEach(() => { + dir.removeCallback(); + }); + + it("uses global storage when no workspace is open", async () => { + const app = { + ...createMockApp({ globalStoragePath: dir.name }), + workspaceStoragePath: undefined, + }; + + const quickQueriesDir = await getQuickQueriesDir(app); + + expect(quickQueriesDir).toBe(join(dir.name, "quick-queries")); + expect(await pathExists(quickQueriesDir)).toBe(true); + }); + + it("prefers workspace storage when a workspace is open", async () => { + const workspaceStoragePath = join(dir.name, "workspace-storage"); + const app = createMockApp({ + workspaceStoragePath, + globalStoragePath: dir.name, + }); + + const quickQueriesDir = await getQuickQueriesDir(app); + + expect(quickQueriesDir).toBe(join(workspaceStoragePath, "quick-queries")); + expect(await pathExists(quickQueriesDir)).toBe(true); + }); +});