Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions extensions/ql-vscode/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
12 changes: 12 additions & 0 deletions extensions/ql-vscode/src/local-queries/quick-query-dir.ts
Original file line number Diff line number Diff line change
@@ -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<string> {
const storagePath = app.workspaceStoragePath ?? app.globalStoragePath;
const queriesPath = join(storagePath, QUICK_QUERIES_DIR_NAME);
await ensureDir(queriesPath, { mode: 0o700 });
return queriesPath;
}
15 changes: 2 additions & 13 deletions extensions/ql-vscode/src/local-queries/quick-query.ts
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -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";
Expand All @@ -24,16 +23,6 @@ export function isQuickQueryPath(queryPath: string): boolean {
return basename(queryPath) === QUICK_QUERY_QUERY_NAME;
}

async function getQuickQueriesDir(app: App): Promise<string> {
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),
Expand Down
Original file line number Diff line number Diff line change
@@ -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);
});
});