Add Ballerina language support (#3584)
* Add Ballerina language support * Remove project subpath * Add review suggestions * Add debugger related changes * Add minor review comments * Add ballerina tests * Add ballerina to test workflows * Add ballerina related changes * Add ballerina script type * Fix lint issues * Migrate from bal init to bal new
This commit is contained in:
Родитель
fb67f66aa0
Коммит
cd2e6326a5
|
@ -7,6 +7,30 @@ steps:
|
|||
displayName: 'Start X Virtual Frame Buffer'
|
||||
condition: eq(variables['Agent.OS'], 'Linux')
|
||||
|
||||
# Tempoary workaround for https://github.com/ballerina-platform/ballerina-distribution/issues/4537
|
||||
- script: |
|
||||
curl -o ballerina.deb 'https://dist.ballerina.io/downloads/2201.6.0/ballerina-2201.6.0-swan-lake-linux-x64.deb'
|
||||
sudo dpkg -i ballerina.deb
|
||||
rm -f ballerina.deb
|
||||
displayName: Install Ballerina(Linux)
|
||||
condition: eq(variables['Agent.OS'], 'Linux')
|
||||
|
||||
- script: |
|
||||
curl -o ballerina.pkg 'https://dist.ballerina.io/downloads/2201.6.0/ballerina-2201.6.0-swan-lake-macos-x64.pkg'
|
||||
sudo installer -pkg ballerina.pkg -target /
|
||||
rm -f ballerina.pkg
|
||||
echo '##vso[task.prependpath]/Library/Ballerina/bin'
|
||||
displayName: Install Ballerina(MacOS)
|
||||
condition: eq(variables['Agent.OS'], 'Darwin')
|
||||
|
||||
- script: |
|
||||
curl -o ballerina.msi https://dist.ballerina.io/downloads/2201.6.0/ballerina-2201.6.0-swan-lake-windows-x64.msi
|
||||
msiexec /i ballerina.msi /quiet /qr /L*V "C:\Temp\msilog.log"
|
||||
del ballerina.msi
|
||||
echo "##vso[task.setvariable variable=PATH]C:\Program Files\Ballerina\bin;$(PATH)"
|
||||
displayName: Install Ballerina(Windows)
|
||||
condition: eq(variables['Agent.OS'], 'Windows_NT')
|
||||
|
||||
- task: UsePythonVersion@0
|
||||
displayName: 'Use Python 3.7.x'
|
||||
inputs:
|
||||
|
@ -46,4 +70,3 @@ steps:
|
|||
testResultsFiles: '*-results.xml'
|
||||
testRunTitle: '$(Agent.OS)'
|
||||
condition: succeededOrFailed()
|
||||
|
|
@ -812,6 +812,7 @@
|
|||
"PowerShell",
|
||||
"Python",
|
||||
"TypeScript",
|
||||
"Ballerina",
|
||||
"Custom"
|
||||
],
|
||||
"description": "%azureFunctions.projectLanguage%",
|
||||
|
@ -825,6 +826,7 @@
|
|||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
""
|
||||
]
|
||||
},
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -0,0 +1,121 @@
|
|||
[
|
||||
{
|
||||
"id": "HttpTrigger-Ballerina",
|
||||
"runtime": "2",
|
||||
"files": {
|
||||
"%functionName%.bal": "import ballerinax/azure.functions;\n\n// This function gets triggered by an HTTP call with the name query parameter and returns a processed HTTP output to the caller.\n@functions:HttpTrigger{\n authLevel: \"%authLevel%\"\n}\nlistener functions:HttpListener httpListener = new functions:HttpListener();\nservice /%functionName% on httpListener {\n resource function get .(string name) returns string {\n return \"Hello, \" + name + \"!\";\n }\n}\n"
|
||||
},
|
||||
"metadata": {
|
||||
"defaultFunctionName": "httpTrigger",
|
||||
"description": "$HttpTrigger_description",
|
||||
"name": "HTTP trigger",
|
||||
"language": "Ballerina",
|
||||
"triggerType": "httpTrigger",
|
||||
"category": [
|
||||
"$temp_category_core",
|
||||
"$temp_category_api"
|
||||
],
|
||||
"categoryStyle": "http",
|
||||
"enabledInTryMode": true,
|
||||
"userPrompt": [
|
||||
"authLevel"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "BlobTrigger-Ballerina",
|
||||
"runtime": "2",
|
||||
"files": {
|
||||
"%functionName%.bal": "import ballerinax/azure.functions;\nimport ballerina/log;\n\n// The following Function will be invoked when a new blob added to the specified blob storage.\n@functions:BlobTrigger {\n path: \"%path%\",\n connection: \"%connection%\"\n}\nlistener functions:BlobListener blobListener = new functions:BlobListener();\n\nservice \"%functionName%\" on blobListener {\n remote function onUpdate(byte[] blobIn) {\n log:printInfo(\"Blob Store updated with file of \" + blobIn.length().toString() + \" bytes\");\n }\n}\n"
|
||||
},
|
||||
"metadata": {
|
||||
"defaultFunctionName": "blobTrigger",
|
||||
"description": "$BlobTrigger_description",
|
||||
"name": "Blob trigger",
|
||||
"language": "Ballerina",
|
||||
"triggerType": "blobTrigger",
|
||||
"category": [
|
||||
"$temp_category_core",
|
||||
"$temp_category_dataProcessing"
|
||||
],
|
||||
"categoryStyle": "blob",
|
||||
"enabledInTryMode": true,
|
||||
"userPrompt": [
|
||||
"connection",
|
||||
"path"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "CosmosDBTrigger-Ballerina",
|
||||
"runtime": "2",
|
||||
"files": {
|
||||
"%functionName%.bal": "import ballerina/log;\nimport ballerinax/azure.functions;\n\n// The following Function will be invoked when an entry is added to CosmosDB collection.\n@functions:CosmosDBTrigger {connectionStringSetting: \"%connectionStringSetting%\", databaseName: \"%databaseName%\", collectionName: \"%collectionName%\"}\nlistener functions:CosmosDBListener cosmosEp = new ();\n\ntype Users record {\n string id;\n string name;\n};\n\nservice \"%functionName%\" on cosmosEp {\n remote function onUpdate(Users[] users) {\n log:printInfo(users.toJsonString());\n }\n}\n"
|
||||
},
|
||||
"metadata": {
|
||||
"defaultFunctionName": "cosmosTrigger",
|
||||
"description": "$CosmosDBTrigger_description",
|
||||
"name": "CosmosDB trigger",
|
||||
"language": "Ballerina",
|
||||
"triggerType": "cosmosDBTrigger",
|
||||
"category": [
|
||||
"$temp_category_core",
|
||||
"$temp_category_dataProcessing"
|
||||
],
|
||||
"categoryStyle": "cosmosDB",
|
||||
"enabledInTryMode": true,
|
||||
"userPrompt": [
|
||||
"connectionStringSetting",
|
||||
"databaseName",
|
||||
"collectionName"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "QueueTrigger-Ballerina",
|
||||
"runtime": "2",
|
||||
"files": {
|
||||
"%functionName%.bal": "import ballerina/log;\nimport ballerinax/azure.functions;\n\n\n// The following Function will be executed when a message is added to the queue storage.\n@functions:QueueTrigger {\n queueName: \"%queueName%\",\n connection: \"%connection%\"\n}\nlistener functions:QueueListener queueListener = new functions:QueueListener();\n\nservice \"%functionName%\" on queueListener {\n remote function onMessage(string message) {\n log:printInfo(\"Queue message received: \" + message);\n }\n}\n"
|
||||
},
|
||||
"metadata": {
|
||||
"defaultFunctionName": "queueTrigger",
|
||||
"description": "$QueueTrigger_description",
|
||||
"name": "Queue trigger",
|
||||
"language": "Ballerina",
|
||||
"triggerType": "queueTrigger",
|
||||
"category": [
|
||||
"$temp_category_core",
|
||||
"$temp_category_dataProcessing"
|
||||
],
|
||||
"categoryStyle": "queue",
|
||||
"enabledInTryMode": true,
|
||||
"userPrompt": [
|
||||
"connection",
|
||||
"queueName"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "TimerTrigger-Ballerina",
|
||||
"runtime": "2",
|
||||
"files": {
|
||||
"%functionName%.bal": "import ballerina/time;\nimport ballerina/log;\nimport ballerinax/azure.functions;\n\n// The following function will be invoked periodically according to the schedule given.\n@functions:TimerTrigger {schedule: \"%schedule%\"}\nlistener functions:TimerListener timerEp = new ();\n\nservice \"%functionName%\" on timerEp {\n remote function onTrigger(functions:TimerMetadata metadata) {\n log:printInfo(\"Function Executed at \" + time:utcToString(time:utcNow()));\n }\n}\n"
|
||||
},
|
||||
"metadata": {
|
||||
"defaultFunctionName": "timerTrigger",
|
||||
"description": "$TimerTrigger_description",
|
||||
"name": "Timer trigger",
|
||||
"language": "Ballerina",
|
||||
"triggerType": "timerTrigger",
|
||||
"category": [
|
||||
"$temp_category_core",
|
||||
"$temp_category_dataProcessing"
|
||||
],
|
||||
"categoryStyle": "timer",
|
||||
"enabledInTryMode": true,
|
||||
"userPrompt": [
|
||||
"schedule"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
|
@ -0,0 +1 @@
|
|||
1.0.0
|
|
@ -92,6 +92,8 @@ async function getCompiledProjectInfo(context: IActionContext, projectPath: stri
|
|||
} else {
|
||||
return { compiledProjectPath: path.join(projectPath, getJavaDebugSubpath(functionAppName, buildTool)), isIsolated: false };
|
||||
}
|
||||
} else if (projectLanguage === ProjectLanguage.Ballerina) {
|
||||
return { compiledProjectPath: path.join(projectPath, "target", "azure_functions"), isIsolated: false };
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
|
|
|
@ -10,6 +10,8 @@ import { IFunctionTemplate } from '../../templates/IFunctionTemplate';
|
|||
import { isNodeV4Plus, isPythonV2Plus } from '../../utils/programmingModelUtils';
|
||||
import { addBindingSettingSteps } from '../addBinding/settingSteps/addBindingSettingSteps';
|
||||
import { JavaPackageNameStep } from '../createNewProject/javaSteps/JavaPackageNameStep';
|
||||
import { BallerinaFunctionCreateStep } from './ballerinaSteps/BallerinaFunctionCreateStep';
|
||||
import { BallerinaFunctionNameStep } from './ballerinaSteps/BallerinaFunctionNameStep';
|
||||
import { DotnetFunctionCreateStep } from './dotnetSteps/DotnetFunctionCreateStep';
|
||||
import { DotnetFunctionNameStep } from './dotnetSteps/DotnetFunctionNameStep';
|
||||
import { DotnetNamespaceStep } from './dotnetSteps/DotnetNamespaceStep';
|
||||
|
@ -45,6 +47,9 @@ export class FunctionSubWizard {
|
|||
case ProjectLanguage.Java:
|
||||
promptSteps.push(new JavaPackageNameStep(), new JavaFunctionNameStep());
|
||||
break;
|
||||
case ProjectLanguage.Ballerina:
|
||||
promptSteps.push(new BallerinaFunctionNameStep());
|
||||
break;
|
||||
case ProjectLanguage.CSharp:
|
||||
case ProjectLanguage.FSharp:
|
||||
promptSteps.push(new DotnetFunctionNameStep(), new DotnetNamespaceStep());
|
||||
|
@ -81,6 +86,9 @@ export class FunctionSubWizard {
|
|||
case ProjectLanguage.TypeScript:
|
||||
executeSteps.push(new TypeScriptFunctionCreateStep());
|
||||
break;
|
||||
case ProjectLanguage.Ballerina:
|
||||
executeSteps.push(new BallerinaFunctionCreateStep());
|
||||
break;
|
||||
default:
|
||||
if (isV2PythonModel) {
|
||||
executeSteps.push(new PythonFunctionCreateStep());
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { AzExtFsExtra, nonNullProp } from '@microsoft/vscode-azext-utils';
|
||||
import * as path from 'path';
|
||||
import { FunctionCreateStepBase } from '../FunctionCreateStepBase';
|
||||
import { IBallerinaFunctionTemplate, IBallerinaFunctionWizardContext } from './IBallerinaFunctionWizardContext';
|
||||
|
||||
export class BallerinaFunctionCreateStep extends FunctionCreateStepBase<IBallerinaFunctionWizardContext> {
|
||||
public async executeCore(context: IBallerinaFunctionWizardContext): Promise<string> {
|
||||
const functionPath = context.projectPath;
|
||||
await AzExtFsExtra.ensureDir(functionPath);
|
||||
|
||||
const functionName = nonNullProp(context, 'functionName');
|
||||
const fileName = `${functionName}.bal`;
|
||||
|
||||
const template: IBallerinaFunctionTemplate = nonNullProp(context, 'functionTemplate');
|
||||
await Promise.all(Object.keys(template.templateFiles).map(async f => {
|
||||
let contents = template.templateFiles[f];
|
||||
contents = contents.replace(/%functionName%/g, functionName);
|
||||
|
||||
for (const setting of template.userPromptedSettings) {
|
||||
// the setting name keys are lowercased
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
||||
contents = contents.replace(new RegExp(`%${setting.name}%`, 'g'), context[setting.name.toLowerCase()]);
|
||||
}
|
||||
|
||||
await AzExtFsExtra.writeFile(path.join(functionPath, fileName), contents);
|
||||
}));
|
||||
|
||||
return path.join(functionPath, fileName);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { AzExtFsExtra } from '@microsoft/vscode-azext-utils';
|
||||
import { localize } from "../../../localize";
|
||||
import { IFunctionTemplate } from '../../../templates/IFunctionTemplate';
|
||||
import { nonNullProp } from '../../../utils/nonNull';
|
||||
import { getBallerinaFunctionFilePath, getBallerinaPackagePath, IBallerinaProjectWizardContext } from '../../createNewProject/ballerinaSteps/IBallerinaProjectWizardContext';
|
||||
import { FunctionNameStepBase } from '../FunctionNameStepBase';
|
||||
import { IFunctionWizardContext } from '../IFunctionWizardContext';
|
||||
|
||||
export class BallerinaFunctionNameStep extends FunctionNameStepBase<IFunctionWizardContext & IBallerinaProjectWizardContext> {
|
||||
protected async getUniqueFunctionName(context: IFunctionWizardContext & IBallerinaProjectWizardContext): Promise<string | undefined> {
|
||||
const template: IFunctionTemplate = nonNullProp(context, 'functionTemplate');
|
||||
return await this.getUniqueFsPath(getBallerinaPackagePath(context.projectPath), template.defaultFunctionName, '.bal');
|
||||
}
|
||||
|
||||
protected async validateFunctionNameCore(context: IFunctionWizardContext & IBallerinaProjectWizardContext, name: string): Promise<string | undefined> {
|
||||
if (await AzExtFsExtra.pathExists(getBallerinaFunctionFilePath(context.projectPath, name))) {
|
||||
return localize('existingError', 'A function with name "{0}" already exists in package "{1}".', name);
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IFunctionTemplate } from '../../../templates/IFunctionTemplate';
|
||||
import { IFunctionWizardContext } from '../IFunctionWizardContext';
|
||||
|
||||
export interface IBallerinaFunctionWizardContext extends IFunctionWizardContext {
|
||||
functionTemplate?: IBallerinaFunctionTemplate;
|
||||
}
|
||||
|
||||
export interface IBallerinaFunctionTemplate extends IFunctionTemplate {
|
||||
templateFiles: { [filename: string]: string };
|
||||
}
|
|
@ -23,6 +23,7 @@ import { PysteinProjectCreateStep } from './ProjectCreateStep/PysteinProjectCrea
|
|||
import { PythonProjectCreateStep } from './ProjectCreateStep/PythonProjectCreateStep';
|
||||
import { ScriptProjectCreateStep } from './ProjectCreateStep/ScriptProjectCreateStep';
|
||||
import { TypeScriptProjectCreateStep } from './ProjectCreateStep/TypeScriptProjectCreateStep';
|
||||
import { addBallerinaCreateProjectSteps } from './ballerinaSteps/addBallerinaCreateProjectSteps';
|
||||
import { DotnetRuntimeStep } from './dotnetSteps/DotnetRuntimeStep';
|
||||
import { addJavaCreateProjectSteps } from './javaSteps/addJavaCreateProjectSteps';
|
||||
|
||||
|
@ -47,6 +48,7 @@ export class NewProjectLanguageStep extends AzureWizardPromptStep<IProjectWizard
|
|||
{ label: ProjectLanguage.Python, data: { language: ProjectLanguage.Python } },
|
||||
{ label: pythonNewModelPreview, data: { language: ProjectLanguage.Python, model: previewPythonModel } },
|
||||
{ label: ProjectLanguage.Java, data: { language: ProjectLanguage.Java } },
|
||||
{ label: ProjectLanguage.Ballerina, data: { language: ProjectLanguage.Ballerina } },
|
||||
{ label: ProjectLanguage.PowerShell, data: { language: ProjectLanguage.PowerShell } },
|
||||
{ label: localize('customHandler', 'Custom Handler'), data: { language: ProjectLanguage.Custom } }
|
||||
];
|
||||
|
@ -111,6 +113,9 @@ export class NewProjectLanguageStep extends AzureWizardPromptStep<IProjectWizard
|
|||
case ProjectLanguage.Java:
|
||||
await addJavaCreateProjectSteps(context, promptSteps, executeSteps);
|
||||
break;
|
||||
case ProjectLanguage.Ballerina:
|
||||
await addBallerinaCreateProjectSteps(context, promptSteps, executeSteps);
|
||||
break;
|
||||
case ProjectLanguage.Custom:
|
||||
executeSteps.push(new CustomProjectCreateStep());
|
||||
break;
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { AzExtFsExtra } from '@microsoft/vscode-azext-utils';
|
||||
import { Progress } from 'vscode';
|
||||
import { BallerinaBackend, ballerinaTomlFileName } from '../../../constants';
|
||||
import { ballerinaUtils } from '../../../utils/ballerinaUtils';
|
||||
import { IBallerinaProjectWizardContext } from '../ballerinaSteps/IBallerinaProjectWizardContext';
|
||||
import { ScriptProjectCreateStep } from './ScriptProjectCreateStep';
|
||||
import path = require('path');
|
||||
|
||||
export class BallerinaProjectCreateStep extends ScriptProjectCreateStep {
|
||||
protected gitignore: string = ballerinaGitIgnore;
|
||||
|
||||
public async executeCore(context: IBallerinaProjectWizardContext, progress: Progress<{ message?: string | undefined; increment?: number | undefined }>): Promise<void> {
|
||||
await ballerinaUtils.getBallerinaVersion(context);
|
||||
const ballerinaTomlPath: string = path.join(context.projectPath, ballerinaTomlFileName);
|
||||
|
||||
// Having a Ballerina.toml file specifies a Ballerina project. If it doesn't exist, create one using the 'bal init' command.
|
||||
if (!await AzExtFsExtra.pathExists(ballerinaTomlPath)) {
|
||||
await ballerinaUtils.executeInit(context);
|
||||
let ballerinaTomlContents: string = await AzExtFsExtra.readFile(ballerinaTomlPath);
|
||||
const buildOptions: string = await this.getBuildOptions(context);
|
||||
ballerinaTomlContents = ballerinaTomlContents + buildOptions;
|
||||
await AzExtFsExtra.writeFile(ballerinaTomlPath, ballerinaTomlContents);
|
||||
}
|
||||
await super.executeCore(context, progress);
|
||||
}
|
||||
|
||||
async getBuildOptions(context: IBallerinaProjectWizardContext): Promise<string> {
|
||||
return `cloud="azure_functions"
|
||||
${context.balBackend === BallerinaBackend.native ? 'graalvm=true' : ''}`;
|
||||
}
|
||||
}
|
||||
|
||||
const ballerinaGitIgnore: string = `target/`;
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { AzureWizardPromptStep, IAzureQuickPickItem } from "@microsoft/vscode-azext-utils";
|
||||
import { BallerinaBackend } from "../../../constants";
|
||||
import { localize } from "../../../localize";
|
||||
import { IBallerinaProjectWizardContext } from "./IBallerinaProjectWizardContext";
|
||||
|
||||
export class BallerinaBackendStep extends AzureWizardPromptStep<IBallerinaProjectWizardContext> {
|
||||
|
||||
public async prompt(context: IBallerinaProjectWizardContext): Promise<void> {
|
||||
const picks: IAzureQuickPickItem<BallerinaBackend>[] = [
|
||||
{ label: 'JVM', data: BallerinaBackend.jvm },
|
||||
{ label: 'Native', data: BallerinaBackend.native },
|
||||
];
|
||||
const placeHolder: string = localize('selectBallerinaBackend', 'Select the backend for Ballerina project');
|
||||
context.balBackend = (await context.ui.showQuickPick(picks, { placeHolder })).data;
|
||||
}
|
||||
|
||||
public shouldPrompt(context: IBallerinaProjectWizardContext): boolean {
|
||||
return !context.balBackend;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as path from 'path';
|
||||
import { BallerinaBackend } from '../../../constants';
|
||||
import { IProjectWizardContext } from "../IProjectWizardContext";
|
||||
|
||||
export interface IBallerinaProjectWizardContext extends IProjectWizardContext {
|
||||
balBackend?: BallerinaBackend;
|
||||
}
|
||||
|
||||
export function getBallerinaPackagePath(projectPath: string): string {
|
||||
return path.join(projectPath);
|
||||
}
|
||||
|
||||
export function getBallerinaFunctionFilePath(projectPath: string, functionName: string): string {
|
||||
return path.join(getBallerinaPackagePath(projectPath), functionName + '.bal');
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { AzureWizardExecuteStep, AzureWizardPromptStep } from "@microsoft/vscode-azext-utils";
|
||||
import { ballerinaUtils } from "../../../utils/ballerinaUtils";
|
||||
import { IProjectWizardContext } from "../IProjectWizardContext";
|
||||
import { BallerinaProjectCreateStep } from "../ProjectCreateStep/BallerinaProjectCreateStep";
|
||||
import { BallerinaBackendStep } from "./BallerinaBackendStep";
|
||||
import { IBallerinaProjectWizardContext } from "./IBallerinaProjectWizardContext";
|
||||
|
||||
export async function addBallerinaCreateProjectSteps(
|
||||
context: IBallerinaProjectWizardContext,
|
||||
promptSteps: AzureWizardPromptStep<IProjectWizardContext>[],
|
||||
executeSteps: AzureWizardExecuteStep<IProjectWizardContext>[]): Promise<void> {
|
||||
await ballerinaUtils.getBallerinaVersion(context);
|
||||
promptSteps.push(new BallerinaBackendStep());
|
||||
executeSteps.push(new BallerinaProjectCreateStep());
|
||||
}
|
|
@ -9,6 +9,7 @@ import { previewPythonModel, ProjectLanguage } from '../../constants';
|
|||
import { pythonNewModelPreview } from '../../constants-nls';
|
||||
import { localize } from '../../localize';
|
||||
import { IProjectWizardContext } from '../createNewProject/IProjectWizardContext';
|
||||
import { BallerinaInitVSCodeStep } from './InitVSCodeStep/BallerinaInitVSCodeStep';
|
||||
import { DotnetInitVSCodeStep } from './InitVSCodeStep/DotnetInitVSCodeStep';
|
||||
import { DotnetScriptInitVSCodeStep } from './InitVSCodeStep/DotnetScriptInitVSCodeStep';
|
||||
import { JavaScriptInitVSCodeStep } from './InitVSCodeStep/JavaScriptInitVSCodeStep';
|
||||
|
@ -24,6 +25,7 @@ export class InitVSCodeLanguageStep extends AzureWizardPromptStep<IProjectWizard
|
|||
public async prompt(context: IProjectWizardContext): Promise<void> {
|
||||
// Display all languages, even if we don't have full support for them
|
||||
const languagePicks: IAzureQuickPickItem<{ language: ProjectLanguage, model?: number }>[] = [
|
||||
{ label: ProjectLanguage.Ballerina, data: { language: ProjectLanguage.Ballerina } },
|
||||
{ label: ProjectLanguage.CSharp, data: { language: ProjectLanguage.CSharp } },
|
||||
{ label: ProjectLanguage.CSharpScript, data: { language: ProjectLanguage.CSharpScript } },
|
||||
{ label: ProjectLanguage.FSharp, data: { language: ProjectLanguage.FSharp } },
|
||||
|
@ -84,6 +86,9 @@ export async function addInitVSCodeSteps(
|
|||
case ProjectLanguage.FSharpScript:
|
||||
executeSteps.push(new DotnetScriptInitVSCodeStep());
|
||||
break;
|
||||
case ProjectLanguage.Ballerina:
|
||||
executeSteps.push(new BallerinaInitVSCodeStep());
|
||||
break;
|
||||
default:
|
||||
executeSteps.push(new ScriptInitVSCodeStep());
|
||||
break;
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { DebugConfiguration, TaskDefinition } from 'vscode';
|
||||
import { ProjectLanguage, func, hostStartCommand, hostStartTaskName } from '../../../constants';
|
||||
import { ballerinaDebugConfig } from '../../../debug/BallerinaDebugProvider';
|
||||
import { getFuncWatchProblemMatcher } from '../../../vsCodeConfig/settings';
|
||||
import { convertToFunctionsTaskLabel } from '../../../vsCodeConfig/tasks';
|
||||
import { IBallerinaProjectWizardContext } from '../../createNewProject/ballerinaSteps/IBallerinaProjectWizardContext';
|
||||
import { isBallerinaProject } from '../detectProjectLanguage';
|
||||
import { InitVSCodeStepBase } from './InitVSCodeStepBase';
|
||||
|
||||
const ballerinaPackageTaskLabel: string = convertToFunctionsTaskLabel('package');
|
||||
|
||||
export class BallerinaInitVSCodeStep extends InitVSCodeStepBase {
|
||||
protected preDeployTask: string = ballerinaPackageTaskLabel;
|
||||
|
||||
private _debugSubpath: string = "target/azure_functions";
|
||||
|
||||
protected async executeCore(context: IBallerinaProjectWizardContext): Promise<void> {
|
||||
const isProject: boolean = await isBallerinaProject(context.projectPath);
|
||||
if (!isProject) {
|
||||
this._debugSubpath = "azure_functions";
|
||||
}
|
||||
|
||||
this.setDeploySubpath(context, this._debugSubpath);
|
||||
}
|
||||
|
||||
protected getTasks(language: ProjectLanguage): TaskDefinition[] {
|
||||
return [
|
||||
{
|
||||
type: func,
|
||||
label: hostStartTaskName,
|
||||
command: hostStartCommand,
|
||||
problemMatcher: getFuncWatchProblemMatcher(language),
|
||||
isBackground: true,
|
||||
options: {
|
||||
cwd: this._debugSubpath
|
||||
},
|
||||
dependsOn: ballerinaPackageTaskLabel
|
||||
},
|
||||
{
|
||||
label: ballerinaPackageTaskLabel,
|
||||
command: "bal build",
|
||||
type: 'shell',
|
||||
group: {
|
||||
kind: 'build',
|
||||
isDefault: true
|
||||
}
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
protected getDebugConfiguration(): DebugConfiguration {
|
||||
return ballerinaDebugConfig;
|
||||
}
|
||||
|
||||
protected getRecommendedExtensions(): string[] {
|
||||
return ['WSO2.ballerina'];
|
||||
}
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
import { AzExtFsExtra, IActionContext } from '@microsoft/vscode-azext-utils';
|
||||
import * as path from 'path';
|
||||
import { buildGradleFileName, localSettingsFileName, packageJsonFileName, pomXmlFileName, previewPythonModel, ProjectLanguage, pythonFunctionAppFileName, workerRuntimeKey } from '../../constants';
|
||||
import { buildGradleFileName, localSettingsFileName, packageJsonFileName, pomXmlFileName, previewPythonModel, ProjectLanguage, pythonFunctionAppFileName, workerRuntimeKey, ballerinaTomlFileName } from '../../constants';
|
||||
import { getLocalSettingsJson, ILocalSettingsJson } from '../../funcConfig/local.settings';
|
||||
import { dotnetUtils } from '../../utils/dotnetUtils';
|
||||
import { hasNodeJsDependency, tryGetPackageJson } from '../../utils/nodeJsUtils';
|
||||
|
@ -42,6 +42,10 @@ export async function detectProjectLanguage(context: IActionContext, projectPath
|
|||
if (await isFSharpProject(context, projectPath)) {
|
||||
detectedLangs.push(ProjectLanguage.FSharp);
|
||||
}
|
||||
|
||||
if (await isBallerinaProject(projectPath)) {
|
||||
detectedLangs.push(ProjectLanguage.Ballerina);
|
||||
}
|
||||
|
||||
await detectLanguageFromLocalSettings(context, detectedLangs, projectPath);
|
||||
|
||||
|
@ -81,6 +85,10 @@ async function isTypeScriptProject(projectPath: string): Promise<boolean> {
|
|||
return await hasNodeJsDependency(projectPath, 'typescript', true);
|
||||
}
|
||||
|
||||
export async function isBallerinaProject(projectPath: string): Promise<boolean> {
|
||||
return await AzExtFsExtra.pathExists(path.join(projectPath, ballerinaTomlFileName));
|
||||
}
|
||||
|
||||
/**
|
||||
* If the user has a "local.settings.json" file, we may be able to infer the langauge from the setting "FUNCTIONS_WORKER_RUNTIME"
|
||||
*/
|
||||
|
|
|
@ -32,6 +32,7 @@ export enum ProjectLanguage {
|
|||
PowerShell = 'PowerShell',
|
||||
Python = 'Python',
|
||||
TypeScript = 'TypeScript',
|
||||
Ballerina = 'Ballerina',
|
||||
Custom = 'Custom'
|
||||
}
|
||||
|
||||
|
@ -69,6 +70,12 @@ export enum JavaBuildTool {
|
|||
gradle = 'gradle'
|
||||
}
|
||||
|
||||
export const ballerinaTomlFileName: string = "Ballerina.toml"
|
||||
export enum BallerinaBackend {
|
||||
jvm = 'jvm',
|
||||
native = 'native'
|
||||
}
|
||||
|
||||
export enum PackageManager {
|
||||
npm = 'npm',
|
||||
brew = 'brew'
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { DebugConfiguration, WorkspaceFolder } from 'vscode';
|
||||
import { hostStartTaskName, localhost } from '../constants';
|
||||
import { localize } from '../localize';
|
||||
import { FuncDebugProviderBase } from './FuncDebugProviderBase';
|
||||
|
||||
export const defaultBallerinaDebugPort: number = 5005;
|
||||
|
||||
export const ballerinaDebugConfig: DebugConfiguration = {
|
||||
name: localize('attachBallerina', 'Attach to Ballerina Functions'),
|
||||
type: 'ballerina',
|
||||
request: 'attach',
|
||||
hostName: localhost,
|
||||
port: defaultBallerinaDebugPort,
|
||||
preLaunchTask: hostStartTaskName
|
||||
};
|
||||
|
||||
export class BallerinaDebugProvider extends FuncDebugProviderBase {
|
||||
public readonly workerArgKey: string = 'BALLERINA_DEBUG_FLAGS';
|
||||
protected readonly defaultPortOrPipeName: number = defaultBallerinaDebugPort;
|
||||
protected readonly debugConfig: DebugConfiguration = ballerinaDebugConfig;
|
||||
|
||||
public async getWorkerArgValue(folder: WorkspaceFolder): Promise<string> {
|
||||
const port: string | number = this.getDebugPortOrPipeName(folder);
|
||||
return `-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=${port}`;
|
||||
}
|
||||
|
||||
protected getDebugConfigPort(debugConfiguration: DebugConfiguration): number | undefined {
|
||||
const debugPort: string | undefined = <string | undefined>debugConfiguration.debuggeePort;
|
||||
if (debugPort !== undefined) {
|
||||
return parseInt(debugPort);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
}
|
|
@ -45,7 +45,7 @@ export abstract class FuncDebugProviderBase implements DebugConfigurationProvide
|
|||
context.errorHandling.suppressDisplay = true;
|
||||
context.telemetry.suppressIfSuccessful = true;
|
||||
|
||||
this._debugPorts.set(folder, <number | undefined>debugConfiguration.port);
|
||||
this._debugPorts.set(folder, this.getDebugConfigPort(debugConfiguration));
|
||||
if (hostStartTaskNameRegExp.test(debugConfiguration.preLaunchTask as string)) {
|
||||
context.telemetry.properties.isActivationEvent = 'false';
|
||||
context.telemetry.suppressIfSuccessful = false;
|
||||
|
@ -62,6 +62,10 @@ export abstract class FuncDebugProviderBase implements DebugConfigurationProvide
|
|||
return result;
|
||||
}
|
||||
|
||||
protected getDebugConfigPort(debugConfiguration: DebugConfiguration): number | undefined {
|
||||
return <number | undefined>debugConfiguration.port;
|
||||
}
|
||||
|
||||
protected getDebugPortOrPipeName(folder: WorkspaceFolder): number | string {
|
||||
return this._debugPorts.get(folder) || this.defaultPortOrPipeName;
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import { getFuncCliPath } from '../funcCoreTools/getFuncCliPath';
|
|||
import { venvUtils } from '../utils/venvUtils';
|
||||
import { getFuncWatchProblemMatcher, getWorkspaceSetting } from '../vsCodeConfig/settings';
|
||||
import { getTasks } from '../vsCodeConfig/tasks';
|
||||
import { BallerinaDebugProvider } from './BallerinaDebugProvider';
|
||||
import { FuncDebugProviderBase } from './FuncDebugProviderBase';
|
||||
import { JavaDebugProvider } from './JavaDebugProvider';
|
||||
import { NodeDebugProvider } from './NodeDebugProvider';
|
||||
|
@ -22,12 +23,14 @@ export class FuncTaskProvider implements TaskProvider {
|
|||
private readonly _nodeDebugProvider: NodeDebugProvider;
|
||||
private readonly _pythonDebugProvider: PythonDebugProvider;
|
||||
private readonly _javaDebugProvider: JavaDebugProvider;
|
||||
private readonly _ballerinaDebugProvider: BallerinaDebugProvider;
|
||||
private readonly _powershellDebugProvider: PowerShellDebugProvider;
|
||||
|
||||
constructor(nodeDebugProvider: NodeDebugProvider, pythonDebugProvider: PythonDebugProvider, javaDebugProvider: JavaDebugProvider, powershellDebugProvider: PowerShellDebugProvider) {
|
||||
constructor(nodeDebugProvider: NodeDebugProvider, pythonDebugProvider: PythonDebugProvider, javaDebugProvider: JavaDebugProvider, ballerinaDebugProvider: BallerinaDebugProvider, powershellDebugProvider: PowerShellDebugProvider) {
|
||||
this._nodeDebugProvider = nodeDebugProvider;
|
||||
this._pythonDebugProvider = pythonDebugProvider;
|
||||
this._javaDebugProvider = javaDebugProvider;
|
||||
this._ballerinaDebugProvider = ballerinaDebugProvider;
|
||||
this._powershellDebugProvider = powershellDebugProvider;
|
||||
}
|
||||
|
||||
|
@ -134,6 +137,9 @@ export class FuncTaskProvider implements TaskProvider {
|
|||
case ProjectLanguage.Java:
|
||||
debugProvider = this._javaDebugProvider;
|
||||
break;
|
||||
case ProjectLanguage.Ballerina:
|
||||
debugProvider = this._ballerinaDebugProvider
|
||||
break;
|
||||
case ProjectLanguage.PowerShell:
|
||||
debugProvider = this._powershellDebugProvider;
|
||||
break;
|
||||
|
|
|
@ -19,6 +19,7 @@ import { uploadAppSettingsFromApi } from './commands/api/uploadAppSettingsFromAp
|
|||
import { runPostFunctionCreateStepsFromCache } from './commands/createFunction/FunctionCreateStepBase';
|
||||
import { registerCommands } from './commands/registerCommands';
|
||||
import { func } from './constants';
|
||||
import { BallerinaDebugProvider } from './debug/BallerinaDebugProvider';
|
||||
import { FuncTaskProvider } from './debug/FuncTaskProvider';
|
||||
import { JavaDebugProvider } from './debug/JavaDebugProvider';
|
||||
import { NodeDebugProvider } from './debug/NodeDebugProvider';
|
||||
|
@ -75,14 +76,16 @@ export async function activateInternal(context: vscode.ExtensionContext, perfSta
|
|||
const nodeDebugProvider: NodeDebugProvider = new NodeDebugProvider();
|
||||
const pythonDebugProvider: PythonDebugProvider = new PythonDebugProvider();
|
||||
const javaDebugProvider: JavaDebugProvider = new JavaDebugProvider();
|
||||
const ballerinaDebugProvider: BallerinaDebugProvider = new BallerinaDebugProvider();
|
||||
const powershellDebugProvider: PowerShellDebugProvider = new PowerShellDebugProvider();
|
||||
|
||||
// These don't actually overwrite "node", "python", etc. - they just add to it
|
||||
context.subscriptions.push(vscode.debug.registerDebugConfigurationProvider('node', nodeDebugProvider));
|
||||
context.subscriptions.push(vscode.debug.registerDebugConfigurationProvider('python', pythonDebugProvider));
|
||||
context.subscriptions.push(vscode.debug.registerDebugConfigurationProvider('java', javaDebugProvider));
|
||||
context.subscriptions.push(vscode.debug.registerDebugConfigurationProvider('ballerina', ballerinaDebugProvider));
|
||||
context.subscriptions.push(vscode.debug.registerDebugConfigurationProvider('PowerShell', powershellDebugProvider));
|
||||
context.subscriptions.push(vscode.workspace.registerTaskProvider(func, new FuncTaskProvider(nodeDebugProvider, pythonDebugProvider, javaDebugProvider, powershellDebugProvider)));
|
||||
context.subscriptions.push(vscode.workspace.registerTaskProvider(func, new FuncTaskProvider(nodeDebugProvider, pythonDebugProvider, javaDebugProvider, ballerinaDebugProvider, powershellDebugProvider)));
|
||||
|
||||
context.subscriptions.push(vscode.window.registerUriHandler({
|
||||
handleUri
|
||||
|
|
|
@ -5,29 +5,31 @@
|
|||
|
||||
import { IActionContext, parseError } from '@microsoft/vscode-azext-utils';
|
||||
import { ConfigurationChangeEvent, Disposable, workspace } from 'vscode';
|
||||
import { ProjectLanguage, projectTemplateKeySetting, TemplateFilter } from '../constants';
|
||||
import { ext, TemplateSource } from '../extensionVariables';
|
||||
import { FuncVersion } from '../FuncVersion';
|
||||
import { ProjectLanguage, TemplateFilter, projectTemplateKeySetting } from '../constants';
|
||||
import { TemplateSource, ext } from '../extensionVariables';
|
||||
import { localize } from '../localize';
|
||||
import { delay } from '../utils/delay';
|
||||
import { nonNullValue } from '../utils/nonNull';
|
||||
import { isNodeV4Plus, isPythonV2Plus } from '../utils/programmingModelUtils';
|
||||
import { requestUtils } from '../utils/requestUtils';
|
||||
import { getWorkspaceSetting } from '../vsCodeConfig/settings';
|
||||
import { DotnetTemplateProvider } from './dotnet/DotnetTemplateProvider';
|
||||
import { getDotnetVerifiedTemplateIds } from './dotnet/getDotnetVerifiedTemplateIds';
|
||||
import { IBindingTemplate } from './IBindingTemplate';
|
||||
import { IFunctionTemplate, TemplateCategory } from './IFunctionTemplate';
|
||||
import { ITemplates } from './ITemplates';
|
||||
import { getJavaVerifiedTemplateIds } from './java/getJavaVerifiedTemplateIds';
|
||||
import { TemplateProviderBase } from './TemplateProviderBase';
|
||||
import { BallerinaTemplateProvider } from './ballerina/BallerinaTemplateProvider';
|
||||
import { getBallerinaVerifiedTemplateIds } from './ballerina/getBallerinaVerifiedTemplateIds';
|
||||
import { DotnetTemplateProvider } from './dotnet/DotnetTemplateProvider';
|
||||
import { getDotnetVerifiedTemplateIds } from './dotnet/getDotnetVerifiedTemplateIds';
|
||||
import { JavaTemplateProvider } from './java/JavaTemplateProvider';
|
||||
import { getScriptVerifiedTemplateIds } from './script/getScriptVerifiedTemplateIds';
|
||||
import { getJavaVerifiedTemplateIds } from './java/getJavaVerifiedTemplateIds';
|
||||
import { NodeV4Provider } from './script/NodeV4Provider';
|
||||
import { IScriptFunctionTemplate } from './script/parseScriptTemplates';
|
||||
import { PysteinTemplateProvider } from './script/PysteinTemplateProvider';
|
||||
import { ScriptBundleTemplateProvider } from './script/ScriptBundleTemplateProvider';
|
||||
import { ScriptTemplateProvider } from './script/ScriptTemplateProvider';
|
||||
import { TemplateProviderBase } from './TemplateProviderBase';
|
||||
import { getScriptVerifiedTemplateIds } from './script/getScriptVerifiedTemplateIds';
|
||||
import { IScriptFunctionTemplate } from './script/parseScriptTemplates';
|
||||
|
||||
type CachedProviders = { providers: TemplateProviderBase[]; templatesTask?: Promise<ITemplates> }
|
||||
|
||||
|
@ -60,6 +62,9 @@ export class CentralTemplateProvider implements Disposable {
|
|||
case ProjectLanguage.Java:
|
||||
providers.push(new JavaTemplateProvider(version, projectPath, language, projectTemplateKey));
|
||||
break;
|
||||
case ProjectLanguage.Ballerina:
|
||||
providers.push(new BallerinaTemplateProvider(version, projectPath, language, projectTemplateKey));
|
||||
break;
|
||||
default:
|
||||
if (isPythonV2Plus(language, languageModel)) {
|
||||
providers.push(new PysteinTemplateProvider(version, projectPath, language, projectTemplateKey));
|
||||
|
@ -73,6 +78,7 @@ export class CentralTemplateProvider implements Disposable {
|
|||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return providers;
|
||||
}
|
||||
|
||||
|
@ -85,7 +91,7 @@ export class CentralTemplateProvider implements Disposable {
|
|||
return templates.functionTemplates.filter((t: IFunctionTemplate) => t.categories.find((c: TemplateCategory) => c === TemplateCategory.Core) !== undefined);
|
||||
case TemplateFilter.Verified:
|
||||
default:
|
||||
const verifiedTemplateIds = getScriptVerifiedTemplateIds(version).concat(getDotnetVerifiedTemplateIds(version)).concat(getJavaVerifiedTemplateIds());
|
||||
const verifiedTemplateIds = getScriptVerifiedTemplateIds(version).concat(getDotnetVerifiedTemplateIds(version)).concat(getJavaVerifiedTemplateIds().concat(getBallerinaVerifiedTemplateIds()));
|
||||
return templates.functionTemplates.filter((t: IFunctionTemplate) => verifiedTemplateIds.find(vt => typeof vt === 'string' ? vt === t.id : vt.test(t.id)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,10 +6,10 @@
|
|||
import { AzExtFsExtra, IActionContext } from '@microsoft/vscode-azext-utils';
|
||||
import * as path from 'path';
|
||||
import { Disposable, env } from 'vscode';
|
||||
import { FuncVersion } from '../FuncVersion';
|
||||
import { ProjectLanguage } from '../constants';
|
||||
import { NotImplementedError } from '../errors';
|
||||
import { ext } from '../extensionVariables';
|
||||
import { FuncVersion } from '../FuncVersion';
|
||||
import { IBindingTemplate } from './IBindingTemplate';
|
||||
import { IFunctionTemplate } from './IFunctionTemplate';
|
||||
import { ITemplates } from './ITemplates';
|
||||
|
@ -18,7 +18,8 @@ export enum TemplateType {
|
|||
Script = 'Script',
|
||||
ScriptBundle = 'ScriptBundle',
|
||||
Dotnet = '.NET',
|
||||
Java = 'Java'
|
||||
Java = 'Java',
|
||||
Ballerina = 'Ballerina',
|
||||
}
|
||||
|
||||
export abstract class TemplateProviderBase implements Disposable {
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { AzExtFsExtra, IActionContext } from '@microsoft/vscode-azext-utils';
|
||||
import * as path from 'path';
|
||||
import { IBindingTemplate } from '../IBindingTemplate';
|
||||
import { IFunctionTemplate } from '../IFunctionTemplate';
|
||||
import { ITemplates } from '../ITemplates';
|
||||
import { TemplateProviderBase, TemplateType } from '../TemplateProviderBase';
|
||||
import { getScriptResourcesLanguage } from '../script/getScriptResourcesLanguage';
|
||||
import { parseScriptTemplates } from '../script/parseScriptTemplates';
|
||||
|
||||
export class BallerinaTemplateProvider extends TemplateProviderBase {
|
||||
public templateType: TemplateType = TemplateType.Ballerina;
|
||||
|
||||
protected get backupSubpath(): string {
|
||||
return path.join('ballerina');
|
||||
}
|
||||
|
||||
protected _rawResources: object;
|
||||
protected _rawTemplates: object[];
|
||||
protected _rawBindings: object;
|
||||
|
||||
public async getCachedTemplates(): Promise<ITemplates | undefined> {
|
||||
return await this.getBackupTemplates();
|
||||
}
|
||||
|
||||
public async getLatestTemplateVersion(_context: IActionContext): Promise<string> {
|
||||
return '1.0';
|
||||
}
|
||||
|
||||
public async getLatestTemplates(_context: IActionContext, _latestTemplateVersion: string): Promise<ITemplates> {
|
||||
return await this.getBackupTemplates();
|
||||
}
|
||||
|
||||
public async getBackupTemplates(): Promise<ITemplates> {
|
||||
return await this.parseTemplates(this.getBackupPath());
|
||||
}
|
||||
|
||||
public async updateBackupTemplates(): Promise<void> {
|
||||
// NOTE: No-op as the templates are only bundled with this extension.
|
||||
await Promise.resolve();
|
||||
}
|
||||
|
||||
public async cacheTemplates(): Promise<void> {
|
||||
// NOTE: No-op as the templates are only bundled with this extension.
|
||||
await Promise.resolve();
|
||||
}
|
||||
|
||||
public async clearCachedTemplates(): Promise<void> {
|
||||
// NOTE: No-op as the templates are only bundled with this extension.
|
||||
await Promise.resolve();
|
||||
}
|
||||
|
||||
public includeTemplate(template: IFunctionTemplate | IBindingTemplate): boolean {
|
||||
return this.isFunctionTemplate(template)
|
||||
&& template.language === this.language
|
||||
&& !!template.triggerType
|
||||
}
|
||||
|
||||
protected async parseTemplates(rootPath: string): Promise<ITemplates> {
|
||||
const paths: ITemplatePaths = this.getTemplatePaths(rootPath);
|
||||
this._rawTemplates = await AzExtFsExtra.readJSON<object[]>(paths.templates);
|
||||
this._rawBindings = await AzExtFsExtra.readJSON<object>(paths.bindings);
|
||||
this._rawResources = await AzExtFsExtra.readJSON<object>(paths.resources);
|
||||
|
||||
return parseScriptTemplates(this._rawResources, this._rawTemplates, this._rawBindings);
|
||||
}
|
||||
|
||||
protected getResourcesLanguage(): string {
|
||||
return this.resourcesLanguage || getScriptResourcesLanguage();
|
||||
}
|
||||
|
||||
private getTemplatePaths(rootPath: string): ITemplatePaths {
|
||||
const resources: string = path.join(rootPath, 'resources', `Resources.json`);
|
||||
const templates: string = path.join(rootPath, 'templates', 'templates.json');
|
||||
const bindings: string = path.join(rootPath, 'bindings', 'bindings.json');
|
||||
return { resources, templates, bindings };
|
||||
}
|
||||
|
||||
private isFunctionTemplate(template: IFunctionTemplate | IBindingTemplate): template is IFunctionTemplate {
|
||||
return (template as IFunctionTemplate).id !== undefined;
|
||||
}
|
||||
}
|
||||
|
||||
interface ITemplatePaths {
|
||||
resources: string;
|
||||
templates: string;
|
||||
bindings: string;
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
export function getBallerinaVerifiedTemplateIds(): string[] {
|
||||
return [
|
||||
'HttpTrigger-Ballerina',
|
||||
'BlobTrigger-Ballerina',
|
||||
'CosmosDBTrigger-Ballerina',
|
||||
'QueueTrigger-Ballerina',
|
||||
'TimerTrigger-Ballerina'
|
||||
];
|
||||
}
|
|
@ -166,6 +166,8 @@ async function getCompiledProjectInfo(context: IActionContext, projectPath: stri
|
|||
} else {
|
||||
return { compiledProjectPath: path.join(projectPath, getJavaDebugSubpath(functionAppName, buildTool)), isIsolated: false };
|
||||
}
|
||||
} else if (projectLanguage === ProjectLanguage.Ballerina) {
|
||||
return { compiledProjectPath: projectPath, isIsolated: false };
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { DialogResponses } from "@microsoft/vscode-azext-utils";
|
||||
import { unlinkSync } from 'fs';
|
||||
import * as vscode from 'vscode';
|
||||
import { IProjectWizardContext } from "../commands/createNewProject/IProjectWizardContext";
|
||||
import { localize } from '../localize';
|
||||
import { openUrl } from '../utils/openUrl';
|
||||
import { cpUtils } from './cpUtils';
|
||||
|
||||
export namespace ballerinaUtils {
|
||||
const ballerinaCommand: string = 'bal';
|
||||
|
||||
export async function executeInit(context: IProjectWizardContext): Promise<void> {
|
||||
try {
|
||||
await cpUtils.executeCommand(undefined, context.projectPath, ballerinaCommand, 'new', '.');
|
||||
|
||||
// Remove unwanted files generated by Ballerina new command
|
||||
const gitIgnorePath: string = `${context.projectPath}/.gitignore`;
|
||||
unlinkSync(gitIgnorePath);
|
||||
const mainBalPath: string = `${context.projectPath}/main.bal`;
|
||||
unlinkSync(mainBalPath);
|
||||
const devContainerPath: string = `${context.projectPath}/.devcontainer.json`;
|
||||
unlinkSync(devContainerPath);
|
||||
} catch (error) {
|
||||
handleBallerinaNotFoundErr(context);
|
||||
}
|
||||
}
|
||||
|
||||
export async function getBallerinaVersion(context: IProjectWizardContext): Promise<number> {
|
||||
const ballerinaVersion: number | undefined = await checkVersionByCLI();
|
||||
if (!ballerinaVersion) {
|
||||
handleBallerinaNotFoundErr(context);
|
||||
}
|
||||
return ballerinaVersion;
|
||||
}
|
||||
|
||||
function handleBallerinaNotFoundErr(context: IProjectWizardContext): never {
|
||||
const message: string = localize('ballerinaNotFound', 'Failed to get Ballerina installation. Please ensure that Ballerina is in your system path');
|
||||
|
||||
if (!context.errorHandling.suppressDisplay) {
|
||||
// don't wait
|
||||
void vscode.window.showErrorMessage(message, DialogResponses.learnMore).then(async (result) => {
|
||||
if (result === DialogResponses.learnMore) {
|
||||
await openUrl('https://ballerina.io/downloads/');
|
||||
}
|
||||
});
|
||||
context.errorHandling.suppressDisplay = true;
|
||||
}
|
||||
|
||||
throw new Error(message);
|
||||
}
|
||||
|
||||
async function checkVersionByCLI(): Promise<number | undefined> {
|
||||
const result: cpUtils.ICommandResult = await cpUtils.tryExecuteCommand(undefined, undefined, "bal", '--version');
|
||||
const output: string = result.cmdOutputIncludingStderr;
|
||||
const regexp = /Ballerina (\d+\.\d+\.\d+)/;
|
||||
const match = regexp.exec(output);
|
||||
return match ? flattenMajorVersion(match[1]) : undefined;
|
||||
}
|
||||
|
||||
function flattenMajorVersion(version: string): number {
|
||||
const regexp = /\d+/g;
|
||||
const match = regexp.exec(version);
|
||||
let javaVersion = 0;
|
||||
if (match) {
|
||||
javaVersion = parseInt(match[0], 10);
|
||||
}
|
||||
|
||||
return javaVersion;
|
||||
}
|
||||
}
|
|
@ -80,6 +80,7 @@ export function getRootFunctionsWorkerRuntime(language: string | undefined): str
|
|||
case ProjectLanguage.CSharp:
|
||||
case ProjectLanguage.FSharp:
|
||||
return 'dotnet';
|
||||
case ProjectLanguage.Ballerina:
|
||||
case ProjectLanguage.Java:
|
||||
return 'java';
|
||||
case ProjectLanguage.Python:
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as path from 'path';
|
||||
import * as vscode from 'vscode';
|
||||
import { FuncVersion, ProjectLanguage, funcVersionSetting, projectLanguageSetting } from '../../extension.bundle';
|
||||
import { allTemplateSources, isLongRunningVersion } from '../global.test';
|
||||
import { getRotatingAuthLevel } from '../nightly/getRotatingValue';
|
||||
import { runWithFuncSetting } from '../runWithSetting';
|
||||
import { CreateFunctionTestCase, FunctionTesterBase } from './FunctionTesterBase';
|
||||
|
||||
class BallerinaFunctionTester extends FunctionTesterBase {
|
||||
public language: ProjectLanguage = ProjectLanguage.Ballerina;
|
||||
|
||||
public getExpectedPaths(functionName: string): string[] {
|
||||
return [
|
||||
path.join(functionName + '.bal')
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
for (const version of [FuncVersion.v2, FuncVersion.v3, FuncVersion.v4]) {
|
||||
for (const source of allTemplateSources) {
|
||||
addSuite(new BallerinaFunctionTester(version, source));
|
||||
}
|
||||
}
|
||||
|
||||
function addSuite(tester: FunctionTesterBase): void {
|
||||
const testCases: CreateFunctionTestCase[] = [
|
||||
{
|
||||
functionName: 'Blob trigger',
|
||||
inputs: [
|
||||
'AzureWebJobsStorage', // Use existing app setting
|
||||
'test-path/{name}'
|
||||
]
|
||||
},
|
||||
{
|
||||
functionName: 'CosmosDB trigger',
|
||||
inputs: [
|
||||
'AzureWebJobsStorage', // Use existing app setting
|
||||
'dbName',
|
||||
'collectionName'
|
||||
]
|
||||
},
|
||||
{
|
||||
functionName: 'HTTP trigger',
|
||||
inputs: [
|
||||
getRotatingAuthLevel()
|
||||
]
|
||||
},
|
||||
{
|
||||
functionName: 'Queue trigger',
|
||||
inputs: [
|
||||
'AzureWebJobsStorage', // Use existing app setting
|
||||
'testqueue'
|
||||
]
|
||||
},
|
||||
{
|
||||
functionName: 'Timer trigger',
|
||||
inputs: [
|
||||
'0 * * */3 * *'
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
tester.addParallelSuite(testCases, {
|
||||
isLongRunning: isLongRunningVersion(tester.version),
|
||||
addTests: () => {
|
||||
// https://github.com/Microsoft/vscode-azurefunctions/blob/main/docs/api.md#create-local-function
|
||||
test('createFunction API (deprecated)', async () => {
|
||||
const templateId: string = `HttpTrigger-${tester.language}`;
|
||||
const functionName: string = 'createFunctionApi';
|
||||
const authLevel: string = 'Anonymous';
|
||||
// Intentionally testing weird casing for authLevel
|
||||
await runWithFuncSetting(projectLanguageSetting, tester.language, async () => {
|
||||
await runWithFuncSetting(funcVersionSetting, tester.version, async () => {
|
||||
await vscode.commands.executeCommand('azureFunctions.createFunction', tester.projectPath, templateId, functionName, { aUtHLevel: authLevel });
|
||||
});
|
||||
});
|
||||
await tester.validateFunction(tester.projectPath, functionName, [authLevel]);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
|
@ -13,7 +13,7 @@ import * as vscode from 'vscode';
|
|||
import { copyFunctionUrl, createGenericClient, createNewProjectInternal, deployProductionSlot, FuncVersion, getRandomHexString, nonNullProp } from '../../extension.bundle';
|
||||
import { addParallelSuite, ParallelTest, runInSeries } from '../addParallelSuite';
|
||||
import { getTestWorkspaceFolder } from '../global.test';
|
||||
import { defaultTestFuncVersion, getCSharpValidateOptions, getJavaScriptValidateOptions, getPowerShellValidateOptions, getPythonValidateOptions, getTypeScriptValidateOptions, IValidateProjectOptions, validateProject } from '../project/validateProject';
|
||||
import { defaultTestFuncVersion, getCSharpValidateOptions, getJavaScriptValidateOptions, getBallerinaValidateOptions, getPowerShellValidateOptions, getPythonValidateOptions, getTypeScriptValidateOptions, IValidateProjectOptions, validateProject } from '../project/validateProject';
|
||||
import { getRotatingAuthLevel, getRotatingLocation, getRotatingNodeVersion, getRotatingPythonVersion } from './getRotatingValue';
|
||||
import { resourceGroupsToDelete } from './global.nightly.test';
|
||||
|
||||
|
@ -25,6 +25,7 @@ interface CreateProjectAndDeployTestCase extends ICreateProjectAndDeployOptions
|
|||
const testCases: CreateProjectAndDeployTestCase[] = [
|
||||
{ title: 'JavaScript', ...getJavaScriptValidateOptions(true), deployInputs: [getRotatingNodeVersion()] },
|
||||
{ title: 'TypeScript', ...getTypeScriptValidateOptions(), deployInputs: [getRotatingNodeVersion()] },
|
||||
{ title: 'Ballerina', ...getBallerinaValidateOptions(), deployInputs: [/java.*11/i] },
|
||||
// All C# tests on mac and .NET 6 on windows are consistently timing out for some unknown reason. Will skip for now
|
||||
{ title: 'C# .NET Core 3.1', buildMachineOsToSkip: 'darwin', ...getCSharpValidateOptions('netcoreapp3.1'), createProjectInputs: [/net.*3/i], deployInputs: [/net.*3/i], createFunctionInputs: ['Company.Function'] },
|
||||
{ title: 'C# .NET 5', buildMachineOsToSkip: 'darwin', ...getCSharpValidateOptions('net5.0'), createProjectInputs: [/net.*5/i], deployInputs: [/net.*5/i], createFunctionInputs: ['Company.Function'] },
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
import { TestActionContext, TestInput } from '@microsoft/vscode-azext-dev';
|
||||
import * as path from 'path';
|
||||
import { createNewProjectInternal, getRandomHexString, hiddenStacksSetting, ProjectLanguage } from '../../extension.bundle';
|
||||
import { ProjectLanguage, createNewProjectInternal, getRandomHexString, hiddenStacksSetting } from '../../extension.bundle';
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import * as api from '../../src/vscode-azurefunctions.api';
|
||||
import { testFolderPath } from '../global.test';
|
||||
|
@ -33,7 +33,7 @@ export async function createAndValidateProject(context: TestActionContext, optio
|
|||
|
||||
// All languages except Java support creating a function after creating a project
|
||||
// Java needs to fix this issue first: https://github.com/Microsoft/vscode-azurefunctions/issues/81
|
||||
if (language !== ProjectLanguage.Java) {
|
||||
if (language !== (ProjectLanguage.Java)) {
|
||||
// don't create function
|
||||
inputs.push(/skip for now/i);
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import { FuncVersion, JavaBuildTool, ProjectLanguage, TemplateSource } from '../
|
|||
import { addParallelSuite, ParallelTest } from '../addParallelSuite';
|
||||
import { allTemplateSources, runForTemplateSource, shouldSkipVersion } from '../global.test';
|
||||
import { createAndValidateProject, ICreateProjectTestOptions } from './createAndValidateProject';
|
||||
import { getCSharpValidateOptions, getCustomValidateOptions, getDotnetScriptValidateOptions, getFSharpValidateOptions, getJavaScriptValidateOptions, getJavaValidateOptions, getPowerShellValidateOptions, getPythonValidateOptions, getTypeScriptValidateOptions } from './validateProject';
|
||||
import { getBallerinaValidateOptions, getCSharpValidateOptions, getCustomValidateOptions, getDotnetScriptValidateOptions, getFSharpValidateOptions, getJavaScriptValidateOptions, getJavaValidateOptions, getPowerShellValidateOptions, getPythonValidateOptions, getTypeScriptValidateOptions } from './validateProject';
|
||||
|
||||
interface CreateProjectTestCase extends ICreateProjectTestOptions {
|
||||
description?: string;
|
||||
|
@ -59,6 +59,13 @@ for (const version of [FuncVersion.v2, FuncVersion.v3, FuncVersion.v4]) {
|
|||
inputs: javaBaseInputs.concat(/Maven/i),
|
||||
description: JavaBuildTool.maven
|
||||
});
|
||||
const ballerinaBaseInputs: (TestInput | string | RegExp)[] = [/JVM/i];
|
||||
|
||||
testCases.push({
|
||||
...getBallerinaValidateOptions(version),
|
||||
inputs: ballerinaBaseInputs,
|
||||
description: 'ballerina'
|
||||
});
|
||||
}
|
||||
|
||||
testCases.push({ ...getCustomValidateOptions(FuncVersion.v3) });
|
||||
|
|
|
@ -8,7 +8,7 @@ import { AzExtFsExtra } from '@microsoft/vscode-azext-utils';
|
|||
import * as path from 'path';
|
||||
import { FuncVersion, getRandomHexString, initProjectForVSCode, JavaBuildTool, ProjectLanguage } from '../../extension.bundle';
|
||||
import { cleanTestWorkspace, testFolderPath } from '../global.test';
|
||||
import { getCSharpValidateOptions, getCustomValidateOptions, getFSharpValidateOptions, getJavaScriptValidateOptions, getJavaValidateOptions, getPowerShellValidateOptions, getPythonValidateOptions, getTypeScriptValidateOptions, IValidateProjectOptions, validateProject } from './validateProject';
|
||||
import { getBallerinaValidateOptions, getCSharpValidateOptions, getCustomValidateOptions, getFSharpValidateOptions, getJavaScriptValidateOptions, getJavaValidateOptions, getPowerShellValidateOptions, getPythonValidateOptions, getTypeScriptValidateOptions, IValidateProjectOptions, validateProject } from './validateProject';
|
||||
|
||||
suite('Init Project For VS Code', function (this: Mocha.Suite): void {
|
||||
this.timeout(30 * 1000);
|
||||
|
@ -116,6 +116,19 @@ suite('Init Project For VS Code', function (this: Mocha.Suite): void {
|
|||
await initAndValidateProject({ ...getJavaValidateOptions(appName, JavaBuildTool.gradle), mockFiles });
|
||||
});
|
||||
|
||||
test('Ballerina', async () => {
|
||||
const mockFiles: MockFile[] = [
|
||||
{
|
||||
fsPath: 'Ballerina.toml',
|
||||
contents: `[package]
|
||||
org = "testorg"
|
||||
name = "azf_test"
|
||||
version = "0.1.0"`
|
||||
}
|
||||
];
|
||||
await initAndValidateProject({ ...getBallerinaValidateOptions(), mockFiles });
|
||||
});
|
||||
|
||||
test('PowerShell', async () => {
|
||||
await initAndValidateProject({ ...getPowerShellValidateOptions(), mockFiles: [['HttpTriggerPS', 'run.ps1'], 'profile.ps1', 'requirements.psd1'] });
|
||||
});
|
||||
|
|
|
@ -204,6 +204,34 @@ export function getJavaValidateOptions(appName: string, buildTool: string, versi
|
|||
};
|
||||
}
|
||||
|
||||
export function getBallerinaValidateOptions(version: FuncVersion = defaultTestFuncVersion): IValidateProjectOptions {
|
||||
return {
|
||||
language: ProjectLanguage.Ballerina,
|
||||
version,
|
||||
expectedSettings: {
|
||||
'azureFunctions.projectLanguage': ProjectLanguage.Ballerina,
|
||||
'azureFunctions.projectRuntime': version,
|
||||
'azureFunctions.preDeployTask': 'package (functions)',
|
||||
'azureFunctions.deploySubpath': 'target/azure_functions',
|
||||
'debug.internalConsoleOptions': 'neverOpen',
|
||||
},
|
||||
expectedExtensionRecs: [
|
||||
'WSO2.ballerina',
|
||||
],
|
||||
expectedDebugConfigs: [
|
||||
'Attach to Ballerina Functions'
|
||||
],
|
||||
expectedTasks: [
|
||||
'func: host start',
|
||||
'package (functions)'
|
||||
],
|
||||
expectedPaths: ['Ballerina.toml'],
|
||||
excludedPaths: [
|
||||
'.funcignore'
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
export function getDotnetScriptValidateOptions(language: ProjectLanguage, version: FuncVersion = defaultTestFuncVersion): IValidateProjectOptions {
|
||||
return {
|
||||
language,
|
||||
|
|
|
@ -45,9 +45,10 @@ function addSuite(source: TemplateSource | undefined): void {
|
|||
{ language: ProjectLanguage.PowerShell, version: FuncVersion.v2, expectedCount: 14 },
|
||||
{ language: ProjectLanguage.PowerShell, version: FuncVersion.v3, expectedCount: 14 },
|
||||
{ language: ProjectLanguage.PowerShell, version: FuncVersion.v4, expectedCount: 14 },
|
||||
{ language: ProjectLanguage.Java, version: FuncVersion.v2, expectedCount: 4 }
|
||||
{ language: ProjectLanguage.Java, version: FuncVersion.v2, expectedCount: 4 },
|
||||
// https://github.com/microsoft/vscode-azurefunctions/issues/1605
|
||||
// { language: ProjectLanguage.Java, version: FuncVersion.v3, expectedCount: 4}]
|
||||
{ language: ProjectLanguage.Ballerina, version: FuncVersion.v4, expectedCount: 5 }
|
||||
];
|
||||
|
||||
let testWorkspacePath: string;
|
||||
|
|
Загрузка…
Ссылка в новой задаче