Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,12 @@
},
"enablement": "!virtualWorkspace"
},
{
"command": "azureFunctions.createNewProjectWithDockerfile",
"title": "%azureFunctions.createNewProjectWithDockerfile%",
"category": "Azure Functions",
"enablement": "!virtualWorkspace"
},
{
"command": "azureFunctions.createSlot",
"title": "%azureFunctions.createSlot%",
Expand Down Expand Up @@ -381,6 +387,10 @@
"command": "azureFunctions.createNewProject",
"group": "1_projects@2"
},
{
"command": "azureFunctions.createNewProjectWithDockerfile",
"group": "1_projects@3"
},
{
"command": "azureFunctions.deploy",
"group": "2_deploy@1"
Expand Down
1 change: 1 addition & 0 deletions package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"azureFunctions.createFunctionAppAdvanced": "Create Function App in Azure... (Advanced)",
"azureFunctions.createFunctionAppDetail": "For serverless, event driven apps and automation.",
"azureFunctions.createNewProject": "Create New Project...",
"azureFunctions.createNewProjectWithDockerfile": "Create New Containerized Project...",
"azureFunctions.createPythonVenv": "Create a virtual environment when creating a new Python project.",
"azureFunctions.createSlot": "Create Slot...",
"azureFunctions.createServiceConnector": "Create connection...",
Expand Down
12 changes: 11 additions & 1 deletion src/commands/createNewProject/createNewProject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { AzureWizard, type IActionContext } from '@microsoft/vscode-azext-utils';
import { AzureWizard, UserCancelledError, type IActionContext } from '@microsoft/vscode-azext-utils';
import { window } from 'vscode';
import { latestGAVersion, tryParseFuncVersion } from '../../FuncVersion';
import { funcVersionSetting, projectLanguageSetting, projectOpenBehaviorSetting, projectTemplateKeySetting, type ProjectLanguage } from '../../constants';
import { ext } from '../../extensionVariables';
import { addLocalFuncTelemetry } from '../../funcCoreTools/getLocalFuncCoreToolsVersion';
import { tryGetLocalFuncVersion } from '../../funcCoreTools/tryGetLocalFuncVersion';
import { validateFuncCoreToolsInstalled } from '../../funcCoreTools/validateFuncCoreToolsInstalled';
import { localize } from '../../localize';
import { getGlobalSetting, getWorkspaceSetting } from '../../vsCodeConfig/settings';
import type * as api from '../../vscode-azurefunctions.api';
Expand All @@ -18,6 +19,7 @@ import { FolderListStep } from './FolderListStep';
import { NewProjectLanguageStep } from './NewProjectLanguageStep';
import { OpenBehaviorStep } from './OpenBehaviorStep';
import { OpenFolderStep } from './OpenFolderStep';
import { CreateDockerfileProjectStep } from './dockerfileSteps/CreateDockerfileProjectStep';

/**
* @deprecated Use AzureFunctionsExtensionApi.createFunction instead
Expand Down Expand Up @@ -54,6 +56,13 @@ export async function createNewProjectInternal(context: IActionContext, options:
const wizardContext: Partial<IFunctionWizardContext> & IActionContext = Object.assign(context, options, { language, version: tryParseFuncVersion(version), projectTemplateKey });
const optionalExecuteStep = options.executeStep;

if (optionalExecuteStep instanceof CreateDockerfileProjectStep) {
const message: string = localize('installFuncTools', 'You must have the Azure Functions Core Tools installed to run this command.');
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Since we know what command they are running, I think we should tell them specifically that they need to have the core tools installed to create a containerized function project or whatever.

if (!await validateFuncCoreToolsInstalled(context, message)) {
throw new UserCancelledError('validateFuncCoreToolsInstalled');
}
}

if (options.folderPath) {
FolderListStep.setProjectPath(wizardContext, options.folderPath);
}
Expand All @@ -70,6 +79,7 @@ export async function createNewProjectInternal(context: IActionContext, options:
promptSteps: [new FolderListStep(), new NewProjectLanguageStep(options.templateId, options.functionSettings), new OpenBehaviorStep()],
executeSteps: optionalExecuteStep ? [optionalExecuteStep, new OpenFolderStep()] : [new OpenFolderStep()]
});

await wizard.prompt();
await wizard.execute();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.md in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { ext } from "@microsoft/vscode-azext-serviceconnector";
import { AzureWizardExecuteStep, nonNullValueAndProp } from "@microsoft/vscode-azext-utils";
import { cpUtils } from "../../../utils/cpUtils";
import { type IFunctionWizardContext } from "../../createFunction/IFunctionWizardContext";

export class CreateDockerfileProjectStep extends AzureWizardExecuteStep<IFunctionWizardContext>{
public priority: number = 100;

public async execute(context: IFunctionWizardContext): Promise<void> {
let language = nonNullValueAndProp(context, 'language').toLowerCase();
if (language === 'c#') {
language = 'csharp';
}

await cpUtils.executeCommand(ext.outputChannel, nonNullValueAndProp(context, 'projectPath'), "func", "init", "--worker-runtime", language, "--docker");
}

public shouldExecute(): boolean {
return true;
}
}
4 changes: 3 additions & 1 deletion src/commands/registerCommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ import { copyFunctionUrl } from './copyFunctionUrl';
import { createChildNode } from './createChildNode';
import { createFunctionFromCommand } from './createFunction/createFunction';
import { createFunctionApp, createFunctionAppAdvanced } from './createFunctionApp/createFunctionApp';
import { createNewProjectFromCommand } from './createNewProject/createNewProject';
import { createNewProjectFromCommand, createNewProjectInternal } from './createNewProject/createNewProject';
import { CreateDockerfileProjectStep } from './createNewProject/dockerfileSteps/CreateDockerfileProjectStep';
import { createSlot } from './createSlot';
import { deleteFunction } from './deleteFunction';
import { deleteFunctionApp } from './deleteFunctionApp';
Expand Down Expand Up @@ -75,6 +76,7 @@ export function registerCommands(): void {
registerCommandWithTreeNodeUnwrapping('azureFunctions.createFunctionApp', createFunctionApp);
registerCommandWithTreeNodeUnwrapping('azureFunctions.createFunctionAppAdvanced', createFunctionAppAdvanced);
registerCommand('azureFunctions.createNewProject', createNewProjectFromCommand);
registerCommandWithTreeNodeUnwrapping('azureFunctions.createNewProjectWithDockerfile', async (context: IActionContext) => await createNewProjectInternal(context, { executeStep: new CreateDockerfileProjectStep(), languageFilter: /Python|C\#|(Java|Type)Script|PowerShell$/i }));
registerCommandWithTreeNodeUnwrapping('azureFunctions.createSlot', createSlot);
registerCommandWithTreeNodeUnwrapping('azureFunctions.deleteFunction', deleteFunction);
registerCommandWithTreeNodeUnwrapping('azureFunctions.deleteFunctionApp', deleteFunctionApp);
Expand Down
2 changes: 1 addition & 1 deletion src/funcCoreTools/validateFuncCoreToolsInstalled.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { getFuncCliPath, hasFuncCliSetting } from './getFuncCliPath';
import { getFuncPackageManagers } from './getFuncPackageManagers';
import { installFuncCoreTools, lastCoreToolsInstallCommand } from './installFuncCoreTools';

export async function validateFuncCoreToolsInstalled(context: IActionContext, message: string, workspacePath: string): Promise<boolean> {
export async function validateFuncCoreToolsInstalled(context: IActionContext, message: string, workspacePath?: string): Promise<boolean> {
let input: MessageItem | undefined;
let installed: boolean = false;
let failedInstall: string = localize('failedInstallFuncTools', 'Core Tools installation has failed and will have to be installed manually.');
Expand Down