From 13c3c8efe4270bd7a8e26f038bc0485bc1c8a155 Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 22 Mar 2023 15:47:30 +0000 Subject: [PATCH 1/9] Convert extensions/ql-vscode/src/cli.ts to call typed commands --- extensions/ql-vscode/src/cli.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/ql-vscode/src/cli.ts b/extensions/ql-vscode/src/cli.ts index ae24e905b..45c6a7f6c 100644 --- a/extensions/ql-vscode/src/cli.ts +++ b/extensions/ql-vscode/src/cli.ts @@ -9,7 +9,7 @@ import { Readable } from "stream"; import { StringDecoder } from "string_decoder"; import tk from "tree-kill"; import { promisify } from "util"; -import { CancellationToken, commands, Disposable, Uri } from "vscode"; +import { CancellationToken, Disposable, Uri } from "vscode"; import { BQRSInfo, DecodedBqrsChunk } from "./pure/bqrs-cli-types"; import { allowCanaryQueryServer, CliConfig } from "./config"; @@ -1375,7 +1375,7 @@ export class CodeQLCliServer implements Disposable { if (!this._version) { this._version = this.refreshVersion(); // this._version is only undefined upon config change, so we reset CLI-based context key only when necessary. - await commands.executeCommand( + await this.app.commands.execute( "setContext", "codeql.supportsEvalLog", await this.cliConstraints.supportsPerQueryEvalLog(), From ddf5b3aac292ddd861245455cea33e9a9b6ce1c4 Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 22 Mar 2023 15:50:06 +0000 Subject: [PATCH 2/9] Convert extensions/ql-vscode/src/databaseFetcher.ts to call typed commands --- extensions/ql-vscode/src/common/commands.ts | 1 + extensions/ql-vscode/src/databaseFetcher.ts | 12 ++++++++---- extensions/ql-vscode/src/local-databases-ui.ts | 4 ++++ .../cli-integration/databaseFetcher.test.ts | 3 +++ .../vscode-tests/cli-integration/new-query.test.ts | 2 ++ .../vscode-tests/cli-integration/queries.test.ts | 2 ++ 6 files changed, 20 insertions(+), 4 deletions(-) diff --git a/extensions/ql-vscode/src/common/commands.ts b/extensions/ql-vscode/src/common/commands.ts index aa7792624..0a308c1b5 100644 --- a/extensions/ql-vscode/src/common/commands.ts +++ b/extensions/ql-vscode/src/common/commands.ts @@ -35,6 +35,7 @@ export type SingleSelectionCommandFunction = ( // Builtin commands where the implementation is provided by VS Code and not by this extension. // See https://code.visualstudio.com/api/references/commands export type BuiltInVsCodeCommands = { + "codeQLDatabases.focus": () => Promise; "markdown.showPreviewToSide": (uri: Uri) => Promise; setContext: ( key: `${"codeql" | "codeQL"}${string}`, diff --git a/extensions/ql-vscode/src/databaseFetcher.ts b/extensions/ql-vscode/src/databaseFetcher.ts index ac63fffbb..cd6c9acf9 100644 --- a/extensions/ql-vscode/src/databaseFetcher.ts +++ b/extensions/ql-vscode/src/databaseFetcher.ts @@ -1,7 +1,7 @@ import fetch, { Response } from "node-fetch"; import { zip } from "zip-a-folder"; import { Open } from "unzipper"; -import { Uri, CancellationToken, commands, window } from "vscode"; +import { Uri, CancellationToken, window } from "vscode"; import { CodeQLCliServer } from "./cli"; import { ensureDir, @@ -26,6 +26,7 @@ import { isValidGitHubNwo, } from "./common/github-url-identifier-helper"; import { Credentials } from "./common/authentication"; +import { AppCommandManager } from "./common/commands"; /** * Prompts a user to fetch a database from a remote location. Database is assumed to be an archive file. @@ -34,6 +35,7 @@ import { Credentials } from "./common/authentication"; * @param storagePath where to store the unzipped database. */ export async function promptImportInternetDatabase( + commandManager: AppCommandManager, databaseManager: DatabaseManager, storagePath: string, progress: ProgressCallback, @@ -61,7 +63,7 @@ export async function promptImportInternetDatabase( ); if (item) { - await commands.executeCommand("codeQLDatabases.focus"); + await commandManager.execute("codeQLDatabases.focus"); void showAndLogInformationMessage( "Database downloaded and imported successfully.", ); @@ -78,6 +80,7 @@ export async function promptImportInternetDatabase( * @param storagePath where to store the unzipped database. */ export async function promptImportGithubDatabase( + commandManager: AppCommandManager, databaseManager: DatabaseManager, storagePath: string, credentials: Credentials | undefined, @@ -141,7 +144,7 @@ export async function promptImportGithubDatabase( cli, ); if (item) { - await commands.executeCommand("codeQLDatabases.focus"); + await commandManager.execute("codeQLDatabases.focus"); void showAndLogInformationMessage( "Database downloaded and imported successfully.", ); @@ -158,6 +161,7 @@ export async function promptImportGithubDatabase( * @param storagePath where to store the unzipped database. */ export async function importArchiveDatabase( + commandManager: AppCommandManager, databaseUrl: string, databaseManager: DatabaseManager, storagePath: string, @@ -177,7 +181,7 @@ export async function importArchiveDatabase( cli, ); if (item) { - await commands.executeCommand("codeQLDatabases.focus"); + await commandManager.execute("codeQLDatabases.focus"); void showAndLogInformationMessage( "Database unzipped and imported successfully.", ); diff --git a/extensions/ql-vscode/src/local-databases-ui.ts b/extensions/ql-vscode/src/local-databases-ui.ts index 81bf64097..f1d88edb6 100644 --- a/extensions/ql-vscode/src/local-databases-ui.ts +++ b/extensions/ql-vscode/src/local-databases-ui.ts @@ -451,6 +451,7 @@ export class DatabaseUI extends DisposableObject { return withProgress( async (progress, token) => { await promptImportInternetDatabase( + this.app.commands, this.databaseManager, this.storagePath, progress, @@ -470,6 +471,7 @@ export class DatabaseUI extends DisposableObject { const credentials = isCanary() ? this.app.credentials : undefined; await promptImportGithubDatabase( + this.app.commands, this.databaseManager, this.storagePath, credentials, @@ -607,6 +609,7 @@ export class DatabaseUI extends DisposableObject { // Assume user has selected an archive if the file has a .zip extension if (uri.path.endsWith(".zip")) { await importArchiveDatabase( + this.app.commands, uri.toString(true), this.databaseManager, this.storagePath, @@ -762,6 +765,7 @@ export class DatabaseUI extends DisposableObject { // we are selecting a database archive. Must unzip into a workspace-controlled area // before importing. return await importArchiveDatabase( + this.app.commands, uri.toString(true), this.databaseManager, this.storagePath, diff --git a/extensions/ql-vscode/test/vscode-tests/cli-integration/databaseFetcher.test.ts b/extensions/ql-vscode/test/vscode-tests/cli-integration/databaseFetcher.test.ts index 407c22176..3ba6d5806 100644 --- a/extensions/ql-vscode/test/vscode-tests/cli-integration/databaseFetcher.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/cli-integration/databaseFetcher.test.ts @@ -9,6 +9,7 @@ import { promptImportInternetDatabase, } from "../../../src/databaseFetcher"; import { cleanDatabases, dbLoc, DB_URL, storagePath } from "../global.helper"; +import { createMockCommandManager } from "../../__mocks__/commandsMock"; jest.setTimeout(60_000); @@ -53,6 +54,7 @@ describe("DatabaseFetcher", () => { it("should add a database from a folder", async () => { const uri = Uri.file(dbLoc); let dbItem = await importArchiveDatabase( + createMockCommandManager(), uri.toString(true), databaseManager, storagePath, @@ -75,6 +77,7 @@ describe("DatabaseFetcher", () => { inputBoxStub.mockResolvedValue(DB_URL); let dbItem = await promptImportInternetDatabase( + createMockCommandManager(), databaseManager, storagePath, progressCallback, diff --git a/extensions/ql-vscode/test/vscode-tests/cli-integration/new-query.test.ts b/extensions/ql-vscode/test/vscode-tests/cli-integration/new-query.test.ts index a7d8f9d4b..4d47f3b02 100644 --- a/extensions/ql-vscode/test/vscode-tests/cli-integration/new-query.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/cli-integration/new-query.test.ts @@ -13,6 +13,7 @@ import { extLogger, ProgressReporter } from "../../../src/common"; import { QueryResultType } from "../../../src/pure/new-messages"; import { cleanDatabases, dbLoc, storagePath } from "../global.helper"; import { importArchiveDatabase } from "../../../src/databaseFetcher"; +import { createMockCommandManager } from "../../__mocks__/commandsMock"; const baseDir = join(__dirname, "../../../test/data"); @@ -147,6 +148,7 @@ describeWithCodeQL()("using the new query server", () => { await cleanDatabases(extension.databaseManager); const uri = Uri.file(dbLoc); const maybeDbItem = await importArchiveDatabase( + createMockCommandManager(), uri.toString(true), extension.databaseManager, storagePath, diff --git a/extensions/ql-vscode/test/vscode-tests/cli-integration/queries.test.ts b/extensions/ql-vscode/test/vscode-tests/cli-integration/queries.test.ts index 65b304235..b750bbae9 100644 --- a/extensions/ql-vscode/test/vscode-tests/cli-integration/queries.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/cli-integration/queries.test.ts @@ -26,6 +26,7 @@ import { createInitialQueryInfo } from "../../../src/run-queries-shared"; import { QueryRunner } from "../../../src/queryRunner"; import { CompletedQueryInfo } from "../../../src/query-results"; import { SELECT_QUERY_NAME } from "../../../src/contextual/locationFinder"; +import { createMockCommandManager } from "../../__mocks__/commandsMock"; jest.setTimeout(20_000); @@ -78,6 +79,7 @@ describeWithCodeQL()("Queries", () => { await cleanDatabases(databaseManager); const uri = Uri.file(dbLoc); const maybeDbItem = await importArchiveDatabase( + createMockCommandManager(), uri.toString(true), databaseManager, storagePath, From c394b7c4f0f341497a226963e5e7203b4ce5833d Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 22 Mar 2023 16:19:58 +0000 Subject: [PATCH 3/9] Convert extensions/ql-vscode/src/helpers.ts to call typed commands --- extensions/ql-vscode/src/common/commands.ts | 1 + extensions/ql-vscode/src/extension.ts | 2 +- extensions/ql-vscode/src/helpers.ts | 8 +++-- .../vscode-tests/no-workspace/helpers.test.ts | 34 +++++++------------ 4 files changed, 20 insertions(+), 25 deletions(-) diff --git a/extensions/ql-vscode/src/common/commands.ts b/extensions/ql-vscode/src/common/commands.ts index 0a308c1b5..171ff5be8 100644 --- a/extensions/ql-vscode/src/common/commands.ts +++ b/extensions/ql-vscode/src/common/commands.ts @@ -42,6 +42,7 @@ export type BuiltInVsCodeCommands = { value: unknown, ) => Promise; "workbench.action.reloadWindow": () => Promise; + "vscode.openFolder": (uri: Uri) => Promise; }; // Commands that are available before the extension is fully activated. diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index 63ece980d..b1c6211f2 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -573,7 +573,7 @@ async function installOrUpdateThenTryActivate( await installOrUpdateDistribution(ctx, app, distributionManager, config); try { - await prepareCodeTour(); + await prepareCodeTour(app.commands); } catch (e: unknown) { void extLogger.log( `Could not open tutorial workspace automatically: ${getErrorMessage(e)}`, diff --git a/extensions/ql-vscode/src/helpers.ts b/extensions/ql-vscode/src/helpers.ts index 33f5abd45..2576f6b48 100644 --- a/extensions/ql-vscode/src/helpers.ts +++ b/extensions/ql-vscode/src/helpers.ts @@ -16,7 +16,6 @@ import { window as Window, workspace, env, - commands, } from "vscode"; import { CodeQLCliServer, QlpacksInfo } from "./cli"; import { UserCancellationException } from "./progress"; @@ -27,6 +26,7 @@ import { RedactableError } from "./pure/errors"; import { getQlPackPath } from "./pure/ql"; import { dbSchemeToLanguage } from "./common/query-language"; import { isCodespacesTemplate } from "./config"; +import { AppCommandManager } from "./common/commands"; // Shared temporary folder for the extension. export const tmpDir = dirSync({ @@ -271,7 +271,9 @@ export function isFolderAlreadyInWorkspace(folderName: string) { /** Check if the current workspace is the CodeTour and open the workspace folder. * Without this, we can't run the code tour correctly. **/ -export async function prepareCodeTour(): Promise { +export async function prepareCodeTour( + commandManager: AppCommandManager, +): Promise { if (workspace.workspaceFolders?.length) { const currentFolder = workspace.workspaceFolders[0].uri.fsPath; @@ -308,7 +310,7 @@ export async function prepareCodeTour(): Promise { `In prepareCodeTour() method, going to open the tutorial workspace file: ${tutorialWorkspacePath}`, ); - await commands.executeCommand("vscode.openFolder", tutorialWorkspaceUri); + await commandManager.execute("vscode.openFolder", tutorialWorkspaceUri); } } } diff --git a/extensions/ql-vscode/test/vscode-tests/no-workspace/helpers.test.ts b/extensions/ql-vscode/test/vscode-tests/no-workspace/helpers.test.ts index 8fe7a47bd..49bb5117d 100644 --- a/extensions/ql-vscode/test/vscode-tests/no-workspace/helpers.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/no-workspace/helpers.test.ts @@ -1,5 +1,4 @@ import { - commands, EnvironmentVariableCollection, EnvironmentVariableMutator, Event, @@ -41,6 +40,7 @@ import { import { reportStreamProgress } from "../../../src/progress"; import { QueryLanguage } from "../../../src/common/query-language"; import { Setting } from "../../../src/config"; +import { createMockCommandManager } from "../../__mocks__/commandsMock"; describe("helpers", () => { describe("Invocation rate limiter", () => { @@ -612,13 +612,11 @@ describe("prepareCodeTour", () => { await mkdir(tourDirPath); // spy that we open the workspace file by calling the 'vscode.openFolder' command - const commandSpy = jest.spyOn(commands, "executeCommand"); - commandSpy.mockImplementation(() => Promise.resolve()); - - await prepareCodeTour(); + const executeCommand = jest.fn(); + await prepareCodeTour(createMockCommandManager({ executeCommand })); expect(showInformationMessageSpy).toHaveBeenCalled(); - expect(commandSpy).toHaveBeenCalledWith( + expect(executeCommand).toHaveBeenCalledWith( "vscode.openFolder", expect.objectContaining({ path: Uri.parse(tutorialWorkspacePath).fsPath, @@ -641,12 +639,10 @@ describe("prepareCodeTour", () => { await mkdir(tourDirPath); // spy that we open the workspace file by calling the 'vscode.openFolder' command - const commandSpy = jest.spyOn(commands, "executeCommand"); - commandSpy.mockImplementation(() => Promise.resolve()); + const executeCommand = jest.fn(); + await prepareCodeTour(createMockCommandManager({ executeCommand })); - await prepareCodeTour(); - - expect(commandSpy).not.toHaveBeenCalled(); + expect(executeCommand).not.toHaveBeenCalled(); }); }); }); @@ -658,24 +654,20 @@ describe("prepareCodeTour", () => { await mkdir(tourDirPath); // spy that we open the workspace file by calling the 'vscode.openFolder' command - const commandSpy = jest.spyOn(commands, "executeCommand"); - commandSpy.mockImplementation(() => Promise.resolve()); + const executeCommand = jest.fn(); + await prepareCodeTour(createMockCommandManager({ executeCommand })); - await prepareCodeTour(); - - expect(commandSpy).not.toHaveBeenCalled(); + expect(executeCommand).not.toHaveBeenCalled(); }); }); describe("if we're in a different repo with no tour", () => { it("should not open the tutorial workspace", async () => { // spy that we open the workspace file by calling the 'vscode.openFolder' command - const commandSpy = jest.spyOn(commands, "executeCommand"); - commandSpy.mockImplementation(() => Promise.resolve()); + const executeCommand = jest.fn(); + await prepareCodeTour(createMockCommandManager({ executeCommand })); - await prepareCodeTour(); - - expect(commandSpy).not.toHaveBeenCalled(); + expect(executeCommand).not.toHaveBeenCalled(); }); }); }); From 8b9003e84564c2a18aad41abf46008c88fb9a511 Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 22 Mar 2023 16:42:34 +0000 Subject: [PATCH 4/9] Convert extensions/ql-vscode/src/local-databases.ts to call typed commands --- extensions/ql-vscode/src/extension.ts | 2 +- extensions/ql-vscode/src/local-databases.ts | 4 +++- .../vscode-tests/minimal-workspace/local-databases.test.ts | 2 ++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index b1c6211f2..cb0a58771 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -678,7 +678,7 @@ async function activateWithInstalledDistribution( } void extLogger.log("Initializing database manager."); - const dbm = new DatabaseManager(ctx, qs, cliServer, extLogger); + const dbm = new DatabaseManager(ctx, app, qs, cliServer, extLogger); // Let this run async. void dbm.loadPersistedState(); diff --git a/extensions/ql-vscode/src/local-databases.ts b/extensions/ql-vscode/src/local-databases.ts index 3d390b472..918ddd5fc 100644 --- a/extensions/ql-vscode/src/local-databases.ts +++ b/extensions/ql-vscode/src/local-databases.ts @@ -28,6 +28,7 @@ import { redactableError } from "./pure/errors"; import { isCodespacesTemplate } from "./config"; import { QlPackGenerator } from "./qlpack-generator"; import { QueryLanguage } from "./common/query-language"; +import { App } from "./common/app"; /** * databases.ts @@ -593,6 +594,7 @@ export class DatabaseManager extends DisposableObject { constructor( private readonly ctx: ExtensionContext, + private readonly app: App, private readonly qs: QueryRunner, private readonly cli: cli.CodeQLCliServer, public logger: Logger, @@ -875,7 +877,7 @@ export class DatabaseManager extends DisposableObject { this._currentDatabaseItem = item; this.updatePersistedCurrentDatabaseItem(); - await vscode.commands.executeCommand( + await this.app.commands.execute( "setContext", "codeQL.currentDatabaseItem", item?.name, diff --git a/extensions/ql-vscode/test/vscode-tests/minimal-workspace/local-databases.test.ts b/extensions/ql-vscode/test/vscode-tests/minimal-workspace/local-databases.test.ts index 6c4167c06..c106110e8 100644 --- a/extensions/ql-vscode/test/vscode-tests/minimal-workspace/local-databases.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/minimal-workspace/local-databases.test.ts @@ -25,6 +25,7 @@ import * as helpers from "../../../src/helpers"; import { Setting } from "../../../src/config"; import { QlPackGenerator } from "../../../src/qlpack-generator"; import { mockedObject } from "../utils/mocking.helpers"; +import { createMockApp } from "../../__mocks__/appMock"; describe("local databases", () => { const MOCK_DB_OPTIONS: FullDatabaseOptions = { @@ -87,6 +88,7 @@ describe("local databases", () => { databaseManager = new DatabaseManager( extensionContext, + createMockApp({}), mockedObject({ registerDatabase: registerSpy, deregisterDatabase: deregisterSpy, From ff418b5487febbc182f797e5a4656a2cce7c9e47 Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 22 Mar 2023 16:44:41 +0000 Subject: [PATCH 5/9] Convert extensions/ql-vscode/src/query-editor.ts to call typed commands --- extensions/ql-vscode/src/extension.ts | 1 + extensions/ql-vscode/src/query-editor.ts | 17 +++++++++++++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index cb0a58771..7d6b7dfcc 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -879,6 +879,7 @@ async function activateWithInstalledDistribution( const allCommands: AllExtensionCommands = { ...getCommands(app, cliServer, qs), ...getQueryEditorCommands({ + commandManager: app.commands, queryRunner: qs, cliServer, qhelpTmpDir: qhelpTmpDir.name, diff --git a/extensions/ql-vscode/src/query-editor.ts b/extensions/ql-vscode/src/query-editor.ts index 23b8101c7..5821dc781 100644 --- a/extensions/ql-vscode/src/query-editor.ts +++ b/extensions/ql-vscode/src/query-editor.ts @@ -1,13 +1,15 @@ -import { commands, Uri, window } from "vscode"; +import { Uri, window } from "vscode"; import { CodeQLCliServer } from "./cli"; import { QueryRunner } from "./queryRunner"; import { basename, join } from "path"; import { getErrorMessage } from "./pure/helpers-pure"; import { redactableError } from "./pure/errors"; import { showAndLogExceptionWithTelemetry } from "./helpers"; -import { QueryEditorCommands } from "./common/commands"; +import { AppCommandManager, QueryEditorCommands } from "./common/commands"; type QueryEditorOptions = { + commandManager: AppCommandManager; + queryRunner: QueryRunner; cliServer: CodeQLCliServer; @@ -15,6 +17,7 @@ type QueryEditorOptions = { }; export function getQueryEditorCommands({ + commandManager, queryRunner, cliServer, qhelpTmpDir, @@ -29,11 +32,17 @@ export function getQueryEditorCommands({ // Since we are tracking extension usage through commands, this command mirrors the "codeQL.openReferencedFile" command "codeQL.openReferencedFileContextExplorer": openReferencedFileCommand, "codeQL.previewQueryHelp": async (selectedQuery: Uri) => - await previewQueryHelp(cliServer, qhelpTmpDir, selectedQuery), + await previewQueryHelp( + commandManager, + cliServer, + qhelpTmpDir, + selectedQuery, + ), }; } async function previewQueryHelp( + commandManager: AppCommandManager, cliServer: CodeQLCliServer, qhelpTmpDir: string, selectedQuery: Uri, @@ -49,7 +58,7 @@ async function previewQueryHelp( const uri = Uri.file(absolutePathToMd); try { await cliServer.generateQueryHelp(pathToQhelp, absolutePathToMd); - await commands.executeCommand("markdown.showPreviewToSide", uri); + await commandManager.execute("markdown.showPreviewToSide", uri); } catch (e) { const errorMessage = getErrorMessage(e).includes( "Generating qhelp in markdown", From 2a2cb2659715bd59913938e0a8898f49f84dae9b Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 22 Mar 2023 16:49:24 +0000 Subject: [PATCH 6/9] Convert extensions/ql-vscode/src/test-ui.ts to call typed commands --- extensions/ql-vscode/src/common/commands.ts | 8 +++++++- extensions/ql-vscode/src/extension.ts | 2 +- extensions/ql-vscode/src/test-ui.ts | 7 ++++--- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/extensions/ql-vscode/src/common/commands.ts b/extensions/ql-vscode/src/common/commands.ts index 171ff5be8..27f303e55 100644 --- a/extensions/ql-vscode/src/common/commands.ts +++ b/extensions/ql-vscode/src/common/commands.ts @@ -1,5 +1,5 @@ import type { CommandManager } from "../packages/commands"; -import type { Uri, Range } from "vscode"; +import type { Uri, Range, TextDocumentShowOptions } from "vscode"; import type { AstItem } from "../astViewer"; import type { DbTreeViewItem } from "../databases/ui/db-tree-view-item"; import type { DatabaseItem } from "../local-databases"; @@ -42,6 +42,12 @@ export type BuiltInVsCodeCommands = { value: unknown, ) => Promise; "workbench.action.reloadWindow": () => Promise; + "vscode.diff": ( + leftSideResource: Uri, + rightSideResource: Uri, + title?: string, + columnOrOptions?: TextDocumentShowOptions, + ) => Promise; "vscode.openFolder": (uri: Uri) => Promise; }; diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index 7d6b7dfcc..c3babbedd 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -851,7 +851,7 @@ async function activateWithInstalledDistribution( ); ctx.subscriptions.push(testAdapterFactory); - const testUIService = new TestUIService(testHub); + const testUIService = new TestUIService(app, testHub); ctx.subscriptions.push(testUIService); testUiCommands = testUIService.getCommands(); diff --git a/extensions/ql-vscode/src/test-ui.ts b/extensions/ql-vscode/src/test-ui.ts index 5739d438f..45b8f41a7 100644 --- a/extensions/ql-vscode/src/test-ui.ts +++ b/extensions/ql-vscode/src/test-ui.ts @@ -1,6 +1,6 @@ import { lstat, copy, pathExists, createFile } from "fs-extra"; import { basename } from "path"; -import { Uri, TextDocumentShowOptions, commands, window } from "vscode"; +import { Uri, TextDocumentShowOptions, window } from "vscode"; import { TestHub, TestController, @@ -16,6 +16,7 @@ import { TestTreeNode } from "./test-tree-node"; import { DisposableObject } from "./pure/disposable-object"; import { QLTestAdapter, getExpectedFile, getActualFile } from "./test-adapter"; import { TestUICommands } from "./common/commands"; +import { App } from "./common/app"; type VSCodeTestEvent = | TestRunStartedEvent @@ -44,7 +45,7 @@ class QLTestListener extends DisposableObject { export class TestUIService extends DisposableObject implements TestController { private readonly listeners: Map = new Map(); - constructor(private readonly testHub: TestHub) { + constructor(private readonly app: App, private readonly testHub: TestHub) { super(); testHub.registerTestController(this); @@ -105,7 +106,7 @@ export class TestUIService extends DisposableObject implements TestController { if (await pathExists(actualPath)) { const actualUri = Uri.file(actualPath); - await commands.executeCommand( + await this.app.commands.execute( "vscode.diff", expectedUri, actualUri, From d7e061e1595f957b5b767e9fa27b0902a092f085 Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 22 Mar 2023 16:55:50 +0000 Subject: [PATCH 7/9] Convert extensions/ql-vscode/src/databases/ui/db-panel.ts to use typed commands --- extensions/ql-vscode/src/common/commands.ts | 1 + extensions/ql-vscode/src/databases/db-module.ts | 2 +- extensions/ql-vscode/src/databases/ui/db-panel.ts | 9 ++++----- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/extensions/ql-vscode/src/common/commands.ts b/extensions/ql-vscode/src/common/commands.ts index 27f303e55..5919ae02c 100644 --- a/extensions/ql-vscode/src/common/commands.ts +++ b/extensions/ql-vscode/src/common/commands.ts @@ -48,6 +48,7 @@ export type BuiltInVsCodeCommands = { title?: string, columnOrOptions?: TextDocumentShowOptions, ) => Promise; + "vscode.open": (uri: Uri) => Promise; "vscode.openFolder": (uri: Uri) => Promise; }; diff --git a/extensions/ql-vscode/src/databases/db-module.ts b/extensions/ql-vscode/src/databases/db-module.ts index 8c287cc32..8d47f75a8 100644 --- a/extensions/ql-vscode/src/databases/db-module.ts +++ b/extensions/ql-vscode/src/databases/db-module.ts @@ -43,7 +43,7 @@ export class DbModule extends DisposableObject { await this.dbConfigStore.initialize(); - this.dbPanel = new DbPanel(this.dbManager, app.credentials); + this.dbPanel = new DbPanel(app, this.dbManager); this.push(this.dbPanel); this.push(this.dbConfigStore); diff --git a/extensions/ql-vscode/src/databases/ui/db-panel.ts b/extensions/ql-vscode/src/databases/ui/db-panel.ts index 7df235347..80a0eec5b 100644 --- a/extensions/ql-vscode/src/databases/ui/db-panel.ts +++ b/extensions/ql-vscode/src/databases/ui/db-panel.ts @@ -1,5 +1,4 @@ import { - commands, QuickPickItem, TreeView, TreeViewExpansionEvent, @@ -31,8 +30,8 @@ import { DbTreeViewItem } from "./db-tree-view-item"; import { getGitHubUrl } from "./db-tree-view-item-action"; import { getControllerRepo } from "../../variant-analysis/run-remote-query"; import { getErrorMessage } from "../../pure/helpers-pure"; -import { Credentials } from "../../common/authentication"; import { DatabasePanelCommands } from "../../common/commands"; +import { App } from "../../common/app"; export interface RemoteDatabaseQuickPickItem extends QuickPickItem { kind: string; @@ -47,8 +46,8 @@ export class DbPanel extends DisposableObject { private readonly treeView: TreeView; public constructor( + private readonly app: App, private readonly dbManager: DbManager, - private readonly credentials: Credentials, ) { super(); @@ -369,13 +368,13 @@ export class DbPanel extends DisposableObject { ); } - await commands.executeCommand("vscode.open", Uri.parse(githubUrl)); + await this.app.commands.execute("vscode.open", Uri.parse(githubUrl)); } private async setupControllerRepository(): Promise { try { // This will also validate that the controller repository is valid - await getControllerRepo(this.credentials); + await getControllerRepo(this.app.credentials); } catch (e: unknown) { if (e instanceof UserCancellationException) { return; From 14dc391229991443106e18a6454868627442debb Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 22 Mar 2023 17:06:24 +0000 Subject: [PATCH 8/9] Convert extensions/ql-vscode/src/legacy-query-server/queryserver-client.ts to call typed commands --- extensions/ql-vscode/src/extension.ts | 9 ++++++++- .../src/legacy-query-server/queryserver-client.ts | 6 ++++-- .../vscode-tests/cli-integration/legacy-query.test.ts | 2 ++ 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index c3babbedd..52f1295d6 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -667,7 +667,12 @@ async function activateWithInstalledDistribution( ctx.subscriptions.push(statusBar); void extLogger.log("Initializing query server client."); - const qs = await createQueryServer(qlConfigurationListener, cliServer, ctx); + const qs = await createQueryServer( + app, + qlConfigurationListener, + cliServer, + ctx, + ); for (const glob of PACK_GLOBS) { const fsWatcher = workspace.createFileSystemWatcher(glob); @@ -1044,6 +1049,7 @@ function addUnhandledRejectionListener() { } async function createQueryServer( + app: ExtensionApp, qlConfigurationListener: QueryServerConfigListener, cliServer: CodeQLCliServer, ctx: ExtensionContext, @@ -1074,6 +1080,7 @@ async function createQueryServer( return new NewQueryRunner(qs); } else { const qs = new LegacyQueryServerClient( + app, qlConfigurationListener, cliServer, qsOpts, diff --git a/extensions/ql-vscode/src/legacy-query-server/queryserver-client.ts b/extensions/ql-vscode/src/legacy-query-server/queryserver-client.ts index 25e60db23..50c0278db 100644 --- a/extensions/ql-vscode/src/legacy-query-server/queryserver-client.ts +++ b/extensions/ql-vscode/src/legacy-query-server/queryserver-client.ts @@ -1,7 +1,7 @@ import { ensureFile } from "fs-extra"; import { DisposableObject } from "../pure/disposable-object"; -import { CancellationToken, commands } from "vscode"; +import { CancellationToken } from "vscode"; import { createMessageConnection, RequestType } from "vscode-jsonrpc/node"; import * as cli from "../cli"; import { QueryServerConfig } from "../config"; @@ -15,6 +15,7 @@ import { } from "../pure/legacy-messages"; import { ProgressCallback, ProgressTask } from "../progress"; import { ServerProcess } from "../json-rpc-server"; +import { App } from "../common/app"; type WithProgressReporting = ( task: ( @@ -56,6 +57,7 @@ export class QueryServerClient extends DisposableObject { public activeQueryLogger: Logger; constructor( + app: App, readonly config: QueryServerConfig, readonly cliServer: cli.CodeQLCliServer, readonly opts: ServerOpts, @@ -69,7 +71,7 @@ export class QueryServerClient extends DisposableObject { if (config.onDidChangeConfiguration !== undefined) { this.push( config.onDidChangeConfiguration(() => - commands.executeCommand("codeQL.restartQueryServer"), + app.commands.execute("codeQL.restartQueryServer"), ), ); } diff --git a/extensions/ql-vscode/test/vscode-tests/cli-integration/legacy-query.test.ts b/extensions/ql-vscode/test/vscode-tests/cli-integration/legacy-query.test.ts index 6c014b609..faacb6db2 100644 --- a/extensions/ql-vscode/test/vscode-tests/cli-integration/legacy-query.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/cli-integration/legacy-query.test.ts @@ -12,6 +12,7 @@ import { CodeQLExtensionInterface } from "../../../src/extension"; import { describeWithCodeQL } from "../cli"; import { QueryServerClient } from "../../../src/legacy-query-server/queryserver-client"; import { extLogger, ProgressReporter } from "../../../src/common"; +import { createMockApp } from "../../__mocks__/appMock"; const baseDir = join(__dirname, "../../../test/data"); @@ -121,6 +122,7 @@ describeWithCodeQL()("using the legacy query server", () => { cliServer.quiet = true; qs = new QueryServerClient( + createMockApp({}), { codeQlPath: (await extension.distributionManager.getCodeQlPathWithoutVersionCheck()) || From e0dd8c7392533425226cde6408e2d338a19fc566 Mon Sep 17 00:00:00 2001 From: Robert Date: Thu, 23 Mar 2023 13:04:30 +0000 Subject: [PATCH 9/9] Add comment about codeQLDatabases.focus --- extensions/ql-vscode/src/common/commands.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/extensions/ql-vscode/src/common/commands.ts b/extensions/ql-vscode/src/common/commands.ts index 5919ae02c..74b6c3313 100644 --- a/extensions/ql-vscode/src/common/commands.ts +++ b/extensions/ql-vscode/src/common/commands.ts @@ -35,6 +35,7 @@ export type SingleSelectionCommandFunction = ( // Builtin commands where the implementation is provided by VS Code and not by this extension. // See https://code.visualstudio.com/api/references/commands export type BuiltInVsCodeCommands = { + // The codeQLDatabases.focus command is provided by VS Code because we've registered the custom view "codeQLDatabases.focus": () => Promise; "markdown.showPreviewToSide": (uri: Uri) => Promise; setContext: (