Skip to content

Commit

Permalink
Support java 17 runtime when create function project (#3311)
Browse files Browse the repository at this point in the history
* Support create java 17 function project

* Force to use latest maven archetype when create maven function project

* Fix validation issue in `verifyAppSettings`

* Add validation for local java runtime

* Resolve issues in test cases

* Fix wording and migrate to `AzExtFsExtra`

* Update version for gradle plugin and java library
  • Loading branch information
Flanker32 authored Sep 13, 2022
1 parent c93afcb commit 9a25d46
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ import { AzExtFsExtra } from '@microsoft/vscode-azext-utils';
import * as path from 'path';
import { Progress } from 'vscode';
import { buildGradleFileName, JavaBuildTool, settingsGradleFileName } from '../../../constants';
import { localize } from '../../../localize';
import { confirmOverwriteFile } from '../../../utils/fs';
import { gradleUtils } from '../../../utils/gradleUtils';
import { javaUtils } from '../../../utils/javaUtils';
import { nonNullProp } from '../../../utils/nonNull';
import { IJavaProjectWizardContext } from '../javaSteps/IJavaProjectWizardContext';
import { java11, java8 } from '../javaSteps/JavaVersionStep';
import { java8 } from '../javaSteps/JavaVersionStep';
import { ScriptProjectCreateStep } from './ScriptProjectCreateStep';

const backupGradlePluginVersion = "1.8.2";
const backupGradlePluginVersion = "1.11.0";
const metaDataUrl = "https://plugins.gradle.org/m2/com/microsoft/azure/azure-functions-gradle-plugin/maven-metadata.xml";

export class GradleProjectCreateStep extends ScriptProjectCreateStep {
Expand Down Expand Up @@ -54,14 +54,9 @@ export class GradleProjectCreateStep extends ScriptProjectCreateStep {
return `rootProject.name = "${context.javaArtifactId}"`;
}

getCompatibilityVersion(javaVersion: string | undefined): string {
if (javaVersion === java8) {
return "1.8";
} else if (javaVersion === java11) {
return "11";
} else {
throw new Error(localize('invalidJavaVersion', 'Invalid Java version "{0}".', javaVersion));
}
getCompatibilityVersion(context: IJavaProjectWizardContext): string {
const javaVersion: string = nonNullProp(context, 'javaVersion');
return javaVersion === java8 ? "1.8" : javaVersion;
}

async getBuildGradleContent(context: IJavaProjectWizardContext): Promise<string> {
Expand All @@ -75,13 +70,13 @@ group '${context.javaGroupId}'
version '${context.javaProjectVersion}'
dependencies {
implementation 'com.microsoft.azure.functions:azure-functions-java-library:1.4.2'
implementation 'com.microsoft.azure.functions:azure-functions-java-library:2.0.1'
testImplementation 'org.junit.jupiter:junit-jupiter:5.6.2'
testImplementation 'org.mockito:mockito-core:3.3.3'
}
sourceCompatibility = '${this.getCompatibilityVersion(context.javaVersion)}'
targetCompatibility = '${this.getCompatibilityVersion(context.javaVersion)}'
sourceCompatibility = '${this.getCompatibilityVersion(context)}'
targetCompatibility = '${this.getCompatibilityVersion(context)}'
compileJava.options.encoding = 'UTF-8'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export class MavenProjectCreateStep extends ProjectCreateStepBase {
'archetype:generate',
mavenUtils.formatMavenArg('DarchetypeGroupId', 'com.microsoft.azure'),
mavenUtils.formatMavenArg('DarchetypeArtifactId', 'azure-functions-archetype'),
mavenUtils.formatMavenArg('DarchetypeVersion', 'LATEST'),
mavenUtils.formatMavenArg('DjavaVersion', javaVersion),
mavenUtils.formatMavenArg('DgroupId', nonNullProp(context, 'javaGroupId')),
mavenUtils.formatMavenArg('DartifactId', artifactId),
Expand Down
33 changes: 29 additions & 4 deletions src/commands/createNewProject/javaSteps/JavaVersionStep.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,54 @@
*--------------------------------------------------------------------------------------------*/

import { AzureWizardPromptStep, IAzureQuickPickItem } from "@microsoft/vscode-azext-utils";
import { previewDescription } from "../../../constants";
import { hasMinFuncCliVersion } from "../../../funcCoreTools/hasMinFuncCliVersion";
import { localize } from "../../../localize";
import { IJavaProjectWizardContext } from "./IJavaProjectWizardContext";
import { getJavaVersion } from "./JavaVersions";

export const java8: string = '8';
export const java11: string = '11';
export const java17: string = '17';

type javaVersionInfo = {
label: string,
data: string,
description?: string,
miniFunc: string
}

const versionInfo: javaVersionInfo[] = [
{ label: 'Java 8', data: java8, miniFunc: '1.0.0' },
{ label: 'Java 11', data: java11, miniFunc: '3.0.2630' },
{ label: 'Java 17', data: java17, miniFunc: '4.0.0', description: previewDescription }
];

export class JavaVersionStep extends AzureWizardPromptStep<IJavaProjectWizardContext> {

public static async setDefaultVersion(context: IJavaProjectWizardContext): Promise<void> {
if (!await hasMinFuncCliVersion(context, '3.0.2630', context.version)) {
context.javaVersion = java8;
}
}

public async prompt(context: IJavaProjectWizardContext): Promise<void> {
const picks: IAzureQuickPickItem<string>[] = [
{ label: 'Java 8', data: java8 },
{ label: 'Java 11', data: java11 },
];
const picks: IAzureQuickPickItem<string>[] = await this.getPicks(context);
const placeHolder: string = localize('selectJavaVersion', 'Select a version of Java');
context.javaVersion = (await context.ui.showQuickPick(picks, { placeHolder })).data;
}

async getPicks(context: IJavaProjectWizardContext): Promise<IAzureQuickPickItem<string>[]> {
const javaVersion: number = await getJavaVersion();
const result: IAzureQuickPickItem<string>[] = [];
for (const version of versionInfo) {
if (await hasMinFuncCliVersion(context, version.miniFunc, context.version) && javaVersion >= Number(version.data)) {
result.push(version);
}
}
return result;
}

public shouldPrompt(context: IJavaProjectWizardContext): boolean {
return !context.javaVersion;
}
Expand Down
69 changes: 69 additions & 0 deletions src/commands/createNewProject/javaSteps/JavaVersions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*---------------------------------------------------------------------------------------------
* 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 { cpUtils } from "../../../utils/cpUtils";

import * as path from 'path';

export async function getJavaVersion(): Promise<number> {
const javaHome: string | undefined = process.env['JAVA_HOME'];
let javaVersion = javaHome ? await checkVersionInReleaseFile(javaHome) : undefined;
if (!javaVersion) {
javaVersion = await checkVersionByCLI(javaHome ? path.join(javaHome, 'bin', 'java') : 'java');
}
if (!javaVersion) {
const message: string = localize('javaNotFound', 'Failed to get Java version. Please ensure that Java is installed and JAVA_HOME environment variable is set.');
throw new Error(message);
}
return javaVersion;
}

async function checkVersionInReleaseFile(javaHome: string): Promise<number | undefined> {
if (!javaHome) {
return undefined;
}
const releaseFile = path.join(javaHome, "release");
if (!await AzExtFsExtra.pathExists(releaseFile)) {
return undefined;
}

try {
const content = await AzExtFsExtra.readFile(releaseFile);
const regexp = /^JAVA_VERSION="(.*)"/gm;
const match = regexp.exec(content.toString());
return match ? flattenMajorVersion(match[1]) : undefined;
} catch (error) {
// ignore
return undefined;
}
}

async function checkVersionByCLI(javaExec: string): Promise<number | undefined> {
if (!javaExec) {
return undefined;
}
const result: cpUtils.ICommandResult = await cpUtils.tryExecuteCommand(undefined, undefined, javaExec, '-version');
const output: string = result.cmdOutputIncludingStderr;
const regexp = /version "(.*)"/g;
const match = regexp.exec(output);
return match ? flattenMajorVersion(match[1]) : undefined;
}

function flattenMajorVersion(version: string): number {
// Ignore '1.' prefix for legacy Java versions
if (version.startsWith("1.")) {
version = version.substring(2);
}

const regexp = /\d+/g;
const match = regexp.exec(version);
let javaVersion = 0;
if (match) {
javaVersion = parseInt(match[0], 10);
}

return javaVersion;
}
4 changes: 2 additions & 2 deletions src/commands/deploy/verifyAppSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export async function verifyAppSettings(context: IActionContext, node: SlotTreeI
await verifyVersionAndLanguage(context, projectPath, node.site.fullName, version, language, appSettings.properties);

// update the settings if the remote runtime was changed
let updateAppSettings: boolean = appSettings[workerRuntimeKey] !== remoteRuntime;
let updateAppSettings: boolean = appSettings.properties[workerRuntimeKey] !== remoteRuntime;
if (node.site.isLinux) {
const remoteBuildSettingsChanged = verifyLinuxRemoteBuildSettings(context, appSettings.properties, bools);
updateAppSettings ||= remoteBuildSettingsChanged;
Expand All @@ -38,7 +38,7 @@ export async function verifyAppSettings(context: IActionContext, node: SlotTreeI
if (updateAppSettings) {
await client.updateApplicationSettings(appSettings);
// if the user cancels the deployment, the app settings node doesn't reflect the updated settings
await node.appSettingsTreeItem.refresh(context);
await node.appSettingsTreeItem?.refresh(context);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion test/project/createNewProject.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ for (const version of [FuncVersion.v2, FuncVersion.v3, FuncVersion.v4]) {
const appName: string = 'javaApp';
const javaBaseInputs: (TestInput | string | RegExp)[] = [TestInput.UseDefaultValue, TestInput.UseDefaultValue, TestInput.UseDefaultValue, TestInput.UseDefaultValue, appName];
if (version !== FuncVersion.v2) { // v2 doesn't support picking a java version
javaBaseInputs.unshift(/11/);
javaBaseInputs.unshift(/8/);
}

testCases.push({
Expand Down

0 comments on commit 9a25d46

Please sign in to comment.