From 74ae0bc35a7850aa019de2abd44588362788817d Mon Sep 17 00:00:00 2001 From: shati-patel <42641846+shati-patel@users.noreply.github.com> Date: Thu, 13 Jan 2022 16:18:02 +0000 Subject: [PATCH 01/10] Add "pack install" and "pack download" commands --- extensions/ql-vscode/package.json | 8 ++ extensions/ql-vscode/src/cli.ts | 8 ++ extensions/ql-vscode/src/extension.ts | 21 ++++ extensions/ql-vscode/src/packaging.ts | 144 ++++++++++++++++++++++++++ 4 files changed, 181 insertions(+) create mode 100644 extensions/ql-vscode/src/packaging.ts diff --git a/extensions/ql-vscode/package.json b/extensions/ql-vscode/package.json index 882a0d91305..470cf2c3bdc 100644 --- a/extensions/ql-vscode/package.json +++ b/extensions/ql-vscode/package.json @@ -373,6 +373,14 @@ "command": "codeQL.clearCache", "title": "CodeQL: Clear Cache" }, + { + "command": "codeQL.installPacks", + "title": "CodeQL: Install Packs" + }, + { + "command": "codeQL.downloadPacks", + "title": "CodeQL: Download Packs" + }, { "command": "codeQLDatabases.setCurrentDatabase", "title": "Set Current Database" diff --git a/extensions/ql-vscode/src/cli.ts b/extensions/ql-vscode/src/cli.ts index 7e7a8d16694..e575728d39b 100644 --- a/extensions/ql-vscode/src/cli.ts +++ b/extensions/ql-vscode/src/cli.ts @@ -845,6 +845,14 @@ export class CodeQLCliServer implements Disposable { ); } + /** + * Downloads a specified pack. + * @param pack The `` of the pack to download. + */ + async packDownload(pack: string) { + return this.runJsonCodeQlCliCommand(['pack', 'download'], [pack], 'Downloading packs'); + } + async packInstall(dir: string) { return this.runJsonCodeQlCliCommand(['pack', 'install'], [dir], 'Installing pack dependencies'); } diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index 551d74f5ed4..b80bf2536ed 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -83,6 +83,7 @@ import { RemoteQuery } from './remote-queries/remote-query'; import { URLSearchParams } from 'url'; import { RemoteQueriesInterfaceManager } from './remote-queries/remote-queries-interface'; import { sampleRemoteQuery, sampleRemoteQueryResult } from './remote-queries/sample-data'; +import { handleDownloadPacks, handleInstallPacks } from './packaging'; /** * extension.ts @@ -922,6 +923,26 @@ async function activateWithInstalledDistribution( } })); + ctx.subscriptions.push( + commandRunnerWithProgress('codeQL.installPacks', async ( + progress: ProgressCallback + ) => + await handleInstallPacks(cliServer, progress), + { + title: 'Installing packs', + } + )); + + ctx.subscriptions.push( + commandRunnerWithProgress('codeQL.downloadPacks', async ( + progress: ProgressCallback + ) => + await handleDownloadPacks(cliServer, progress), + { + title: 'Downloading packs', + } + )); + commands.registerCommand('codeQL.showLogs', () => { logger.show(); }); diff --git a/extensions/ql-vscode/src/packaging.ts b/extensions/ql-vscode/src/packaging.ts new file mode 100644 index 00000000000..e9dd4e4b265 --- /dev/null +++ b/extensions/ql-vscode/src/packaging.ts @@ -0,0 +1,144 @@ +import { CodeQLCliServer } from './cli'; +import * as fs from 'fs-extra'; +import * as path from 'path'; +import { + getOnDiskWorkspaceFolders, + showAndLogErrorMessage, + showAndLogInformationMessage, +} from './helpers'; +import { window } from 'vscode'; +import { ProgressCallback } from './commandRunner'; + +const CORE_PACKS = [ + 'codeql/cpp-all', + 'codeql/csharp-all', + 'codeql/go-all', + 'codeql/java-all', + 'codeql/javascript-all', + 'codeql/python-all', + 'codeql/ruby-all', +]; + +/** + * Lists all workspace folders that contain a qlpack.yml file. + * + * Note: This currently only finds packs at the root of a workspace folder. + * TODO: Add support for packs in subfolders. + */ +function getWorkspacePacks(): string[] { + const packs: string[] = []; + const workspaceFolders = getOnDiskWorkspaceFolders(); + for (const folder of workspaceFolders) { + const qlpackYml = path.join(folder, 'qlpack.yml'); + if (fs.pathExistsSync(qlpackYml)) { + packs.push(folder); + } + } + return packs; +} + +/** + * Prompts user to choose packs to download, and downloads them. + * + * @param cliServer The CLI server. + * @param progress A progress callback. + */ +export async function handleDownloadPacks( + cliServer: CodeQLCliServer, + progress: ProgressCallback, +): Promise { + progress({ + message: 'Choose packs to download', + step: 1, + maxStep: 2, + }); + let packsToDownload: string[] = []; + const corePackOption = 'Download core CodeQL packs'; + const customPackOption = 'Download custom specified pack'; + const quickpick = await window.showQuickPick( + [corePackOption, customPackOption], + { ignoreFocusOut: true } + ); + if (quickpick === corePackOption) { + packsToDownload = CORE_PACKS; + } else if (quickpick === customPackOption) { + const customPack = await window.showInputBox({ + prompt: + 'Enter the of the pack to download', + ignoreFocusOut: true, + }); + if (customPack) { + packsToDownload.push(customPack); + } else { + void showAndLogErrorMessage('No pack specified.'); + } + } + if (packsToDownload && packsToDownload.length > 0) { + progress({ + message: `Downloading ${packsToDownload.join(', ')}`, + step: 2, + maxStep: 2, + }); + for (const pack of packsToDownload) { + try { + await cliServer.packDownload(pack); + } catch (error) { + void showAndLogErrorMessage(`Unable to download pack ${pack}. See logs for more details.`); + } + } + void showAndLogInformationMessage('Finished downloading packs.'); + } +} + +/** + * Prompts user to choose packs to install, and installs them. + * + * @param cliServer The CLI server. + * @param progress A progress callback. + */ +export async function handleInstallPacks( + cliServer: CodeQLCliServer, + progress: ProgressCallback, +): Promise { + progress({ + message: 'Choose packs to install', + step: 1, + maxStep: 2, + }); + let packsToInstall: string[] = []; + const workspacePackOption = 'Install workspace packs'; + const customPackOption = 'Install custom specified pack'; + const quickpick = await window.showQuickPick( + [workspacePackOption, customPackOption], + { ignoreFocusOut: true } + ); + if (quickpick === workspacePackOption) { + packsToInstall = getWorkspacePacks(); + } else if (quickpick === customPackOption) { + const customPack = await window.showInputBox({ + prompt: + 'Enter the root directory of the pack to install (as an absolute path)', + ignoreFocusOut: true, + }); + if (customPack) { + packsToInstall.push(customPack); + } else { + void showAndLogErrorMessage('No pack specified.'); + } + } + if (packsToInstall && packsToInstall.length > 0) { + progress({ + message: `Installing ${packsToInstall.join(', ')}`, + step: 2, + maxStep: 2, + }); + for (const pack of packsToInstall) { + try { + await cliServer.packInstall(pack); + } catch (error) { + void showAndLogErrorMessage(`Unable to install pack ${pack}. See logs for more details.`); + } + } + void showAndLogInformationMessage('Finished installing packs.'); + } +} From c3c422fe50af5f20a977758fee820ec921a9a6af Mon Sep 17 00:00:00 2001 From: shati-patel <42641846+shati-patel@users.noreply.github.com> Date: Fri, 14 Jan 2022 15:56:37 +0000 Subject: [PATCH 02/10] Address review comments 1. Hard-code more common query packs 2. Correctly resolve workspace packs 3. Only install workspace packs --- extensions/ql-vscode/src/cli.ts | 6 +- extensions/ql-vscode/src/packaging.ts | 127 ++++++++++++-------------- 2 files changed, 62 insertions(+), 71 deletions(-) diff --git a/extensions/ql-vscode/src/cli.ts b/extensions/ql-vscode/src/cli.ts index e575728d39b..dcd7c402419 100644 --- a/extensions/ql-vscode/src/cli.ts +++ b/extensions/ql-vscode/src/cli.ts @@ -847,10 +847,10 @@ export class CodeQLCliServer implements Disposable { /** * Downloads a specified pack. - * @param pack The `` of the pack to download. + * @param packs The `` of the packs to download. */ - async packDownload(pack: string) { - return this.runJsonCodeQlCliCommand(['pack', 'download'], [pack], 'Downloading packs'); + async packDownload(packs: string[]) { + return this.runJsonCodeQlCliCommand(['pack', 'download'], packs, 'Downloading packs'); } async packInstall(dir: string) { diff --git a/extensions/ql-vscode/src/packaging.ts b/extensions/ql-vscode/src/packaging.ts index e9dd4e4b265..a4df45bd310 100644 --- a/extensions/ql-vscode/src/packaging.ts +++ b/extensions/ql-vscode/src/packaging.ts @@ -1,42 +1,26 @@ import { CodeQLCliServer } from './cli'; -import * as fs from 'fs-extra'; -import * as path from 'path'; import { getOnDiskWorkspaceFolders, showAndLogErrorMessage, showAndLogInformationMessage, + showAndLogWarningMessage, } from './helpers'; -import { window } from 'vscode'; -import { ProgressCallback } from './commandRunner'; +import { QuickPickItem, window } from 'vscode'; +import { ProgressCallback, UserCancellationException } from './commandRunner'; +import { logger } from './logging'; -const CORE_PACKS = [ - 'codeql/cpp-all', - 'codeql/csharp-all', - 'codeql/go-all', - 'codeql/java-all', - 'codeql/javascript-all', - 'codeql/python-all', - 'codeql/ruby-all', +const QUERY_PACKS = [ + 'codeql/cpp-queries', + 'codeql/csharp-queries', + 'codeql/go-queries', + 'codeql/java-queries', + 'codeql/javascript-queries', + 'codeql/python-queries', + 'codeql/ruby-queries', + 'codeql/csharp-solorigate-queries', + 'codeql/javascript-experimental-atm-queries', ]; -/** - * Lists all workspace folders that contain a qlpack.yml file. - * - * Note: This currently only finds packs at the root of a workspace folder. - * TODO: Add support for packs in subfolders. - */ -function getWorkspacePacks(): string[] { - const packs: string[] = []; - const workspaceFolders = getOnDiskWorkspaceFolders(); - for (const folder of workspaceFolders) { - const qlpackYml = path.join(folder, 'qlpack.yml'); - if (fs.pathExistsSync(qlpackYml)) { - packs.push(folder); - } - } - return packs; -} - /** * Prompts user to choose packs to download, and downloads them. * @@ -53,14 +37,14 @@ export async function handleDownloadPacks( maxStep: 2, }); let packsToDownload: string[] = []; - const corePackOption = 'Download core CodeQL packs'; + const queryPackOption = 'Download core query packs'; const customPackOption = 'Download custom specified pack'; const quickpick = await window.showQuickPick( - [corePackOption, customPackOption], + [queryPackOption, customPackOption], { ignoreFocusOut: true } ); - if (quickpick === corePackOption) { - packsToDownload = CORE_PACKS; + if (quickpick === queryPackOption) { + packsToDownload = QUERY_PACKS; } else if (quickpick === customPackOption) { const customPack = await window.showInputBox({ prompt: @@ -70,26 +54,30 @@ export async function handleDownloadPacks( if (customPack) { packsToDownload.push(customPack); } else { - void showAndLogErrorMessage('No pack specified.'); + throw new UserCancellationException('No pack specified.'); } } if (packsToDownload && packsToDownload.length > 0) { progress({ - message: `Downloading ${packsToDownload.join(', ')}`, + message: 'Downloading packs. This may take a few minutes.', step: 2, maxStep: 2, }); - for (const pack of packsToDownload) { - try { - await cliServer.packDownload(pack); - } catch (error) { - void showAndLogErrorMessage(`Unable to download pack ${pack}. See logs for more details.`); - } + try { + await cliServer.packDownload(packsToDownload); + void showAndLogInformationMessage('Finished downloading packs.'); + } catch (error) { + void showAndLogErrorMessage( + 'Unable to download all packs. See logs for more details.' + ); } - void showAndLogInformationMessage('Finished downloading packs.'); } } +interface QLPackQuickPickItem extends QuickPickItem { + packRootDir: string[]; +} + /** * Prompts user to choose packs to install, and installs them. * @@ -105,40 +93,43 @@ export async function handleInstallPacks( step: 1, maxStep: 2, }); - let packsToInstall: string[] = []; - const workspacePackOption = 'Install workspace packs'; - const customPackOption = 'Install custom specified pack'; - const quickpick = await window.showQuickPick( - [workspacePackOption, customPackOption], - { ignoreFocusOut: true } - ); - if (quickpick === workspacePackOption) { - packsToInstall = getWorkspacePacks(); - } else if (quickpick === customPackOption) { - const customPack = await window.showInputBox({ - prompt: - 'Enter the root directory of the pack to install (as an absolute path)', - ignoreFocusOut: true, - }); - if (customPack) { - packsToInstall.push(customPack); - } else { - void showAndLogErrorMessage('No pack specified.'); - } - } + const workspacePacks = await cliServer.resolveQlpacks(getOnDiskWorkspaceFolders()); + const quickPickItems = Object.entries(workspacePacks).map(([key, value]) => ({ + label: key, + packRootDir: value, + })); + const packsToInstall = await window.showQuickPick(quickPickItems, { + placeHolder: 'Select packs to install', + canPickMany: true, + ignoreFocusOut: true, + }); if (packsToInstall && packsToInstall.length > 0) { progress({ - message: `Installing ${packsToInstall.join(', ')}`, + message: 'Installing packs. This may take a few minutes.', step: 2, maxStep: 2, }); + const failedPacks = []; + const errors = []; for (const pack of packsToInstall) { try { - await cliServer.packInstall(pack); + for (const dir of pack.packRootDir) { + await cliServer.packInstall(dir); + } } catch (error) { - void showAndLogErrorMessage(`Unable to install pack ${pack}. See logs for more details.`); + failedPacks.push(pack.label); + errors.push(error); } } - void showAndLogInformationMessage('Finished installing packs.'); + if (failedPacks.length > 0) { + void logger.log(`Errors:\n${errors.join('\n')}`); + void showAndLogWarningMessage( + `Unable to install some packs: ${failedPacks.join(', ')}. See logs for more details.` + ); + } else { + void showAndLogInformationMessage('Finished installing packs.'); + } + } else { + throw new UserCancellationException('No packs selected.'); } } From da59c42284386deb81d2354a634b93278c807bed Mon Sep 17 00:00:00 2001 From: shati-patel <42641846+shati-patel@users.noreply.github.com> Date: Fri, 14 Jan 2022 15:57:38 +0000 Subject: [PATCH 03/10] Update changelog --- extensions/ql-vscode/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/extensions/ql-vscode/CHANGELOG.md b/extensions/ql-vscode/CHANGELOG.md index 79e28206748..220abd9014d 100644 --- a/extensions/ql-vscode/CHANGELOG.md +++ b/extensions/ql-vscode/CHANGELOG.md @@ -3,6 +3,7 @@ ## [UNRELEASED] - Fix a bug where the results view moved column even when it was already visible. [#1070](https://github.com/github/vscode-codeql/pull/1070) +- Add packaging-related commands. _CodeQL: Download Packs_ downloads packs from the package registry, and _CodeQL: Install Packs_ installs dependencies for packs in your workspace. [#1076](https://github.com/github/vscode-codeql/pull/1076) ## 1.5.9 - 17 December 2021 From 9efa7ae6f434b82d29d7c6d41e8b2f12c0bf4af5 Mon Sep 17 00:00:00 2001 From: shati-patel <42641846+shati-patel@users.noreply.github.com> Date: Mon, 17 Jan 2022 18:32:37 +0000 Subject: [PATCH 04/10] First attempt at tests --- extensions/ql-vscode/src/packaging.ts | 4 +- .../cli-integration/packaging.test.ts | 108 ++++++++++++++++++ 2 files changed, 110 insertions(+), 2 deletions(-) create mode 100644 extensions/ql-vscode/src/vscode-tests/cli-integration/packaging.test.ts diff --git a/extensions/ql-vscode/src/packaging.ts b/extensions/ql-vscode/src/packaging.ts index a4df45bd310..f34d0b8a8bb 100644 --- a/extensions/ql-vscode/src/packaging.ts +++ b/extensions/ql-vscode/src/packaging.ts @@ -37,7 +37,7 @@ export async function handleDownloadPacks( maxStep: 2, }); let packsToDownload: string[] = []; - const queryPackOption = 'Download core query packs'; + const queryPackOption = 'Download all core query packs'; const customPackOption = 'Download custom specified pack'; const quickpick = await window.showQuickPick( [queryPackOption, customPackOption], @@ -57,7 +57,7 @@ export async function handleDownloadPacks( throw new UserCancellationException('No pack specified.'); } } - if (packsToDownload && packsToDownload.length > 0) { + if (packsToDownload?.length > 0) { progress({ message: 'Downloading packs. This may take a few minutes.', step: 2, diff --git a/extensions/ql-vscode/src/vscode-tests/cli-integration/packaging.test.ts b/extensions/ql-vscode/src/vscode-tests/cli-integration/packaging.test.ts new file mode 100644 index 00000000000..db4537e96c7 --- /dev/null +++ b/extensions/ql-vscode/src/vscode-tests/cli-integration/packaging.test.ts @@ -0,0 +1,108 @@ +import * as sinon from 'sinon'; +import { extensions, window } from 'vscode'; +import 'mocha'; +import * as path from 'path'; + +import * as pq from 'proxyquire'; + +import { CodeQLCliServer } from '../../cli'; +import { CodeQLExtensionInterface } from '../../extension'; +import { expect } from 'chai'; + +const proxyquire = pq.noPreserveCache(); + +describe('Packaging commands', function() { + let sandbox: sinon.SinonSandbox; + + // up to 3 minutes per test + this.timeout(3 * 60 * 1000); + + let cli: CodeQLCliServer; + let progress: sinon.SinonSpy; + let quickPickSpy: sinon.SinonStub; + let inputBoxSpy: sinon.SinonStub; + let showAndLogErrorMessageSpy: sinon.SinonStub; + let showAndLogInformationMessageSpy: sinon.SinonStub; + let mod: any; + + beforeEach(async function() { + sandbox = sinon.createSandbox(); + + const extension = await extensions + .getExtension>( + 'GitHub.vscode-codeql' + )! + .activate(); + if ('cliServer' in extension) { + cli = extension.cliServer; + } else { + throw new Error( + 'Extension not initialized. Make sure cli is downloaded and installed properly.' + ); + } + + progress = sandbox.spy(); + quickPickSpy = sandbox.stub(window, 'showQuickPick'); + inputBoxSpy = sandbox.stub(window, 'showInputBox'); + showAndLogErrorMessageSpy = sandbox.stub(); + showAndLogInformationMessageSpy = sandbox.stub(); + mod = proxyquire('../../packaging', { + '../helpers': { + showAndLogErrorMessage: showAndLogErrorMessageSpy, + showAndLogInformationMessage: showAndLogInformationMessageSpy, + }, + }); + }); + + afterEach(() => { + sandbox.restore(); + }); + + it('should download all core query packs', async () => { + quickPickSpy.resolves('Download all core query packs'); + + await mod.handleDownloadPacks(cli, progress); + expect(showAndLogInformationMessageSpy.firstCall.args[0]).to.contain( + 'Finished downloading packs.' + ); + }); + + it('should download valid user-specified pack', async () => { + quickPickSpy.resolves('Download custom specified pack'); + inputBoxSpy.resolves('codeql/csharp-solorigate-queries'); + + await mod.handleDownloadPacks(cli, progress); + expect(showAndLogInformationMessageSpy.firstCall.args[0]).to.contain( + 'Finished downloading packs.' + ); + }); + + it('should show error for invalid user-specified pack', async () => { + quickPickSpy.resolves('Download custom specified pack'); + inputBoxSpy.resolves('foo/not-a-real-pack@0.0.1'); + + await mod.handleDownloadPacks(cli, progress); + + expect(showAndLogErrorMessageSpy.firstCall.args[0]).to.contain( + 'Unable to download all packs.' + ); + }); + + it('should install selected workspace packs', async () => { + const rootDir = path.join(__dirname, '../../../src/vscode-tests/cli-integration/data'); + quickPickSpy.resolves( + [ + { + label: 'integration-test-queries-javascript', + packRootDir: [rootDir], + }, + ] + ); + + await mod.handleInstallPacks(cli, progress); + + expect(showAndLogInformationMessageSpy.firstCall.args[0]).to.contain( + 'Finished installing packs.' + ); + }); +}); From 9a780c42ef14a724f114fa469a78661f3acfc2f7 Mon Sep 17 00:00:00 2001 From: shati-patel <42641846+shati-patel@users.noreply.github.com> Date: Mon, 17 Jan 2022 20:20:27 +0000 Subject: [PATCH 05/10] Fix import + throw error --- extensions/ql-vscode/src/packaging.ts | 5 ++--- .../src/vscode-tests/cli-integration/packaging.test.ts | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/extensions/ql-vscode/src/packaging.ts b/extensions/ql-vscode/src/packaging.ts index f34d0b8a8bb..89945e2881a 100644 --- a/extensions/ql-vscode/src/packaging.ts +++ b/extensions/ql-vscode/src/packaging.ts @@ -3,7 +3,6 @@ import { getOnDiskWorkspaceFolders, showAndLogErrorMessage, showAndLogInformationMessage, - showAndLogWarningMessage, } from './helpers'; import { QuickPickItem, window } from 'vscode'; import { ProgressCallback, UserCancellationException } from './commandRunner'; @@ -123,8 +122,8 @@ export async function handleInstallPacks( } if (failedPacks.length > 0) { void logger.log(`Errors:\n${errors.join('\n')}`); - void showAndLogWarningMessage( - `Unable to install some packs: ${failedPacks.join(', ')}. See logs for more details.` + throw new Error( + `Unable to install packs: ${failedPacks.join(', ')}. See logs for more details.` ); } else { void showAndLogInformationMessage('Finished installing packs.'); diff --git a/extensions/ql-vscode/src/vscode-tests/cli-integration/packaging.test.ts b/extensions/ql-vscode/src/vscode-tests/cli-integration/packaging.test.ts index db4537e96c7..f6821920032 100644 --- a/extensions/ql-vscode/src/vscode-tests/cli-integration/packaging.test.ts +++ b/extensions/ql-vscode/src/vscode-tests/cli-integration/packaging.test.ts @@ -47,7 +47,7 @@ describe('Packaging commands', function() { showAndLogErrorMessageSpy = sandbox.stub(); showAndLogInformationMessageSpy = sandbox.stub(); mod = proxyquire('../../packaging', { - '../helpers': { + './helpers': { showAndLogErrorMessage: showAndLogErrorMessageSpy, showAndLogInformationMessage: showAndLogInformationMessageSpy, }, From 3c4838db8eb259d07881bcdfb74d98f0f799cead Mon Sep 17 00:00:00 2001 From: shati-patel <42641846+shati-patel@users.noreply.github.com> Date: Mon, 17 Jan 2022 20:35:00 +0000 Subject: [PATCH 06/10] Catch error in tests --- .../cli-integration/packaging.test.ts | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/extensions/ql-vscode/src/vscode-tests/cli-integration/packaging.test.ts b/extensions/ql-vscode/src/vscode-tests/cli-integration/packaging.test.ts index f6821920032..2c8fcab68ad 100644 --- a/extensions/ql-vscode/src/vscode-tests/cli-integration/packaging.test.ts +++ b/extensions/ql-vscode/src/vscode-tests/cli-integration/packaging.test.ts @@ -88,21 +88,22 @@ describe('Packaging commands', function() { ); }); - it('should install selected workspace packs', async () => { + it('should attempt to install selected workspace packs', async () => { const rootDir = path.join(__dirname, '../../../src/vscode-tests/cli-integration/data'); - quickPickSpy.resolves( - [ - { - label: 'integration-test-queries-javascript', - packRootDir: [rootDir], - }, - ] - ); - - await mod.handleInstallPacks(cli, progress); + quickPickSpy.resolves([ + { + label: 'integration-test-queries-javascript', + packRootDir: [rootDir], + }, + ]); - expect(showAndLogInformationMessageSpy.firstCall.args[0]).to.contain( - 'Finished installing packs.' - ); + try { + await mod.handleInstallPacks(cli, progress); + expect(showAndLogInformationMessageSpy.firstCall.args[0]).to.contain( + 'Finished installing packs.' + ); + } catch (error) { + expect(error.message).to.contain('Unable to install packs:'); + } }); }); From 7a04ff023d73f79de8fbe151ffdf8479914db97e Mon Sep 17 00:00:00 2001 From: shati-patel <42641846+shati-patel@users.noreply.github.com> Date: Tue, 18 Jan 2022 11:53:10 +0000 Subject: [PATCH 07/10] Add separate tests for valid/invalid pack install --- extensions/ql-vscode/src/packaging.ts | 2 +- .../data-invalid-pack/qlpack.yml | 4 +++ .../cli-integration/packaging.test.ts | 25 +++++++++++++++---- 3 files changed, 25 insertions(+), 6 deletions(-) create mode 100644 extensions/ql-vscode/src/vscode-tests/cli-integration/data-invalid-pack/qlpack.yml diff --git a/extensions/ql-vscode/src/packaging.ts b/extensions/ql-vscode/src/packaging.ts index 89945e2881a..9f4d027ceb2 100644 --- a/extensions/ql-vscode/src/packaging.ts +++ b/extensions/ql-vscode/src/packaging.ts @@ -123,7 +123,7 @@ export async function handleInstallPacks( if (failedPacks.length > 0) { void logger.log(`Errors:\n${errors.join('\n')}`); throw new Error( - `Unable to install packs: ${failedPacks.join(', ')}. See logs for more details.` + `Unable to install packs: ${failedPacks.join(', ')}. See log for more details.` ); } else { void showAndLogInformationMessage('Finished installing packs.'); diff --git a/extensions/ql-vscode/src/vscode-tests/cli-integration/data-invalid-pack/qlpack.yml b/extensions/ql-vscode/src/vscode-tests/cli-integration/data-invalid-pack/qlpack.yml new file mode 100644 index 00000000000..ff1b342d3f9 --- /dev/null +++ b/extensions/ql-vscode/src/vscode-tests/cli-integration/data-invalid-pack/qlpack.yml @@ -0,0 +1,4 @@ +name: foo/bar +version: 0.0.0 +dependencies: + foo/baz: '*' diff --git a/extensions/ql-vscode/src/vscode-tests/cli-integration/packaging.test.ts b/extensions/ql-vscode/src/vscode-tests/cli-integration/packaging.test.ts index 2c8fcab68ad..dc3f490ee8b 100644 --- a/extensions/ql-vscode/src/vscode-tests/cli-integration/packaging.test.ts +++ b/extensions/ql-vscode/src/vscode-tests/cli-integration/packaging.test.ts @@ -77,7 +77,7 @@ describe('Packaging commands', function() { ); }); - it('should show error for invalid user-specified pack', async () => { + it('should show error when downloading invalid user-specified pack', async () => { quickPickSpy.resolves('Download custom specified pack'); inputBoxSpy.resolves('foo/not-a-real-pack@0.0.1'); @@ -88,7 +88,7 @@ describe('Packaging commands', function() { ); }); - it('should attempt to install selected workspace packs', async () => { + it('should install valid workspace pack', async () => { const rootDir = path.join(__dirname, '../../../src/vscode-tests/cli-integration/data'); quickPickSpy.resolves([ { @@ -97,11 +97,26 @@ describe('Packaging commands', function() { }, ]); + await mod.handleInstallPacks(cli, progress); + expect(showAndLogInformationMessageSpy.firstCall.args[0]).to.contain( + 'Finished installing packs.' + ); + }); + + it('should throw an error when installing invalid workspace pack', async () => { + const rootDir = path.join(__dirname, '../../../src/vscode-tests/cli-integration/data-invalid-pack'); + quickPickSpy.resolves([ + { + label: 'foo/bar', + packRootDir: [rootDir], + }, + ]); + try { + // expect this to throw an error await mod.handleInstallPacks(cli, progress); - expect(showAndLogInformationMessageSpy.firstCall.args[0]).to.contain( - 'Finished installing packs.' - ); + // This line should not be reached + expect(true).to.be.false; } catch (error) { expect(error.message).to.contain('Unable to install packs:'); } From 5c5a1b2b267faefa3d3c9ed805a8dbbfcb322775 Mon Sep 17 00:00:00 2001 From: shati-patel <42641846+shati-patel@users.noreply.github.com> Date: Tue, 18 Jan 2022 12:28:45 +0000 Subject: [PATCH 08/10] Add CLI version constraint for packaging --- extensions/ql-vscode/src/cli.ts | 9 +++++++++ extensions/ql-vscode/src/packaging.ts | 10 +++++++++- .../src/vscode-tests/cli-integration/packaging.test.ts | 8 ++++++-- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/extensions/ql-vscode/src/cli.ts b/extensions/ql-vscode/src/cli.ts index dcd7c402419..2afd3b91e14 100644 --- a/extensions/ql-vscode/src/cli.ts +++ b/extensions/ql-vscode/src/cli.ts @@ -1199,6 +1199,11 @@ export class CliVersionConstraint { */ public static CLI_VERSION_WITH_OLD_EVAL_STATS = new SemVer('2.7.4'); + /** + * CLI version where packaging was introduced. + */ + public static CLI_VERSION_WITH_PACKAGING = new SemVer('2.6.0'); + constructor(private readonly cli: CodeQLCliServer) { /**/ } @@ -1250,4 +1255,8 @@ export class CliVersionConstraint { async supportsOldEvalStats() { return this.isVersionAtLeast(CliVersionConstraint.CLI_VERSION_WITH_OLD_EVAL_STATS); } + + async supportsPackaging() { + return this.isVersionAtLeast(CliVersionConstraint.CLI_VERSION_WITH_PACKAGING); + } } diff --git a/extensions/ql-vscode/src/packaging.ts b/extensions/ql-vscode/src/packaging.ts index 9f4d027ceb2..5e9a647b8d5 100644 --- a/extensions/ql-vscode/src/packaging.ts +++ b/extensions/ql-vscode/src/packaging.ts @@ -1,4 +1,4 @@ -import { CodeQLCliServer } from './cli'; +import { CliVersionConstraint, CodeQLCliServer } from './cli'; import { getOnDiskWorkspaceFolders, showAndLogErrorMessage, @@ -30,6 +30,10 @@ export async function handleDownloadPacks( cliServer: CodeQLCliServer, progress: ProgressCallback, ): Promise { + if (!(await cliServer.cliConstraints.supportsPackaging())) { + throw new Error(`Packaging commands are not supported by this version of CodeQL. Please upgrade to v${CliVersionConstraint.CLI_VERSION_WITH_PACKAGING + } or later.`); + } progress({ message: 'Choose packs to download', step: 1, @@ -87,6 +91,10 @@ export async function handleInstallPacks( cliServer: CodeQLCliServer, progress: ProgressCallback, ): Promise { + if (!(await cliServer.cliConstraints.supportsPackaging())) { + throw new Error(`Packaging commands are not supported by this version of CodeQL. Please upgrade to v${CliVersionConstraint.CLI_VERSION_WITH_PACKAGING + } or later.`); + } progress({ message: 'Choose packs to install', step: 1, diff --git a/extensions/ql-vscode/src/vscode-tests/cli-integration/packaging.test.ts b/extensions/ql-vscode/src/vscode-tests/cli-integration/packaging.test.ts index dc3f490ee8b..1c52ec5b9f6 100644 --- a/extensions/ql-vscode/src/vscode-tests/cli-integration/packaging.test.ts +++ b/extensions/ql-vscode/src/vscode-tests/cli-integration/packaging.test.ts @@ -5,7 +5,7 @@ import * as path from 'path'; import * as pq from 'proxyquire'; -import { CodeQLCliServer } from '../../cli'; +import { CliVersionConstraint, CodeQLCliServer } from '../../cli'; import { CodeQLExtensionInterface } from '../../extension'; import { expect } from 'chai'; @@ -40,7 +40,11 @@ describe('Packaging commands', function() { 'Extension not initialized. Make sure cli is downloaded and installed properly.' ); } - + if (!(await cli.cliConstraints.supportsPackaging())) { + console.log(`Packaging commands are not supported on CodeQL CLI v${CliVersionConstraint.CLI_VERSION_WITH_PACKAGING + }. Skipping this test.`); + this.skip(); + } progress = sandbox.spy(); quickPickSpy = sandbox.stub(window, 'showQuickPick'); inputBoxSpy = sandbox.stub(window, 'showInputBox'); From c46ace41a9b4ae74cc3f2b2958126941672d60f2 Mon Sep 17 00:00:00 2001 From: shati-patel <42641846+shati-patel@users.noreply.github.com> Date: Wed, 19 Jan 2022 13:43:20 +0000 Subject: [PATCH 09/10] Update wording to be more clear --- extensions/ql-vscode/package.json | 4 ++-- extensions/ql-vscode/src/extension.ts | 8 ++++---- extensions/ql-vscode/src/packaging.ts | 14 +++++++------- .../vscode-tests/cli-integration/packaging.test.ts | 8 ++++---- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/extensions/ql-vscode/package.json b/extensions/ql-vscode/package.json index 470cf2c3bdc..f2a36f95d36 100644 --- a/extensions/ql-vscode/package.json +++ b/extensions/ql-vscode/package.json @@ -374,8 +374,8 @@ "title": "CodeQL: Clear Cache" }, { - "command": "codeQL.installPacks", - "title": "CodeQL: Install Packs" + "command": "codeQL.installPackDependencies", + "title": "CodeQL: Install Pack Dependencies" }, { "command": "codeQL.downloadPacks", diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index b80bf2536ed..0cd0dc70670 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -83,7 +83,7 @@ import { RemoteQuery } from './remote-queries/remote-query'; import { URLSearchParams } from 'url'; import { RemoteQueriesInterfaceManager } from './remote-queries/remote-queries-interface'; import { sampleRemoteQuery, sampleRemoteQueryResult } from './remote-queries/sample-data'; -import { handleDownloadPacks, handleInstallPacks } from './packaging'; +import { handleDownloadPacks, handleInstallPackDependencies } from './packaging'; /** * extension.ts @@ -924,12 +924,12 @@ async function activateWithInstalledDistribution( })); ctx.subscriptions.push( - commandRunnerWithProgress('codeQL.installPacks', async ( + commandRunnerWithProgress('codeQL.installPackDependencies', async ( progress: ProgressCallback ) => - await handleInstallPacks(cliServer, progress), + await handleInstallPackDependencies(cliServer, progress), { - title: 'Installing packs', + title: 'Installing pack dependencies', } )); diff --git a/extensions/ql-vscode/src/packaging.ts b/extensions/ql-vscode/src/packaging.ts index 5e9a647b8d5..68f7f30879e 100644 --- a/extensions/ql-vscode/src/packaging.ts +++ b/extensions/ql-vscode/src/packaging.ts @@ -71,7 +71,7 @@ export async function handleDownloadPacks( void showAndLogInformationMessage('Finished downloading packs.'); } catch (error) { void showAndLogErrorMessage( - 'Unable to download all packs. See logs for more details.' + 'Unable to download all packs. See log for more details.' ); } } @@ -87,7 +87,7 @@ interface QLPackQuickPickItem extends QuickPickItem { * @param cliServer The CLI server. * @param progress A progress callback. */ -export async function handleInstallPacks( +export async function handleInstallPackDependencies( cliServer: CodeQLCliServer, progress: ProgressCallback, ): Promise { @@ -96,7 +96,7 @@ export async function handleInstallPacks( } or later.`); } progress({ - message: 'Choose packs to install', + message: 'Choose packs to install dependencies for', step: 1, maxStep: 2, }); @@ -106,13 +106,13 @@ export async function handleInstallPacks( packRootDir: value, })); const packsToInstall = await window.showQuickPick(quickPickItems, { - placeHolder: 'Select packs to install', + placeHolder: 'Select packs to install dependencies for', canPickMany: true, ignoreFocusOut: true, }); if (packsToInstall && packsToInstall.length > 0) { progress({ - message: 'Installing packs. This may take a few minutes.', + message: 'Installing dependencies. This may take a few minutes.', step: 2, maxStep: 2, }); @@ -131,10 +131,10 @@ export async function handleInstallPacks( if (failedPacks.length > 0) { void logger.log(`Errors:\n${errors.join('\n')}`); throw new Error( - `Unable to install packs: ${failedPacks.join(', ')}. See log for more details.` + `Unable to install pack dependencies for: ${failedPacks.join(', ')}. See log for more details.` ); } else { - void showAndLogInformationMessage('Finished installing packs.'); + void showAndLogInformationMessage('Finished installing pack dependencies.'); } } else { throw new UserCancellationException('No packs selected.'); diff --git a/extensions/ql-vscode/src/vscode-tests/cli-integration/packaging.test.ts b/extensions/ql-vscode/src/vscode-tests/cli-integration/packaging.test.ts index 1c52ec5b9f6..29d5bdb2b88 100644 --- a/extensions/ql-vscode/src/vscode-tests/cli-integration/packaging.test.ts +++ b/extensions/ql-vscode/src/vscode-tests/cli-integration/packaging.test.ts @@ -101,9 +101,9 @@ describe('Packaging commands', function() { }, ]); - await mod.handleInstallPacks(cli, progress); + await mod.handleInstallPackDependencies(cli, progress); expect(showAndLogInformationMessageSpy.firstCall.args[0]).to.contain( - 'Finished installing packs.' + 'Finished installing pack dependencies.' ); }); @@ -118,11 +118,11 @@ describe('Packaging commands', function() { try { // expect this to throw an error - await mod.handleInstallPacks(cli, progress); + await mod.handleInstallPackDependencies(cli, progress); // This line should not be reached expect(true).to.be.false; } catch (error) { - expect(error.message).to.contain('Unable to install packs:'); + expect(error.message).to.contain('Unable to install pack dependencies'); } }); }); From 0185c398a6ffad293790dfcb569f28cd74d06ca4 Mon Sep 17 00:00:00 2001 From: Shati Patel <42641846+shati-patel@users.noreply.github.com> Date: Wed, 19 Jan 2022 20:30:16 +0000 Subject: [PATCH 10/10] Update extensions/ql-vscode/CHANGELOG.md Co-authored-by: Aditya Sharad <6874315+adityasharad@users.noreply.github.com> --- extensions/ql-vscode/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/ql-vscode/CHANGELOG.md b/extensions/ql-vscode/CHANGELOG.md index 220abd9014d..094f539376c 100644 --- a/extensions/ql-vscode/CHANGELOG.md +++ b/extensions/ql-vscode/CHANGELOG.md @@ -3,7 +3,7 @@ ## [UNRELEASED] - Fix a bug where the results view moved column even when it was already visible. [#1070](https://github.com/github/vscode-codeql/pull/1070) -- Add packaging-related commands. _CodeQL: Download Packs_ downloads packs from the package registry, and _CodeQL: Install Packs_ installs dependencies for packs in your workspace. [#1076](https://github.com/github/vscode-codeql/pull/1076) +- Add packaging-related commands. _CodeQL: Download Packs_ downloads query packs from the package registry that can be run locally, and _CodeQL: Install Pack Dependencies_ installs dependencies for packs in your workspace. [#1076](https://github.com/github/vscode-codeql/pull/1076) ## 1.5.9 - 17 December 2021