Basic support for extension bundles
This commit is contained in:
Родитель
dbfa2fc5f5
Коммит
783cc3e89d
|
@ -68,7 +68,11 @@ export class FunctionConfig {
|
|||
}
|
||||
|
||||
public get isHttpTrigger(): boolean {
|
||||
return !!this.inBinding && !!this.inBinding.type && this.inBinding.type.toLowerCase() === 'httptrigger';
|
||||
return !!this.inBinding && !!this.inBinding.type && /^http/i.test(this.inBinding.type);
|
||||
}
|
||||
|
||||
public get isTimerTrigger(): boolean {
|
||||
return !!this.inBinding && !!this.inBinding.type && /^timer/i.test(this.inBinding.type);
|
||||
}
|
||||
|
||||
public get authLevel(): HttpAuthLevel {
|
||||
|
|
|
@ -6,12 +6,14 @@
|
|||
import * as fse from 'fs-extra';
|
||||
import * as path from 'path';
|
||||
import { Progress, Uri, window, workspace } from 'vscode';
|
||||
import { AzureWizardExecuteStep, callWithTelemetryAndErrorHandling, IActionContext } from 'vscode-azureextensionui';
|
||||
import { localSettingsFileName } from '../../constants';
|
||||
import { AzureWizardExecuteStep, callWithTelemetryAndErrorHandling, IActionContext, parseError } from 'vscode-azureextensionui';
|
||||
import { hostFileName, localSettingsFileName, ProjectRuntime } from '../../constants';
|
||||
import { ext } from '../../extensionVariables';
|
||||
import { IHostJson } from '../../funcConfig/host';
|
||||
import { validateAzureWebJobsStorage } from '../../LocalAppSettings';
|
||||
import { localize } from '../../localize';
|
||||
import { IFunctionTemplate } from '../../templates/IFunctionTemplate';
|
||||
import { writeFormattedJson } from '../../utils/fs';
|
||||
import { nonNullProp } from '../../utils/nonNull';
|
||||
import { getContainingWorkspace } from '../../utils/workspace';
|
||||
import { IFunctionWizardContext } from './IFunctionWizardContext';
|
||||
|
@ -53,6 +55,10 @@ export abstract class FunctionCreateStepBase<T extends IFunctionWizardContext> e
|
|||
progress.report({ message: localize('creatingFunction', 'Creating new {0}...', template.name) });
|
||||
|
||||
const newFilePath: string = await this.executeCore(wizardContext);
|
||||
if (wizardContext.runtime !== ProjectRuntime.v1 && !template.isHttpTrigger && !template.isTimerTrigger) {
|
||||
await this.verifyExtensionBundle(wizardContext);
|
||||
}
|
||||
|
||||
const cachedFunc: ICachedFunction = { projectPath: wizardContext.projectPath, newFilePath, isHttpTrigger: template.isHttpTrigger };
|
||||
|
||||
if (wizardContext.openBehavior) {
|
||||
|
@ -65,6 +71,23 @@ export abstract class FunctionCreateStepBase<T extends IFunctionWizardContext> e
|
|||
runPostFunctionCreateSteps(cachedFunc);
|
||||
}
|
||||
|
||||
public async verifyExtensionBundle(wizardContext: T): Promise<void> {
|
||||
const hostFilePath: string = path.join(wizardContext.projectPath, hostFileName);
|
||||
try {
|
||||
const hostJson: IHostJson = <IHostJson>await fse.readJSON(hostFilePath);
|
||||
if (!hostJson.extensionBundle) {
|
||||
// https://github.com/Microsoft/vscode-azurefunctions/issues/1202
|
||||
hostJson.extensionBundle = {
|
||||
id: 'Microsoft.Azure.Functions.ExtensionBundle',
|
||||
version: '[1.*, 2.0.0)'
|
||||
};
|
||||
await writeFormattedJson(hostFilePath, hostJson);
|
||||
}
|
||||
} catch (error) {
|
||||
throw new Error(localize('failedToParseHostJson', 'Failed to parse {0}: {1}', hostFileName, parseError(error).message));
|
||||
}
|
||||
}
|
||||
|
||||
public shouldExecute(wizardContext: T): boolean {
|
||||
return !!wizardContext.functionTemplate;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import * as os from 'os';
|
|||
import * as path from 'path';
|
||||
import { Progress } from 'vscode';
|
||||
import { gitignoreFileName, hostFileName, localSettingsFileName, ProjectRuntime, proxiesFileName } from '../../../constants';
|
||||
import { IHostJson } from '../../../funcConfig/host';
|
||||
import { ILocalAppSettings } from '../../../LocalAppSettings';
|
||||
import { confirmOverwriteFile, writeFormattedJson } from "../../../utils/fs";
|
||||
import { nonNullProp } from '../../../utils/nonNull';
|
||||
|
@ -24,7 +25,7 @@ export class ScriptProjectCreateStep extends ProjectCreateStepBase {
|
|||
const runtime: ProjectRuntime = nonNullProp(wizardContext, 'runtime');
|
||||
const hostJsonPath: string = path.join(wizardContext.projectPath, hostFileName);
|
||||
if (await confirmOverwriteFile(hostJsonPath)) {
|
||||
const hostJson: object = this.getHostContent(runtime);
|
||||
const hostJson: IHostJson = this.getHostContent(runtime);
|
||||
await writeFormattedJson(hostJsonPath, hostJson);
|
||||
}
|
||||
|
||||
|
@ -71,7 +72,7 @@ local.settings.json`));
|
|||
}
|
||||
}
|
||||
|
||||
private getHostContent(runtime: ProjectRuntime): object {
|
||||
private getHostContent(runtime: ProjectRuntime): IHostJson {
|
||||
if (runtime === ProjectRuntime.v2) {
|
||||
if (this.supportsManagedDependencies) {
|
||||
return {
|
||||
|
|
|
@ -36,7 +36,7 @@ export abstract class InitVSCodeStepBase extends AzureWizardExecuteStep<IProject
|
|||
|
||||
const vscodePath: string = path.join(wizardContext.workspacePath, '.vscode');
|
||||
await fse.ensureDir(vscodePath);
|
||||
await this.writeTasksJson(wizardContext, vscodePath, runtime);
|
||||
await this.writeTasksJson(wizardContext, vscodePath);
|
||||
await this.writeLaunchJson(wizardContext.workspaceFolder, vscodePath, runtime);
|
||||
await this.writeSettingsJson(wizardContext.workspaceFolder, vscodePath, language, runtime);
|
||||
await this.writeExtensionsJson(vscodePath, language);
|
||||
|
@ -55,7 +55,7 @@ export abstract class InitVSCodeStepBase extends AzureWizardExecuteStep<IProject
|
|||
}
|
||||
|
||||
protected abstract executeCore(wizardContext: IProjectWizardContext): Promise<void>;
|
||||
protected abstract getTasks(runtime: ProjectRuntime): TaskDefinition[];
|
||||
protected abstract getTasks(): TaskDefinition[];
|
||||
protected getDebugConfiguration?(runtime: ProjectRuntime): DebugConfiguration;
|
||||
protected getRecommendedExtensions?(language: ProjectLanguage): string[];
|
||||
|
||||
|
@ -71,8 +71,8 @@ export abstract class InitVSCodeStepBase extends AzureWizardExecuteStep<IProject
|
|||
return path.posix.join(subDir, fsPath);
|
||||
}
|
||||
|
||||
private async writeTasksJson(wizardContext: IProjectWizardContext, vscodePath: string, runtime: ProjectRuntime): Promise<void> {
|
||||
const newTasks: TaskDefinition[] = this.getTasks(runtime);
|
||||
private async writeTasksJson(wizardContext: IProjectWizardContext, vscodePath: string): Promise<void> {
|
||||
const newTasks: TaskDefinition[] = this.getTasks();
|
||||
for (const task of newTasks) {
|
||||
// tslint:disable-next-line: strict-boolean-expressions no-unsafe-any
|
||||
let cwd: string = (task.options && task.options.cwd) || '.';
|
||||
|
|
|
@ -7,7 +7,7 @@ import * as fse from 'fs-extra';
|
|||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
import { DebugConfiguration, TaskDefinition } from 'vscode';
|
||||
import { extensionPrefix, extInstallCommand, extInstallTaskName, func, funcWatchProblemMatcher, gitignoreFileName, hostStartCommand, isWindows, localSettingsFileName, packTaskName, Platform, pythonVenvSetting } from "../../../constants";
|
||||
import { extensionPrefix, extInstallCommand, func, funcWatchProblemMatcher, gitignoreFileName, hostStartCommand, isWindows, localSettingsFileName, packTaskName, Platform, pythonVenvSetting } from "../../../constants";
|
||||
import { pythonDebugConfig } from '../../../debug/PythonDebugProvider';
|
||||
import { azureWebJobsStorageKey, getLocalAppSettings, ILocalAppSettings } from '../../../LocalAppSettings';
|
||||
import { writeFormattedJson } from '../../../utils/fs';
|
||||
|
@ -21,6 +21,8 @@ export class PythonInitVSCodeStep extends ScriptInitVSCodeStep {
|
|||
private _venvName: string | undefined;
|
||||
|
||||
protected async executeCore(wizardContext: IProjectWizardContext): Promise<void> {
|
||||
await super.executeCore(wizardContext);
|
||||
|
||||
const zipPath: string = this.setDeploySubpath(wizardContext, `${path.basename(wizardContext.projectPath)}.zip`);
|
||||
|
||||
this._venvName = await getExistingVenv(wizardContext.projectPath);
|
||||
|
@ -38,18 +40,28 @@ export class PythonInitVSCodeStep extends ScriptInitVSCodeStep {
|
|||
}
|
||||
|
||||
protected getTasks(): TaskDefinition[] {
|
||||
const pipInstallLabel: string = 'pipInstall';
|
||||
const dependsOn: string | undefined = this.requiresFuncExtensionsInstall ? extInstallCommand : this._venvName ? pipInstallLabel : undefined;
|
||||
const tasks: TaskDefinition[] = [
|
||||
{
|
||||
type: func,
|
||||
command: hostStartCommand,
|
||||
problemMatcher: funcWatchProblemMatcher,
|
||||
isBackground: true,
|
||||
dependsOn: extInstallTaskName
|
||||
dependsOn
|
||||
}
|
||||
];
|
||||
|
||||
if (this._venvName) {
|
||||
const pipInstallLabel: string = 'pipInstall';
|
||||
if (this.requiresFuncExtensionsInstall) {
|
||||
tasks.push({
|
||||
type: func,
|
||||
command: extInstallCommand,
|
||||
dependsOn: pipInstallLabel,
|
||||
problemMatcher: []
|
||||
});
|
||||
}
|
||||
|
||||
const venvSettingReference: string = `\${config:${extensionPrefix}.${pythonVenvSetting}}`;
|
||||
|
||||
function getPipInstallCommand(platform: NodeJS.Platform): string {
|
||||
|
@ -57,12 +69,6 @@ export class PythonInitVSCodeStep extends ScriptInitVSCodeStep {
|
|||
}
|
||||
|
||||
tasks.push(
|
||||
{
|
||||
type: func,
|
||||
command: extInstallCommand,
|
||||
dependsOn: pipInstallLabel,
|
||||
problemMatcher: []
|
||||
},
|
||||
{
|
||||
label: pipInstallLabel,
|
||||
type: 'shell',
|
||||
|
|
|
@ -3,8 +3,10 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as semver from 'semver';
|
||||
import { TaskDefinition } from 'vscode';
|
||||
import { extInstallTaskName, func, funcWatchProblemMatcher, hostStartCommand, ProjectRuntime } from '../../../constants';
|
||||
import { getLocalFuncCoreToolsVersion } from '../../../funcCoreTools/getLocalFuncCoreToolsVersion';
|
||||
import { IProjectWizardContext } from '../../createNewProject/IProjectWizardContext';
|
||||
import { InitVSCodeStepBase } from './InitVSCodeStepBase';
|
||||
|
||||
|
@ -12,28 +14,41 @@ import { InitVSCodeStepBase } from './InitVSCodeStepBase';
|
|||
* Base class for all projects based on a simple script (i.e. JavaScript, C# Script, Bash, etc.) that don't require compilation
|
||||
*/
|
||||
export class ScriptInitVSCodeStep extends InitVSCodeStepBase {
|
||||
protected getTasks(runtime: ProjectRuntime): TaskDefinition[] {
|
||||
protected requiresFuncExtensionsInstall: boolean = false;
|
||||
|
||||
protected getTasks(): TaskDefinition[] {
|
||||
return [
|
||||
{
|
||||
type: func,
|
||||
command: hostStartCommand,
|
||||
problemMatcher: funcWatchProblemMatcher,
|
||||
dependsOn: runtime === ProjectRuntime.v1 ? undefined : extInstallTaskName,
|
||||
dependsOn: this.requiresFuncExtensionsInstall ? extInstallTaskName : undefined,
|
||||
isBackground: true
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
protected async executeCore(wizardContext: IProjectWizardContext): Promise<void> {
|
||||
// "func extensions install" task creates C# build artifacts that should be hidden
|
||||
// See issue: https://github.com/Microsoft/vscode-azurefunctions/pull/699
|
||||
this.settings.push({ prefix: 'files', key: 'exclude', value: { obj: true, bin: true } });
|
||||
if (wizardContext.runtime === ProjectRuntime.v2) {
|
||||
try {
|
||||
const currentVersion: string | null = await getLocalFuncCoreToolsVersion();
|
||||
// Starting after this version, projects can use extension bundle instead of running "func extensions install"
|
||||
this.requiresFuncExtensionsInstall = !!currentVersion && semver.lte(currentVersion, '2.5.553');
|
||||
} catch {
|
||||
// use default of false
|
||||
}
|
||||
}
|
||||
|
||||
this.setDeploySubpath(wizardContext, '.');
|
||||
if (!this.preDeployTask) {
|
||||
if (wizardContext.runtime !== ProjectRuntime.v1) {
|
||||
if (this.requiresFuncExtensionsInstall) {
|
||||
// "func extensions install" task creates C# build artifacts that should be hidden
|
||||
// See issue: https://github.com/Microsoft/vscode-azurefunctions/pull/699
|
||||
this.settings.push({ prefix: 'files', key: 'exclude', value: { obj: true, bin: true } });
|
||||
|
||||
if (!this.preDeployTask) {
|
||||
this.preDeployTask = extInstallTaskName;
|
||||
}
|
||||
}
|
||||
|
||||
this.setDeploySubpath(wizardContext, '.');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { TaskDefinition } from 'vscode';
|
||||
import { extInstallTaskName, func, funcWatchProblemMatcher, hostStartCommand, ProjectRuntime } from '../../../constants';
|
||||
import { extInstallTaskName, func, funcWatchProblemMatcher, hostStartCommand } from '../../../constants';
|
||||
import { JavaScriptInitVSCodeStep } from "./JavaScriptInitVSCodeStep";
|
||||
|
||||
const npmPruneTaskLabel: string = 'npm prune';
|
||||
|
@ -14,7 +14,7 @@ const npmBuildTaskLabel: string = 'npm build';
|
|||
export class TypeScriptInitVSCodeStep extends JavaScriptInitVSCodeStep {
|
||||
public readonly preDeployTask: string = npmPruneTaskLabel;
|
||||
|
||||
public getTasks(runtime: ProjectRuntime): TaskDefinition[] {
|
||||
public getTasks(): TaskDefinition[] {
|
||||
return [
|
||||
{
|
||||
type: func,
|
||||
|
@ -27,7 +27,7 @@ export class TypeScriptInitVSCodeStep extends JavaScriptInitVSCodeStep {
|
|||
type: 'shell',
|
||||
label: npmBuildTaskLabel,
|
||||
command: 'npm run build',
|
||||
dependsOn: runtime === ProjectRuntime.v1 ? npmInstallTaskLabel : [extInstallTaskName, npmInstallTaskLabel],
|
||||
dependsOn: this.requiresFuncExtensionsInstall ? [extInstallTaskName, npmInstallTaskLabel] : npmInstallTaskLabel,
|
||||
problemMatcher: '$tsc'
|
||||
},
|
||||
{
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
This folder contains logic related to Azure Functions project files, like "local.settings.json", "host.json", and "function.json".
|
|
@ -0,0 +1,15 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
export interface IHostJson {
|
||||
version?: string;
|
||||
managedDependency?: {
|
||||
enabled?: boolean;
|
||||
};
|
||||
extensionBundle?: {
|
||||
id?: string;
|
||||
version?: string;
|
||||
};
|
||||
}
|
|
@ -18,6 +18,7 @@ export interface IFunctionTemplate {
|
|||
defaultFunctionName: string;
|
||||
language: string;
|
||||
isHttpTrigger: boolean;
|
||||
isTimerTrigger: boolean;
|
||||
userPromptedSettings: IFunctionSetting[];
|
||||
categories: TemplateCategory[];
|
||||
}
|
||||
|
|
|
@ -54,7 +54,8 @@ function parseDotnetTemplate(rawTemplate: IRawTemplate): IFunctionTemplate {
|
|||
}
|
||||
|
||||
return {
|
||||
isHttpTrigger: rawTemplate.Name.toLowerCase().startsWith('http') || rawTemplate.Name.toLowerCase().endsWith('webhook'),
|
||||
isHttpTrigger: /^http/i.test(rawTemplate.Name) || /webhook$/i.test(rawTemplate.Name),
|
||||
isTimerTrigger: /^timer/i.test(rawTemplate.Name),
|
||||
id: rawTemplate.Identity,
|
||||
name: rawTemplate.Name,
|
||||
defaultFunctionName: rawTemplate.DefaultName,
|
||||
|
|
|
@ -197,6 +197,7 @@ export function parseScriptTemplate(rawTemplate: IRawTemplate, resources: IResou
|
|||
return {
|
||||
functionConfig: functionConfig,
|
||||
isHttpTrigger: functionConfig.isHttpTrigger,
|
||||
isTimerTrigger: functionConfig.isTimerTrigger,
|
||||
id: rawTemplate.id,
|
||||
name: getResourceValue(resources, rawTemplate.metadata.name),
|
||||
defaultFunctionName: rawTemplate.metadata.defaultFunctionName,
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
This folder contains logic related to VS Code project files, like "settings.json", "tasks.json", and "launch.json".
|
|
@ -13,8 +13,7 @@ export function getJavaScriptValidateOptions(): IValidateProjectOptions {
|
|||
expectedSettings: {
|
||||
projectLanguage: ProjectLanguage.JavaScript,
|
||||
projectRuntime: ProjectRuntime.v2,
|
||||
deploySubpath: '.',
|
||||
preDeployTask: 'func: extensions install'
|
||||
deploySubpath: '.'
|
||||
},
|
||||
expectedPaths: [
|
||||
],
|
||||
|
@ -135,7 +134,6 @@ export function getPythonValidateOptions(projectName: string, venvName: string):
|
|||
'Attach to Python Functions'
|
||||
],
|
||||
expectedTasks: [
|
||||
'extensions install',
|
||||
'pipInstall',
|
||||
'host start'
|
||||
]
|
||||
|
@ -196,8 +194,7 @@ export function getPowerShellValidateOptions(): IValidateProjectOptions {
|
|||
expectedSettings: {
|
||||
projectLanguage: ProjectLanguage.PowerShell,
|
||||
projectRuntime: ProjectRuntime.v2,
|
||||
deploySubpath: '.',
|
||||
preDeployTask: 'func: extensions install'
|
||||
deploySubpath: '.'
|
||||
},
|
||||
expectedPaths: [
|
||||
'profile.ps1',
|
||||
|
|
Загрузка…
Ссылка в новой задаче