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:
Anjana Supun 2023-07-15 01:39:46 +05:30 коммит произвёл GitHub
Родитель fb67f66aa0
Коммит cd2e6326a5
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
38 изменённых файлов: 830 добавлений и 22 удалений

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

@ -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;