Allow programatic use of deploy, createFunction, and createNewProject

This commit is contained in:
Eric Jizba 2018-01-09 12:42:29 -08:00
Родитель 32b2fb8317
Коммит 4af25798c3
14 изменённых файлов: 277 добавлений и 149 удалений

57
docs/api.md Normal file
Просмотреть файл

@ -0,0 +1,57 @@
# Azure Functions API
The following extension commands are supported for programatic use. If a parameter is not specified, the user will be prompted for the value. You must list 'ms-azuretools.vscode-azurefunctions' under the 'extensionDependencies' section of your package.json to ensure these apis are available to your extension.
> NOTE: The functions extension is still in preview and the apis are subject to change.
Commands:
* [Create New Project](#create-new-project)
* [Create Function](#create-function)
* [Deploy](#deploy)
## Create New Project
### Parameters
|Name|Type|Description|
|---|---|---|
|projectPath|string|Absolute file path that will contain your new project. If the path doesn't exist, it will be created.|
|language|string|The currently supported languages are 'JavaScript' and 'Java'.|
|openFolder|boolean|(Defaulted to true) Represents whether or not to open the project folder after it has been created. If true, the extension host may be restarted when the folder is opened.|
### Example Usage
```typescript
await vscode.commands.executeCommand('azureFunctions.createNewProject', projectPath, 'JavaScript', false /* openFolder */);
```
## Create Function
### Parameters
|Name|Type|Description|
|---|---|---|
|projectPath|string|Absolute file path that contains your project.|
|templateId|string|The id of the template you want to create.|
|functionName|string|The name of the function to be created.|
|functionSettings|...string[]|Any settings unique to a template. For example, the HttpTrigger template requires an AuthorizationLevel parameter.|
### Example Usage
```typescript
await vscode.commands.executeCommand('azureFunctions.createFunction', projectPath, 'HttpTrigger-JavaScript', 'HttpTrigger1', 'Anonymous');
```
## Deploy
### Parameters
|Name|Type|Description|
|---|---|---|
|projectPath|string|Absolute file path that contains your project.|
|functionAppId|string|The id of the function app you are deploying to.|
### Example Usage
```typescript
await vscode.commands.executeCommand('azureFunctions.deploy', projectPath, '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/exampleGroup/providers/Microsoft.Web/sites/exampleSite');
```

Просмотреть файл

@ -6,7 +6,7 @@
import { IUserInterface } from "../../IUserInterface";
import { Template } from "../../templates/Template";
export abstract class AbstractFunctionCreator {
export abstract class FunctionCreatorBase {
protected readonly _functionNameRegex: RegExp = /^[a-zA-Z][a-zA-Z\d_\-]*$/;
protected _functionAppPath: string;
protected _template: Template;
@ -20,6 +20,6 @@ export abstract class AbstractFunctionCreator {
* Prompt for any settings that are specific to this creator
* This includes the function name (Since the name could have different restrictions for different languages)
*/
public abstract async promptForSettings(ui: IUserInterface): Promise<void>;
public abstract async promptForSettings(ui: IUserInterface, functionName: string | undefined): Promise<void>;
public abstract async createFunction(userSettings: { [propertyName: string]: string }): Promise<string | undefined>;
}

Просмотреть файл

@ -14,13 +14,13 @@ import { cpUtils } from "../../utils/cpUtils";
import * as fsUtil from '../../utils/fs';
import { getFullClassName, parseJavaClassName, validatePackageName } from "../../utils/javaNameUtils";
import { mavenUtils } from "../../utils/mavenUtils";
import { AbstractFunctionCreator } from './AbstractFunctionCreator';
import { FunctionCreatorBase } from './FunctionCreatorBase';
function getNewJavaFunctionFilePath(functionAppPath: string, packageName: string, functionName: string): string {
return path.join(functionAppPath, 'src', 'main', 'java', ...packageName.split('.'), `${parseJavaClassName(functionName)}.java`);
}
export class JavaFunctionCreator extends AbstractFunctionCreator {
export class JavaFunctionCreator extends FunctionCreatorBase {
private _outputChannel: OutputChannel;
private _packageName: string;
private _functionName: string;
@ -30,15 +30,19 @@ export class JavaFunctionCreator extends AbstractFunctionCreator {
this._outputChannel = outputChannel;
}
public async promptForSettings(ui: IUserInterface): Promise<void> {
public async promptForSettings(ui: IUserInterface, functionName: string | undefined): Promise<void> {
const packagePlaceHolder: string = localize('azFunc.java.packagePlaceHolder', 'Package');
const packagePrompt: string = localize('azFunc.java.packagePrompt', 'Provide a package name');
this._packageName = await ui.showInputBox(packagePlaceHolder, packagePrompt, false, validatePackageName, 'com.function');
const defaultFunctionName: string | undefined = await fsUtil.getUniqueJavaFsPath(this._functionAppPath, this._packageName, `${convertTemplateIdToJava(this._template.id)}Java`);
const placeHolder: string = localize('azFunc.funcNamePlaceholder', 'Function name');
const prompt: string = localize('azFunc.funcNamePrompt', 'Provide a function name');
this._functionName = await ui.showInputBox(placeHolder, prompt, false, (s: string) => this.validateTemplateName(s), defaultFunctionName || this._template.defaultFunctionName);
if (!functionName) {
const defaultFunctionName: string | undefined = await fsUtil.getUniqueJavaFsPath(this._functionAppPath, this._packageName, `${convertTemplateIdToJava(this._template.id)}Java`);
const placeHolder: string = localize('azFunc.funcNamePlaceholder', 'Function name');
const prompt: string = localize('azFunc.funcNamePrompt', 'Provide a function name');
this._functionName = await ui.showInputBox(placeHolder, prompt, false, (s: string) => this.validateTemplateName(s), defaultFunctionName || this._template.defaultFunctionName);
} else {
this._functionName = functionName;
}
}
public async createFunction(userSettings: { [propertyName: string]: string }): Promise<string | undefined> {

Просмотреть файл

@ -10,7 +10,7 @@ import { localize } from "../../localize";
import { ProjectLanguage } from '../../ProjectSettings';
import { Template } from "../../templates/Template";
import * as fsUtil from '../../utils/fs';
import { AbstractFunctionCreator } from './AbstractFunctionCreator';
import { FunctionCreatorBase } from './FunctionCreatorBase';
function getFileNameFromLanguage(language: string): string | undefined {
switch (language) {
@ -38,7 +38,7 @@ function getFileNameFromLanguage(language: string): string | undefined {
/**
* Function creator for multiple languages that don't require compilation (JavaScript, C# Script, Bash, etc.)
*/
export class ScriptFunctionCreator extends AbstractFunctionCreator {
export class ScriptFunctionCreator extends FunctionCreatorBase {
private _language: string;
private _functionName: string;
@ -47,11 +47,15 @@ export class ScriptFunctionCreator extends AbstractFunctionCreator {
this._language = language;
}
public async promptForSettings(ui: IUserInterface): Promise<void> {
const defaultFunctionName: string | undefined = await fsUtil.getUniqueFsPath(this._functionAppPath, this._template.defaultFunctionName);
const prompt: string = localize('azFunc.funcNamePrompt', 'Provide a function name');
const placeHolder: string = localize('azFunc.funcNamePlaceholder', 'Function name');
this._functionName = await ui.showInputBox(placeHolder, prompt, false, (s: string) => this.validateTemplateName(s), defaultFunctionName || this._template.defaultFunctionName);
public async promptForSettings(ui: IUserInterface, functionName: string | undefined): Promise<void> {
if (!functionName) {
const defaultFunctionName: string | undefined = await fsUtil.getUniqueFsPath(this._functionAppPath, this._template.defaultFunctionName);
const prompt: string = localize('azFunc.funcNamePrompt', 'Provide a function name');
const placeHolder: string = localize('azFunc.funcNamePlaceholder', 'Function name');
this._functionName = await ui.showInputBox(placeHolder, prompt, false, (s: string) => this.validateTemplateName(s), defaultFunctionName || this._template.defaultFunctionName);
} else {
this._functionName = functionName;
}
}
public async createFunction(userSettings: { [propertyName: string]: string; }): Promise<string | undefined> {

Просмотреть файл

@ -20,7 +20,7 @@ import { TemplateData } from '../../templates/TemplateData';
import * as workspaceUtil from '../../utils/workspace';
import { VSCodeUI } from '../../VSCodeUI';
import { createNewProject } from '../createNewProject/createNewProject';
import { AbstractFunctionCreator } from './AbstractFunctionCreator';
import { FunctionCreatorBase } from './FunctionCreatorBase';
import { JavaFunctionCreator } from './JavaFunctionCreator';
import { ScriptFunctionCreator } from './ScriptFunctionCreator';
@ -35,7 +35,7 @@ async function validateIsFunctionApp(telemetryProperties: TelemetryProperties, o
const message: string = localize('azFunc.notFunctionApp', 'The selected folder is not a function app project. Initialize Project?');
const result: vscode.MessageItem | undefined = await vscode.window.showWarningMessage(message, DialogResponses.yes, DialogResponses.skipForNow, DialogResponses.cancel);
if (result === DialogResponses.yes) {
await createNewProject(telemetryProperties, outputChannel, functionAppPath, false, ui);
await createNewProject(telemetryProperties, outputChannel, functionAppPath, undefined, false, ui);
} else if (result !== DialogResponses.skipForNow) {
throw new UserCancelledError();
}
@ -82,10 +82,17 @@ export async function createFunction(
outputChannel: vscode.OutputChannel,
azureAccount: AzureAccount,
templateData: TemplateData,
ui: IUserInterface = new VSCodeUI()): Promise<void> {
ui: IUserInterface = new VSCodeUI(),
functionAppPath?: string,
templateId?: string,
functionName?: string,
...functionSettings: (string)[]): Promise<void> {
if (functionAppPath === undefined) {
const folderPlaceholder: string = localize('azFunc.selectFunctionAppFolderExisting', 'Select the folder containing your function app');
functionAppPath = await workspaceUtil.selectWorkspaceFolder(ui, folderPlaceholder);
}
const folderPlaceholder: string = localize('azFunc.selectFunctionAppFolderExisting', 'Select the folder containing your function app');
const functionAppPath: string = await workspaceUtil.selectWorkspaceFolder(ui, folderPlaceholder);
await validateIsFunctionApp(telemetryProperties, outputChannel, functionAppPath, ui);
const localAppSettings: LocalAppSettings = new LocalAppSettings(ui, azureAccount, functionAppPath);
@ -97,16 +104,29 @@ export async function createFunction(
const templateFilter: TemplateFilter = await getTemplateFilter();
telemetryProperties.templateFilter = templateFilter;
const templatePicks: PickWithData<Template>[] = (await templateData.getTemplates(language, runtime, templateFilter, ui)).map((t: Template) => new PickWithData<Template>(t, t.name));
const templatePlaceHolder: string = localize('azFunc.selectFuncTemplate', 'Select a function template');
const template: Template = (await ui.showQuickPick<Template>(templatePicks, templatePlaceHolder)).data;
let template: Template;
if (!templateId) {
const templates: Template[] = await templateData.getTemplates(language, runtime, templateFilter, ui);
const templatePicks: PickWithData<Template>[] = templates.map((t: Template) => new PickWithData<Template>(t, t.name));
const templatePlaceHolder: string = localize('azFunc.selectFuncTemplate', 'Select a function template');
template = (await ui.showQuickPick<Template>(templatePicks, templatePlaceHolder)).data;
} else {
const templates: Template[] = await templateData.getTemplates(language, runtime, TemplateFilter.All, ui);
const foundTemplate: Template | undefined = templates.find((t: Template) => t.id === templateId);
if (foundTemplate) {
template = foundTemplate;
} else {
throw new Error(localize('templateNotFound', 'Could not find template with language "{0}", runtime "{1}", and id "{2}".', language, runtime, templateId));
}
}
telemetryProperties.templateId = template.id;
if (!template.functionConfig.isHttpTrigger) {
await localAppSettings.validateAzureWebJobsStorage();
}
let functionCreator: AbstractFunctionCreator;
let functionCreator: FunctionCreatorBase;
switch (language) {
case ProjectLanguage.Java:
functionCreator = new JavaFunctionCreator(functionAppPath, template, outputChannel);
@ -116,14 +136,20 @@ export async function createFunction(
break;
}
await functionCreator.promptForSettings(ui);
await functionCreator.promptForSettings(ui, functionName);
const userSettings: { [propertyName: string]: string } = {};
for (const settingName of template.userPromptedSettings) {
const setting: ConfigSetting | undefined = await templateData.getSetting(runtime, template.functionConfig.inBindingType, settingName);
if (setting) {
const defaultValue: string | undefined = template.functionConfig.inBinding[settingName];
const settingValue: string | undefined = await promptForSetting(ui, localAppSettings, setting, defaultValue);
let settingValue: string | undefined;
if (functionSettings.length > 0) {
settingValue = functionSettings.shift();
} else {
const defaultValue: string | undefined = template.functionConfig.inBinding[settingName];
settingValue = await promptForSetting(ui, localAppSettings, setting, defaultValue);
}
userSettings[settingName] = settingValue ? settingValue : '';
}
}

Просмотреть файл

@ -39,17 +39,21 @@ const funcProblemMatcher: {} = {
}
};
export async function createNewProject(telemetryProperties: TelemetryProperties, outputChannel: OutputChannel, functionAppPath?: string, openFolder: boolean = true, ui: IUserInterface = new VSCodeUI()): Promise<void> {
export async function createNewProject(telemetryProperties: TelemetryProperties, outputChannel: OutputChannel, functionAppPath?: string, language?: string, openFolder: boolean = true, ui: IUserInterface = new VSCodeUI()): Promise<void> {
if (functionAppPath === undefined) {
functionAppPath = await workspaceUtil.selectWorkspaceFolder(ui, localize('azFunc.selectFunctionAppFolderNew', 'Select the folder that will contain your function app'));
}
await fse.ensureDir(functionAppPath);
// Only display 'supported' languages that can be debugged in VS Code
const languagePicks: Pick[] = [
new Pick(ProjectLanguage.JavaScript),
new Pick(ProjectLanguage.Java)
];
const language: string = (await ui.showQuickPick(languagePicks, localize('azFunc.selectFuncTemplate', 'Select a language for your function project'))).label;
if (!language) {
language = (await ui.showQuickPick(languagePicks, localize('azFunc.selectFuncTemplate', 'Select a language for your function project'))).label;
}
telemetryProperties.projectLanguage = language;
let projectCreator: IProjectCreator;

Просмотреть файл

@ -22,32 +22,51 @@ import { convertStringToRuntime, extensionPrefix, getProjectLanguage, getProject
import { FunctionAppTreeItem } from '../tree/FunctionAppTreeItem';
import { FunctionsTreeItem } from '../tree/FunctionsTreeItem';
import { FunctionTreeItem } from '../tree/FunctionTreeItem';
import * as azUtils from '../utils/azure';
import { cpUtils } from '../utils/cpUtils';
import { mavenUtils } from '../utils/mavenUtils';
import { nodeUtils } from '../utils/nodeUtils';
import * as workspaceUtil from '../utils/workspace';
import { VSCodeUI } from '../VSCodeUI';
export async function deploy(telemetryProperties: TelemetryProperties, tree: AzureTreeDataProvider, outputChannel: vscode.OutputChannel, context?: IAzureParentNode<FunctionAppTreeItem> | vscode.Uri, ui: IUserInterface = new VSCodeUI()): Promise<void> {
const uri: vscode.Uri | undefined = context && context instanceof vscode.Uri ? context : undefined;
let node: IAzureParentNode<FunctionAppTreeItem> | undefined = context && !(context instanceof vscode.Uri) ? context : undefined;
export async function deploy(telemetryProperties: TelemetryProperties, tree: AzureTreeDataProvider, outputChannel: vscode.OutputChannel, deployPath?: vscode.Uri | string, functionAppId?: string | {}, ui: IUserInterface = new VSCodeUI()): Promise<void> {
let deployFsPath: string;
if (!deployPath) {
deployFsPath = await workspaceUtil.selectWorkspaceFolder(ui, localize('azFunc.selectZipDeployFolder', 'Select the folder to zip and deploy'));
} else if (deployPath instanceof vscode.Uri) {
deployFsPath = deployPath.fsPath;
} else {
deployFsPath = deployPath;
}
let folderPath: string = uri ? uri.fsPath : await workspaceUtil.selectWorkspaceFolder(ui, localize('azFunc.selectZipDeployFolder', 'Select the folder to zip and deploy'));
if (!node) {
let node: IAzureParentNode<FunctionAppTreeItem>;
if (!functionAppId || typeof (functionAppId) !== 'string') {
node = <IAzureParentNode<FunctionAppTreeItem>>await tree.showNodePicker(FunctionAppTreeItem.contextValue);
} else {
const subscriptionId: string = azUtils.getSubscriptionFromId(functionAppId);
const subscriptionNode: IAzureParentNode | undefined = <IAzureParentNode | undefined>(await tree.getChildren()).find((n: IAzureNode) => n.subscription.subscriptionId === subscriptionId);
if (subscriptionNode) {
const functionAppNode: IAzureNode | undefined = (await subscriptionNode.getCachedChildren()).find((n: IAzureNode) => n.treeItem.id === functionAppId);
if (functionAppNode) {
node = <IAzureParentNode<FunctionAppTreeItem>>functionAppNode;
} else {
throw new Error(localize('noMatchingFunctionApp', 'Failed to find a function app matching id "{0}".', functionAppId));
}
} else {
throw new Error(localize('noMatchingSubscription', 'Failed to find a subscription matching id "{0}".', subscriptionId));
}
}
const client: WebSiteManagementClient = nodeUtils.getWebSiteClient(node);
const siteWrapper: SiteWrapper = node.treeItem.siteWrapper;
const language: ProjectLanguage = await getProjectLanguage(folderPath, ui);
const language: ProjectLanguage = await getProjectLanguage(deployFsPath, ui);
telemetryProperties.projectLanguage = language;
const runtime: ProjectRuntime = await getProjectRuntime(language, ui);
telemetryProperties.projectRuntime = runtime;
if (language === ProjectLanguage.Java) {
folderPath = await getJavaFolderPath(outputChannel, folderPath, ui);
deployFsPath = await getJavaFolderPath(outputChannel, deployFsPath, ui);
}
await verifyRuntimeIsCompatible(runtime, outputChannel, client, siteWrapper);
@ -63,7 +82,7 @@ export async function deploy(telemetryProperties: TelemetryProperties, tree: Azu
outputChannel.appendLine(localize('stopFunctionApp', 'Stopping Function App: {0} ...', siteWrapper.appName));
await siteWrapper.stop(client);
}
await siteWrapper.deploy(folderPath, client, outputChannel, extensionPrefix);
await siteWrapper.deploy(deployFsPath, client, outputChannel, extensionPrefix);
} finally {
if (language === ProjectLanguage.Java) {
outputChannel.appendLine(localize('startFunctionApp', 'Starting Function App: {0} ...', siteWrapper.appName));

Просмотреть файл

@ -28,6 +28,7 @@ import { TemplateData } from './templates/TemplateData';
import { FunctionAppProvider } from './tree/FunctionAppProvider';
import { FunctionAppTreeItem } from './tree/FunctionAppTreeItem';
import { FunctionTreeItem } from './tree/FunctionTreeItem';
import { VSCodeUI } from './VSCodeUI';
let reporter: TelemetryReporter | undefined;
@ -58,14 +59,16 @@ export function activate(context: vscode.ExtensionContext): void {
actionHandler.registerCommand('azureFunctions.refresh', async (node?: IAzureNode) => await tree.refresh(node));
actionHandler.registerCommand('azureFunctions.loadMore', async (node: IAzureNode) => await tree.loadMore(node));
actionHandler.registerCommand('azureFunctions.openInPortal', async (node?: IAzureNode<FunctionAppTreeItem>) => await openInPortal(tree, node));
actionHandler.registerCommandWithCustomTelemetry('azureFunctions.createFunction', async (properties: TelemetryProperties, _measurements: TelemetryMeasurements) => await createFunction(properties, outputChannel, azureAccount, templateData));
actionHandler.registerCommandWithCustomTelemetry('azureFunctions.createNewProject', async (properties: TelemetryProperties, _measurements: TelemetryMeasurements) => await createNewProject(properties, outputChannel));
actionHandler.registerCommandWithCustomTelemetry('azureFunctions.createFunction', async (properties: TelemetryProperties, _measurements: TelemetryMeasurements, functionAppPath?: string, templateId?: string, functionName?: string, ...functionSettings: string[]) => {
await createFunction(properties, outputChannel, azureAccount, templateData, new VSCodeUI(), functionAppPath, templateId, functionName, ...functionSettings);
});
actionHandler.registerCommandWithCustomTelemetry('azureFunctions.createNewProject', async (properties: TelemetryProperties, _measurements: TelemetryMeasurements, functionAppPath?: string, language?: string, openFolder?: boolean | undefined) => await createNewProject(properties, outputChannel, functionAppPath, language, openFolder));
actionHandler.registerCommand('azureFunctions.createFunctionApp', async (node?: IAzureParentNode) => await createChildNode(tree, AzureTreeDataProvider.subscriptionContextValue, node));
actionHandler.registerCommand('azureFunctions.startFunctionApp', async (node?: IAzureNode<FunctionAppTreeItem>) => await startFunctionApp(tree, node));
actionHandler.registerCommand('azureFunctions.stopFunctionApp', async (node?: IAzureNode<FunctionAppTreeItem>) => await stopFunctionApp(tree, node));
actionHandler.registerCommand('azureFunctions.restartFunctionApp', async (node?: IAzureNode<FunctionAppTreeItem>) => await restartFunctionApp(tree, node));
actionHandler.registerCommand('azureFunctions.deleteFunctionApp', async (node?: IAzureParentNode) => await deleteNode(tree, FunctionAppTreeItem.contextValue, node));
actionHandler.registerCommandWithCustomTelemetry('azureFunctions.deploy', async (properties: TelemetryProperties, _measurements: TelemetryMeasurements, arg?: IAzureParentNode<FunctionAppTreeItem> | vscode.Uri) => await deploy(properties, tree, outputChannel, arg));
actionHandler.registerCommandWithCustomTelemetry('azureFunctions.deploy', async (properties: TelemetryProperties, _measurements: TelemetryMeasurements, deployPath: vscode.Uri | string, functionAppId?: string) => await deploy(properties, tree, outputChannel, deployPath, functionAppId));
actionHandler.registerCommandWithCustomTelemetry('azureFunctions.configureDeploymentSource', async (properties: TelemetryProperties, _measurements: TelemetryMeasurements, node?: IAzureNode<FunctionAppTreeItem>) => await configureDeploymentSource(properties, tree, outputChannel, node));
actionHandler.registerCommand('azureFunctions.copyFunctionUrl', async (node?: IAzureNode<FunctionTreeItem>) => await copyFunctionUrl(tree, node));
actionHandler.registerCommand('azureFunctions.deleteFunction', async (node?: IAzureNode) => await deleteNode(tree, FunctionTreeItem.contextValue, node));

Просмотреть файл

@ -173,7 +173,7 @@ export class TemplateData {
for (const rawTemplate of rawTemplates) {
try {
this._templatesMap[runtime].push(new Template(rawTemplate, resources));
} catch {
} catch (error) {
// Ignore errors so that a single poorly formed template does not affect other templates
}
}

Просмотреть файл

@ -16,14 +16,22 @@ import { IUserInterface, PickWithData } from '../IUserInterface';
import { localize } from '../localize';
import { getResourceTypeLabel, ResourceType } from '../templates/ConfigSetting';
function getResourceGroupFromId(id: string): string {
function parseResourceId(id: string): RegExpMatchArray {
const matches: RegExpMatchArray | null = id.match(/\/subscriptions\/(.*)\/resourceGroups\/(.*)\/providers\/(.*)\/(.*)/);
if (matches === null || matches.length < 3) {
throw new Error(localize('azFunc.InvalidResourceId', 'Invalid Azure Resource Id'));
}
return matches[2];
return matches;
}
function getResourceGroupFromId(id: string): string {
return parseResourceId(id) [2];
}
export function getSubscriptionFromId(id: string): string {
return parseResourceId(id) [1];
}
interface IBaseResourceWithName extends BaseResource {

Просмотреть файл

@ -12,7 +12,7 @@ export namespace gitUtils {
try {
await cpUtils.executeCommand(undefined, workingDirectory, gitCommand, '--version');
return true;
} catch {
} catch (error) {
return false;
}
}

Просмотреть файл

@ -11,7 +11,7 @@ export namespace mavenUtils {
export async function validateMavenInstalled(workingDirectory: string): Promise<void> {
try {
await cpUtils.executeCommand(undefined, workingDirectory, mvnCommand, '--version');
} catch {
} catch (error) {
throw new Error(localize('azFunc.mvnNotFound', 'Failed to find "maven" on path.'));
}
}

Просмотреть файл

@ -16,39 +16,39 @@ import * as fsUtil from '../src/utils/fs';
import { TestAzureAccount } from './TestAzureAccount';
import { TestUI } from './TestUI';
const templateData: TemplateData = new TemplateData();
const testFolder: string = path.join(os.tmpdir(), `azFunc.createFuncTests${fsUtil.getRandomHexString()}`);
const outputChannel: vscode.OutputChannel = vscode.window.createOutputChannel('Azure Functions Test');
const projectConfiguration: WorkspaceConfiguration = vscode.workspace.getConfiguration(extensionPrefix);
// tslint:disable-next-line:no-backbone-get-set-outside-model
const oldTemplateFilter: string | undefined = projectConfiguration.get(templateFilterSetting);
const oldProjectLanguage: string | undefined = projectConfiguration.get(projectLanguageSetting);
const oldProjectRuntime: string | undefined = projectConfiguration.get(projectRuntimeSetting);
suiteSetup(async () => {
await fse.ensureDir(path.join(testFolder, '.vscode'));
// Pretend to create the parent function app
await Promise.all([
fse.writeFile(path.join(testFolder, 'host.json'), ''),
fse.writeFile(path.join(testFolder, 'local.settings.json'), '{ "Values": { "AzureWebJobsStorage": "test" } }'),
fse.writeFile(path.join(testFolder, '.vscode', 'launch.json'), '')
]);
await projectConfiguration.update(templateFilterSetting, TemplateFilter.Core, vscode.ConfigurationTarget.Global);
await projectConfiguration.update(projectLanguageSetting, ProjectLanguage.JavaScript, vscode.ConfigurationTarget.Global);
await projectConfiguration.update(projectRuntimeSetting, ProjectRuntime.one, vscode.ConfigurationTarget.Global);
});
suiteTeardown(async () => {
outputChannel.dispose();
await fse.remove(testFolder);
await projectConfiguration.update(templateFilterSetting, oldTemplateFilter, vscode.ConfigurationTarget.Global);
await projectConfiguration.update(projectLanguageSetting, oldProjectLanguage, vscode.ConfigurationTarget.Global);
await projectConfiguration.update(projectRuntimeSetting, oldProjectRuntime, vscode.ConfigurationTarget.Global);
});
// tslint:disable-next-line:max-func-body-length
suite('Create Core Function Tests', () => {
suite('Create JavaScript Core Function Tests', () => {
const templateData: TemplateData = new TemplateData();
const testFolder: string = path.join(os.tmpdir(), `azFunc.createFuncTests${fsUtil.getRandomHexString()}`);
const outputChannel: vscode.OutputChannel = vscode.window.createOutputChannel('Azure Functions Test');
const projectConfiguration: WorkspaceConfiguration = vscode.workspace.getConfiguration(extensionPrefix);
// tslint:disable-next-line:no-backbone-get-set-outside-model
const oldTemplateFilter: string | undefined = projectConfiguration.get(templateFilterSetting);
const oldProjectLanguage: string | undefined = projectConfiguration.get(projectLanguageSetting);
const oldProjectRuntime: string | undefined = projectConfiguration.get(projectRuntimeSetting);
suiteSetup(async () => {
await fse.ensureDir(path.join(testFolder, '.vscode'));
// Pretend to create the parent function app
await Promise.all([
fse.writeFile(path.join(testFolder, 'host.json'), ''),
fse.writeFile(path.join(testFolder, 'local.settings.json'), '{ "Values": { "AzureWebJobsStorage": "test" } }'),
fse.writeFile(path.join(testFolder, '.vscode', 'launch.json'), '')
]);
await projectConfiguration.update(templateFilterSetting, TemplateFilter.Core, vscode.ConfigurationTarget.Global);
await projectConfiguration.update(projectLanguageSetting, ProjectLanguage.JavaScript, vscode.ConfigurationTarget.Global);
await projectConfiguration.update(projectRuntimeSetting, ProjectRuntime.one, vscode.ConfigurationTarget.Global);
});
suiteTeardown(async () => {
outputChannel.dispose();
await fse.remove(testFolder);
await projectConfiguration.update(templateFilterSetting, oldTemplateFilter, vscode.ConfigurationTarget.Global);
await projectConfiguration.update(projectLanguageSetting, oldProjectLanguage, vscode.ConfigurationTarget.Global);
await projectConfiguration.update(projectRuntimeSetting, oldProjectRuntime, vscode.ConfigurationTarget.Global);
});
const blobTrigger: string = 'Blob trigger';
test(blobTrigger, async () => {
await testCreateFunction(
@ -58,7 +58,7 @@ suite('Create Core Function Tests', () => {
'connectionString',
undefined // Use default path
);
});
}).timeout(6000);
const cosmosDBTrigger: string = 'Cosmos DB trigger';
test(cosmosDBTrigger, async () => {
@ -160,23 +160,35 @@ suite('Create Core Function Tests', () => {
undefined // Use default schedule
);
});
});
async function testCreateFunction(templateName: string, ...inputs: (string | undefined)[]): Promise<void> {
// Setup common inputs
const funcName: string = templateName.replace(/ /g, '');
inputs.unshift(funcName); // Specify the function name
inputs.unshift(templateName); // Select the function template
inputs.unshift(testFolder); // Select the test func app folder
if (vscode.workspace.workspaceFolders && vscode.workspace.workspaceFolders.length > 0) {
inputs.unshift('$(file-directory) Browse...'); // If the test environment has an open workspace, select the 'Browse...' option
test('createFunction API', async () => {
const templateId: string = 'HttpTrigger-JavaScript';
const functionName: string = 'createFunctionApi';
const authLevel: string = 'Anonymous';
await vscode.commands.executeCommand('azureFunctions.createFunction', testFolder, templateId, functionName, authLevel);
await validateFunction(functionName);
}).timeout(5000);
async function testCreateFunction(templateName: string, ...inputs: (string | undefined) []): Promise<void> {
// Setup common inputs
const funcName: string = templateName.replace(/ /g, '');
inputs.unshift(funcName); // Specify the function name
inputs.unshift(templateName); // Select the function template
inputs.unshift(testFolder); // Select the test func app folder
if (vscode.workspace.workspaceFolders && vscode.workspace.workspaceFolders.length > 0) {
inputs.unshift('$(file-directory) Browse...'); // If the test environment has an open workspace, select the 'Browse...' option
}
const ui: TestUI = new TestUI(inputs);
await createFunction({}, outputChannel, new TestAzureAccount(), templateData, ui);
assert.equal(inputs.length, 0, 'Not all inputs were used.');
await validateFunction(funcName);
}
const ui: TestUI = new TestUI(inputs);
await createFunction({}, outputChannel, new TestAzureAccount(), templateData, ui);
assert.equal(inputs.length, 0, 'Not all inputs were used.');
const functionPath: string = path.join(testFolder, funcName);
assert.equal(await fse.pathExists(path.join(functionPath, 'index.js')), true, 'index.js does not exist');
assert.equal(await fse.pathExists(path.join(functionPath, 'function.json')), true, 'function.json does not exist');
}
async function validateFunction(funcName: string): Promise<void> {
const functionPath: string = path.join(testFolder, funcName);
assert.equal(await fse.pathExists(path.join(functionPath, 'index.js')), true, 'index.js does not exist');
assert.equal(await fse.pathExists(path.join(functionPath, 'function.json')), true, 'function.json does not exist');
}
});

Просмотреть файл

@ -13,15 +13,9 @@ import { ProjectLanguage } from '../src/ProjectSettings';
import * as fsUtil from '../src/utils/fs';
import { TestUI } from './TestUI';
const testFolderPath: string = path.join(os.tmpdir(), `azFunc.createNewProjectTests${fsUtil.getRandomHexString()}`);
const outputChannel: vscode.OutputChannel = vscode.window.createOutputChannel('Azure Functions Test');
suite('Create New Java Project Tests', () => {
suiteSetup(async () => {
await fse.ensureDir(testFolderPath);
});
suite('Create New Project Tests', () => {
const testFolderPath: string = path.join(os.tmpdir(), `azFunc.createNewProjectTests${fsUtil.getRandomHexString()}`);
const outputChannel: vscode.OutputChannel = vscode.window.createOutputChannel('Azure Functions Test');
suiteTeardown(async () => {
outputChannel.dispose();
await fse.remove(testFolderPath);
@ -29,7 +23,9 @@ suite('Create New Java Project Tests', () => {
const javaProject: string = 'JavaProject';
test(javaProject, async () => {
const projectPath: string = path.join(testFolderPath, javaProject);
await testCreateNewProject(
projectPath,
ProjectLanguage.Java,
undefined,
undefined,
@ -37,54 +33,49 @@ suite('Create New Java Project Tests', () => {
undefined,
undefined
);
await testJavaProjectFilesExist(testFolderPath);
await testJavaProjectFilesExist(projectPath);
}).timeout(60 * 1000);
});
suite('Create New JavaScript Project Tests', () => {
suiteSetup(async () => {
await fse.ensureDir(testFolderPath);
});
suiteTeardown(async () => {
outputChannel.dispose();
await fse.remove(testFolderPath);
});
const javaScriptProject: string = 'JavaScriptProject';
test(javaScriptProject, async () => {
await testCreateNewProject(ProjectLanguage.JavaScript);
await testProjectFilesExist(testFolderPath);
}).timeout(10 * 1000);
});
const projectPath: string = path.join(testFolderPath, javaScriptProject);
await testCreateNewProject(projectPath, ProjectLanguage.JavaScript);
await testProjectFilesExist(projectPath);
});
async function testCreateNewProject(language: string, ...inputs: (string | undefined)[]): Promise<void> {
// Setup common inputs
inputs.unshift(language); // Specify the function name
inputs.unshift(testFolderPath); // Select the test func app folder
if (vscode.workspace.workspaceFolders && vscode.workspace.workspaceFolders.length > 0) {
inputs.unshift('$(file-directory) Browse...'); // If the test environment has an open workspace, select the 'Browse...' option
test('createNewProject API', async () => {
const projectPath: string = path.join(testFolderPath, 'createNewProjectApi');
await vscode.commands.executeCommand('azureFunctions.createNewProject', projectPath, 'JavaScript', false /* openFolder */);
await testProjectFilesExist(projectPath);
});
async function testCreateNewProject(projectPath: string, language: string, ...inputs: (string | undefined)[]): Promise<void> {
// Setup common inputs
inputs.unshift(language); // Specify the function name
inputs.unshift(projectPath); // Select the test func app folder
if (vscode.workspace.workspaceFolders && vscode.workspace.workspaceFolders.length > 0) {
inputs.unshift('$(file-directory) Browse...'); // If the test environment has an open workspace, select the 'Browse...' option
}
const ui: TestUI = new TestUI(inputs);
await createNewProject({}, outputChannel, undefined, undefined, false, ui);
assert.equal(inputs.length, 0, 'Not all inputs were used.');
}
const ui: TestUI = new TestUI(inputs);
await createNewProject({}, outputChannel, undefined, false, ui);
assert.equal(inputs.length, 0, 'Not all inputs were used.');
}
async function testProjectFilesExist(projectPath: string): Promise<void> {
assert.equal(await fse.pathExists(path.join(projectPath, '.gitignore')), true, '.gitignore does not exist');
assert.equal(await fse.pathExists(path.join(projectPath, 'host.json')), true, 'host.json does not exist');
assert.equal(await fse.pathExists(path.join(projectPath, 'local.settings.json')), true, 'function.json does not exist');
assert.equal(await fse.pathExists(path.join(projectPath, '.git')), true, '.git folder does not exist');
const vscodePath: string = path.join(projectPath, '.vscode');
assert.equal(await fse.pathExists(path.join(vscodePath, 'settings.json')), true, 'settings.json does not exist');
assert.equal(await fse.pathExists(path.join(vscodePath, 'launch.json')), true, 'launch.json does not exist');
assert.equal(await fse.pathExists(path.join(vscodePath, 'tasks.json')), true, 'tasks.json does not exist');
}
async function testProjectFilesExist(projectPath: string): Promise<void> {
assert.equal(await fse.pathExists(path.join(projectPath, '.gitignore')), true, '.gitignore does not exist');
assert.equal(await fse.pathExists(path.join(projectPath, 'host.json')), true, 'host.json does not exist');
assert.equal(await fse.pathExists(path.join(projectPath, 'local.settings.json')), true, 'function.json does not exist');
assert.equal(await fse.pathExists(path.join(projectPath, '.git')), true, '.git folder does not exist');
const vscodePath: string = path.join(projectPath, '.vscode');
assert.equal(await fse.pathExists(path.join(vscodePath, 'settings.json')), true, 'settings.json does not exist');
assert.equal(await fse.pathExists(path.join(vscodePath, 'launch.json')), true, 'launch.json does not exist');
assert.equal(await fse.pathExists(path.join(vscodePath, 'tasks.json')), true, 'tasks.json does not exist');
}
async function testJavaProjectFilesExist(projectPath: string): Promise<void> {
await testProjectFilesExist(projectPath);
assert.equal(await fse.pathExists(path.join(projectPath, 'src')), true, 'src folder does not exist');
assert.equal(await fse.pathExists(path.join(projectPath, 'pom.xml')), true, 'pom.xml does not exist');
}
async function testJavaProjectFilesExist(projectPath: string): Promise<void> {
await testProjectFilesExist(projectPath);
assert.equal(await fse.pathExists(path.join(projectPath, 'src')), true, 'src folder does not exist');
assert.equal(await fse.pathExists(path.join(projectPath, 'pom.xml')), true, 'pom.xml does not exist');
}
});