diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f46a7af..02058291 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to the "vscode-java-dependency" extension will be documented The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## 0.25.2 + +- ux - Check extension existence on-the-fly when needed by @FluoriteCafe-work in https://github.com/microsoft/vscode-java-dependency/pull/911 + ## 0.25.0 - feat - Remind users to upgrade old (<21) Java and EOL Spring Boot/Framework versions by @FluoriteCafe-work in https://github.com/microsoft/vscode-java-dependency/pull/901 - feat - Improve ProjectCommand.getMainClasses by @snjeza in https://github.com/microsoft/vscode-java-dependency/pull/883 diff --git a/package-lock.json b/package-lock.json index 86f0b6a8..02feb80c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "vscode-java-dependency", - "version": "0.25.0", + "version": "0.25.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "vscode-java-dependency", - "version": "0.25.0", + "version": "0.25.2", "license": "MIT", "dependencies": { "await-lock": "^2.2.2", diff --git a/package.json b/package.json index 31fd592f..118693fb 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "vscode-java-dependency", "displayName": "Project Manager for Java", "description": "%description%", - "version": "0.25.0", + "version": "0.25.2", "publisher": "vscjava", "preview": false, "aiKey": "5c642b22-e845-4400-badb-3f8509a70777", @@ -593,7 +593,7 @@ }, { "command": "_java.view.modernizeJavaProject", - "when": "explorerResourceIsFolder && java:serverMode && isModernizationExtensionInstalled", + "when": "explorerResourceIsFolder && java:serverMode", "group": "1_javaactions@40" }, { diff --git a/src/constants.ts b/src/constants.ts index 659e67ca..8bb176a5 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -35,6 +35,7 @@ export namespace ExtensionName { export const JAVA_LANGUAGE_SUPPORT: string = "redhat.java"; export const APP_MODERNIZATION_FOR_JAVA = "vscjava.migrate-java-to-azure"; export const APP_MODERNIZATION_UPGRADE_FOR_JAVA = "vscjava.vscode-java-upgrade"; + export const APP_MODERNIZATION_EXTENSION_NAME = "GitHub Copilot app modernization"; } export namespace Upgrade { diff --git a/src/upgrade/dependency.metadata.ts b/src/upgrade/dependency.metadata.ts index 8b31b04f..71a793c8 100644 --- a/src/upgrade/dependency.metadata.ts +++ b/src/upgrade/dependency.metadata.ts @@ -11,7 +11,7 @@ export const DEPENDENCY_JAVA_RUNTIME = { "reason": UpgradeReason.JRE_TOO_OLD, "supportedVersion": `>=${LATEST_JAVA_LTS_VESRION}`, "suggestedVersion": { - "name": String(LATEST_JAVA_LTS_VESRION), + "name": `Java ${LATEST_JAVA_LTS_VESRION}`, "description": "latest LTS version", }, } as const; diff --git a/src/upgrade/display/notificationManager.ts b/src/upgrade/display/notificationManager.ts index 1b6c98d0..c597e746 100644 --- a/src/upgrade/display/notificationManager.ts +++ b/src/upgrade/display/notificationManager.ts @@ -1,17 +1,19 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. -import { commands, ExtensionContext, window } from "vscode"; +import { commands, ExtensionContext, extensions, window } from "vscode"; import type { IUpgradeIssuesRenderer, UpgradeIssue } from "../type"; import { buildFixPrompt, buildNotificationMessage } from "../utility"; import { Commands } from "../../commands"; import { Settings } from "../../settings"; import { instrumentOperation, sendInfo } from "vscode-extension-telemetry-wrapper"; +import { ExtensionName } from "../../constants"; const KEY_PREFIX = 'javaupgrade.notificationManager'; const NEXT_SHOW_TS_KEY = `${KEY_PREFIX}.nextShowTs`; const BUTTON_TEXT_UPGRADE = "Upgrade Now"; +const BUTTON_TEXT_INSTALL_AND_UPGRADE = "Install Extension and Upgrade"; const BUTTON_TEXT_NOT_NOW = "Not Now"; const SECONDS_IN_A_DAY = 24 * 60 * 60; @@ -47,11 +49,13 @@ class NotificationManager implements IUpgradeIssuesRenderer { } this.hasShown = true; + const hasExtension = !!extensions.getExtension(ExtensionName.APP_MODERNIZATION_UPGRADE_FOR_JAVA); const prompt = buildFixPrompt(issue); - const notificationMessage = buildNotificationMessage(issue); + const notificationMessage = buildNotificationMessage(issue, hasExtension); + const upgradeButtonText = hasExtension ? BUTTON_TEXT_UPGRADE : BUTTON_TEXT_INSTALL_AND_UPGRADE; const selection = await window.showInformationMessage( notificationMessage, - BUTTON_TEXT_UPGRADE, + upgradeButtonText, BUTTON_TEXT_NOT_NOW); sendInfo(operationId, { operationName: "java.dependency.upgradeNotification.runUpgrade", @@ -59,7 +63,7 @@ class NotificationManager implements IUpgradeIssuesRenderer { }); switch (selection) { - case BUTTON_TEXT_UPGRADE: { + case upgradeButtonText: { commands.executeCommand(Commands.JAVA_UPGRADE_WITH_COPILOT, prompt); break; } diff --git a/src/upgrade/upgradeManager.ts b/src/upgrade/upgradeManager.ts index 60e270e4..9808a3ac 100644 --- a/src/upgrade/upgradeManager.ts +++ b/src/upgrade/upgradeManager.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. -import { commands, type ExtensionContext, extensions, workspace, type WorkspaceFolder } from "vscode"; +import { commands, type ExtensionContext, workspace, type WorkspaceFolder } from "vscode"; import { Jdtls } from "../java/jdtls"; import { languageServerApiManager } from "../languageServerApi/languageServerApiManager"; @@ -11,28 +11,33 @@ import { Commands } from "../commands"; import notificationManager from "./display/notificationManager"; import { Settings } from "../settings"; import assessmentManager from "./assessmentManager"; +import { checkOrInstallAppModExtension, checkOrPromptToInstallAppModExtension } from "./utility"; const DEFAULT_UPGRADE_PROMPT = "Upgrade Java project dependency to latest version."; function shouldRunCheckup() { - return Settings.getEnableDependencyCheckup() - && !!extensions.getExtension(ExtensionName.APP_MODERNIZATION_UPGRADE_FOR_JAVA); + return Settings.getEnableDependencyCheckup(); } class UpgradeManager { public static initialize(context: ExtensionContext) { notificationManager.initialize(context); - // Commands to be used + // Upgrade project context.subscriptions.push(instrumentOperationAsVsCodeCommand(Commands.JAVA_UPGRADE_WITH_COPILOT, async (promptText?: string) => { + await checkOrInstallAppModExtension(ExtensionName.APP_MODERNIZATION_UPGRADE_FOR_JAVA); const promptToUse = promptText ?? DEFAULT_UPGRADE_PROMPT; await commands.executeCommand(Commands.GOTO_AGENT_MODE, { prompt: promptToUse }); })); - commands.executeCommand('setContext', 'isModernizationExtensionInstalled', - !!extensions.getExtension(ExtensionName.APP_MODERNIZATION_FOR_JAVA)); - context.subscriptions.push(instrumentOperationAsVsCodeCommand(Commands.VIEW_MODERNIZE_JAVA_PROJECT, () => { - commands.executeCommand("workbench.view.extension.azureJavaMigrationExplorer"); + + // Show modernization view + context.subscriptions.push(instrumentOperationAsVsCodeCommand(Commands.VIEW_MODERNIZE_JAVA_PROJECT, async () => { + await checkOrPromptToInstallAppModExtension( + ExtensionName.APP_MODERNIZATION_FOR_JAVA, + "Install GitHub Copilot app modernization to modernize the Java project.", + "Install Extension and Modernize"); + await commands.executeCommand("workbench.view.extension.azureJavaMigrationExplorer"); })); UpgradeManager.scan(); diff --git a/src/upgrade/utility.ts b/src/upgrade/utility.ts index 1735f599..b14bb81b 100644 --- a/src/upgrade/utility.ts +++ b/src/upgrade/utility.ts @@ -1,10 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. -import { Uri } from "vscode"; +import { commands, extensions, Uri, window } from "vscode"; import * as semver from "semver"; import { UpgradeReason, type UpgradeIssue } from "./type"; -import { Upgrade } from "../constants"; +import { ExtensionName, Upgrade } from "../constants"; function findEolDate(currentVersion: string, eolDate: Record): string | null { @@ -20,7 +20,7 @@ function findEolDate(currentVersion: string, eolDate: Record): s return null; } -export function buildNotificationMessage(issue: UpgradeIssue): string { +export function buildNotificationMessage(issue: UpgradeIssue, hasExtension: boolean): string { const { packageId, currentVersion, @@ -29,21 +29,22 @@ export function buildNotificationMessage(issue: UpgradeIssue): string { packageDisplayName } = issue; + const upgradeWord = hasExtension ? "upgrade" : `install ${ExtensionName.APP_MODERNIZATION_EXTENSION_NAME} extension and upgrade`; if (packageId === Upgrade.PACKAGE_ID_FOR_JAVA_RUNTIME) { - return `The current project is using an older Java runtime (${currentVersion}). Do you want to upgrade to the latest LTS version ${suggestedVersionName}?`; + return `This project is using an older Java runtime (${currentVersion}). Would you like to ${upgradeWord} it to ${suggestedVersionName} (latest LTS)?`; } switch (reason) { case UpgradeReason.END_OF_LIFE: { const { eolDate } = issue; const versionEolDate = findEolDate(currentVersion, eolDate); - return `The current project is using ${packageDisplayName} ${currentVersion}, which has reached end of life${versionEolDate ? ` in ${versionEolDate}` : "" - }. Do you want to upgrade to ${suggestedVersionName} (${suggestedVersionDescription})?`; + return `This project is using ${packageDisplayName} ${currentVersion}, which has reached end of life${versionEolDate ? ` in ${versionEolDate}` : "" + }. Would you like to ${upgradeWord} it to ${suggestedVersionName} (${suggestedVersionDescription})?`; } case UpgradeReason.DEPRECATED: default: { - return `The current project is using ${packageDisplayName} ${currentVersion}, which has been deprecated. Do you want to upgrade to ${suggestedVersionName} (${suggestedVersionDescription})?`; + return `This project is using ${packageDisplayName} ${currentVersion}, which has been deprecated. Would you like to ${upgradeWord} it to ${suggestedVersionName} (${suggestedVersionDescription})?`; } } } @@ -73,3 +74,47 @@ export function normalizePath(path: string): string { return Uri.parse(path).toString(); } +async function checkOrPromptToEnableAppModExtension() { + if (extensions.getExtension(ExtensionName.APP_MODERNIZATION_FOR_JAVA)) { + return; + } + + // The extension is disabled if we cannot detect the extension after installing it. + await commands.executeCommand("workbench.extensions.search", ExtensionName.APP_MODERNIZATION_FOR_JAVA); + const BTN_TEXT = "Show extension in sidebar"; + const choice2 = await window.showInformationMessage( + `${ExtensionName.APP_MODERNIZATION_EXTENSION_NAME} extension is needed for the feature to work but it seems disabled. Please enable it manually and try again.`, + BTN_TEXT + ); + if (choice2 === BTN_TEXT) { + await commands.executeCommand("workbench.extensions.search", ExtensionName.APP_MODERNIZATION_FOR_JAVA); + } +} + +export async function checkOrPromptToInstallAppModExtension( + extensionIdToCheck: string, + notificationText: string, + buttonText: string): Promise { + if (extensions.getExtension(extensionIdToCheck)) { + return; + } + + const choice = await window.showInformationMessage(notificationText, buttonText); + if (choice === buttonText) { + await commands.executeCommand("workbench.extensions.installExtension", ExtensionName.APP_MODERNIZATION_FOR_JAVA); + } else { + return; + } + + await checkOrPromptToEnableAppModExtension(); +} + +export async function checkOrInstallAppModExtension( + extensionIdToCheck: string): Promise { + if (extensions.getExtension(extensionIdToCheck)) { + return; + } + + await commands.executeCommand("workbench.extensions.installExtension", ExtensionName.APP_MODERNIZATION_FOR_JAVA); + await checkOrPromptToEnableAppModExtension(); +} \ No newline at end of file