From 8c7c30ffee69cfa9473413634942c4ace80dd399 Mon Sep 17 00:00:00 2001 From: David Thompson Date: Fri, 5 Mar 2021 14:38:59 -0500 Subject: [PATCH] RESTEasy can be excluded if using code.quarkus.io Reads the data from code.quarkus.io or code.quarkus.redhat.com to see which quarkus extensions are required. This means if code.quarkus.io is used, then resteasy is not required. Reads the Open API of the code quarkus instance to determine if the option to prevent sample code being generated is present. If it is, then it adds another step to the project generation wizard to specify if sample code should be generated. Closes #322 Signed-off-by: David Thompson --- package-lock.json | 49 +++++++++-- package.json | 3 + src/commands/registerCommands.ts | 2 +- src/definitions/QExtension.ts | 7 +- src/definitions/inputState.ts | 1 + src/extension.ts | 4 +- .../vscodeUiTest/ProjectGenerationWizard.ts | 21 ++++- .../suite/projectGenerationTest.ts | 62 +++++++------ src/utils/codeQuarkusApiUtils.ts | 86 +++++++++++++++++++ src/utils/requestUtils.ts | 1 + .../generateProject/ExtensionsPicker.ts | 2 +- .../generateProject/generationWizard.ts | 33 ++++++- tslint.json | 3 +- 13 files changed, 225 insertions(+), 49 deletions(-) create mode 100644 src/utils/codeQuarkusApiUtils.ts diff --git a/package-lock.json b/package-lock.json index 1c1f592b..aec0b6dc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -265,6 +265,12 @@ "@types/node": "*" } }, + "@types/ejs": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/ejs/-/ejs-3.0.7.tgz", + "integrity": "sha512-AUxAGNIPr7wQmzdFMNhHy/RkR5kk8gSzAZIuCYY//6ZYJKHvnjezmoEYP34coPleUPnqrUWt03cCq7NzNaA/qg==", + "dev": true + }, "@types/eslint": { "version": "7.2.7", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.2.7.tgz", @@ -300,6 +306,12 @@ "@types/node": "*" } }, + "@types/js-yaml": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.2.tgz", + "integrity": "sha512-KbeHS/Y4R+k+5sWXEYzAZKuB1yQlZtEghuhRxrVRLaqhtoG5+26JwQsa4HyS3AWX8v1Uwukma5HheduUDskasA==", + "dev": true + }, "@types/json-schema": { "version": "7.0.7", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz", @@ -4201,13 +4213,18 @@ "dev": true }, "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", - "dev": true, + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "argparse": "^2.0.1" + }, + "dependencies": { + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + } } }, "jsbn": { @@ -7385,6 +7402,16 @@ "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", "dev": true + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } } } }, @@ -7907,6 +7934,16 @@ "path-is-absolute": "^1.0.0" } }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, "jsonfile": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", diff --git a/package.json b/package.json index 0beb0577..07bda1bf 100644 --- a/package.json +++ b/package.json @@ -267,7 +267,9 @@ "devDependencies": { "@types/chai": "^4.2.3", "@types/chai-fs": "^2.0.2", + "@types/ejs": "^3.0.5", "@types/fs-extra": "^7.0.0", + "@types/js-yaml": "^4.0.0", "@types/lodash": "^4.14.149", "@types/mocha": "^5.2.6", "@types/node": "^10.14.16", @@ -302,6 +304,7 @@ "find-up": "^4.1.0", "fs-extra": "^8.0.1", "glob": "^7.1.4", + "js-yaml": "^4.0.0", "lodash": "^4.17.21", "request": "^2.88.0", "request-promise": "^4.2.4", diff --git a/src/commands/registerCommands.ts b/src/commands/registerCommands.ts index 98e7f641..fd74f9d1 100644 --- a/src/commands/registerCommands.ts +++ b/src/commands/registerCommands.ts @@ -7,8 +7,8 @@ import { WelcomeWebview } from "../webviews/WelcomeWebview"; import { addExtensionsWizard } from "../wizards/addExtensions/addExtensionsWizard"; import { buildBinary } from "../wizards/binary/buildBinary"; import { startDebugging } from "../wizards/debugging/startDebugging"; -import { generateProjectWizard } from "../wizards/generateProject/generationWizard"; import { deployToOpenShift } from "../wizards/deployToOpenShift/deployToOpenShift"; +import { generateProjectWizard } from "../wizards/generateProject/generationWizard"; const NOT_A_QUARKUS_PROJECT = new Error('No Quarkus projects were detected in this folder'); const STANDARD_MODE_REQUEST_FAILED = new Error('Error occurred while requesting standard mode from the Java language server'); diff --git a/src/definitions/QExtension.ts b/src/definitions/QExtension.ts index 7e8036f0..1b459c5a 100644 --- a/src/definitions/QExtension.ts +++ b/src/definitions/QExtension.ts @@ -28,14 +28,14 @@ export class QExtension { artifactId: string; isRequired: boolean; - constructor(name: string, category: string, description: string, labels: string[], groupId: string, artifactId: string) { + constructor(name: string, category: string, description: string, labels: string[], groupId: string, artifactId: string, isRequired: boolean) { this.name = name; this.category = category; this.description = description; this.labels = labels; this.groupId = groupId; this.artifactId = artifactId; - this.isRequired = name === 'RESTEasy JAX-RS'; // 'RESTEasy JAX-RS' is included in every Quarkus project + this.isRequired = isRequired; } getGroupIdArtifactIdString() { @@ -61,7 +61,7 @@ export function convertToQExtension(extension: APIExtension): QExtension { artifactId = extension.id; } return new QExtension(extension.name, extension.category, extension.description, - extension.labels, groupId, artifactId); + extension.labels, groupId, artifactId, extension.default); } /** @@ -76,4 +76,5 @@ export interface APIExtension { shortName: string; category: string; order: Number; + default: boolean; } diff --git a/src/definitions/inputState.ts b/src/definitions/inputState.ts index d2c2d045..838ba0d7 100644 --- a/src/definitions/inputState.ts +++ b/src/definitions/inputState.ts @@ -34,6 +34,7 @@ export interface ProjectGenState extends State { packageName: string; resourceName: string; targetDir: Uri; + isGenerateSampleCode: boolean; } export interface AddExtensionsState extends State { diff --git a/src/extension.ts b/src/extension.ts index e3eefc42..5b804e9c 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -13,19 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { TelemetryService } from '@redhat-developer/vscode-redhat-telemetry'; import * as path from 'path'; import { commands, ConfigurationChangeEvent, Disposable, ExtensionContext, languages, Terminal, TextDocument, window, workspace } from 'vscode'; import { registerVSCodeCommands } from './commands/registerCommands'; -import { VSCODE_QUARKUS_EXTENSION_NAME } from './definitions/constants'; import { ProjectLabelInfo } from './definitions/ProjectLabelInfo'; import { PropertiesLanguageMismatch, QuarkusConfig } from './QuarkusConfig'; import { QuarkusContext } from './QuarkusContext'; import quarkusProjectListener from './QuarkusProjectListener'; import { terminalCommandRunner } from './terminal/terminalCommandRunner'; +import { initTelemetryService } from './utils/telemetryUtils'; import { WelcomeWebview } from './webviews/WelcomeWebview'; import { createTerminateDebugListener } from './wizards/debugging/terminateProcess'; -import { initTelemetryService } from './utils/telemetryUtils'; export async function activate(context: ExtensionContext) { diff --git a/src/test/vscodeUiTest/ProjectGenerationWizard.ts b/src/test/vscodeUiTest/ProjectGenerationWizard.ts index 0ed56898..92998c61 100644 --- a/src/test/vscodeUiTest/ProjectGenerationWizard.ts +++ b/src/test/vscodeUiTest/ProjectGenerationWizard.ts @@ -14,8 +14,7 @@ * limitations under the License. */ import * as _ from 'lodash'; - -import { InputBox, QuickPickItem, Workbench, WebDriver, WebElement, By, until, Key } from 'vscode-extension-tester'; +import { By, InputBox, Key, QuickPickItem, WebDriver, WebElement, Workbench } from 'vscode-extension-tester'; import { DialogHandler, OpenDialog } from 'vscode-extension-tester-native'; /** @@ -30,7 +29,7 @@ export class ProjectGenerationWizard extends InputBox { /** * The number of steps the wizard has */ - private lastStep: number = 7; + private lastStep: number = 8; /** * Opens the project generation wizard @@ -78,6 +77,9 @@ export class ProjectGenerationWizard extends InputBox { await wizard.confirm(); } } + await wizard.focusQuickPick(0); + await wizard.next(); + await wizard.focusQuickPick(0); await wizard.next(); const dialog: OpenDialog = await DialogHandler.getOpenDialog(); @@ -213,6 +215,19 @@ export class ProjectGenerationWizard extends InputBox { return (await this.getNthQuickPickItemInfo(n)).label; } + /** + * Focuses on the quick pick with the given index + * + * @param n the index of the quick pick option to focus + * @returns when the quick pick is focused + */ + public async focusQuickPick(n: number): Promise { + const quickPickToFocus: QuickPickItem = await this.findQuickPick(n); + while (!(await quickPickToFocus.getAttribute('class')).includes('focused')) { + await this.sendKeys(Key.DOWN); + } + } + /** * Returns the `n`th quick pick item's `QuickPickItemInfo` * @param n diff --git a/src/test/vscodeUiTest/suite/projectGenerationTest.ts b/src/test/vscodeUiTest/suite/projectGenerationTest.ts index 80485caf..99e28484 100644 --- a/src/test/vscodeUiTest/suite/projectGenerationTest.ts +++ b/src/test/vscodeUiTest/suite/projectGenerationTest.ts @@ -100,76 +100,82 @@ describe('Project generation tests', function() { expect(resourceName).equals('GreetingResource'); await wizard.next(); - await wizard.sendKeys(Key.DOWN, Key.UP); - - expect(await wizard.getNthQuickPickItemLabel(0)).to.have.string('1 extension selected'); - await wizard.sendKeys(Key.DOWN, Key.DOWN); - await wizard.confirm(); - expect(await wizard.getNthQuickPickItemLabel(0)).to.have.string('2 extensions selected'); - await wizard.sendKeys(Key.DOWN, Key.DOWN, Key.DOWN); + await wizard.focusQuickPick(0); + expect(await wizard.getNthQuickPickItemLabel(0)).to.have.string('0 extensions selected'); + await wizard.focusQuickPick(2); await wizard.confirm(); - expect(await wizard.getNthQuickPickItemLabel(0)).to.have.string('3 extensions selected'); - await wizard.sendKeys(Key.DOWN); + expect(await wizard.getNthQuickPickItemLabel(0)).to.have.string('1 extension selected'); + await wizard.focusQuickPick(3); await wizard.confirm(); expect(await wizard.getNthQuickPickItemLabel(0)).to.have.string('2 extensions selected'); - await wizard.sendKeys(Key.DOWN); + await wizard.focusQuickPick(1); await wizard.confirm(); expect(await wizard.getNthQuickPickItemLabel(0)).to.have.string('1 extension selected'); + await wizard.focusQuickPick(1); + await wizard.confirm(); + expect(await wizard.getNthQuickPickItemLabel(0)).to.have.string('0 extensions selected'); await wizard.cancel(); }); /** * Tests if the project generation wizard has correct - * step values at the wizard's title bar: (1/7), (2/7) + * step values at the wizard's title bar: (1/8), (2/8) */ it('should have correct step values', async function() { this.timeout(30000); const wizard: ProjectGenerationWizard = await ProjectGenerationWizard.openWizard(driver); - expect(await wizard.getInputBoxTitle()).to.have.string('1/7'); + expect(await wizard.getInputBoxTitle()).to.have.string('1/8'); expect(await wizard.getBackButton()).to.not.be.ok; await wizard.next(); - expect(await wizard.getInputBoxTitle()).to.have.string('2/7'); + expect(await wizard.getInputBoxTitle()).to.have.string('2/8'); await wizard.next(); - expect(await wizard.getInputBoxTitle()).to.have.string('3/7'); + expect(await wizard.getInputBoxTitle()).to.have.string('3/8'); await wizard.next(); - expect(await wizard.getInputBoxTitle()).to.have.string('4/7'); + expect(await wizard.getInputBoxTitle()).to.have.string('4/8'); await wizard.next(); - expect(await wizard.getInputBoxTitle()).to.have.string('5/7'); + expect(await wizard.getInputBoxTitle()).to.have.string('5/8'); await wizard.next(); - expect(await wizard.getInputBoxTitle()).to.have.string('6/7'); + expect(await wizard.getInputBoxTitle()).to.have.string('6/8'); await wizard.next(); - expect(await wizard.getInputBoxTitle()).to.have.string('7/7'); + expect(await wizard.getInputBoxTitle()).to.have.string('7/8'); + await wizard.focusQuickPick(0); + await wizard.next(); + + expect(await wizard.getInputBoxTitle()).to.have.string('8/8'); + await wizard.prev(); + + expect(await wizard.getInputBoxTitle()).to.have.string('7/8'); await wizard.prev(); - expect(await wizard.getInputBoxTitle()).to.have.string('6/7'); + expect(await wizard.getInputBoxTitle()).to.have.string('6/8'); await wizard.prev(); - expect(await wizard.getInputBoxTitle()).to.have.string('5/7'); + expect(await wizard.getInputBoxTitle()).to.have.string('5/8'); await wizard.prev(); - expect(await wizard.getInputBoxTitle()).to.have.string('4/7'); + expect(await wizard.getInputBoxTitle()).to.have.string('4/8'); await wizard.prev(); - expect(await wizard.getInputBoxTitle()).to.have.string('3/7'); + expect(await wizard.getInputBoxTitle()).to.have.string('3/8'); await wizard.prev(); - expect(await wizard.getInputBoxTitle()).to.have.string('2/7'); + expect(await wizard.getInputBoxTitle()).to.have.string('2/8'); await wizard.prev(); - expect(await wizard.getInputBoxTitle()).to.have.string('1/7'); + expect(await wizard.getInputBoxTitle()).to.have.string('1/8'); expect(await wizard.getBackButton()).to.not.be.ok; await wizard.next(); - expect(await wizard.getInputBoxTitle()).to.have.string('2/7'); + expect(await wizard.getInputBoxTitle()).to.have.string('2/8'); await wizard.prev(); - expect(await wizard.getInputBoxTitle()).to.have.string('1/7'); + expect(await wizard.getInputBoxTitle()).to.have.string('1/8'); expect(await wizard.getBackButton()).to.not.be.ok; await wizard.cancel(); @@ -333,7 +339,7 @@ describe('Project generation tests', function() { * validation messages */ it('should have correct input validation messages', async function() { - this.timeout(30000); + this.timeout(60000); const wizard: ProjectGenerationWizard = await ProjectGenerationWizard.openWizard(driver); await wizard.next(); @@ -430,7 +436,7 @@ describe('Project generation tests', function() { * Tests if the extensions picker displays extensions without duplicates. */ it('should display extensions without duplicates', async function() { - this.timeout(60000); + this.timeout(120000); const wizard: ProjectGenerationWizard = await ProjectGenerationWizard.openWizard(driver); await wizard.next(); await wizard.next(); diff --git a/src/utils/codeQuarkusApiUtils.ts b/src/utils/codeQuarkusApiUtils.ts new file mode 100644 index 00000000..abbf63d8 --- /dev/null +++ b/src/utils/codeQuarkusApiUtils.ts @@ -0,0 +1,86 @@ +/** + * Copyright 2021 Red Hat, Inc. and others. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { IncomingMessage } from "http"; +import * as https from "https"; +import * as yaml from "js-yaml"; +import * as path from "path"; +import { URL } from "url"; +import { QuarkusConfig } from "../QuarkusConfig"; + +const HTTP_MATCHER = new RegExp('^http://'); + +export interface CodeQuarkusFunctionality { + canExcludeSampleCode: boolean; +} + +/** + * Returns the capabilities of the Code Quarkus API instance that is defined in the user settings + * + * @returns the capabilities of the Code Quarkus API instance that is defined in the user settings + * @throws if something goes wrong when getting the functionality from OpenAPI + */ +export async function getCodeQuarkusApiFunctionality(): Promise { + let oldOpenApiUrl: string = path.dirname(QuarkusConfig.getApiUrl()) + '/openapi'; + let newOpenApiUrl: string = path.dirname(QuarkusConfig.getApiUrl()) + '/q/openapi'; + oldOpenApiUrl = oldOpenApiUrl.replace(HTTP_MATCHER, "https://"); + newOpenApiUrl = newOpenApiUrl.replace(HTTP_MATCHER, "https://"); + let openApiYaml: string; + try { + openApiYaml = await httpsGet(newOpenApiUrl); + } catch { + openApiYaml = await httpsGet(oldOpenApiUrl); + } + const openApiData: any = yaml.load(openApiYaml); + + return { + canExcludeSampleCode: openApiData?.paths?.['/api/download']?.get?.parameters?.filter(p => p?.name === 'ne').length > 0 + } as CodeQuarkusFunctionality; +} + +/** + * Returns a set of capabilities that are implemented by all Code Quarkus APIs + * + * @returns a set of capabilities that are implemented by all Code Quarkus APIs + */ +export function getDefaultFunctionality() { + return { + canExcludeSampleCode: false + } as CodeQuarkusFunctionality; +} + +/** + * Returns the GET response body if the code is 200 and rejects otherwise + * + * @param url URL to GET + * @returns the response body if the code is 200 and rejects otherwise + * @throws if anything goes wrong (not 200 response, any other errors during get) + */ +async function httpsGet(url: string): Promise { + return new Promise((resolve, reject) => { + https.get(url, (res: IncomingMessage) => { + if (res.statusCode === 301 || res.statusCode === 302) { + httpsGet(new URL(url).origin + res.headers.location) // + .then(resolve, reject); + } else if (res.statusCode !== 200) { + reject(`${res.statusCode}: ${res.statusMessage}`); + } + res.on('data', (d: Buffer) => { + resolve(d.toString('utf8')); + }); + }) + .on('error', reject); + }); +} diff --git a/src/utils/requestUtils.ts b/src/utils/requestUtils.ts index 893caab0..1c7f77f2 100644 --- a/src/utils/requestUtils.ts +++ b/src/utils/requestUtils.ts @@ -75,6 +75,7 @@ export async function downloadProject(state: ProjectGenState): Promise `a=${state.artifactId}&` + `v=${state.projectVersion}&` + `c=${state.packageName}.${state.resourceName}&` + + `${(state.isGenerateSampleCode === undefined ? '' : `ne=${!state.isGenerateSampleCode}&`)}` + `e=${chosenIds.join('&e=')}`; const buffer: Buffer = await tryGetProjectBuffer(qProjectUrl); diff --git a/src/wizards/generateProject/ExtensionsPicker.ts b/src/wizards/generateProject/ExtensionsPicker.ts index ff0c5ac4..3a63cf18 100644 --- a/src/wizards/generateProject/ExtensionsPicker.ts +++ b/src/wizards/generateProject/ExtensionsPicker.ts @@ -251,7 +251,7 @@ export class ExtensionsPicker { const numSelected: number = this.selectedExtensions.length; items.push({ type: Type.Stop, - label: `$(tasklist) ${numSelected} extension${numSelected > 1 ? 's' : ''} selected`, + label: `$(tasklist) ${numSelected} extension${numSelected !== 1 ? 's' : ''} selected`, description: '', detail: 'Press to continue' }); diff --git a/src/wizards/generateProject/generationWizard.ts b/src/wizards/generateProject/generationWizard.ts index 087e59fc..a5806611 100644 --- a/src/wizards/generateProject/generationWizard.ts +++ b/src/wizards/generateProject/generationWizard.ts @@ -12,7 +12,8 @@ import { BuildToolName, INPUT_TITLE } from '../../definitions/constants'; import { ProjectGenState } from '../../definitions/inputState'; import { QExtension } from '../../definitions/QExtension'; import { QuarkusContext } from '../../QuarkusContext'; -import { MultiStepInput } from '../../utils/multiStepUtils'; +import { CodeQuarkusFunctionality, getCodeQuarkusApiFunctionality, getDefaultFunctionality } from '../../utils/codeQuarkusApiUtils'; +import { MultiStepInput, QuickPickParameters } from '../../utils/multiStepUtils'; import { downloadProject } from '../../utils/requestUtils'; import { ExtensionsPicker } from './ExtensionsPicker'; import { validateArtifactId, validateGroupId, validatePackageName, validateResourceName, validateVersion } from './validateInput'; @@ -24,8 +25,15 @@ import { validateArtifactId, validateGroupId, validatePackageName, validateResou */ export async function generateProjectWizard() { + let apiCapabilities: CodeQuarkusFunctionality; + try { + apiCapabilities = await getCodeQuarkusApiFunctionality(); + } catch (e) { + apiCapabilities = getDefaultFunctionality(); + } + const state: Partial = { - totalSteps: 7 + totalSteps: 7 + (apiCapabilities.canExcludeSampleCode ? 1 : 0) }; async function collectInputs(state: Partial) { @@ -139,7 +147,26 @@ export async function generateProjectWizard() { prompt: 'Your resource name', validate: validateResourceName }); - return (input: MultiStepInput) => ExtensionsPicker.createExtensionsPicker(input, state, { showLastUsed: true, showRequiredExtensions: true, allowZeroExtensions: true }); + return (input: MultiStepInput) => ExtensionsPicker.createExtensionsPicker( + input, state, { showLastUsed: true, showRequiredExtensions: true, allowZeroExtensions: true }, + (apiCapabilities.canExcludeSampleCode ? inputGenerateSampleCode: undefined)); + } + + async function inputGenerateSampleCode(input: MultiStepInput, state: Partial) { + const YES: string = 'Include sample code'; + const NO: string = 'Do not include sample code'; + const quickPickItems: QuickPickItem[] = [ + {label: YES, picked: true}, + {label: NO} + ]; + + state.isGenerateSampleCode = (await input.showQuickPick>({ + title: INPUT_TITLE, + placeholder: 'Should sample code be included? Additional dependencies may be added along with the sample.', + step: input.getStepNumber(), + totalSteps: state.totalSteps, + items: quickPickItems, + })).label === YES; } await collectInputs(state); diff --git a/tslint.json b/tslint.json index 92f83ad2..93bfdd0e 100644 --- a/tslint.json +++ b/tslint.json @@ -74,7 +74,8 @@ }, "linterOptions": { "exclude": [ - "test-resources" + "test-resources", + "out/**/*" ] } }