From 387200595acb3477b5a7819b40336633169d24a8 Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Wed, 10 Sep 2025 12:35:01 +0800 Subject: [PATCH 01/73] feat(jdtls): add `PomPath` to metadata --- .../src/com/microsoft/jdtls/ext/core/model/PackageNode.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/model/PackageNode.java b/jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/model/PackageNode.java index 92fa4cf7..90864f01 100644 --- a/jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/model/PackageNode.java +++ b/jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/model/PackageNode.java @@ -88,6 +88,8 @@ public class PackageNode { private static final String MAX_SOURCE_VERSION = "MaxSourceVersion"; + private static final String POM_PATH = "PomPath"; + /** * The name of the PackageNode. */ @@ -181,6 +183,10 @@ public static PackageNode createNodeForProject(IJavaElement javaElement) { int jdkLevel = (int) (CompilerOptions.versionToJdkLevel(sourceVersion, true) >>> 16); int majorVersion = Math.max(0, jdkLevel - ClassFileConstants.MAJOR_VERSION_0); projectNode.setMetaDataValue(MAX_SOURCE_VERSION, majorVersion); + IFile existingPom = proj.getFile("pom.xml"); + if (existingPom.exists()) { + projectNode.setMetaDataValue(POM_PATH, existingPom.getLocation().toOSString()); + } } catch (CoreException e) { // do nothing } From 55747879a40093302d08ef9769eaab2d0c632a78 Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Wed, 10 Sep 2025 12:41:01 +0800 Subject: [PATCH 02/73] feat: MetadataManager --- src/constants.ts | 6 ++++++ src/upgrade/dependency.data.ts | 14 ++++++++++++ src/upgrade/metadataManager.ts | 39 ++++++++++++++++++++++++++++++++++ src/upgrade/type.ts | 3 +++ src/upgrade/utility.ts | 3 +++ 5 files changed, 65 insertions(+) create mode 100644 src/upgrade/dependency.data.ts create mode 100644 src/upgrade/metadataManager.ts create mode 100644 src/upgrade/type.ts create mode 100644 src/upgrade/utility.ts diff --git a/src/constants.ts b/src/constants.ts index df01101c..f6274538 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -35,6 +35,12 @@ export namespace ExtensionName { export const JAVA_LANGUAGE_SUPPORT: string = "redhat.java"; } +export namespace Upgrade { + export const DIAGNOSTICS_GROUP_ID_FOR_JAVA_ENGINE = "java-upgrade-assistant"; + export const DIAGNOSTICS_NAME_FOR_JAVA_ENGINE = "Java Upgrade Assistant"; + export const LATEST_JAVA_LTS_VESRION = 21; +} + /** * The files names for all the build files we support. */ diff --git a/src/upgrade/dependency.data.ts b/src/upgrade/dependency.data.ts new file mode 100644 index 00000000..f9bb4ba8 --- /dev/null +++ b/src/upgrade/dependency.data.ts @@ -0,0 +1,14 @@ +import type { DependencyCheckMetadata } from "./type"; + +const DEPENDENCIES_TO_SCAN: DependencyCheckMetadata = { + "org.springframework.boot:*": { + "name": "Spring Boot", + "supportedVersion": "2.7.x || >=3.2.x", + }, + "org.springframework:*": { + "name": "Spring Framework", + "supportedVersion": "5.3.x || >=6.2.x", + } +}; + +export default DEPENDENCIES_TO_SCAN; \ No newline at end of file diff --git a/src/upgrade/metadataManager.ts b/src/upgrade/metadataManager.ts new file mode 100644 index 00000000..36c526e0 --- /dev/null +++ b/src/upgrade/metadataManager.ts @@ -0,0 +1,39 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +import type { DependencyCheckMetadata, DependencyCheckResult } from "./type"; +import { Upgrade } from "../constants"; +import { buildPackageId } from "./utility"; +import DEPENDENCIES_TO_SCAN from "./dependency.data"; + + +class MetadataManager { + private dependencyCheckMetadata: DependencyCheckMetadata = DEPENDENCIES_TO_SCAN; + + public getMetadataById(givenPackageId: string): DependencyCheckResult | undefined { + const splits = givenPackageId.split(":", 2); + const groupId = splits[0]; + const artifactId = splits[1] ?? ""; + + if (groupId === Upgrade.DIAGNOSTICS_GROUP_ID_FOR_JAVA_ENGINE) { + return { + name: Upgrade.DIAGNOSTICS_NAME_FOR_JAVA_ENGINE, + supportedVersion: `>=${Upgrade.LATEST_JAVA_LTS_VESRION}`, + packageRuleUsed: buildPackageId(Upgrade.DIAGNOSTICS_GROUP_ID_FOR_JAVA_ENGINE, "*"), + }; + } + + const packageId = buildPackageId(groupId, artifactId); + const packageIdWithWildcardArtifactId = buildPackageId(groupId, "*"); + return this.getMetadata(packageId) ?? this.getMetadata(packageIdWithWildcardArtifactId); + } + + private getMetadata(packageRuleUsed: string): DependencyCheckResult | undefined { + return this.dependencyCheckMetadata[packageRuleUsed] ? { + ...this.dependencyCheckMetadata[packageRuleUsed], packageRuleUsed + } : undefined; + } +} + +const metadataManager = new MetadataManager(); +export default metadataManager; \ No newline at end of file diff --git a/src/upgrade/type.ts b/src/upgrade/type.ts new file mode 100644 index 00000000..cb19b979 --- /dev/null +++ b/src/upgrade/type.ts @@ -0,0 +1,3 @@ +export type DependencyCheckItem = { name: string, supportedVersion: string }; +export type DependencyCheckMetadata = Record; +export type DependencyCheckResult = DependencyCheckItem & { packageRuleUsed: string }; \ No newline at end of file diff --git a/src/upgrade/utility.ts b/src/upgrade/utility.ts new file mode 100644 index 00000000..e3161b46 --- /dev/null +++ b/src/upgrade/utility.ts @@ -0,0 +1,3 @@ +export function buildPackageId(groupId: string, artifactId: string): string { + return `${groupId}:${artifactId}`; +} \ No newline at end of file From 3988de5e029df87c81cc199421e75d6774c53515 Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Wed, 10 Sep 2025 12:44:12 +0800 Subject: [PATCH 03/73] feat: add command `triggerJavaUpgradeTool` --- package.json | 7 ++++++- package.nls.json | 1 + src/commands.ts | 2 ++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index df286b18..a6231ea1 100644 --- a/package.json +++ b/package.json @@ -288,6 +288,11 @@ "command": "java.view.package.renameFile", "title": "%contributes.commands.java.view.package.renameFile%", "category": "Java" + }, + { + "command": "java.view.triggerJavaUpgradeTool", + "title": "%contributes.commands.java.view.triggerJavaUpgradeTool%", + "category": "Java" } ], "configuration": { @@ -1092,4 +1097,4 @@ "vscode-extension-telemetry-wrapper": "^0.14.0", "vscode-tas-client": "^0.1.75" } -} +} \ No newline at end of file diff --git a/package.nls.json b/package.nls.json index 8feb8343..e7f2f8b5 100644 --- a/package.nls.json +++ b/package.nls.json @@ -24,6 +24,7 @@ "contributes.commands.java.view.package.copyRelativeFilePath": "Copy Relative Path", "contributes.commands.java.view.package.new": "New...", "contributes.commands.java.view.package.newJavaClass": "Class...", + "contributes.commands.java.view.triggerJavaUpgradeTool": "Upgrade dependencies", "contributes.commands.java.view.package.newJavaInterface": "Interface...", "contributes.commands.java.view.package.newJavaEnum": "Enum...", "contributes.commands.java.view.package.newJavaRecord": "Record...", diff --git a/src/commands.ts b/src/commands.ts index a2564835..0e3a736a 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -42,6 +42,8 @@ export namespace Commands { export const VIEW_PACKAGE_NEW_JAVA_CLASS = "java.view.package.newJavaClass"; + export const VIEW_TRIGGER_JAVA_UPGRADE_TOOL = "java.view.triggerJavaUpgradeTool"; + export const VIEW_PACKAGE_NEW_JAVA_INTERFACE = "java.view.package.newJavaInterface"; export const VIEW_PACKAGE_NEW_JAVA_ENUM = "java.view.package.newJavaEnum"; From bf7eb0481d0b0bdc9963941f0d006b4b6ff1af1c Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Wed, 10 Sep 2025 12:44:29 +0800 Subject: [PATCH 04/73] feat: NotificationManager --- src/upgrade/display/notificationManager.ts | 34 ++++++++++++++++++ src/upgrade/type.ts | 18 +++++++++- src/upgrade/utility.ts | 40 ++++++++++++++++++++++ 3 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 src/upgrade/display/notificationManager.ts diff --git a/src/upgrade/display/notificationManager.ts b/src/upgrade/display/notificationManager.ts new file mode 100644 index 00000000..dc1c76a3 --- /dev/null +++ b/src/upgrade/display/notificationManager.ts @@ -0,0 +1,34 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +import { commands, window } from "vscode"; +import type { FileIssues } from "../type"; +import { buildFixPrompt, buildMessage } from "../utility"; +import { Commands } from "../../commands"; + +class NotificationManager { + private hasShown = false; + + + async refresh(issues: FileIssues) { + const targetIssue = Object.values(issues)[0]; + + if (!targetIssue) { + return; + } + + if (this.hasShown) { + return; + } + + const buttonText = "Upgrade"; + const selection = await window.showInformationMessage(buildMessage(targetIssue), buttonText); + this.hasShown = true; + if (selection === buttonText) { + commands.executeCommand(Commands.VIEW_TRIGGER_JAVA_UPGRADE_TOOL, buildFixPrompt(targetIssue)); + } + } +} + +const notificationManager = new NotificationManager(); +export default notificationManager; \ No newline at end of file diff --git a/src/upgrade/type.ts b/src/upgrade/type.ts index cb19b979..ce339951 100644 --- a/src/upgrade/type.ts +++ b/src/upgrade/type.ts @@ -1,3 +1,19 @@ export type DependencyCheckItem = { name: string, supportedVersion: string }; export type DependencyCheckMetadata = Record; -export type DependencyCheckResult = DependencyCheckItem & { packageRuleUsed: string }; \ No newline at end of file +export type DependencyCheckResult = DependencyCheckItem & { packageRuleUsed: string }; + +export enum UpgradeReason { + END_OF_LIFE, + CVE, + ENGINE_TOO_OLD, +}; + +export type UpgradeIssue = { + packageId: string; + packageDisplayName?: string; + reason: UpgradeReason; + currentVersion: string; + suggestedVersion?: string; +}; + +export type FileIssues = Record; \ No newline at end of file diff --git a/src/upgrade/utility.ts b/src/upgrade/utility.ts index e3161b46..fe94a2d1 100644 --- a/src/upgrade/utility.ts +++ b/src/upgrade/utility.ts @@ -1,3 +1,43 @@ +import { UpgradeReason, type UpgradeIssue } from "./type"; + +export function buildMessage(issue: UpgradeIssue): string { + const { packageId, packageDisplayName, currentVersion, reason } = issue; + const name = packageDisplayName ?? packageId; + + switch (reason) { + case UpgradeReason.END_OF_LIFE: { + return `Your project dependency ${name} (${currentVersion}) is in end-of-life. Consider upgrading using GitHub Copilot for better security and performance.`; + } + case UpgradeReason.CVE: { + return `Your project dependency ${name} (${currentVersion}) has CVE. Consider upgrading using GitHub Copilot for better security.`; + } + case UpgradeReason.ENGINE_TOO_OLD: { + return `Your project Java version (${currentVersion}) is too old. Consider upgrading using GitHub Copilot for better performance and features.`; + } + } +} + +export function buildFixPrompt(issue: UpgradeIssue): string { + const { packageId, packageDisplayName, reason, suggestedVersion } = issue; + const name = packageDisplayName ?? packageId; + + const suffix = [ + ...(suggestedVersion ? [`The target version is ${suggestedVersion}.`] : []) + ]; + + switch (reason) { + case UpgradeReason.END_OF_LIFE: { + return [`Upgrade the package ${name} using Java Upgrade Tool.`, ...suffix].join(" "); + } + case UpgradeReason.CVE: { + return [`Upgrade the package ${name} to resolve CVE using Java Upgrade Tool.`, ...suffix].join(" "); + } + case UpgradeReason.ENGINE_TOO_OLD: { + return [`Upgrade Java version using Java Upgrade Tool.`, ...suffix].join(" "); + } + } +} + export function buildPackageId(groupId: string, artifactId: string): string { return `${groupId}:${artifactId}`; } \ No newline at end of file From 18be55efc4321d856bd347c8eac9d36322e0d2dd Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Wed, 10 Sep 2025 12:46:49 +0800 Subject: [PATCH 05/73] feat: IssueManager --- src/upgrade/issueManager.ts | 42 +++++++++++++++++++++++++++++++++++++ src/upgrade/utility.ts | 5 +++++ 2 files changed, 47 insertions(+) create mode 100644 src/upgrade/issueManager.ts diff --git a/src/upgrade/issueManager.ts b/src/upgrade/issueManager.ts new file mode 100644 index 00000000..0651c0d8 --- /dev/null +++ b/src/upgrade/issueManager.ts @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +import notificationManager from "./display/notificationManager"; +import type { FileIssues, UpgradeIssue } from "./type"; +import { normalizePath } from "./utility"; + +class IssueManager { + private issuesList: Record = {}; + + + public addIssue(pomPath: string, issue: UpgradeIssue) { + const { packageId } = issue; + const normalizedPath = normalizePath(pomPath); + if (!this.issuesList[normalizedPath]) { + this.issuesList[normalizedPath] = {}; + } + this.issuesList[normalizedPath][packageId] = issue; + this.refreshDisplay(this.issuesList[normalizedPath]); + } + + public removeIssue(pomPath: string, packageId: string) { + const normalizedPath = normalizePath(pomPath); + if (!this.issuesList[normalizedPath] || !this.issuesList[normalizedPath][packageId]) { + return; + } + delete this.issuesList[normalizedPath][packageId]; + this.refreshDisplay(this.issuesList[normalizedPath]); + } + + public getIssues(filePath: string): FileIssues { + const normalizedPath = normalizePath(filePath); + return this.issuesList[normalizedPath] ?? {}; + } + + private refreshDisplay(issues: FileIssues) { + notificationManager.refresh(issues); + } +} + +const issueManager = new IssueManager(); +export default issueManager; \ No newline at end of file diff --git a/src/upgrade/utility.ts b/src/upgrade/utility.ts index fe94a2d1..bea5b53b 100644 --- a/src/upgrade/utility.ts +++ b/src/upgrade/utility.ts @@ -1,3 +1,4 @@ +import { Uri } from "vscode"; import { UpgradeReason, type UpgradeIssue } from "./type"; export function buildMessage(issue: UpgradeIssue): string { @@ -40,4 +41,8 @@ export function buildFixPrompt(issue: UpgradeIssue): string { export function buildPackageId(groupId: string, artifactId: string): string { return `${groupId}:${artifactId}`; +} + +export function normalizePath(path: string): string { + return Uri.parse(path).toString(); } \ No newline at end of file From 560048c1ac17ea4691c5f4c88820c1feda514a29 Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Wed, 10 Sep 2025 12:59:21 +0800 Subject: [PATCH 06/73] feat(upgradeManager): collect issues on load and workspace folder update --- src/extension.ts | 8 +- src/syncHandler.ts | 2 + src/upgrade/issueManager.ts | 42 ----------- src/upgrade/upgradeManager.ts | 136 ++++++++++++++++++++++++++++++++++ 4 files changed, 144 insertions(+), 44 deletions(-) delete mode 100644 src/upgrade/issueManager.ts create mode 100644 src/upgrade/upgradeManager.ts diff --git a/src/extension.ts b/src/extension.ts index 531b5ac3..2794c870 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -2,8 +2,10 @@ // Licensed under the MIT license. import * as path from "path"; -import { commands, Diagnostic, Extension, ExtensionContext, extensions, languages, - Range, tasks, TextDocument, TextEditor, Uri, window, workspace } from "vscode"; +import { + commands, Diagnostic, Extension, ExtensionContext, extensions, languages, + Range, tasks, TextDocument, TextEditor, Uri, window, workspace +} from "vscode"; import { dispose as disposeTelemetryWrapper, initializeFromJsonFile, instrumentOperation, instrumentOperationAsVsCodeCommand, sendInfo } from "vscode-extension-telemetry-wrapper"; import { Commands, contextManager } from "../extension.bundle"; import { BuildTaskProvider } from "./tasks/build/buildTaskProvider"; @@ -20,9 +22,11 @@ import { DiagnosticProvider } from "./tasks/buildArtifact/migration/DiagnosticPr import { setContextForDeprecatedTasks, updateExportTaskType } from "./tasks/buildArtifact/migration/utils"; import { CodeActionProvider } from "./tasks/buildArtifact/migration/CodeActionProvider"; import { newJavaFile } from "./explorerCommands/new"; +import upgradeManager from "./upgrade/upgradeManager"; export async function activate(context: ExtensionContext): Promise { contextManager.initialize(context); + upgradeManager.initialize(context); await initializeFromJsonFile(context.asAbsolutePath("./package.json")); await initExpService(context); await instrumentOperation("activation", activateExtension)(context); diff --git a/src/syncHandler.ts b/src/syncHandler.ts index d6d247c0..40315fa0 100644 --- a/src/syncHandler.ts +++ b/src/syncHandler.ts @@ -13,6 +13,7 @@ import { DataNode } from "./views/dataNode"; import { ExplorerNode } from "./views/explorerNode"; import { explorerNodeCache } from "./views/nodeCache/explorerNodeCache"; import { Jdtls } from "./java/jdtls"; +import upgradeManager from "./upgrade/upgradeManager"; const ENABLE_AUTO_REFRESH: string = "java.view.package.enableAutoRefresh"; const DISABLE_AUTO_REFRESH: string = "java.view.package.disableAutoRefresh"; @@ -46,6 +47,7 @@ class SyncHandler implements Disposable { this.disposables.push(workspace.onDidChangeWorkspaceFolders(() => { this.refresh(); + upgradeManager.scan(); })); try { diff --git a/src/upgrade/issueManager.ts b/src/upgrade/issueManager.ts deleted file mode 100644 index 0651c0d8..00000000 --- a/src/upgrade/issueManager.ts +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. - -import notificationManager from "./display/notificationManager"; -import type { FileIssues, UpgradeIssue } from "./type"; -import { normalizePath } from "./utility"; - -class IssueManager { - private issuesList: Record = {}; - - - public addIssue(pomPath: string, issue: UpgradeIssue) { - const { packageId } = issue; - const normalizedPath = normalizePath(pomPath); - if (!this.issuesList[normalizedPath]) { - this.issuesList[normalizedPath] = {}; - } - this.issuesList[normalizedPath][packageId] = issue; - this.refreshDisplay(this.issuesList[normalizedPath]); - } - - public removeIssue(pomPath: string, packageId: string) { - const normalizedPath = normalizePath(pomPath); - if (!this.issuesList[normalizedPath] || !this.issuesList[normalizedPath][packageId]) { - return; - } - delete this.issuesList[normalizedPath][packageId]; - this.refreshDisplay(this.issuesList[normalizedPath]); - } - - public getIssues(filePath: string): FileIssues { - const normalizedPath = normalizePath(filePath); - return this.issuesList[normalizedPath] ?? {}; - } - - private refreshDisplay(issues: FileIssues) { - notificationManager.refresh(issues); - } -} - -const issueManager = new IssueManager(); -export default issueManager; \ No newline at end of file diff --git a/src/upgrade/upgradeManager.ts b/src/upgrade/upgradeManager.ts new file mode 100644 index 00000000..89434b3a --- /dev/null +++ b/src/upgrade/upgradeManager.ts @@ -0,0 +1,136 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +import { commands, type ExtensionContext, workspace, type WorkspaceFolder } from "vscode"; +import * as semver from 'semver' +import { Jdtls } from "../java/jdtls"; +import { languageServerApiManager } from "../languageServerApi/languageServerApiManager"; +import { NodeKind, type INodeData } from "../java/nodeData"; +import { Upgrade } from "../constants"; +import { UpgradeIssue, UpgradeReason } from "./type"; +import { instrumentOperationAsVsCodeCommand } from "vscode-extension-telemetry-wrapper"; +import { Commands } from "../commands"; +import metadataManager from "./metadataManager"; +import { buildPackageId } from "./utility"; + +const DEFAULT_UPGRADE_PROMPT = "Upgrade Java project dependency"; + +function getJavaIssues(data: INodeData): UpgradeIssue[] { + const javaVersion = data.metaData?.MaxSourceVersion as number | undefined; + if (!javaVersion) { + return []; + } + if (javaVersion < Upgrade.LATEST_JAVA_LTS_VESRION) { + return [{ + packageId: buildPackageId(Upgrade.DIAGNOSTICS_GROUP_ID_FOR_JAVA_ENGINE, "*"), + reason: UpgradeReason.ENGINE_TOO_OLD, + currentVersion: String(javaVersion), + suggestedVersion: String(Upgrade.LATEST_JAVA_LTS_VESRION), + }]; + } + + return []; +} + +function getDependencyIssues(data: INodeData): UpgradeIssue[] { + const versionString = data.metaData?.["maven.version"]; + const groupId = data.metaData?.["maven.groupId"]; + const artifactId = data.metaData?.["maven.artifactId"]; + const packageId = buildPackageId(groupId, artifactId); + const supportedVersionDefinition = metadataManager.getMetadataById(packageId); + if (!versionString || !groupId || !supportedVersionDefinition) { + return []; + } + const currentVersion = semver.coerce(versionString); + if (!currentVersion) { + return []; + } + if (!semver.satisfies(currentVersion, supportedVersionDefinition.supportedVersion)) { + return [{ + packageId, + packageDisplayName: supportedVersionDefinition.name, + reason: UpgradeReason.END_OF_LIFE, + currentVersion: versionString, + suggestedVersion: "latest", // TODO + }]; + } + return []; +} + +async function getProjectIssues(projectNode: INodeData): Promise { + const pomPath = projectNode.metaData?.PomPath as string | undefined; + if (!pomPath) { + return []; + } + const issues: UpgradeIssue[] = []; + issues.push(...getJavaIssues(projectNode)); + const packageData = await Jdtls.getPackageData({ kind: NodeKind.Project, projectUri: projectNode.uri }); + packageData + .filter(x => x.kind === NodeKind.Container) + .forEach(async (packageContainer) => { + const packages = await Jdtls.getPackageData({ + kind: NodeKind.Container, + projectUri: projectNode.uri, + path: packageContainer.path, + }); + packages.forEach( + (pkg) => { + issues.push(...getDependencyIssues(pkg)) + } + ); + }); + return issues; +} + +class UpgradeManager { + public initialize(context: ExtensionContext) { + // Command to be used + context.subscriptions.push(instrumentOperationAsVsCodeCommand(Commands.VIEW_TRIGGER_JAVA_UPGRADE_TOOL, (promptText?: string) => { + this.runUpgrade(promptText ?? DEFAULT_UPGRADE_PROMPT); + })); + + upgradeManager.scan(); + } + + public scan() { + workspace.workspaceFolders?.forEach((folder) => + this.checkUpgradableComponents(folder) + ); + } + + private async checkUpgradableComponents(folder: WorkspaceFolder) { + if (!await languageServerApiManager.ready()) { + return; + } + const hasJavaError: boolean = await Jdtls.checkImportStatus(); + if (hasJavaError) { + return; + } + + const projectIssues: Record = {}; + const uri = folder.uri.toString(); + const projects = await Jdtls.getProjects(uri); + projects.forEach(async (projectNode) => { + const pomPath = projectNode.metaData?.PomPath as string | undefined; + if (!pomPath) { + return; + } + + const issues = await getProjectIssues(projectNode); + projectIssues[pomPath] = issues; + }); + + // TODO: show notification + } + + + private async runUpgrade(promptText: string) { + await commands.executeCommand("workbench.action.chat.open", { + query: promptText, + isPartialQuery: true + }); + } +} + +const upgradeManager = new UpgradeManager(); +export default upgradeManager; \ No newline at end of file From 0503046904676428f503f3987f30f4ef256ca7b5 Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Wed, 10 Sep 2025 13:53:59 +0800 Subject: [PATCH 07/73] feat: integrate the flow --- src/upgrade/display/notificationManager.ts | 38 +++++++++++++------ src/upgrade/metadataManager.ts | 7 ++-- src/upgrade/type.ts | 5 +-- src/upgrade/upgradeManager.ts | 43 +++++++++++++--------- src/upgrade/utility.ts | 23 ++---------- 5 files changed, 60 insertions(+), 56 deletions(-) diff --git a/src/upgrade/display/notificationManager.ts b/src/upgrade/display/notificationManager.ts index dc1c76a3..c1d5e57c 100644 --- a/src/upgrade/display/notificationManager.ts +++ b/src/upgrade/display/notificationManager.ts @@ -2,32 +2,48 @@ // Licensed under the MIT license. import { commands, window } from "vscode"; -import type { FileIssues } from "../type"; -import { buildFixPrompt, buildMessage } from "../utility"; +import type { UpgradeIssue } from "../type"; +import { buildFixPrompt } from "../utility"; import { Commands } from "../../commands"; class NotificationManager { private hasShown = false; - - async refresh(issues: FileIssues) { - const targetIssue = Object.values(issues)[0]; - - if (!targetIssue) { + async triggerNotification(projectIssues: Record) { + if (!this.shouldShow()) { return; } - if (this.hasShown) { - return; + const lines = [ + "Fix the following version issues:", + ]; + for (const [pomPath, issues] of Object.entries(projectIssues)) { + lines.push(""); + lines.push(`For project "${pomPath}":`); + const linesForCurrentProject = new Set(); + for (const issue of issues) { + linesForCurrentProject.add(buildFixPrompt(issue)); + } + lines.push(...linesForCurrentProject); + lines.push("\n"); } + const prompt = lines.join("\n"); + const projectCount = Object.keys(projectIssues).length; + const issueCount = Object.values(projectIssues).map(x => x.length).reduce((a, b) => a + b, 0); + const buttonText = "Upgrade"; - const selection = await window.showInformationMessage(buildMessage(targetIssue), buttonText); + const selection = await window.showInformationMessage(`${issueCount} version issue(s) found in ${projectCount} project(s).`, buttonText); this.hasShown = true; if (selection === buttonText) { - commands.executeCommand(Commands.VIEW_TRIGGER_JAVA_UPGRADE_TOOL, buildFixPrompt(targetIssue)); + commands.executeCommand(Commands.VIEW_TRIGGER_JAVA_UPGRADE_TOOL, prompt); } } + + private shouldShow() { + // TODO: fix + return !this.hasShown; + } } const notificationManager = new NotificationManager(); diff --git a/src/upgrade/metadataManager.ts b/src/upgrade/metadataManager.ts index 36c526e0..28e992ed 100644 --- a/src/upgrade/metadataManager.ts +++ b/src/upgrade/metadataManager.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. -import type { DependencyCheckMetadata, DependencyCheckResult } from "./type"; +import type { DependencyCheckMetadata, DependencyCheckItem } from "./type"; import { Upgrade } from "../constants"; import { buildPackageId } from "./utility"; import DEPENDENCIES_TO_SCAN from "./dependency.data"; @@ -10,7 +10,7 @@ import DEPENDENCIES_TO_SCAN from "./dependency.data"; class MetadataManager { private dependencyCheckMetadata: DependencyCheckMetadata = DEPENDENCIES_TO_SCAN; - public getMetadataById(givenPackageId: string): DependencyCheckResult | undefined { + public getMetadataById(givenPackageId: string): DependencyCheckItem | undefined { const splits = givenPackageId.split(":", 2); const groupId = splits[0]; const artifactId = splits[1] ?? ""; @@ -19,7 +19,6 @@ class MetadataManager { return { name: Upgrade.DIAGNOSTICS_NAME_FOR_JAVA_ENGINE, supportedVersion: `>=${Upgrade.LATEST_JAVA_LTS_VESRION}`, - packageRuleUsed: buildPackageId(Upgrade.DIAGNOSTICS_GROUP_ID_FOR_JAVA_ENGINE, "*"), }; } @@ -28,7 +27,7 @@ class MetadataManager { return this.getMetadata(packageId) ?? this.getMetadata(packageIdWithWildcardArtifactId); } - private getMetadata(packageRuleUsed: string): DependencyCheckResult | undefined { + private getMetadata(packageRuleUsed: string) { return this.dependencyCheckMetadata[packageRuleUsed] ? { ...this.dependencyCheckMetadata[packageRuleUsed], packageRuleUsed } : undefined; diff --git a/src/upgrade/type.ts b/src/upgrade/type.ts index ce339951..45f02cca 100644 --- a/src/upgrade/type.ts +++ b/src/upgrade/type.ts @@ -1,6 +1,5 @@ export type DependencyCheckItem = { name: string, supportedVersion: string }; export type DependencyCheckMetadata = Record; -export type DependencyCheckResult = DependencyCheckItem & { packageRuleUsed: string }; export enum UpgradeReason { END_OF_LIFE, @@ -14,6 +13,4 @@ export type UpgradeIssue = { reason: UpgradeReason; currentVersion: string; suggestedVersion?: string; -}; - -export type FileIssues = Record; \ No newline at end of file +}; \ No newline at end of file diff --git a/src/upgrade/upgradeManager.ts b/src/upgrade/upgradeManager.ts index 89434b3a..43d8342f 100644 --- a/src/upgrade/upgradeManager.ts +++ b/src/upgrade/upgradeManager.ts @@ -12,6 +12,7 @@ import { instrumentOperationAsVsCodeCommand } from "vscode-extension-telemetry-w import { Commands } from "../commands"; import metadataManager from "./metadataManager"; import { buildPackageId } from "./utility"; +import notificationManager from "./display/notificationManager"; const DEFAULT_UPGRADE_PROMPT = "Upgrade Java project dependency"; @@ -65,20 +66,22 @@ async function getProjectIssues(projectNode: INodeData): Promise const issues: UpgradeIssue[] = []; issues.push(...getJavaIssues(projectNode)); const packageData = await Jdtls.getPackageData({ kind: NodeKind.Project, projectUri: projectNode.uri }); - packageData - .filter(x => x.kind === NodeKind.Container) - .forEach(async (packageContainer) => { - const packages = await Jdtls.getPackageData({ - kind: NodeKind.Container, - projectUri: projectNode.uri, - path: packageContainer.path, - }); - packages.forEach( - (pkg) => { - issues.push(...getDependencyIssues(pkg)) - } - ); - }); + await Promise.allSettled( + packageData + .filter(x => x.kind === NodeKind.Container) + .map(async (packageContainer) => { + const packages = await Jdtls.getPackageData({ + kind: NodeKind.Container, + projectUri: projectNode.uri, + path: packageContainer.path, + }); + packages.forEach( + (pkg) => { + issues.push(...getDependencyIssues(pkg)) + } + ); + }) + ); return issues; } @@ -110,17 +113,23 @@ class UpgradeManager { const projectIssues: Record = {}; const uri = folder.uri.toString(); const projects = await Jdtls.getProjects(uri); - projects.forEach(async (projectNode) => { + let hasIssues = false; + await Promise.allSettled(projects.map(async (projectNode) => { const pomPath = projectNode.metaData?.PomPath as string | undefined; if (!pomPath) { return; } const issues = await getProjectIssues(projectNode); + if (issues.length > 0) { + hasIssues = true; + } projectIssues[pomPath] = issues; - }); + })); - // TODO: show notification + if (hasIssues) { + notificationManager.triggerNotification(projectIssues); + } } diff --git a/src/upgrade/utility.ts b/src/upgrade/utility.ts index bea5b53b..6e8e8921 100644 --- a/src/upgrade/utility.ts +++ b/src/upgrade/utility.ts @@ -1,23 +1,6 @@ import { Uri } from "vscode"; import { UpgradeReason, type UpgradeIssue } from "./type"; -export function buildMessage(issue: UpgradeIssue): string { - const { packageId, packageDisplayName, currentVersion, reason } = issue; - const name = packageDisplayName ?? packageId; - - switch (reason) { - case UpgradeReason.END_OF_LIFE: { - return `Your project dependency ${name} (${currentVersion}) is in end-of-life. Consider upgrading using GitHub Copilot for better security and performance.`; - } - case UpgradeReason.CVE: { - return `Your project dependency ${name} (${currentVersion}) has CVE. Consider upgrading using GitHub Copilot for better security.`; - } - case UpgradeReason.ENGINE_TOO_OLD: { - return `Your project Java version (${currentVersion}) is too old. Consider upgrading using GitHub Copilot for better performance and features.`; - } - } -} - export function buildFixPrompt(issue: UpgradeIssue): string { const { packageId, packageDisplayName, reason, suggestedVersion } = issue; const name = packageDisplayName ?? packageId; @@ -28,13 +11,13 @@ export function buildFixPrompt(issue: UpgradeIssue): string { switch (reason) { case UpgradeReason.END_OF_LIFE: { - return [`Upgrade the package ${name} using Java Upgrade Tool.`, ...suffix].join(" "); + return [`Upgrade the package ${name}.`, ...suffix].join(" "); } case UpgradeReason.CVE: { - return [`Upgrade the package ${name} to resolve CVE using Java Upgrade Tool.`, ...suffix].join(" "); + return [`Upgrade the package ${name} to address CVE issues.`, ...suffix].join(" "); } case UpgradeReason.ENGINE_TOO_OLD: { - return [`Upgrade Java version using Java Upgrade Tool.`, ...suffix].join(" "); + return [`Upgrade the version of Java.`, ...suffix].join(" "); } } } From b2406d918c0125b6d526cf9ef0f65e2e5a426150 Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Wed, 10 Sep 2025 14:23:19 +0800 Subject: [PATCH 08/73] feat: add context menu to open modernization tool --- package.json | 10 ++++++++++ package.nls.json | 1 + src/commands.ts | 2 ++ src/upgrade/upgradeManager.ts | 3 +++ 4 files changed, 16 insertions(+) diff --git a/package.json b/package.json index a6231ea1..9a959cac 100644 --- a/package.json +++ b/package.json @@ -293,6 +293,11 @@ "command": "java.view.triggerJavaUpgradeTool", "title": "%contributes.commands.java.view.triggerJavaUpgradeTool%", "category": "Java" + }, + { + "command": "java.view.modernizeJavaProject", + "title": "%contributes.commands.java.view.modernizeJavaProject%", + "category": "Java" } ], "configuration": { @@ -573,6 +578,11 @@ "when": "explorerResourceIsFolder", "group": "1_javaactions@30" }, + { + "command": "java.view.modernizeJavaProject", + "when": "explorerResourceIsFolder", + "group": "1_javaactions@40" + }, { "command": "java.view.package.revealInProjectExplorer", "when": "resourceFilename =~ /(.*\\.gradle)|(.*\\.gradle\\.kts)|(pom\\.xml)$/ && java:serverMode == Standard", diff --git a/package.nls.json b/package.nls.json index e7f2f8b5..5fb6717f 100644 --- a/package.nls.json +++ b/package.nls.json @@ -25,6 +25,7 @@ "contributes.commands.java.view.package.new": "New...", "contributes.commands.java.view.package.newJavaClass": "Class...", "contributes.commands.java.view.triggerJavaUpgradeTool": "Upgrade dependencies", + "contributes.commands.java.view.modernizeJavaProject": "Modernize Java project", "contributes.commands.java.view.package.newJavaInterface": "Interface...", "contributes.commands.java.view.package.newJavaEnum": "Enum...", "contributes.commands.java.view.package.newJavaRecord": "Record...", diff --git a/src/commands.ts b/src/commands.ts index 0e3a736a..8f6053be 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -44,6 +44,8 @@ export namespace Commands { export const VIEW_TRIGGER_JAVA_UPGRADE_TOOL = "java.view.triggerJavaUpgradeTool"; + export const VIEW_MODERNIZE_JAVA_PROJECT = "java.view.modernizeJavaProject"; + export const VIEW_PACKAGE_NEW_JAVA_INTERFACE = "java.view.package.newJavaInterface"; export const VIEW_PACKAGE_NEW_JAVA_ENUM = "java.view.package.newJavaEnum"; diff --git a/src/upgrade/upgradeManager.ts b/src/upgrade/upgradeManager.ts index 43d8342f..0391112c 100644 --- a/src/upgrade/upgradeManager.ts +++ b/src/upgrade/upgradeManager.ts @@ -91,6 +91,9 @@ class UpgradeManager { context.subscriptions.push(instrumentOperationAsVsCodeCommand(Commands.VIEW_TRIGGER_JAVA_UPGRADE_TOOL, (promptText?: string) => { this.runUpgrade(promptText ?? DEFAULT_UPGRADE_PROMPT); })); + context.subscriptions.push(instrumentOperationAsVsCodeCommand(Commands.VIEW_MODERNIZE_JAVA_PROJECT, () => { + commands.executeCommand("workbench.view.extension.azureJavaMigrationExplorer"); + })); upgradeManager.scan(); } From fa488efcc01b748beed363ee868987645f5d4217 Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Wed, 10 Sep 2025 14:23:29 +0800 Subject: [PATCH 09/73] fix: only show modernization menu when related extension is installed --- package.json | 2 +- src/constants.ts | 1 + src/upgrade/upgradeManager.ts | 6 ++++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 9a959cac..aeb9329f 100644 --- a/package.json +++ b/package.json @@ -575,7 +575,7 @@ }, { "command": "_java.project.create.from.fileexplorer.menu", - "when": "explorerResourceIsFolder", + "when": "explorerResourceIsFolder && isModernizationExtensionInstalled", "group": "1_javaactions@30" }, { diff --git a/src/constants.ts b/src/constants.ts index f6274538..639f1b79 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -33,6 +33,7 @@ export namespace Explorer { export namespace ExtensionName { export const JAVA_LANGUAGE_SUPPORT: string = "redhat.java"; + export const APP_MODERNIZATION_FOR_JAVA = "vscjava.migrate-java-to-azure"; } export namespace Upgrade { diff --git a/src/upgrade/upgradeManager.ts b/src/upgrade/upgradeManager.ts index 0391112c..b7db5b5c 100644 --- a/src/upgrade/upgradeManager.ts +++ b/src/upgrade/upgradeManager.ts @@ -1,12 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. -import { commands, type ExtensionContext, workspace, type WorkspaceFolder } from "vscode"; +import { commands, type ExtensionContext, extensions, workspace, type WorkspaceFolder } from "vscode"; import * as semver from 'semver' import { Jdtls } from "../java/jdtls"; import { languageServerApiManager } from "../languageServerApi/languageServerApiManager"; import { NodeKind, type INodeData } from "../java/nodeData"; -import { Upgrade } from "../constants"; +import { ExtensionName, Upgrade } from "../constants"; import { UpgradeIssue, UpgradeReason } from "./type"; import { instrumentOperationAsVsCodeCommand } from "vscode-extension-telemetry-wrapper"; import { Commands } from "../commands"; @@ -91,6 +91,8 @@ class UpgradeManager { context.subscriptions.push(instrumentOperationAsVsCodeCommand(Commands.VIEW_TRIGGER_JAVA_UPGRADE_TOOL, (promptText?: string) => { this.runUpgrade(promptText ?? DEFAULT_UPGRADE_PROMPT); })); + 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"); })); From 9fbc1c230ce251e0eb6ded5746876b79216d2d8f Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Wed, 10 Sep 2025 14:26:21 +0800 Subject: [PATCH 10/73] fix: typo --- package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index aeb9329f..df45d6cf 100644 --- a/package.json +++ b/package.json @@ -575,12 +575,12 @@ }, { "command": "_java.project.create.from.fileexplorer.menu", - "when": "explorerResourceIsFolder && isModernizationExtensionInstalled", + "when": "explorerResourceIsFolder", "group": "1_javaactions@30" }, { "command": "java.view.modernizeJavaProject", - "when": "explorerResourceIsFolder", + "when": "explorerResourceIsFolder && isModernizationExtensionInstalled", "group": "1_javaactions@40" }, { @@ -1107,4 +1107,4 @@ "vscode-extension-telemetry-wrapper": "^0.14.0", "vscode-tas-client": "^0.1.75" } -} \ No newline at end of file +} From c3ee610082d349c9a68d820b84c9a8e00c53a6c3 Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Wed, 10 Sep 2025 14:26:44 +0800 Subject: [PATCH 11/73] chore: fmt --- src/extension.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/extension.ts b/src/extension.ts index 2794c870..d2fe424b 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -2,10 +2,8 @@ // Licensed under the MIT license. import * as path from "path"; -import { - commands, Diagnostic, Extension, ExtensionContext, extensions, languages, - Range, tasks, TextDocument, TextEditor, Uri, window, workspace -} from "vscode"; +import { commands, Diagnostic, Extension, ExtensionContext, extensions, languages, + Range, tasks, TextDocument, TextEditor, Uri, window, workspace } from "vscode"; import { dispose as disposeTelemetryWrapper, initializeFromJsonFile, instrumentOperation, instrumentOperationAsVsCodeCommand, sendInfo } from "vscode-extension-telemetry-wrapper"; import { Commands, contextManager } from "../extension.bundle"; import { BuildTaskProvider } from "./tasks/build/buildTaskProvider"; From 0e998ba6d78398265e4f01fa0eae6a1099b7044a Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Wed, 10 Sep 2025 14:50:21 +0800 Subject: [PATCH 12/73] feat: control reminder display by settings --- package.json | 7 ++++++- package.nls.json | 1 + src/settings.ts | 4 ++++ src/upgrade/upgradeManager.ts | 10 +++++++++- 4 files changed, 20 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index df45d6cf..9b63644b 100644 --- a/package.json +++ b/package.json @@ -333,6 +333,11 @@ "description": "%configuration.java.dependency.packagePresentation%", "default": "flat" }, + "java.dependency.showUpgradeReminder": { + "type": "boolean", + "description": "%configuration.java.dependency.showUpgradeReminder%", + "default": true + }, "java.project.exportJar.targetPath": { "type": "string", "anyOf": [ @@ -1107,4 +1112,4 @@ "vscode-extension-telemetry-wrapper": "^0.14.0", "vscode-tas-client": "^0.1.75" } -} +} \ No newline at end of file diff --git a/package.nls.json b/package.nls.json index 5fb6717f..49613827 100644 --- a/package.nls.json +++ b/package.nls.json @@ -45,6 +45,7 @@ "configuration.java.dependency.autoRefresh": "Synchronize Java Projects explorer with changes", "configuration.java.dependency.refreshDelay": "The delay time (ms) the auto refresh is invoked when changes are detected", "configuration.java.dependency.packagePresentation": "Package presentation mode: flat or hierarchical", + "configuration.java.dependency.showUpgradeReminder": "Show reminders for Java engine or dependency upgrades", "configuration.java.project.explorer.showNonJavaResources": "When enabled, the explorer shows non-Java resources.", "configuration.java.project.exportJar.targetPath.customization": "The output path of the exported jar. Leave it empty if you want to manually pick the output location.", "configuration.java.project.exportJar.targetPath.workspaceFolder": "Export the jar file into the workspace folder. Its name is the same as the folder's.", diff --git a/src/settings.ts b/src/settings.ts index bea8e7c2..565b9d21 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -108,6 +108,10 @@ export class Settings { return workspace.getConfiguration("java.dependency").get("refreshDelay", 2000); } + public static getShowUpgradeReminder() { + return workspace.getConfiguration("java.dependency").get("showUpgradeReminder", true); + } + public static getExportJarTargetPath(): string { // tslint:disable-next-line: no-invalid-template-strings return workspace.getConfiguration("java.project.exportJar").get("targetPath", "${workspaceFolder}/${workspaceFolderBasename}.jar"); diff --git a/src/upgrade/upgradeManager.ts b/src/upgrade/upgradeManager.ts index b7db5b5c..83bdc43a 100644 --- a/src/upgrade/upgradeManager.ts +++ b/src/upgrade/upgradeManager.ts @@ -13,6 +13,7 @@ import { Commands } from "../commands"; import metadataManager from "./metadataManager"; import { buildPackageId } from "./utility"; import notificationManager from "./display/notificationManager"; +import { Settings } from "../settings"; const DEFAULT_UPGRADE_PROMPT = "Upgrade Java project dependency"; @@ -85,6 +86,10 @@ async function getProjectIssues(projectNode: INodeData): Promise return issues; } +function shouldCheckUpgrade() { + return Settings.getShowUpgradeReminder(); +} + class UpgradeManager { public initialize(context: ExtensionContext) { // Command to be used @@ -97,10 +102,13 @@ class UpgradeManager { commands.executeCommand("workbench.view.extension.azureJavaMigrationExplorer"); })); - upgradeManager.scan(); + this.scan(); } public scan() { + if (shouldCheckUpgrade()) { + return; + } workspace.workspaceFolders?.forEach((folder) => this.checkUpgradableComponents(folder) ); From 3b62771e2dcc946e942244e29666569f1fb045b7 Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Wed, 10 Sep 2025 14:51:43 +0800 Subject: [PATCH 13/73] feat: don't scan when upgrade extension does not exist --- src/constants.ts | 1 + src/upgrade/upgradeManager.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/constants.ts b/src/constants.ts index 639f1b79..470ff90a 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -34,6 +34,7 @@ export namespace Explorer { 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 namespace Upgrade { diff --git a/src/upgrade/upgradeManager.ts b/src/upgrade/upgradeManager.ts index 83bdc43a..80c6f671 100644 --- a/src/upgrade/upgradeManager.ts +++ b/src/upgrade/upgradeManager.ts @@ -87,7 +87,7 @@ async function getProjectIssues(projectNode: INodeData): Promise } function shouldCheckUpgrade() { - return Settings.getShowUpgradeReminder(); + return !!extensions.getExtension(ExtensionName.APP_MODERNIZATION_UPGRADE_FOR_JAVA) && Settings.getShowUpgradeReminder(); } class UpgradeManager { From 9043db44a417b880733782b8aef109b307427628 Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Wed, 10 Sep 2025 14:55:03 +0800 Subject: [PATCH 14/73] chore: make class methods static as there are no states here --- src/upgrade/metadataManager.ts | 9 ++++----- src/upgrade/upgradeManager.ts | 30 ++++++++++++++---------------- 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/src/upgrade/metadataManager.ts b/src/upgrade/metadataManager.ts index 28e992ed..2ed19ae8 100644 --- a/src/upgrade/metadataManager.ts +++ b/src/upgrade/metadataManager.ts @@ -8,9 +8,9 @@ import DEPENDENCIES_TO_SCAN from "./dependency.data"; class MetadataManager { - private dependencyCheckMetadata: DependencyCheckMetadata = DEPENDENCIES_TO_SCAN; + private static dependencyCheckMetadata: DependencyCheckMetadata = DEPENDENCIES_TO_SCAN; - public getMetadataById(givenPackageId: string): DependencyCheckItem | undefined { + public static getMetadataById(givenPackageId: string): DependencyCheckItem | undefined { const splits = givenPackageId.split(":", 2); const groupId = splits[0]; const artifactId = splits[1] ?? ""; @@ -27,12 +27,11 @@ class MetadataManager { return this.getMetadata(packageId) ?? this.getMetadata(packageIdWithWildcardArtifactId); } - private getMetadata(packageRuleUsed: string) { + private static getMetadata(packageRuleUsed: string) { return this.dependencyCheckMetadata[packageRuleUsed] ? { ...this.dependencyCheckMetadata[packageRuleUsed], packageRuleUsed } : undefined; } } -const metadataManager = new MetadataManager(); -export default metadataManager; \ No newline at end of file +export default MetadataManager; \ No newline at end of file diff --git a/src/upgrade/upgradeManager.ts b/src/upgrade/upgradeManager.ts index 80c6f671..94a01bfc 100644 --- a/src/upgrade/upgradeManager.ts +++ b/src/upgrade/upgradeManager.ts @@ -90,11 +90,18 @@ function shouldCheckUpgrade() { return !!extensions.getExtension(ExtensionName.APP_MODERNIZATION_UPGRADE_FOR_JAVA) && Settings.getShowUpgradeReminder(); } +async function runUpgrade(promptText: string) { + await commands.executeCommand("workbench.action.chat.open", { + query: promptText, + isPartialQuery: true + }); +} + class UpgradeManager { - public initialize(context: ExtensionContext) { + public static initialize(context: ExtensionContext) { // Command to be used context.subscriptions.push(instrumentOperationAsVsCodeCommand(Commands.VIEW_TRIGGER_JAVA_UPGRADE_TOOL, (promptText?: string) => { - this.runUpgrade(promptText ?? DEFAULT_UPGRADE_PROMPT); + runUpgrade(promptText ?? DEFAULT_UPGRADE_PROMPT); })); commands.executeCommand('setContext', 'isModernizationExtensionInstalled', !!extensions.getExtension(ExtensionName.APP_MODERNIZATION_FOR_JAVA)); @@ -102,19 +109,19 @@ class UpgradeManager { commands.executeCommand("workbench.view.extension.azureJavaMigrationExplorer"); })); - this.scan(); + UpgradeManager.scan(); } - public scan() { + public static scan() { if (shouldCheckUpgrade()) { return; } workspace.workspaceFolders?.forEach((folder) => - this.checkUpgradableComponents(folder) + UpgradeManager.checkUpgradableComponents(folder) ); } - private async checkUpgradableComponents(folder: WorkspaceFolder) { + private static async checkUpgradableComponents(folder: WorkspaceFolder) { if (!await languageServerApiManager.ready()) { return; } @@ -144,15 +151,6 @@ class UpgradeManager { notificationManager.triggerNotification(projectIssues); } } - - - private async runUpgrade(promptText: string) { - await commands.executeCommand("workbench.action.chat.open", { - query: promptText, - isPartialQuery: true - }); - } } -const upgradeManager = new UpgradeManager(); -export default upgradeManager; \ No newline at end of file +export default UpgradeManager; \ No newline at end of file From 06c14d9ab516e19887fb00e02ca0b53bd338722d Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Wed, 10 Sep 2025 15:55:46 +0800 Subject: [PATCH 15/73] fix: typo --- src/upgrade/upgradeManager.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/upgrade/upgradeManager.ts b/src/upgrade/upgradeManager.ts index 94a01bfc..b2ca3828 100644 --- a/src/upgrade/upgradeManager.ts +++ b/src/upgrade/upgradeManager.ts @@ -113,7 +113,7 @@ class UpgradeManager { } public static scan() { - if (shouldCheckUpgrade()) { + if (!shouldCheckUpgrade()) { return; } workspace.workspaceFolders?.forEach((folder) => From 1fac1f0e8098bd50993b326249375cfef886904f Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Wed, 10 Sep 2025 15:55:55 +0800 Subject: [PATCH 16/73] chore: add copyright headers --- src/upgrade/dependency.data.ts | 3 +++ src/upgrade/type.ts | 3 +++ src/upgrade/utility.ts | 3 +++ 3 files changed, 9 insertions(+) diff --git a/src/upgrade/dependency.data.ts b/src/upgrade/dependency.data.ts index f9bb4ba8..af8b519e 100644 --- a/src/upgrade/dependency.data.ts +++ b/src/upgrade/dependency.data.ts @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + import type { DependencyCheckMetadata } from "./type"; const DEPENDENCIES_TO_SCAN: DependencyCheckMetadata = { diff --git a/src/upgrade/type.ts b/src/upgrade/type.ts index 45f02cca..1501515c 100644 --- a/src/upgrade/type.ts +++ b/src/upgrade/type.ts @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + export type DependencyCheckItem = { name: string, supportedVersion: string }; export type DependencyCheckMetadata = Record; diff --git a/src/upgrade/utility.ts b/src/upgrade/utility.ts index 6e8e8921..1b09d9b0 100644 --- a/src/upgrade/utility.ts +++ b/src/upgrade/utility.ts @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + import { Uri } from "vscode"; import { UpgradeReason, type UpgradeIssue } from "./type"; From 97a044a97af1fe1fc6ceeae56dbc86acf9cf2bc9 Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Thu, 11 Sep 2025 12:15:04 +0800 Subject: [PATCH 17/73] chore: skip package dependency check when JRE version issue is found --- src/upgrade/upgradeManager.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/upgrade/upgradeManager.ts b/src/upgrade/upgradeManager.ts index b2ca3828..44caf71f 100644 --- a/src/upgrade/upgradeManager.ts +++ b/src/upgrade/upgradeManager.ts @@ -66,6 +66,10 @@ async function getProjectIssues(projectNode: INodeData): Promise } const issues: UpgradeIssue[] = []; issues.push(...getJavaIssues(projectNode)); + if (issues.length > 0) { + // If Java runtime version issue is found, prompt for it only + return issues; + } const packageData = await Jdtls.getPackageData({ kind: NodeKind.Project, projectUri: projectNode.uri }); await Promise.allSettled( packageData From a554cca5350b0bd35e8b9bf6fb9516051bc498eb Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Thu, 11 Sep 2025 12:16:21 +0800 Subject: [PATCH 18/73] chore: check Settings first as it's cheaper (?) --- src/upgrade/upgradeManager.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/upgrade/upgradeManager.ts b/src/upgrade/upgradeManager.ts index 44caf71f..246ec124 100644 --- a/src/upgrade/upgradeManager.ts +++ b/src/upgrade/upgradeManager.ts @@ -91,7 +91,8 @@ async function getProjectIssues(projectNode: INodeData): Promise } function shouldCheckUpgrade() { - return !!extensions.getExtension(ExtensionName.APP_MODERNIZATION_UPGRADE_FOR_JAVA) && Settings.getShowUpgradeReminder(); + return Settings.getShowUpgradeReminder() + && !!extensions.getExtension(ExtensionName.APP_MODERNIZATION_UPGRADE_FOR_JAVA); } async function runUpgrade(promptText: string) { From 67fba26232853909c4c94344b7d502cfd4bb4b59 Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Thu, 11 Sep 2025 12:25:09 +0800 Subject: [PATCH 19/73] chore: revise fix prompts Reference: https://github.com/devdiv-microsoft/vscode-java-upgrade/blob/f4a0ad1a87e25261bf7b74ff719d7b9eea0b32fc/src/commands.ts --- src/upgrade/utility.ts | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/upgrade/utility.ts b/src/upgrade/utility.ts index 1b09d9b0..1179576c 100644 --- a/src/upgrade/utility.ts +++ b/src/upgrade/utility.ts @@ -3,24 +3,21 @@ import { Uri } from "vscode"; import { UpgradeReason, type UpgradeIssue } from "./type"; +import { Upgrade } from "../constants"; export function buildFixPrompt(issue: UpgradeIssue): string { const { packageId, packageDisplayName, reason, suggestedVersion } = issue; const name = packageDisplayName ?? packageId; - const suffix = [ - ...(suggestedVersion ? [`The target version is ${suggestedVersion}.`] : []) - ]; - switch (reason) { case UpgradeReason.END_OF_LIFE: { - return [`Upgrade the package ${name}.`, ...suffix].join(" "); + return `upgrade package ${name} to ${suggestedVersion ?? "latest version"} using java upgrade tools`; } case UpgradeReason.CVE: { - return [`Upgrade the package ${name} to address CVE issues.`, ...suffix].join(" "); + return `upgrade package ${name} to ${suggestedVersion ?? "latest version"} to address CVE issues using java upgrade tools`; } case UpgradeReason.ENGINE_TOO_OLD: { - return [`Upgrade the version of Java.`, ...suffix].join(" "); + return `upgrade java runtime to latest LTS (${Upgrade.LATEST_JAVA_LTS_VESRION}) using java upgrade tools`; } } } From c667fa21da4684ffbd0658f5f602df7c8a3a2c97 Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Thu, 11 Sep 2025 12:25:22 +0800 Subject: [PATCH 20/73] chore: call `javaupgrade.gotoAgentMode` to trigger prompts --- src/commands.ts | 5 +++++ src/upgrade/upgradeManager.ts | 15 +++++++++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/commands.ts b/src/commands.ts index 8f6053be..c895d9a0 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -160,6 +160,11 @@ export namespace Commands { export const BUILD_PROJECT = "java.project.build"; + /** + * Commands from Java Upgrade Tool + */ + export const GOTO_AGENT_MODE = "javaupgrade.gotoAgentMode"; + /** * Get the project settings */ diff --git a/src/upgrade/upgradeManager.ts b/src/upgrade/upgradeManager.ts index 246ec124..b29dbcb1 100644 --- a/src/upgrade/upgradeManager.ts +++ b/src/upgrade/upgradeManager.ts @@ -96,9 +96,10 @@ function shouldCheckUpgrade() { } async function runUpgrade(promptText: string) { - await commands.executeCommand("workbench.action.chat.open", { - query: promptText, - isPartialQuery: true + await commands.executeCommand('workbench.action.chat.open'); + await commands.executeCommand('workbench.action.chat.newEditSession', { + agentMode: true, + inputValue: promptText, }); } @@ -106,7 +107,13 @@ class UpgradeManager { public static initialize(context: ExtensionContext) { // Command to be used context.subscriptions.push(instrumentOperationAsVsCodeCommand(Commands.VIEW_TRIGGER_JAVA_UPGRADE_TOOL, (promptText?: string) => { - runUpgrade(promptText ?? DEFAULT_UPGRADE_PROMPT); + // The command should typically exist as we checked for the extension before. + const hasAgentModeCommand = !!commands.getCommands(true).then(cmds => cmds.includes(Commands.GOTO_AGENT_MODE)); + if (hasAgentModeCommand) { + commands.executeCommand(Commands.GOTO_AGENT_MODE, { prompt: promptText }); + } else { + runUpgrade(promptText ?? DEFAULT_UPGRADE_PROMPT); + } })); commands.executeCommand('setContext', 'isModernizationExtensionInstalled', !!extensions.getExtension(ExtensionName.APP_MODERNIZATION_FOR_JAVA)); From cda24ca8e22687ea926eeafd6841a961e907fae1 Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Thu, 11 Sep 2025 12:35:43 +0800 Subject: [PATCH 21/73] feat: revise notification message --- src/upgrade/display/notificationManager.ts | 27 +++++----------------- src/upgrade/upgradeManager.ts | 1 + src/upgrade/utility.ts | 12 ++++++++++ 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/src/upgrade/display/notificationManager.ts b/src/upgrade/display/notificationManager.ts index c1d5e57c..96c8ea65 100644 --- a/src/upgrade/display/notificationManager.ts +++ b/src/upgrade/display/notificationManager.ts @@ -3,37 +3,22 @@ import { commands, window } from "vscode"; import type { UpgradeIssue } from "../type"; -import { buildFixPrompt } from "../utility"; +import { buildFixPrompt, buildNotificationMessage } from "../utility"; import { Commands } from "../../commands"; class NotificationManager { private hasShown = false; - async triggerNotification(projectIssues: Record) { + async triggerNotification(issue: UpgradeIssue) { if (!this.shouldShow()) { return; } - const lines = [ - "Fix the following version issues:", - ]; - for (const [pomPath, issues] of Object.entries(projectIssues)) { - lines.push(""); - lines.push(`For project "${pomPath}":`); - const linesForCurrentProject = new Set(); - for (const issue of issues) { - linesForCurrentProject.add(buildFixPrompt(issue)); - } - lines.push(...linesForCurrentProject); - lines.push("\n"); - } - - const prompt = lines.join("\n"); - const projectCount = Object.keys(projectIssues).length; - const issueCount = Object.values(projectIssues).map(x => x.length).reduce((a, b) => a + b, 0); - + const prompt = buildFixPrompt(issue); + const notificationMessage = buildNotificationMessage(issue); const buttonText = "Upgrade"; - const selection = await window.showInformationMessage(`${issueCount} version issue(s) found in ${projectCount} project(s).`, buttonText); + + const selection = await window.showInformationMessage(notificationMessage, buttonText); this.hasShown = true; if (selection === buttonText) { commands.executeCommand(Commands.VIEW_TRIGGER_JAVA_UPGRADE_TOOL, prompt); diff --git a/src/upgrade/upgradeManager.ts b/src/upgrade/upgradeManager.ts index b29dbcb1..d397b2ec 100644 --- a/src/upgrade/upgradeManager.ts +++ b/src/upgrade/upgradeManager.ts @@ -25,6 +25,7 @@ function getJavaIssues(data: INodeData): UpgradeIssue[] { if (javaVersion < Upgrade.LATEST_JAVA_LTS_VESRION) { return [{ packageId: buildPackageId(Upgrade.DIAGNOSTICS_GROUP_ID_FOR_JAVA_ENGINE, "*"), + packageDisplayName: "Java Runtime", reason: UpgradeReason.ENGINE_TOO_OLD, currentVersion: String(javaVersion), suggestedVersion: String(Upgrade.LATEST_JAVA_LTS_VESRION), diff --git a/src/upgrade/utility.ts b/src/upgrade/utility.ts index 1179576c..40a45c9c 100644 --- a/src/upgrade/utility.ts +++ b/src/upgrade/utility.ts @@ -5,6 +5,18 @@ import { Uri } from "vscode"; import { UpgradeReason, type UpgradeIssue } from "./type"; import { Upgrade } from "../constants"; +export function buildNotificationMessage(issue: UpgradeIssue): string { + const { packageId, currentVersion, suggestedVersion, packageDisplayName } = issue; + const name = packageDisplayName ?? packageId; + + if (packageId === buildPackageId(Upgrade.DIAGNOSTICS_GROUP_ID_FOR_JAVA_ENGINE, "*")) { + return `The current project is using an older runtime (Java ${currentVersion}). Do you want to upgrade to the latest LTS (Java ${suggestedVersion})?` + } + + return `The current project is using ${name} ${currentVersion}, which reached end of life. Do you want to upgrade to the latest version${suggestedVersion ? ` (${suggestedVersion})` : "" + }?` +} + export function buildFixPrompt(issue: UpgradeIssue): string { const { packageId, packageDisplayName, reason, suggestedVersion } = issue; const name = packageDisplayName ?? packageId; From 581772126315fa030695caa56eb034f0267993fa Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Thu, 11 Sep 2025 12:36:31 +0800 Subject: [PATCH 22/73] fix: only trigger notification on the first issue found --- src/upgrade/upgradeManager.ts | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/upgrade/upgradeManager.ts b/src/upgrade/upgradeManager.ts index d397b2ec..46bbb921 100644 --- a/src/upgrade/upgradeManager.ts +++ b/src/upgrade/upgradeManager.ts @@ -148,20 +148,18 @@ class UpgradeManager { const projects = await Jdtls.getProjects(uri); let hasIssues = false; await Promise.allSettled(projects.map(async (projectNode) => { - const pomPath = projectNode.metaData?.PomPath as string | undefined; - if (!pomPath) { - return; - } + const pomPath = projectNode.metaData?.PomPath as string | undefined ?? "Unknown POM path"; const issues = await getProjectIssues(projectNode); if (issues.length > 0) { hasIssues = true; + projectIssues[pomPath] = issues; } - projectIssues[pomPath] = issues; })); if (hasIssues) { - notificationManager.triggerNotification(projectIssues); + // only show one issue in notifications + notificationManager.triggerNotification(Object.values(projectIssues)[0][0]); } } } From f6db20c47d978c308b436e7e8f48398ad965b7ad Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Thu, 11 Sep 2025 12:44:34 +0800 Subject: [PATCH 23/73] feat: allow "Not Now" or "Don't Show Again" for notifications --- src/constants.ts | 1 + src/upgrade/display/notificationManager.ts | 67 +++++++++++++++++++--- src/upgrade/upgradeManager.ts | 6 +- 3 files changed, 64 insertions(+), 10 deletions(-) diff --git a/src/constants.ts b/src/constants.ts index 470ff90a..54780b46 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -41,6 +41,7 @@ export namespace Upgrade { export const DIAGNOSTICS_GROUP_ID_FOR_JAVA_ENGINE = "java-upgrade-assistant"; export const DIAGNOSTICS_NAME_FOR_JAVA_ENGINE = "Java Upgrade Assistant"; export const LATEST_JAVA_LTS_VESRION = 21; + export const SESSION_COUNT_BEFORE_NOTIFICATION_RESHOW = 3; } /** diff --git a/src/upgrade/display/notificationManager.ts b/src/upgrade/display/notificationManager.ts index 96c8ea65..22a4d1b8 100644 --- a/src/upgrade/display/notificationManager.ts +++ b/src/upgrade/display/notificationManager.ts @@ -1,33 +1,84 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. -import { commands, window } from "vscode"; +import { commands, ExtensionContext, window } from "vscode"; import type { UpgradeIssue } from "../type"; import { buildFixPrompt, buildNotificationMessage } from "../utility"; import { Commands } from "../../commands"; +import { Upgrade } from "../../constants"; + +const KEY_PREFIX = 'javaupgrade.notificationManager'; +const IS_CANDIDATE_KEY = `${KEY_PREFIX}.isCandidate`; +const SESSION_COUNT_KEY = `${KEY_PREFIX}.sessionCount`; + +const BUTTON_TEXT_UPGRADE = "Upgrade"; +const BUTTON_TEXT_NOT_NOW = "Not Now"; +const BUTTON_TEXT_DONT_SHOW_AGAIN = "Don't Show Again"; class NotificationManager { private hasShown = false; + private context?: ExtensionContext; + + initialize(context: ExtensionContext) { + this.context = context; + } async triggerNotification(issue: UpgradeIssue) { + if (this.hasShown) { + return; + } + this.hasShown = true; + + this.setSessionCount((this.getSessionCount() ?? 0) + 1); + if (!this.shouldShow()) { return; } const prompt = buildFixPrompt(issue); const notificationMessage = buildNotificationMessage(issue); - const buttonText = "Upgrade"; + const selection = await window.showInformationMessage( + notificationMessage, + BUTTON_TEXT_UPGRADE, + BUTTON_TEXT_NOT_NOW, + BUTTON_TEXT_DONT_SHOW_AGAIN); - const selection = await window.showInformationMessage(notificationMessage, buttonText); - this.hasShown = true; - if (selection === buttonText) { - commands.executeCommand(Commands.VIEW_TRIGGER_JAVA_UPGRADE_TOOL, prompt); + switch (selection) { + case BUTTON_TEXT_UPGRADE: { + commands.executeCommand(Commands.VIEW_TRIGGER_JAVA_UPGRADE_TOOL, prompt); + break; + } + case BUTTON_TEXT_NOT_NOW: { + this.setSessionCount(-1 * Upgrade.SESSION_COUNT_BEFORE_NOTIFICATION_RESHOW); + break; + } + case BUTTON_TEXT_DONT_SHOW_AGAIN: { + this.setCandidate(false); + break; + } } + } private shouldShow() { - // TODO: fix - return !this.hasShown; + return this.isCandidate() + && ((this.getSessionCount() ?? 0) >= 0); + } + + private getSessionCount() { + return this.context?.globalState.get(SESSION_COUNT_KEY); + } + + private setSessionCount(num: number) { + return this.context?.globalState.update(SESSION_COUNT_KEY, num); + } + + private isCandidate() { + return this.context?.globalState.get(IS_CANDIDATE_KEY, true); + } + + private setCandidate(isCandidate: boolean) { + this.context?.globalState.update(IS_CANDIDATE_KEY, isCandidate); } } diff --git a/src/upgrade/upgradeManager.ts b/src/upgrade/upgradeManager.ts index 46bbb921..cdca55ad 100644 --- a/src/upgrade/upgradeManager.ts +++ b/src/upgrade/upgradeManager.ts @@ -15,7 +15,7 @@ import { buildPackageId } from "./utility"; import notificationManager from "./display/notificationManager"; import { Settings } from "../settings"; -const DEFAULT_UPGRADE_PROMPT = "Upgrade Java project dependency"; +const DEFAULT_UPGRADE_PROMPT = "Upgrade Java project dependency."; function getJavaIssues(data: INodeData): UpgradeIssue[] { const javaVersion = data.metaData?.MaxSourceVersion as number | undefined; @@ -106,7 +106,9 @@ async function runUpgrade(promptText: string) { class UpgradeManager { public static initialize(context: ExtensionContext) { - // Command to be used + notificationManager.initialize(context); + + // Commands to be used context.subscriptions.push(instrumentOperationAsVsCodeCommand(Commands.VIEW_TRIGGER_JAVA_UPGRADE_TOOL, (promptText?: string) => { // The command should typically exist as we checked for the extension before. const hasAgentModeCommand = !!commands.getCommands(true).then(cmds => cmds.includes(Commands.GOTO_AGENT_MODE)); From 4bc2e937335cfa4d401609c96ba67e4e7f1216e3 Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Thu, 11 Sep 2025 12:57:58 +0800 Subject: [PATCH 24/73] fix(upgradeManager): command calling --- src/upgrade/upgradeManager.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/upgrade/upgradeManager.ts b/src/upgrade/upgradeManager.ts index cdca55ad..4fdea564 100644 --- a/src/upgrade/upgradeManager.ts +++ b/src/upgrade/upgradeManager.ts @@ -15,7 +15,7 @@ import { buildPackageId } from "./utility"; import notificationManager from "./display/notificationManager"; import { Settings } from "../settings"; -const DEFAULT_UPGRADE_PROMPT = "Upgrade Java project dependency."; +const DEFAULT_UPGRADE_PROMPT = "Upgrade Java project dependency to latest version."; function getJavaIssues(data: INodeData): UpgradeIssue[] { const javaVersion = data.metaData?.MaxSourceVersion as number | undefined; @@ -109,13 +109,14 @@ class UpgradeManager { notificationManager.initialize(context); // Commands to be used - context.subscriptions.push(instrumentOperationAsVsCodeCommand(Commands.VIEW_TRIGGER_JAVA_UPGRADE_TOOL, (promptText?: string) => { + context.subscriptions.push(instrumentOperationAsVsCodeCommand(Commands.VIEW_TRIGGER_JAVA_UPGRADE_TOOL, async (promptText?: string) => { + const promptToUse = promptText ?? DEFAULT_UPGRADE_PROMPT; // The command should typically exist as we checked for the extension before. - const hasAgentModeCommand = !!commands.getCommands(true).then(cmds => cmds.includes(Commands.GOTO_AGENT_MODE)); + const hasAgentModeCommand = (await commands.getCommands(true).then(cmds => cmds.includes(Commands.GOTO_AGENT_MODE))); if (hasAgentModeCommand) { - commands.executeCommand(Commands.GOTO_AGENT_MODE, { prompt: promptText }); + await commands.executeCommand(Commands.GOTO_AGENT_MODE, { prompt: promptToUse }); } else { - runUpgrade(promptText ?? DEFAULT_UPGRADE_PROMPT); + await runUpgrade(promptToUse); } })); commands.executeCommand('setContext', 'isModernizationExtensionInstalled', From b93017d6588744f1acdfc30c0894b1fcf6c10aaa Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Thu, 11 Sep 2025 13:46:34 +0800 Subject: [PATCH 25/73] chore: Java uses the word `runtime` instead of `engine` --- src/constants.ts | 4 ++-- src/upgrade/metadataManager.ts | 4 ++-- src/upgrade/type.ts | 2 +- src/upgrade/upgradeManager.ts | 6 +++--- src/upgrade/utility.ts | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/constants.ts b/src/constants.ts index 54780b46..d9cb0390 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -38,8 +38,8 @@ export namespace ExtensionName { } export namespace Upgrade { - export const DIAGNOSTICS_GROUP_ID_FOR_JAVA_ENGINE = "java-upgrade-assistant"; - export const DIAGNOSTICS_NAME_FOR_JAVA_ENGINE = "Java Upgrade Assistant"; + export const DIAGNOSTICS_GROUP_ID_FOR_JAVA_RUNTIME = "java-upgrade-assistant"; + export const DIAGNOSTICS_NAME_FOR_JAVA_RUNTIME = "Java Upgrade Assistant"; export const LATEST_JAVA_LTS_VESRION = 21; export const SESSION_COUNT_BEFORE_NOTIFICATION_RESHOW = 3; } diff --git a/src/upgrade/metadataManager.ts b/src/upgrade/metadataManager.ts index 2ed19ae8..09e99a0b 100644 --- a/src/upgrade/metadataManager.ts +++ b/src/upgrade/metadataManager.ts @@ -15,9 +15,9 @@ class MetadataManager { const groupId = splits[0]; const artifactId = splits[1] ?? ""; - if (groupId === Upgrade.DIAGNOSTICS_GROUP_ID_FOR_JAVA_ENGINE) { + if (groupId === Upgrade.DIAGNOSTICS_GROUP_ID_FOR_JAVA_RUNTIME) { return { - name: Upgrade.DIAGNOSTICS_NAME_FOR_JAVA_ENGINE, + name: Upgrade.DIAGNOSTICS_NAME_FOR_JAVA_RUNTIME, supportedVersion: `>=${Upgrade.LATEST_JAVA_LTS_VESRION}`, }; } diff --git a/src/upgrade/type.ts b/src/upgrade/type.ts index 1501515c..dbbaa5e2 100644 --- a/src/upgrade/type.ts +++ b/src/upgrade/type.ts @@ -7,7 +7,7 @@ export type DependencyCheckMetadata = Record; export enum UpgradeReason { END_OF_LIFE, CVE, - ENGINE_TOO_OLD, + JRE_TOO_OLD, }; export type UpgradeIssue = { diff --git a/src/upgrade/upgradeManager.ts b/src/upgrade/upgradeManager.ts index 4fdea564..7d92f7ee 100644 --- a/src/upgrade/upgradeManager.ts +++ b/src/upgrade/upgradeManager.ts @@ -24,9 +24,9 @@ function getJavaIssues(data: INodeData): UpgradeIssue[] { } if (javaVersion < Upgrade.LATEST_JAVA_LTS_VESRION) { return [{ - packageId: buildPackageId(Upgrade.DIAGNOSTICS_GROUP_ID_FOR_JAVA_ENGINE, "*"), + packageId: buildPackageId(Upgrade.DIAGNOSTICS_GROUP_ID_FOR_JAVA_RUNTIME, "*"), packageDisplayName: "Java Runtime", - reason: UpgradeReason.ENGINE_TOO_OLD, + reason: UpgradeReason.JRE_TOO_OLD, currentVersion: String(javaVersion), suggestedVersion: String(Upgrade.LATEST_JAVA_LTS_VESRION), }]; @@ -114,7 +114,7 @@ class UpgradeManager { // The command should typically exist as we checked for the extension before. const hasAgentModeCommand = (await commands.getCommands(true).then(cmds => cmds.includes(Commands.GOTO_AGENT_MODE))); if (hasAgentModeCommand) { - await commands.executeCommand(Commands.GOTO_AGENT_MODE, { prompt: promptToUse }); + await commands.executeCommand(Commands.GOTO_AGENT_MODE, { prompt: promptToUse }).then(x => console.log("OK", x)).catch(e => console.log("ERR", e)); } else { await runUpgrade(promptToUse); } diff --git a/src/upgrade/utility.ts b/src/upgrade/utility.ts index 40a45c9c..f669d3d0 100644 --- a/src/upgrade/utility.ts +++ b/src/upgrade/utility.ts @@ -9,7 +9,7 @@ export function buildNotificationMessage(issue: UpgradeIssue): string { const { packageId, currentVersion, suggestedVersion, packageDisplayName } = issue; const name = packageDisplayName ?? packageId; - if (packageId === buildPackageId(Upgrade.DIAGNOSTICS_GROUP_ID_FOR_JAVA_ENGINE, "*")) { + if (packageId === buildPackageId(Upgrade.DIAGNOSTICS_GROUP_ID_FOR_JAVA_RUNTIME, "*")) { return `The current project is using an older runtime (Java ${currentVersion}). Do you want to upgrade to the latest LTS (Java ${suggestedVersion})?` } @@ -28,7 +28,7 @@ export function buildFixPrompt(issue: UpgradeIssue): string { case UpgradeReason.CVE: { return `upgrade package ${name} to ${suggestedVersion ?? "latest version"} to address CVE issues using java upgrade tools`; } - case UpgradeReason.ENGINE_TOO_OLD: { + case UpgradeReason.JRE_TOO_OLD: { return `upgrade java runtime to latest LTS (${Upgrade.LATEST_JAVA_LTS_VESRION}) using java upgrade tools`; } } From 2da82b01a97d4c9d87537d49d17170e4c37b5aa2 Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Thu, 11 Sep 2025 15:36:26 +0800 Subject: [PATCH 26/73] chore: remove debug strings --- src/upgrade/upgradeManager.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/upgrade/upgradeManager.ts b/src/upgrade/upgradeManager.ts index 7d92f7ee..695b73fe 100644 --- a/src/upgrade/upgradeManager.ts +++ b/src/upgrade/upgradeManager.ts @@ -114,7 +114,7 @@ class UpgradeManager { // The command should typically exist as we checked for the extension before. const hasAgentModeCommand = (await commands.getCommands(true).then(cmds => cmds.includes(Commands.GOTO_AGENT_MODE))); if (hasAgentModeCommand) { - await commands.executeCommand(Commands.GOTO_AGENT_MODE, { prompt: promptToUse }).then(x => console.log("OK", x)).catch(e => console.log("ERR", e)); + await commands.executeCommand(Commands.GOTO_AGENT_MODE, { prompt: promptToUse }); } else { await runUpgrade(promptToUse); } From 802f9de5b2ec5332094162efb1b1336f583fc283 Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Thu, 11 Sep 2025 15:49:15 +0800 Subject: [PATCH 27/73] feat: support deprecated dependencies (and add Java EE as an example) --- src/upgrade/dependency.data.ts | 14 +++++++++- src/upgrade/metadataManager.ts | 3 ++- src/upgrade/type.ts | 7 +++-- src/upgrade/upgradeManager.ts | 47 ++++++++++++++++++++++++---------- src/upgrade/utility.ts | 6 ++--- 5 files changed, 57 insertions(+), 20 deletions(-) diff --git a/src/upgrade/dependency.data.ts b/src/upgrade/dependency.data.ts index af8b519e..f4faf1fa 100644 --- a/src/upgrade/dependency.data.ts +++ b/src/upgrade/dependency.data.ts @@ -1,16 +1,28 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. -import type { DependencyCheckMetadata } from "./type"; +import { UpgradeReason, type DependencyCheckMetadata } from "./type"; const DEPENDENCIES_TO_SCAN: DependencyCheckMetadata = { "org.springframework.boot:*": { + "reason": UpgradeReason.END_OF_LIFE, "name": "Spring Boot", "supportedVersion": "2.7.x || >=3.2.x", }, "org.springframework:*": { + "reason": UpgradeReason.END_OF_LIFE, "name": "Spring Framework", "supportedVersion": "5.3.x || >=6.2.x", + }, + "javax:javaee-api": { + "reason": UpgradeReason.DEPRECATED, + "name": "Java EE", + "alternative": "Jakarta EE 10", + }, + "javax:javaee-web-api": { + "reason": UpgradeReason.DEPRECATED, + "name": "Java EE", + "alternative": "Jakarta EE 10", } }; diff --git a/src/upgrade/metadataManager.ts b/src/upgrade/metadataManager.ts index 09e99a0b..4d514053 100644 --- a/src/upgrade/metadataManager.ts +++ b/src/upgrade/metadataManager.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. -import type { DependencyCheckMetadata, DependencyCheckItem } from "./type"; +import { type DependencyCheckMetadata, type DependencyCheckItem, UpgradeReason } from "./type"; import { Upgrade } from "../constants"; import { buildPackageId } from "./utility"; import DEPENDENCIES_TO_SCAN from "./dependency.data"; @@ -18,6 +18,7 @@ class MetadataManager { if (groupId === Upgrade.DIAGNOSTICS_GROUP_ID_FOR_JAVA_RUNTIME) { return { name: Upgrade.DIAGNOSTICS_NAME_FOR_JAVA_RUNTIME, + reason: UpgradeReason.END_OF_LIFE, supportedVersion: `>=${Upgrade.LATEST_JAVA_LTS_VESRION}`, }; } diff --git a/src/upgrade/type.ts b/src/upgrade/type.ts index dbbaa5e2..478a6729 100644 --- a/src/upgrade/type.ts +++ b/src/upgrade/type.ts @@ -1,11 +1,14 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. - -export type DependencyCheckItem = { name: string, supportedVersion: string }; +export type DependencyCheckItem = { name: string, reason: UpgradeReason } & ( + { reason: UpgradeReason.END_OF_LIFE, supportedVersion: string } | + { reason: UpgradeReason.DEPRECATED, alternative: string } +); export type DependencyCheckMetadata = Record; export enum UpgradeReason { END_OF_LIFE, + DEPRECATED, CVE, JRE_TOO_OLD, }; diff --git a/src/upgrade/upgradeManager.ts b/src/upgrade/upgradeManager.ts index 695b73fe..73b30407 100644 --- a/src/upgrade/upgradeManager.ts +++ b/src/upgrade/upgradeManager.ts @@ -7,7 +7,7 @@ import { Jdtls } from "../java/jdtls"; import { languageServerApiManager } from "../languageServerApi/languageServerApiManager"; import { NodeKind, type INodeData } from "../java/nodeData"; import { ExtensionName, Upgrade } from "../constants"; -import { UpgradeIssue, UpgradeReason } from "./type"; +import { DependencyCheckItem, UpgradeIssue, UpgradeReason } from "./type"; import { instrumentOperationAsVsCodeCommand } from "vscode-extension-telemetry-wrapper"; import { Commands } from "../commands"; import metadataManager from "./metadataManager"; @@ -35,6 +35,35 @@ function getJavaIssues(data: INodeData): UpgradeIssue[] { return []; } +function getUpgrade(versionString: string, supportedVersionDefinition: DependencyCheckItem): Omit | null { + const { reason } = supportedVersionDefinition; + switch (reason) { + case UpgradeReason.DEPRECATED: { + const { alternative } = supportedVersionDefinition; + return { + packageDisplayName: supportedVersionDefinition.name, + reason, + currentVersion: versionString, + suggestedVersion: alternative, + } + } + case UpgradeReason.END_OF_LIFE: { + const currentSemVer = semver.coerce(versionString); + if (currentSemVer && !semver.satisfies(currentSemVer, supportedVersionDefinition.supportedVersion)) { + return { + packageDisplayName: supportedVersionDefinition.name, + reason, + currentVersion: versionString, + suggestedVersion: "latest", // TODO + } + } + } + + } + + return null; +} + function getDependencyIssues(data: INodeData): UpgradeIssue[] { const versionString = data.metaData?.["maven.version"]; const groupId = data.metaData?.["maven.groupId"]; @@ -44,18 +73,10 @@ function getDependencyIssues(data: INodeData): UpgradeIssue[] { if (!versionString || !groupId || !supportedVersionDefinition) { return []; } - const currentVersion = semver.coerce(versionString); - if (!currentVersion) { - return []; - } - if (!semver.satisfies(currentVersion, supportedVersionDefinition.supportedVersion)) { - return [{ - packageId, - packageDisplayName: supportedVersionDefinition.name, - reason: UpgradeReason.END_OF_LIFE, - currentVersion: versionString, - suggestedVersion: "latest", // TODO - }]; + + const upgrade = getUpgrade(versionString, supportedVersionDefinition); + if (upgrade) { + return [{ ...upgrade, packageId }]; } return []; } diff --git a/src/upgrade/utility.ts b/src/upgrade/utility.ts index f669d3d0..1f9832d9 100644 --- a/src/upgrade/utility.ts +++ b/src/upgrade/utility.ts @@ -22,15 +22,15 @@ export function buildFixPrompt(issue: UpgradeIssue): string { const name = packageDisplayName ?? packageId; switch (reason) { - case UpgradeReason.END_OF_LIFE: { - return `upgrade package ${name} to ${suggestedVersion ?? "latest version"} using java upgrade tools`; - } case UpgradeReason.CVE: { return `upgrade package ${name} to ${suggestedVersion ?? "latest version"} to address CVE issues using java upgrade tools`; } case UpgradeReason.JRE_TOO_OLD: { return `upgrade java runtime to latest LTS (${Upgrade.LATEST_JAVA_LTS_VESRION}) using java upgrade tools`; } + default: { + return `upgrade package ${name} to ${suggestedVersion ?? "latest version"} using java upgrade tools`; + } } } From 82aaf05d030669653befc1c54c0fc3a8f6a71f40 Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Thu, 11 Sep 2025 16:48:43 +0800 Subject: [PATCH 28/73] fix: use 21 when showing latest version --- src/upgrade/upgradeManager.ts | 2 +- src/upgrade/utility.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/upgrade/upgradeManager.ts b/src/upgrade/upgradeManager.ts index 73b30407..87758c09 100644 --- a/src/upgrade/upgradeManager.ts +++ b/src/upgrade/upgradeManager.ts @@ -54,7 +54,7 @@ function getUpgrade(versionString: string, supportedVersionDefinition: Dependenc packageDisplayName: supportedVersionDefinition.name, reason, currentVersion: versionString, - suggestedVersion: "latest", // TODO + suggestedVersion: "latest", } } } diff --git a/src/upgrade/utility.ts b/src/upgrade/utility.ts index 1f9832d9..e39f75db 100644 --- a/src/upgrade/utility.ts +++ b/src/upgrade/utility.ts @@ -10,7 +10,7 @@ export function buildNotificationMessage(issue: UpgradeIssue): string { const name = packageDisplayName ?? packageId; if (packageId === buildPackageId(Upgrade.DIAGNOSTICS_GROUP_ID_FOR_JAVA_RUNTIME, "*")) { - return `The current project is using an older runtime (Java ${currentVersion}). Do you want to upgrade to the latest LTS (Java ${suggestedVersion})?` + return `The current project is using an older runtime (Java ${currentVersion}). Do you want to upgrade to the latest LTS (Java ${Upgrade.LATEST_JAVA_LTS_VESRION})?` } return `The current project is using ${name} ${currentVersion}, which reached end of life. Do you want to upgrade to the latest version${suggestedVersion ? ` (${suggestedVersion})` : "" From 887261c6176b86de3981eb8aa572b29ad2f88fcd Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Thu, 11 Sep 2025 17:48:34 +0800 Subject: [PATCH 29/73] chore: string polishment --- package.nls.json | 12 ++++++------ src/upgrade/display/notificationManager.ts | 2 +- src/upgrade/utility.ts | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package.nls.json b/package.nls.json index 49613827..e5eff474 100644 --- a/package.nls.json +++ b/package.nls.json @@ -12,10 +12,10 @@ "contributes.commands.java.project.update": "Reload Project", "contributes.commands.java.project.reloadProjectFromActiveFile": "Reload Java Project", "contributes.commands.java.view.package.revealInProjectExplorer": "Reveal in Java Project Explorer", - "contributes.commands.java.view.package.changeToFlatPackageView":"Flat View", - "contributes.commands.java.view.package.changeToHierarchicalPackageView":"Hierarchical View", - "contributes.commands.java.view.package.linkWithFolderExplorer":"Link with Editor", - "contributes.commands.java.view.package.unlinkWithFolderExplorer":"Unlink with Editor", + "contributes.commands.java.view.package.changeToFlatPackageView": "Flat View", + "contributes.commands.java.view.package.changeToHierarchicalPackageView": "Hierarchical View", + "contributes.commands.java.view.package.linkWithFolderExplorer": "Link with Editor", + "contributes.commands.java.view.package.unlinkWithFolderExplorer": "Unlink with Editor", "contributes.commands.java.project.explorer.showNonJavaResources": "Show Non-Java Resources", "contributes.commands.java.project.explorer.hideNonJavaResources": "Hide Non-Java Resources", "contributes.commands.java.view.package.revealFileInOS": "Reveal in Explorer", @@ -45,7 +45,7 @@ "configuration.java.dependency.autoRefresh": "Synchronize Java Projects explorer with changes", "configuration.java.dependency.refreshDelay": "The delay time (ms) the auto refresh is invoked when changes are detected", "configuration.java.dependency.packagePresentation": "Package presentation mode: flat or hierarchical", - "configuration.java.dependency.showUpgradeReminder": "Show reminders for Java engine or dependency upgrades", + "configuration.java.dependency.showUpgradeReminder": "Show upgrade reminders for Java runtime or dependencies.", "configuration.java.project.explorer.showNonJavaResources": "When enabled, the explorer shows non-Java resources.", "configuration.java.project.exportJar.targetPath.customization": "The output path of the exported jar. Leave it empty if you want to manually pick the output location.", "configuration.java.project.exportJar.targetPath.workspaceFolder": "Export the jar file into the workspace folder. Its name is the same as the folder's.", @@ -66,4 +66,4 @@ "viewsWelcome.workbench.importFailed": "Oops, something went wrong when opening Java projects. Please use the following action for troubleshooting:\n[Open Problems View](command:workbench.panel.markers.view.focus)", "viewsWelcome.workbench.inLightWeightMode": "To view the projects, you can import the projects into workspace.\n[Import Projects](command:java.server.mode.switch?%5B%22Standard%22,true%5D)", "viewsWelcome.workbench.installLanguageSupport": "The Java Projects explorer requires [Extension Pack for Java](command:extension.open?%5B%22vscjava.vscode-java-pack%22%5D) to provide full features.\n[Install](command:java.project.installExtension?%5B%22vscjava.vscode-java-pack%22%5D)" -} +} \ No newline at end of file diff --git a/src/upgrade/display/notificationManager.ts b/src/upgrade/display/notificationManager.ts index 22a4d1b8..95becf62 100644 --- a/src/upgrade/display/notificationManager.ts +++ b/src/upgrade/display/notificationManager.ts @@ -11,7 +11,7 @@ const KEY_PREFIX = 'javaupgrade.notificationManager'; const IS_CANDIDATE_KEY = `${KEY_PREFIX}.isCandidate`; const SESSION_COUNT_KEY = `${KEY_PREFIX}.sessionCount`; -const BUTTON_TEXT_UPGRADE = "Upgrade"; +const BUTTON_TEXT_UPGRADE = "Upgrade Now"; const BUTTON_TEXT_NOT_NOW = "Not Now"; const BUTTON_TEXT_DONT_SHOW_AGAIN = "Don't Show Again"; diff --git a/src/upgrade/utility.ts b/src/upgrade/utility.ts index e39f75db..f01927c1 100644 --- a/src/upgrade/utility.ts +++ b/src/upgrade/utility.ts @@ -26,7 +26,7 @@ export function buildFixPrompt(issue: UpgradeIssue): string { return `upgrade package ${name} to ${suggestedVersion ?? "latest version"} to address CVE issues using java upgrade tools`; } case UpgradeReason.JRE_TOO_OLD: { - return `upgrade java runtime to latest LTS (${Upgrade.LATEST_JAVA_LTS_VESRION}) using java upgrade tools`; + return `upgrade java runtime to latest LTS version (${Upgrade.LATEST_JAVA_LTS_VESRION}) using java upgrade tools`; } default: { return `upgrade package ${name} to ${suggestedVersion ?? "latest version"} using java upgrade tools`; From 535e19053a5fdf2bae24cb7d9bfcf71429094ebd Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Thu, 11 Sep 2025 17:59:01 +0800 Subject: [PATCH 30/73] fix: fix prompt version insertion issues --- src/upgrade/upgradeManager.ts | 1 - src/upgrade/utility.ts | 11 ++++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/upgrade/upgradeManager.ts b/src/upgrade/upgradeManager.ts index 87758c09..9ff8ce59 100644 --- a/src/upgrade/upgradeManager.ts +++ b/src/upgrade/upgradeManager.ts @@ -54,7 +54,6 @@ function getUpgrade(versionString: string, supportedVersionDefinition: Dependenc packageDisplayName: supportedVersionDefinition.name, reason, currentVersion: versionString, - suggestedVersion: "latest", } } } diff --git a/src/upgrade/utility.ts b/src/upgrade/utility.ts index f01927c1..01649faf 100644 --- a/src/upgrade/utility.ts +++ b/src/upgrade/utility.ts @@ -10,10 +10,10 @@ export function buildNotificationMessage(issue: UpgradeIssue): string { const name = packageDisplayName ?? packageId; if (packageId === buildPackageId(Upgrade.DIAGNOSTICS_GROUP_ID_FOR_JAVA_RUNTIME, "*")) { - return `The current project is using an older runtime (Java ${currentVersion}). Do you want to upgrade to the latest LTS (Java ${Upgrade.LATEST_JAVA_LTS_VESRION})?` + return `The current project is using an older runtime (Java ${currentVersion}). Do you want to upgrade to the latest LTS version${suggestedVersion ? ` (${suggestedVersion})` : ""}?` } - return `The current project is using ${name} ${currentVersion}, which reached end of life. Do you want to upgrade to the latest version${suggestedVersion ? ` (${suggestedVersion})` : "" + return `The current project is using ${name} ${currentVersion}, which reached end of life. Do you want to upgrade to ${suggestedVersion ? ` ${suggestedVersion}` : "the latest version" }?` } @@ -23,13 +23,14 @@ export function buildFixPrompt(issue: UpgradeIssue): string { switch (reason) { case UpgradeReason.CVE: { - return `upgrade package ${name} to ${suggestedVersion ?? "latest version"} to address CVE issues using java upgrade tools`; + return `upgrade package ${name} to ${suggestedVersion ?? "the latest version"} to address CVE issues using java upgrade tools`; } case UpgradeReason.JRE_TOO_OLD: { - return `upgrade java runtime to latest LTS version (${Upgrade.LATEST_JAVA_LTS_VESRION}) using java upgrade tools`; + return `upgrade java runtime to latest LTS version${suggestedVersion ? ` (${suggestedVersion})` : "" + } using java upgrade tools`; } default: { - return `upgrade package ${name} to ${suggestedVersion ?? "latest version"} using java upgrade tools`; + return `upgrade package ${name} to ${suggestedVersion ?? "the latest version"} using java upgrade tools`; } } } From 6655cd8e5a48929a12c80366b83a8447929bdf24 Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Fri, 12 Sep 2025 11:22:36 +0800 Subject: [PATCH 31/73] chore: centralize JRE metadata together --- src/constants.ts | 3 +-- src/upgrade/dependency.data.ts | 10 +++++++++- src/upgrade/metadataManager.ts | 12 +----------- src/upgrade/type.ts | 8 ++++---- src/upgrade/upgradeManager.ts | 8 +++++--- src/upgrade/utility.ts | 2 +- 6 files changed, 21 insertions(+), 22 deletions(-) diff --git a/src/constants.ts b/src/constants.ts index d9cb0390..0648b368 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -38,8 +38,7 @@ export namespace ExtensionName { } export namespace Upgrade { - export const DIAGNOSTICS_GROUP_ID_FOR_JAVA_RUNTIME = "java-upgrade-assistant"; - export const DIAGNOSTICS_NAME_FOR_JAVA_RUNTIME = "Java Upgrade Assistant"; + export const PACKAGE_ID_FOR_JAVA_RUNTIME = "java-runtime:*"; export const LATEST_JAVA_LTS_VESRION = 21; export const SESSION_COUNT_BEFORE_NOTIFICATION_RESHOW = 3; } diff --git a/src/upgrade/dependency.data.ts b/src/upgrade/dependency.data.ts index f4faf1fa..8d47d69c 100644 --- a/src/upgrade/dependency.data.ts +++ b/src/upgrade/dependency.data.ts @@ -1,8 +1,15 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +import { Upgrade } from "../constants"; import { UpgradeReason, type DependencyCheckMetadata } from "./type"; +export const DEPENDENCY_JAVA_RUNTIME = { + "name": "Java Runtime", + "reason": UpgradeReason.JRE_TOO_OLD, + "supportedVersion": `>=${Upgrade.LATEST_JAVA_LTS_VESRION}`, +} as const; + const DEPENDENCIES_TO_SCAN: DependencyCheckMetadata = { "org.springframework.boot:*": { "reason": UpgradeReason.END_OF_LIFE, @@ -23,7 +30,8 @@ const DEPENDENCIES_TO_SCAN: DependencyCheckMetadata = { "reason": UpgradeReason.DEPRECATED, "name": "Java EE", "alternative": "Jakarta EE 10", - } + }, + [Upgrade.PACKAGE_ID_FOR_JAVA_RUNTIME]: DEPENDENCY_JAVA_RUNTIME, }; export default DEPENDENCIES_TO_SCAN; \ No newline at end of file diff --git a/src/upgrade/metadataManager.ts b/src/upgrade/metadataManager.ts index 4d514053..81fb7f21 100644 --- a/src/upgrade/metadataManager.ts +++ b/src/upgrade/metadataManager.ts @@ -1,12 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. -import { type DependencyCheckMetadata, type DependencyCheckItem, UpgradeReason } from "./type"; -import { Upgrade } from "../constants"; +import { type DependencyCheckMetadata, type DependencyCheckItem } from "./type"; import { buildPackageId } from "./utility"; import DEPENDENCIES_TO_SCAN from "./dependency.data"; - class MetadataManager { private static dependencyCheckMetadata: DependencyCheckMetadata = DEPENDENCIES_TO_SCAN; @@ -15,14 +13,6 @@ class MetadataManager { const groupId = splits[0]; const artifactId = splits[1] ?? ""; - if (groupId === Upgrade.DIAGNOSTICS_GROUP_ID_FOR_JAVA_RUNTIME) { - return { - name: Upgrade.DIAGNOSTICS_NAME_FOR_JAVA_RUNTIME, - reason: UpgradeReason.END_OF_LIFE, - supportedVersion: `>=${Upgrade.LATEST_JAVA_LTS_VESRION}`, - }; - } - const packageId = buildPackageId(groupId, artifactId); const packageIdWithWildcardArtifactId = buildPackageId(groupId, "*"); return this.getMetadata(packageId) ?? this.getMetadata(packageIdWithWildcardArtifactId); diff --git a/src/upgrade/type.ts b/src/upgrade/type.ts index 478a6729..5bcbed64 100644 --- a/src/upgrade/type.ts +++ b/src/upgrade/type.ts @@ -1,9 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. -export type DependencyCheckItem = { name: string, reason: UpgradeReason } & ( - { reason: UpgradeReason.END_OF_LIFE, supportedVersion: string } | - { reason: UpgradeReason.DEPRECATED, alternative: string } -); +export type DependencyCheckItemBase = { name: string, reason: UpgradeReason }; +export type DependencyCheckItemEol = DependencyCheckItemBase & { reason: UpgradeReason.END_OF_LIFE | UpgradeReason.JRE_TOO_OLD, supportedVersion: string }; +export type DependencyCheckItemDeprecated = DependencyCheckItemBase & { reason: UpgradeReason.DEPRECATED, alternative: string }; +export type DependencyCheckItem = (DependencyCheckItemEol | DependencyCheckItemDeprecated); export type DependencyCheckMetadata = Record; export enum UpgradeReason { diff --git a/src/upgrade/upgradeManager.ts b/src/upgrade/upgradeManager.ts index 9ff8ce59..d0b7b51b 100644 --- a/src/upgrade/upgradeManager.ts +++ b/src/upgrade/upgradeManager.ts @@ -14,19 +14,21 @@ import metadataManager from "./metadataManager"; import { buildPackageId } from "./utility"; import notificationManager from "./display/notificationManager"; import { Settings } from "../settings"; +import { DEPENDENCY_JAVA_RUNTIME } from "./dependency.data"; const DEFAULT_UPGRADE_PROMPT = "Upgrade Java project dependency to latest version."; function getJavaIssues(data: INodeData): UpgradeIssue[] { const javaVersion = data.metaData?.MaxSourceVersion as number | undefined; + const javaSupportedVersionDefinition = DEPENDENCY_JAVA_RUNTIME; if (!javaVersion) { return []; } if (javaVersion < Upgrade.LATEST_JAVA_LTS_VESRION) { return [{ - packageId: buildPackageId(Upgrade.DIAGNOSTICS_GROUP_ID_FOR_JAVA_RUNTIME, "*"), - packageDisplayName: "Java Runtime", - reason: UpgradeReason.JRE_TOO_OLD, + packageId: Upgrade.PACKAGE_ID_FOR_JAVA_RUNTIME, + packageDisplayName: javaSupportedVersionDefinition.name, + reason: javaSupportedVersionDefinition.reason, currentVersion: String(javaVersion), suggestedVersion: String(Upgrade.LATEST_JAVA_LTS_VESRION), }]; diff --git a/src/upgrade/utility.ts b/src/upgrade/utility.ts index 01649faf..daa1fd8c 100644 --- a/src/upgrade/utility.ts +++ b/src/upgrade/utility.ts @@ -9,7 +9,7 @@ export function buildNotificationMessage(issue: UpgradeIssue): string { const { packageId, currentVersion, suggestedVersion, packageDisplayName } = issue; const name = packageDisplayName ?? packageId; - if (packageId === buildPackageId(Upgrade.DIAGNOSTICS_GROUP_ID_FOR_JAVA_RUNTIME, "*")) { + if (packageId === Upgrade.PACKAGE_ID_FOR_JAVA_RUNTIME) { return `The current project is using an older runtime (Java ${currentVersion}). Do you want to upgrade to the latest LTS version${suggestedVersion ? ` (${suggestedVersion})` : ""}?` } From cabb4698557ece2da9ea143cce6a23ee2ce6f969 Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Fri, 12 Sep 2025 15:01:43 +0800 Subject: [PATCH 32/73] chore: rename settings `java.dependency.showUpgradeReminder` -> `java.dependency.enableDependencyDiagnostics` --- package.json | 4 ++-- package.nls.json | 2 +- src/settings.ts | 4 ++-- src/upgrade/upgradeManager.ts | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 9b63644b..5827ec76 100644 --- a/package.json +++ b/package.json @@ -333,9 +333,9 @@ "description": "%configuration.java.dependency.packagePresentation%", "default": "flat" }, - "java.dependency.showUpgradeReminder": { + "java.dependency.enableDependencyDiagnostics": { "type": "boolean", - "description": "%configuration.java.dependency.showUpgradeReminder%", + "description": "%configuration.java.dependency.enableDependencyDiagnostics%", "default": true }, "java.project.exportJar.targetPath": { diff --git a/package.nls.json b/package.nls.json index e5eff474..822b2a2e 100644 --- a/package.nls.json +++ b/package.nls.json @@ -45,7 +45,7 @@ "configuration.java.dependency.autoRefresh": "Synchronize Java Projects explorer with changes", "configuration.java.dependency.refreshDelay": "The delay time (ms) the auto refresh is invoked when changes are detected", "configuration.java.dependency.packagePresentation": "Package presentation mode: flat or hierarchical", - "configuration.java.dependency.showUpgradeReminder": "Show upgrade reminders for Java runtime or dependencies.", + "configuration.java.dependency.enableDependencyDiagnostics": "Show upgrade reminders for Java runtime or dependencies.", "configuration.java.project.explorer.showNonJavaResources": "When enabled, the explorer shows non-Java resources.", "configuration.java.project.exportJar.targetPath.customization": "The output path of the exported jar. Leave it empty if you want to manually pick the output location.", "configuration.java.project.exportJar.targetPath.workspaceFolder": "Export the jar file into the workspace folder. Its name is the same as the folder's.", diff --git a/src/settings.ts b/src/settings.ts index 565b9d21..5c44a850 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -108,8 +108,8 @@ export class Settings { return workspace.getConfiguration("java.dependency").get("refreshDelay", 2000); } - public static getShowUpgradeReminder() { - return workspace.getConfiguration("java.dependency").get("showUpgradeReminder", true); + public static getEnableDependencyDiagnostics() { + return workspace.getConfiguration("java.dependency").get("enableDependencyDiagnostics", true); } public static getExportJarTargetPath(): string { diff --git a/src/upgrade/upgradeManager.ts b/src/upgrade/upgradeManager.ts index d0b7b51b..9f63bcec 100644 --- a/src/upgrade/upgradeManager.ts +++ b/src/upgrade/upgradeManager.ts @@ -114,7 +114,7 @@ async function getProjectIssues(projectNode: INodeData): Promise } function shouldCheckUpgrade() { - return Settings.getShowUpgradeReminder() + return Settings.getEnableDependencyDiagnostics() && !!extensions.getExtension(ExtensionName.APP_MODERNIZATION_UPGRADE_FOR_JAVA); } From 7c606cb71c7127ad07de81b87cd79d0f80a0af13 Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Fri, 12 Sep 2025 15:09:51 +0800 Subject: [PATCH 33/73] fix: only show Modernize Java Project under Java project environment --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5827ec76..ca6b1812 100644 --- a/package.json +++ b/package.json @@ -585,7 +585,7 @@ }, { "command": "java.view.modernizeJavaProject", - "when": "explorerResourceIsFolder && isModernizationExtensionInstalled", + "when": "explorerResourceIsFolder && java:serverMode && isModernizationExtensionInstalled", "group": "1_javaactions@40" }, { From 4bdc6d617e03f9e9a310276174a3903a32b073be Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Fri, 12 Sep 2025 15:15:19 +0800 Subject: [PATCH 34/73] chore: `java.view.modernizeJavaProject` -> `_java.view.modernizeJavaProject` --- package.json | 4 ++-- src/commands.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index ca6b1812..65b04da7 100644 --- a/package.json +++ b/package.json @@ -295,7 +295,7 @@ "category": "Java" }, { - "command": "java.view.modernizeJavaProject", + "command": "_java.view.modernizeJavaProject", "title": "%contributes.commands.java.view.modernizeJavaProject%", "category": "Java" } @@ -584,7 +584,7 @@ "group": "1_javaactions@30" }, { - "command": "java.view.modernizeJavaProject", + "command": "_java.view.modernizeJavaProject", "when": "explorerResourceIsFolder && java:serverMode && isModernizationExtensionInstalled", "group": "1_javaactions@40" }, diff --git a/src/commands.ts b/src/commands.ts index c895d9a0..d78c0cae 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -44,7 +44,7 @@ export namespace Commands { export const VIEW_TRIGGER_JAVA_UPGRADE_TOOL = "java.view.triggerJavaUpgradeTool"; - export const VIEW_MODERNIZE_JAVA_PROJECT = "java.view.modernizeJavaProject"; + export const VIEW_MODERNIZE_JAVA_PROJECT = "_java.view.modernizeJavaProject"; export const VIEW_PACKAGE_NEW_JAVA_INTERFACE = "java.view.package.newJavaInterface"; From 81b9905815a11ec6389f7fa5451057c15439095f Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Fri, 12 Sep 2025 15:18:04 +0800 Subject: [PATCH 35/73] chore: `java.view.triggerJavaUpgradeTool` -> `_java.upgrade.triggerUpgrade` --- package.json | 8 ++++---- package.nls.json | 2 +- src/commands.ts | 4 ++-- src/upgrade/display/notificationManager.ts | 2 +- src/upgrade/upgradeManager.ts | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index 65b04da7..769bb7ff 100644 --- a/package.json +++ b/package.json @@ -290,13 +290,13 @@ "category": "Java" }, { - "command": "java.view.triggerJavaUpgradeTool", - "title": "%contributes.commands.java.view.triggerJavaUpgradeTool%", + "command": "_java.view.modernizeJavaProject", + "title": "%contributes.commands.java.view.modernizeJavaProject%", "category": "Java" }, { - "command": "_java.view.modernizeJavaProject", - "title": "%contributes.commands.java.view.modernizeJavaProject%", + "command": "_java.upgrade.triggerUpgrade", + "title": "%contributes.commands.java.upgrade.triggerUpgrade%", "category": "Java" } ], diff --git a/package.nls.json b/package.nls.json index 822b2a2e..922cf348 100644 --- a/package.nls.json +++ b/package.nls.json @@ -24,7 +24,6 @@ "contributes.commands.java.view.package.copyRelativeFilePath": "Copy Relative Path", "contributes.commands.java.view.package.new": "New...", "contributes.commands.java.view.package.newJavaClass": "Class...", - "contributes.commands.java.view.triggerJavaUpgradeTool": "Upgrade dependencies", "contributes.commands.java.view.modernizeJavaProject": "Modernize Java project", "contributes.commands.java.view.package.newJavaInterface": "Interface...", "contributes.commands.java.view.package.newJavaEnum": "Enum...", @@ -40,6 +39,7 @@ "contributes.commands.java.view.fileExplorer.newPackage": "New Java Package...", "contributes.submenus.javaProject.new": "New", "contributes.commands.java.view.menus.file.newJavaClass": "New Java File", + "contributes.commands.java.upgrade.triggerUpgrade": "Upgrade dependencies", "configuration.java.dependency.showMembers": "Show the members in the explorer", "configuration.java.dependency.syncWithFolderExplorer": "Link Java Projects Explorer with the active editor", "configuration.java.dependency.autoRefresh": "Synchronize Java Projects explorer with changes", diff --git a/src/commands.ts b/src/commands.ts index d78c0cae..2d6b24c7 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -42,8 +42,6 @@ export namespace Commands { export const VIEW_PACKAGE_NEW_JAVA_CLASS = "java.view.package.newJavaClass"; - export const VIEW_TRIGGER_JAVA_UPGRADE_TOOL = "java.view.triggerJavaUpgradeTool"; - export const VIEW_MODERNIZE_JAVA_PROJECT = "_java.view.modernizeJavaProject"; export const VIEW_PACKAGE_NEW_JAVA_INTERFACE = "java.view.package.newJavaInterface"; @@ -136,6 +134,8 @@ export namespace Commands { export const JAVA_PROJECT_CHECK_IMPORT_STATUS = "java.project.checkImportStatus"; + export const JAVA_UPGRADE_TRIGGER_UPGRADE = "_java.upgrade.triggerUpgrade"; + /** * Commands from Visual Studio Code */ diff --git a/src/upgrade/display/notificationManager.ts b/src/upgrade/display/notificationManager.ts index 95becf62..2213b7ee 100644 --- a/src/upgrade/display/notificationManager.ts +++ b/src/upgrade/display/notificationManager.ts @@ -45,7 +45,7 @@ class NotificationManager { switch (selection) { case BUTTON_TEXT_UPGRADE: { - commands.executeCommand(Commands.VIEW_TRIGGER_JAVA_UPGRADE_TOOL, prompt); + commands.executeCommand(Commands.JAVA_UPGRADE_TRIGGER_UPGRADE, prompt); break; } case BUTTON_TEXT_NOT_NOW: { diff --git a/src/upgrade/upgradeManager.ts b/src/upgrade/upgradeManager.ts index 9f63bcec..a4c631d3 100644 --- a/src/upgrade/upgradeManager.ts +++ b/src/upgrade/upgradeManager.ts @@ -131,7 +131,7 @@ class UpgradeManager { notificationManager.initialize(context); // Commands to be used - context.subscriptions.push(instrumentOperationAsVsCodeCommand(Commands.VIEW_TRIGGER_JAVA_UPGRADE_TOOL, async (promptText?: string) => { + context.subscriptions.push(instrumentOperationAsVsCodeCommand(Commands.JAVA_UPGRADE_TRIGGER_UPGRADE, async (promptText?: string) => { const promptToUse = promptText ?? DEFAULT_UPGRADE_PROMPT; // The command should typically exist as we checked for the extension before. const hasAgentModeCommand = (await commands.getCommands(true).then(cmds => cmds.includes(Commands.GOTO_AGENT_MODE))); From 76a8261a7094fa9366d86eee76d1a62cc29486ad Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Fri, 12 Sep 2025 15:21:09 +0800 Subject: [PATCH 36/73] chore: change JRE package ID to `java:*` --- src/constants.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/constants.ts b/src/constants.ts index 0648b368..6617975e 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -38,7 +38,7 @@ export namespace ExtensionName { } export namespace Upgrade { - export const PACKAGE_ID_FOR_JAVA_RUNTIME = "java-runtime:*"; + export const PACKAGE_ID_FOR_JAVA_RUNTIME = "java:*"; export const LATEST_JAVA_LTS_VESRION = 21; export const SESSION_COUNT_BEFORE_NOTIFICATION_RESHOW = 3; } From 56084e63c1fbcdc71c7fa1def1051c2723c2d18c Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Fri, 12 Sep 2025 15:26:01 +0800 Subject: [PATCH 37/73] chore: centralize `LATEST_JAVA_LTS_VESRION` and `SESSION_COUNT_BEFORE_NOTIFICATION_RESHOW` to individual files --- src/constants.ts | 2 -- src/upgrade/dependency.data.ts | 7 ++++++- src/upgrade/display/notificationManager.ts | 5 +++-- src/upgrade/type.ts | 2 +- src/upgrade/upgradeManager.ts | 11 ++++++----- 5 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/constants.ts b/src/constants.ts index 6617975e..659e67ca 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -39,8 +39,6 @@ export namespace ExtensionName { export namespace Upgrade { export const PACKAGE_ID_FOR_JAVA_RUNTIME = "java:*"; - export const LATEST_JAVA_LTS_VESRION = 21; - export const SESSION_COUNT_BEFORE_NOTIFICATION_RESHOW = 3; } /** diff --git a/src/upgrade/dependency.data.ts b/src/upgrade/dependency.data.ts index 8d47d69c..40450fdd 100644 --- a/src/upgrade/dependency.data.ts +++ b/src/upgrade/dependency.data.ts @@ -4,10 +4,13 @@ import { Upgrade } from "../constants"; import { UpgradeReason, type DependencyCheckMetadata } from "./type"; +const LATEST_JAVA_LTS_VESRION = 21; + export const DEPENDENCY_JAVA_RUNTIME = { "name": "Java Runtime", "reason": UpgradeReason.JRE_TOO_OLD, - "supportedVersion": `>=${Upgrade.LATEST_JAVA_LTS_VESRION}`, + "supportedVersion": `>=${LATEST_JAVA_LTS_VESRION}`, + "suggestedVersion": String(LATEST_JAVA_LTS_VESRION), } as const; const DEPENDENCIES_TO_SCAN: DependencyCheckMetadata = { @@ -15,11 +18,13 @@ const DEPENDENCIES_TO_SCAN: DependencyCheckMetadata = { "reason": UpgradeReason.END_OF_LIFE, "name": "Spring Boot", "supportedVersion": "2.7.x || >=3.2.x", + "suggestedVersion": "6.2", }, "org.springframework:*": { "reason": UpgradeReason.END_OF_LIFE, "name": "Spring Framework", "supportedVersion": "5.3.x || >=6.2.x", + "suggestedVersion": "3.5" }, "javax:javaee-api": { "reason": UpgradeReason.DEPRECATED, diff --git a/src/upgrade/display/notificationManager.ts b/src/upgrade/display/notificationManager.ts index 2213b7ee..896bca17 100644 --- a/src/upgrade/display/notificationManager.ts +++ b/src/upgrade/display/notificationManager.ts @@ -5,7 +5,6 @@ import { commands, ExtensionContext, window } from "vscode"; import type { UpgradeIssue } from "../type"; import { buildFixPrompt, buildNotificationMessage } from "../utility"; import { Commands } from "../../commands"; -import { Upgrade } from "../../constants"; const KEY_PREFIX = 'javaupgrade.notificationManager'; const IS_CANDIDATE_KEY = `${KEY_PREFIX}.isCandidate`; @@ -15,6 +14,8 @@ const BUTTON_TEXT_UPGRADE = "Upgrade Now"; const BUTTON_TEXT_NOT_NOW = "Not Now"; const BUTTON_TEXT_DONT_SHOW_AGAIN = "Don't Show Again"; +const SESSION_COUNT_BEFORE_NOTIFICATION_RESHOW = 3; + class NotificationManager { private hasShown = false; private context?: ExtensionContext; @@ -49,7 +50,7 @@ class NotificationManager { break; } case BUTTON_TEXT_NOT_NOW: { - this.setSessionCount(-1 * Upgrade.SESSION_COUNT_BEFORE_NOTIFICATION_RESHOW); + this.setSessionCount(-1 * SESSION_COUNT_BEFORE_NOTIFICATION_RESHOW); break; } case BUTTON_TEXT_DONT_SHOW_AGAIN: { diff --git a/src/upgrade/type.ts b/src/upgrade/type.ts index 5bcbed64..292dd91c 100644 --- a/src/upgrade/type.ts +++ b/src/upgrade/type.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. export type DependencyCheckItemBase = { name: string, reason: UpgradeReason }; -export type DependencyCheckItemEol = DependencyCheckItemBase & { reason: UpgradeReason.END_OF_LIFE | UpgradeReason.JRE_TOO_OLD, supportedVersion: string }; +export type DependencyCheckItemEol = DependencyCheckItemBase & { reason: UpgradeReason.END_OF_LIFE | UpgradeReason.JRE_TOO_OLD, supportedVersion: string, suggestedVersion: string }; export type DependencyCheckItemDeprecated = DependencyCheckItemBase & { reason: UpgradeReason.DEPRECATED, alternative: string }; export type DependencyCheckItem = (DependencyCheckItemEol | DependencyCheckItemDeprecated); export type DependencyCheckMetadata = Record; diff --git a/src/upgrade/upgradeManager.ts b/src/upgrade/upgradeManager.ts index a4c631d3..78a7b336 100644 --- a/src/upgrade/upgradeManager.ts +++ b/src/upgrade/upgradeManager.ts @@ -20,17 +20,18 @@ const DEFAULT_UPGRADE_PROMPT = "Upgrade Java project dependency to latest versio function getJavaIssues(data: INodeData): UpgradeIssue[] { const javaVersion = data.metaData?.MaxSourceVersion as number | undefined; - const javaSupportedVersionDefinition = DEPENDENCY_JAVA_RUNTIME; + const { name, reason, supportedVersion, suggestedVersion } = DEPENDENCY_JAVA_RUNTIME; if (!javaVersion) { return []; } - if (javaVersion < Upgrade.LATEST_JAVA_LTS_VESRION) { + const currentSemVer = semver.coerce(javaVersion); + if (currentSemVer && !semver.satisfies(currentSemVer, supportedVersion)) { return [{ packageId: Upgrade.PACKAGE_ID_FOR_JAVA_RUNTIME, - packageDisplayName: javaSupportedVersionDefinition.name, - reason: javaSupportedVersionDefinition.reason, + packageDisplayName: name, currentVersion: String(javaVersion), - suggestedVersion: String(Upgrade.LATEST_JAVA_LTS_VESRION), + reason, + suggestedVersion, }]; } From 28d2ee469832149d76a7c8d1e9e029110873d15e Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Fri, 12 Sep 2025 15:27:51 +0800 Subject: [PATCH 38/73] chore: `_java.upgrade.triggerUpgrade` -> `_java.upgradeWithCopilot` --- package.json | 4 ++-- package.nls.json | 2 +- src/commands.ts | 2 +- src/upgrade/display/notificationManager.ts | 2 +- src/upgrade/upgradeManager.ts | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 769bb7ff..d7ddd7a1 100644 --- a/package.json +++ b/package.json @@ -295,8 +295,8 @@ "category": "Java" }, { - "command": "_java.upgrade.triggerUpgrade", - "title": "%contributes.commands.java.upgrade.triggerUpgrade%", + "command": "_java.upgradeWithCopilot", + "title": "%contributes.commands.java.upgradeWithCopilot%", "category": "Java" } ], diff --git a/package.nls.json b/package.nls.json index 922cf348..146acea2 100644 --- a/package.nls.json +++ b/package.nls.json @@ -39,7 +39,7 @@ "contributes.commands.java.view.fileExplorer.newPackage": "New Java Package...", "contributes.submenus.javaProject.new": "New", "contributes.commands.java.view.menus.file.newJavaClass": "New Java File", - "contributes.commands.java.upgrade.triggerUpgrade": "Upgrade dependencies", + "contributes.commands.java.upgradeWithCopilot": "Upgrade dependencies", "configuration.java.dependency.showMembers": "Show the members in the explorer", "configuration.java.dependency.syncWithFolderExplorer": "Link Java Projects Explorer with the active editor", "configuration.java.dependency.autoRefresh": "Synchronize Java Projects explorer with changes", diff --git a/src/commands.ts b/src/commands.ts index 2d6b24c7..f3887ef7 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -134,7 +134,7 @@ export namespace Commands { export const JAVA_PROJECT_CHECK_IMPORT_STATUS = "java.project.checkImportStatus"; - export const JAVA_UPGRADE_TRIGGER_UPGRADE = "_java.upgrade.triggerUpgrade"; + export const JAVA_UPGRADE_WITH_COPILOT = "_java.upgradeWithCopilot"; /** * Commands from Visual Studio Code diff --git a/src/upgrade/display/notificationManager.ts b/src/upgrade/display/notificationManager.ts index 896bca17..534c978a 100644 --- a/src/upgrade/display/notificationManager.ts +++ b/src/upgrade/display/notificationManager.ts @@ -46,7 +46,7 @@ class NotificationManager { switch (selection) { case BUTTON_TEXT_UPGRADE: { - commands.executeCommand(Commands.JAVA_UPGRADE_TRIGGER_UPGRADE, prompt); + commands.executeCommand(Commands.JAVA_UPGRADE_WITH_COPILOT, prompt); break; } case BUTTON_TEXT_NOT_NOW: { diff --git a/src/upgrade/upgradeManager.ts b/src/upgrade/upgradeManager.ts index 78a7b336..a6b57429 100644 --- a/src/upgrade/upgradeManager.ts +++ b/src/upgrade/upgradeManager.ts @@ -132,7 +132,7 @@ class UpgradeManager { notificationManager.initialize(context); // Commands to be used - context.subscriptions.push(instrumentOperationAsVsCodeCommand(Commands.JAVA_UPGRADE_TRIGGER_UPGRADE, async (promptText?: string) => { + context.subscriptions.push(instrumentOperationAsVsCodeCommand(Commands.JAVA_UPGRADE_WITH_COPILOT, async (promptText?: string) => { const promptToUse = promptText ?? DEFAULT_UPGRADE_PROMPT; // The command should typically exist as we checked for the extension before. const hasAgentModeCommand = (await commands.getCommands(true).then(cmds => cmds.includes(Commands.GOTO_AGENT_MODE))); From 2789537642e07fa966b7204169b6fa0ae0713ffc Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Fri, 12 Sep 2025 15:29:42 +0800 Subject: [PATCH 39/73] chore: no need for `PomPath` --- .../jdtls/ext/core/model/PackageNode.java | 6 ------ src/upgrade/upgradeManager.ts | 16 ++++------------ 2 files changed, 4 insertions(+), 18 deletions(-) diff --git a/jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/model/PackageNode.java b/jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/model/PackageNode.java index 90864f01..92fa4cf7 100644 --- a/jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/model/PackageNode.java +++ b/jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/model/PackageNode.java @@ -88,8 +88,6 @@ public class PackageNode { private static final String MAX_SOURCE_VERSION = "MaxSourceVersion"; - private static final String POM_PATH = "PomPath"; - /** * The name of the PackageNode. */ @@ -183,10 +181,6 @@ public static PackageNode createNodeForProject(IJavaElement javaElement) { int jdkLevel = (int) (CompilerOptions.versionToJdkLevel(sourceVersion, true) >>> 16); int majorVersion = Math.max(0, jdkLevel - ClassFileConstants.MAJOR_VERSION_0); projectNode.setMetaDataValue(MAX_SOURCE_VERSION, majorVersion); - IFile existingPom = proj.getFile("pom.xml"); - if (existingPom.exists()) { - projectNode.setMetaDataValue(POM_PATH, existingPom.getLocation().toOSString()); - } } catch (CoreException e) { // do nothing } diff --git a/src/upgrade/upgradeManager.ts b/src/upgrade/upgradeManager.ts index a6b57429..42e945f1 100644 --- a/src/upgrade/upgradeManager.ts +++ b/src/upgrade/upgradeManager.ts @@ -84,10 +84,6 @@ function getDependencyIssues(data: INodeData): UpgradeIssue[] { } async function getProjectIssues(projectNode: INodeData): Promise { - const pomPath = projectNode.metaData?.PomPath as string | undefined; - if (!pomPath) { - return []; - } const issues: UpgradeIssue[] = []; issues.push(...getJavaIssues(projectNode)); if (issues.length > 0) { @@ -169,23 +165,19 @@ class UpgradeManager { return; } - const projectIssues: Record = {}; + const projectIssues: UpgradeIssue[] = []; const uri = folder.uri.toString(); const projects = await Jdtls.getProjects(uri); - let hasIssues = false; await Promise.allSettled(projects.map(async (projectNode) => { - const pomPath = projectNode.metaData?.PomPath as string | undefined ?? "Unknown POM path"; - const issues = await getProjectIssues(projectNode); if (issues.length > 0) { - hasIssues = true; - projectIssues[pomPath] = issues; + projectIssues.push(...issues); } })); - if (hasIssues) { + if (projectIssues.length > 0) { // only show one issue in notifications - notificationManager.triggerNotification(Object.values(projectIssues)[0][0]); + notificationManager.triggerNotification(projectIssues[0]); } } } From 1f0a36f653297e54caada1d3c5cc2f06e5808758 Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Fri, 12 Sep 2025 15:34:06 +0800 Subject: [PATCH 40/73] fix(notificationManager): use settings to control whether to send notification --- src/settings.ts | 4 ++++ src/upgrade/display/notificationManager.ts | 14 +++----------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/settings.ts b/src/settings.ts index 5c44a850..4ea7edb3 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -58,6 +58,10 @@ export class Settings { workspace.getConfiguration("java.dependency").update("packagePresentation", PackagePresentation.Hierarchical, false); } + public static disableWorkspaceDependencyDiagnostics() { + return workspace.getConfiguration("java.dependency").update("enableDependencyDiagnostics", false, ConfigurationTarget.Workspace); + } + public static switchNonJavaResourceFilter(enabled: boolean): void { workspace.getConfiguration("java.project.explorer").update( "showNonJavaResources", diff --git a/src/upgrade/display/notificationManager.ts b/src/upgrade/display/notificationManager.ts index 534c978a..760e2506 100644 --- a/src/upgrade/display/notificationManager.ts +++ b/src/upgrade/display/notificationManager.ts @@ -5,9 +5,9 @@ import { commands, ExtensionContext, window } from "vscode"; import type { UpgradeIssue } from "../type"; import { buildFixPrompt, buildNotificationMessage } from "../utility"; import { Commands } from "../../commands"; +import { Settings } from "../../settings"; const KEY_PREFIX = 'javaupgrade.notificationManager'; -const IS_CANDIDATE_KEY = `${KEY_PREFIX}.isCandidate`; const SESSION_COUNT_KEY = `${KEY_PREFIX}.sessionCount`; const BUTTON_TEXT_UPGRADE = "Upgrade Now"; @@ -54,7 +54,7 @@ class NotificationManager { break; } case BUTTON_TEXT_DONT_SHOW_AGAIN: { - this.setCandidate(false); + Settings.disableWorkspaceDependencyDiagnostics(); break; } } @@ -62,7 +62,7 @@ class NotificationManager { } private shouldShow() { - return this.isCandidate() + return Settings.getEnableDependencyDiagnostics() && ((this.getSessionCount() ?? 0) >= 0); } @@ -73,14 +73,6 @@ class NotificationManager { private setSessionCount(num: number) { return this.context?.globalState.update(SESSION_COUNT_KEY, num); } - - private isCandidate() { - return this.context?.globalState.get(IS_CANDIDATE_KEY, true); - } - - private setCandidate(isCandidate: boolean) { - this.context?.globalState.update(IS_CANDIDATE_KEY, isCandidate); - } } const notificationManager = new NotificationManager(); From fbe2d5fb760d3aaf65abceb8f8b6a911cb0028a0 Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Fri, 12 Sep 2025 15:37:54 +0800 Subject: [PATCH 41/73] chore: split assessment part to `assessmentManager` --- src/upgrade/assessmentManager.ts | 107 ++++++++++++++++++++++++++++++ src/upgrade/upgradeManager.ts | 108 ++----------------------------- 2 files changed, 113 insertions(+), 102 deletions(-) create mode 100644 src/upgrade/assessmentManager.ts diff --git a/src/upgrade/assessmentManager.ts b/src/upgrade/assessmentManager.ts new file mode 100644 index 00000000..6827bd00 --- /dev/null +++ b/src/upgrade/assessmentManager.ts @@ -0,0 +1,107 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +import * as semver from 'semver'; +import { Jdtls } from "../java/jdtls"; +import { NodeKind, type INodeData } from "../java/nodeData"; +import { type DependencyCheckItem, UpgradeReason, type UpgradeIssue } from "./type"; +import { DEPENDENCY_JAVA_RUNTIME } from "./dependency.data"; +import { Upgrade } from '../constants'; +import { buildPackageId } from './utility'; +import metadataManager from './metadataManager'; + +function getJavaIssues(data: INodeData): UpgradeIssue[] { + const javaVersion = data.metaData?.MaxSourceVersion as number | undefined; + const { name, reason, supportedVersion, suggestedVersion } = DEPENDENCY_JAVA_RUNTIME; + if (!javaVersion) { + return []; + } + const currentSemVer = semver.coerce(javaVersion); + if (currentSemVer && !semver.satisfies(currentSemVer, supportedVersion)) { + return [{ + packageId: Upgrade.PACKAGE_ID_FOR_JAVA_RUNTIME, + packageDisplayName: name, + currentVersion: String(javaVersion), + reason, + suggestedVersion, + }]; + } + + return []; +} + +function getUpgrade(versionString: string, supportedVersionDefinition: DependencyCheckItem): Omit | null { + const { reason } = supportedVersionDefinition; + switch (reason) { + case UpgradeReason.DEPRECATED: { + const { alternative } = supportedVersionDefinition; + return { + packageDisplayName: supportedVersionDefinition.name, + reason, + currentVersion: versionString, + suggestedVersion: alternative, + } + } + case UpgradeReason.END_OF_LIFE: { + const currentSemVer = semver.coerce(versionString); + if (currentSemVer && !semver.satisfies(currentSemVer, supportedVersionDefinition.supportedVersion)) { + return { + packageDisplayName: supportedVersionDefinition.name, + reason, + currentVersion: versionString, + } + } + } + + } + + return null; +} + +function getDependencyIssues(data: INodeData): UpgradeIssue[] { + const versionString = data.metaData?.["maven.version"]; + const groupId = data.metaData?.["maven.groupId"]; + const artifactId = data.metaData?.["maven.artifactId"]; + const packageId = buildPackageId(groupId, artifactId); + const supportedVersionDefinition = metadataManager.getMetadataById(packageId); + if (!versionString || !groupId || !supportedVersionDefinition) { + return []; + } + + const upgrade = getUpgrade(versionString, supportedVersionDefinition); + if (upgrade) { + return [{ ...upgrade, packageId }]; + } + return []; +} + +async function getProjectIssues(projectNode: INodeData): Promise { + const issues: UpgradeIssue[] = []; + issues.push(...getJavaIssues(projectNode)); + if (issues.length > 0) { + // If Java runtime version issue is found, prompt for it only + return issues; + } + const packageData = await Jdtls.getPackageData({ kind: NodeKind.Project, projectUri: projectNode.uri }); + await Promise.allSettled( + packageData + .filter(x => x.kind === NodeKind.Container) + .map(async (packageContainer) => { + const packages = await Jdtls.getPackageData({ + kind: NodeKind.Container, + projectUri: projectNode.uri, + path: packageContainer.path, + }); + packages.forEach( + (pkg) => { + issues.push(...getDependencyIssues(pkg)) + } + ); + }) + ); + return issues; +} + +export default { + getProjectIssues +}; \ No newline at end of file diff --git a/src/upgrade/upgradeManager.ts b/src/upgrade/upgradeManager.ts index 42e945f1..3e6868ca 100644 --- a/src/upgrade/upgradeManager.ts +++ b/src/upgrade/upgradeManager.ts @@ -2,113 +2,19 @@ // Licensed under the MIT license. import { commands, type ExtensionContext, extensions, workspace, type WorkspaceFolder } from "vscode"; -import * as semver from 'semver' + import { Jdtls } from "../java/jdtls"; import { languageServerApiManager } from "../languageServerApi/languageServerApiManager"; -import { NodeKind, type INodeData } from "../java/nodeData"; -import { ExtensionName, Upgrade } from "../constants"; -import { DependencyCheckItem, UpgradeIssue, UpgradeReason } from "./type"; +import { ExtensionName } from "../constants"; +import { UpgradeIssue } from "./type"; import { instrumentOperationAsVsCodeCommand } from "vscode-extension-telemetry-wrapper"; import { Commands } from "../commands"; -import metadataManager from "./metadataManager"; -import { buildPackageId } from "./utility"; import notificationManager from "./display/notificationManager"; import { Settings } from "../settings"; -import { DEPENDENCY_JAVA_RUNTIME } from "./dependency.data"; +import assessmentManager from "./assessmentManager"; const DEFAULT_UPGRADE_PROMPT = "Upgrade Java project dependency to latest version."; -function getJavaIssues(data: INodeData): UpgradeIssue[] { - const javaVersion = data.metaData?.MaxSourceVersion as number | undefined; - const { name, reason, supportedVersion, suggestedVersion } = DEPENDENCY_JAVA_RUNTIME; - if (!javaVersion) { - return []; - } - const currentSemVer = semver.coerce(javaVersion); - if (currentSemVer && !semver.satisfies(currentSemVer, supportedVersion)) { - return [{ - packageId: Upgrade.PACKAGE_ID_FOR_JAVA_RUNTIME, - packageDisplayName: name, - currentVersion: String(javaVersion), - reason, - suggestedVersion, - }]; - } - - return []; -} - -function getUpgrade(versionString: string, supportedVersionDefinition: DependencyCheckItem): Omit | null { - const { reason } = supportedVersionDefinition; - switch (reason) { - case UpgradeReason.DEPRECATED: { - const { alternative } = supportedVersionDefinition; - return { - packageDisplayName: supportedVersionDefinition.name, - reason, - currentVersion: versionString, - suggestedVersion: alternative, - } - } - case UpgradeReason.END_OF_LIFE: { - const currentSemVer = semver.coerce(versionString); - if (currentSemVer && !semver.satisfies(currentSemVer, supportedVersionDefinition.supportedVersion)) { - return { - packageDisplayName: supportedVersionDefinition.name, - reason, - currentVersion: versionString, - } - } - } - - } - - return null; -} - -function getDependencyIssues(data: INodeData): UpgradeIssue[] { - const versionString = data.metaData?.["maven.version"]; - const groupId = data.metaData?.["maven.groupId"]; - const artifactId = data.metaData?.["maven.artifactId"]; - const packageId = buildPackageId(groupId, artifactId); - const supportedVersionDefinition = metadataManager.getMetadataById(packageId); - if (!versionString || !groupId || !supportedVersionDefinition) { - return []; - } - - const upgrade = getUpgrade(versionString, supportedVersionDefinition); - if (upgrade) { - return [{ ...upgrade, packageId }]; - } - return []; -} - -async function getProjectIssues(projectNode: INodeData): Promise { - const issues: UpgradeIssue[] = []; - issues.push(...getJavaIssues(projectNode)); - if (issues.length > 0) { - // If Java runtime version issue is found, prompt for it only - return issues; - } - const packageData = await Jdtls.getPackageData({ kind: NodeKind.Project, projectUri: projectNode.uri }); - await Promise.allSettled( - packageData - .filter(x => x.kind === NodeKind.Container) - .map(async (packageContainer) => { - const packages = await Jdtls.getPackageData({ - kind: NodeKind.Container, - projectUri: projectNode.uri, - path: packageContainer.path, - }); - packages.forEach( - (pkg) => { - issues.push(...getDependencyIssues(pkg)) - } - ); - }) - ); - return issues; -} function shouldCheckUpgrade() { return Settings.getEnableDependencyDiagnostics() @@ -169,10 +75,8 @@ class UpgradeManager { const uri = folder.uri.toString(); const projects = await Jdtls.getProjects(uri); await Promise.allSettled(projects.map(async (projectNode) => { - const issues = await getProjectIssues(projectNode); - if (issues.length > 0) { - projectIssues.push(...issues); - } + const issues = await assessmentManager.getProjectIssues(projectNode); + projectIssues.push(...issues); })); if (projectIssues.length > 0) { From 790a5eaf6fcbcde982dadfd066c2c793b90a43e2 Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Fri, 12 Sep 2025 15:40:32 +0800 Subject: [PATCH 42/73] feat: use `DisplayInterface` to organize user faced presentations --- src/upgrade/display/notificationManager.ts | 11 ++++++++--- src/upgrade/type.ts | 6 +++++- src/upgrade/upgradeManager.ts | 2 +- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/upgrade/display/notificationManager.ts b/src/upgrade/display/notificationManager.ts index 760e2506..513719d2 100644 --- a/src/upgrade/display/notificationManager.ts +++ b/src/upgrade/display/notificationManager.ts @@ -2,7 +2,7 @@ // Licensed under the MIT license. import { commands, ExtensionContext, window } from "vscode"; -import type { UpgradeIssue } from "../type"; +import type { DisplayInterface, UpgradeIssue } from "../type"; import { buildFixPrompt, buildNotificationMessage } from "../utility"; import { Commands } from "../../commands"; import { Settings } from "../../settings"; @@ -16,7 +16,7 @@ const BUTTON_TEXT_DONT_SHOW_AGAIN = "Don't Show Again"; const SESSION_COUNT_BEFORE_NOTIFICATION_RESHOW = 3; -class NotificationManager { +class NotificationManager implements DisplayInterface { private hasShown = false; private context?: ExtensionContext; @@ -24,7 +24,12 @@ class NotificationManager { this.context = context; } - async triggerNotification(issue: UpgradeIssue) { + async render(issues: UpgradeIssue[]) { + if (issues.length === 0) { + return; + } + const issue = issues[0]; + if (this.hasShown) { return; } diff --git a/src/upgrade/type.ts b/src/upgrade/type.ts index 292dd91c..edf99789 100644 --- a/src/upgrade/type.ts +++ b/src/upgrade/type.ts @@ -19,4 +19,8 @@ export type UpgradeIssue = { reason: UpgradeReason; currentVersion: string; suggestedVersion?: string; -}; \ No newline at end of file +}; + +export interface DisplayInterface { + render(issues: UpgradeIssue[]): void; +} \ No newline at end of file diff --git a/src/upgrade/upgradeManager.ts b/src/upgrade/upgradeManager.ts index 3e6868ca..522ddbb0 100644 --- a/src/upgrade/upgradeManager.ts +++ b/src/upgrade/upgradeManager.ts @@ -81,7 +81,7 @@ class UpgradeManager { if (projectIssues.length > 0) { // only show one issue in notifications - notificationManager.triggerNotification(projectIssues[0]); + notificationManager.render(projectIssues); } } } From 1872705f97d93b2e7422844fd14f441cf67aa5a9 Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Fri, 12 Sep 2025 15:46:51 +0800 Subject: [PATCH 43/73] chore: string improvements --- package.nls.json | 2 +- src/upgrade/utility.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.nls.json b/package.nls.json index 146acea2..8857731a 100644 --- a/package.nls.json +++ b/package.nls.json @@ -45,7 +45,7 @@ "configuration.java.dependency.autoRefresh": "Synchronize Java Projects explorer with changes", "configuration.java.dependency.refreshDelay": "The delay time (ms) the auto refresh is invoked when changes are detected", "configuration.java.dependency.packagePresentation": "Package presentation mode: flat or hierarchical", - "configuration.java.dependency.enableDependencyDiagnostics": "Show upgrade reminders for Java runtime or dependencies.", + "configuration.java.dependency.enableDependencyDiagnostics": "Show reminders when your Java runtimes or dependencies need an upgrade.", "configuration.java.project.explorer.showNonJavaResources": "When enabled, the explorer shows non-Java resources.", "configuration.java.project.exportJar.targetPath.customization": "The output path of the exported jar. Leave it empty if you want to manually pick the output location.", "configuration.java.project.exportJar.targetPath.workspaceFolder": "Export the jar file into the workspace folder. Its name is the same as the folder's.", diff --git a/src/upgrade/utility.ts b/src/upgrade/utility.ts index daa1fd8c..ff33c19b 100644 --- a/src/upgrade/utility.ts +++ b/src/upgrade/utility.ts @@ -13,7 +13,7 @@ export function buildNotificationMessage(issue: UpgradeIssue): string { return `The current project is using an older runtime (Java ${currentVersion}). Do you want to upgrade to the latest LTS version${suggestedVersion ? ` (${suggestedVersion})` : ""}?` } - return `The current project is using ${name} ${currentVersion}, which reached end of life. Do you want to upgrade to ${suggestedVersion ? ` ${suggestedVersion}` : "the latest version" + return `The current project is using ${name} ${currentVersion}, which has reached end of life. Do you want to upgrade to ${suggestedVersion ? ` ${suggestedVersion}` : "the latest version" }?` } From e9b6917c17deb8e7aa896147f5e9735f5eba1ae2 Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Fri, 12 Sep 2025 16:59:41 +0800 Subject: [PATCH 44/73] chore: get all issues for notification --- src/upgrade/assessmentManager.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/upgrade/assessmentManager.ts b/src/upgrade/assessmentManager.ts index 6827bd00..a15b4173 100644 --- a/src/upgrade/assessmentManager.ts +++ b/src/upgrade/assessmentManager.ts @@ -78,10 +78,6 @@ function getDependencyIssues(data: INodeData): UpgradeIssue[] { async function getProjectIssues(projectNode: INodeData): Promise { const issues: UpgradeIssue[] = []; issues.push(...getJavaIssues(projectNode)); - if (issues.length > 0) { - // If Java runtime version issue is found, prompt for it only - return issues; - } const packageData = await Jdtls.getPackageData({ kind: NodeKind.Project, projectUri: projectNode.uri }); await Promise.allSettled( packageData From e25d0b6a84613decfcd53b3d2b84e9c1d2b22bc5 Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Fri, 12 Sep 2025 17:22:29 +0800 Subject: [PATCH 45/73] feat: add telemetry --- src/upgrade/display/notificationManager.ts | 90 +++++++++++++--------- src/upgrade/upgradeManager.ts | 45 ++++++----- 2 files changed, 78 insertions(+), 57 deletions(-) diff --git a/src/upgrade/display/notificationManager.ts b/src/upgrade/display/notificationManager.ts index 513719d2..6132fea5 100644 --- a/src/upgrade/display/notificationManager.ts +++ b/src/upgrade/display/notificationManager.ts @@ -6,6 +6,7 @@ import type { DisplayInterface, UpgradeIssue } from "../type"; import { buildFixPrompt, buildNotificationMessage } from "../utility"; import { Commands } from "../../commands"; import { Settings } from "../../settings"; +import { instrumentOperation, sendInfo } from "vscode-extension-telemetry-wrapper"; const KEY_PREFIX = 'javaupgrade.notificationManager'; const SESSION_COUNT_KEY = `${KEY_PREFIX}.sessionCount`; @@ -25,45 +26,58 @@ class NotificationManager implements DisplayInterface { } async render(issues: UpgradeIssue[]) { - if (issues.length === 0) { - return; - } - const issue = issues[0]; - - if (this.hasShown) { - return; - } - this.hasShown = true; - - this.setSessionCount((this.getSessionCount() ?? 0) + 1); - - if (!this.shouldShow()) { - return; - } - - const prompt = buildFixPrompt(issue); - const notificationMessage = buildNotificationMessage(issue); - const selection = await window.showInformationMessage( - notificationMessage, - BUTTON_TEXT_UPGRADE, - BUTTON_TEXT_NOT_NOW, - BUTTON_TEXT_DONT_SHOW_AGAIN); - - switch (selection) { - case BUTTON_TEXT_UPGRADE: { - commands.executeCommand(Commands.JAVA_UPGRADE_WITH_COPILOT, prompt); - break; + return (instrumentOperation( + "notificationManager.render", + async (operationId: string) => { + if (issues.length === 0) { + return; + } + const issue = issues[0]; + + if (this.hasShown) { + return; + } + this.hasShown = true; + + this.setSessionCount((this.getSessionCount() ?? 0) + 1); + + if (!this.shouldShow()) { + return; + } + + const prompt = buildFixPrompt(issue); + const notificationMessage = buildNotificationMessage(issue); + const selection = await window.showInformationMessage( + notificationMessage, + BUTTON_TEXT_UPGRADE, + BUTTON_TEXT_NOT_NOW, + BUTTON_TEXT_DONT_SHOW_AGAIN); + + switch (selection) { + case BUTTON_TEXT_UPGRADE: { + commands.executeCommand(Commands.JAVA_UPGRADE_WITH_COPILOT, prompt); + sendInfo(operationId, { + __event_name__: "javaDependency.notificationManager.runUpgrade", + }); + break; + } + case BUTTON_TEXT_NOT_NOW: { + this.setSessionCount(-1 * SESSION_COUNT_BEFORE_NOTIFICATION_RESHOW); + sendInfo(operationId, { + __event_name__: "javaDependency.notificationManager.notNow", + }); + break; + } + case BUTTON_TEXT_DONT_SHOW_AGAIN: { + Settings.disableWorkspaceDependencyDiagnostics(); + sendInfo(operationId, { + __event_name__: "javaDependency.notificationManager.dontShowAgain", + }); + break; + } + } } - case BUTTON_TEXT_NOT_NOW: { - this.setSessionCount(-1 * SESSION_COUNT_BEFORE_NOTIFICATION_RESHOW); - break; - } - case BUTTON_TEXT_DONT_SHOW_AGAIN: { - Settings.disableWorkspaceDependencyDiagnostics(); - break; - } - } - + ))() } private shouldShow() { diff --git a/src/upgrade/upgradeManager.ts b/src/upgrade/upgradeManager.ts index 522ddbb0..6936bd15 100644 --- a/src/upgrade/upgradeManager.ts +++ b/src/upgrade/upgradeManager.ts @@ -7,7 +7,7 @@ import { Jdtls } from "../java/jdtls"; import { languageServerApiManager } from "../languageServerApi/languageServerApiManager"; import { ExtensionName } from "../constants"; import { UpgradeIssue } from "./type"; -import { instrumentOperationAsVsCodeCommand } from "vscode-extension-telemetry-wrapper"; +import { instrumentOperation, instrumentOperationAsVsCodeCommand, sendInfo } from "vscode-extension-telemetry-wrapper"; import { Commands } from "../commands"; import notificationManager from "./display/notificationManager"; import { Settings } from "../settings"; @@ -63,26 +63,33 @@ class UpgradeManager { } private static async checkUpgradableComponents(folder: WorkspaceFolder) { - if (!await languageServerApiManager.ready()) { - return; - } - const hasJavaError: boolean = await Jdtls.checkImportStatus(); - if (hasJavaError) { - return; - } + return (instrumentOperation("upgradeManager.checkUpgradableComponents", + async (operationId: string) => { + if (!await languageServerApiManager.ready()) { + return; + } + const hasJavaError: boolean = await Jdtls.checkImportStatus(); + if (hasJavaError) { + return; + } - const projectIssues: UpgradeIssue[] = []; - const uri = folder.uri.toString(); - const projects = await Jdtls.getProjects(uri); - await Promise.allSettled(projects.map(async (projectNode) => { - const issues = await assessmentManager.getProjectIssues(projectNode); - projectIssues.push(...issues); - })); + const projectIssues: UpgradeIssue[] = []; + const uri = folder.uri.toString(); + const projects = await Jdtls.getProjects(uri); + await Promise.allSettled(projects.map(async (projectNode) => { + const issues = await assessmentManager.getProjectIssues(projectNode); + projectIssues.push(...issues); + sendInfo(operationId, { + issuesFoundForPackageId: projectIssues.map(x => x.packageId).join(","), + }); + })); - if (projectIssues.length > 0) { - // only show one issue in notifications - notificationManager.render(projectIssues); - } + if (projectIssues.length > 0) { + // only show one issue in notifications + notificationManager.render(projectIssues); + } + } + ))() } } From 46f78a8e92626640d82c409ac8a0484c9c6685d3 Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Fri, 12 Sep 2025 17:26:57 +0800 Subject: [PATCH 46/73] fix: add current version to telemetry --- src/upgrade/upgradeManager.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/upgrade/upgradeManager.ts b/src/upgrade/upgradeManager.ts index 6936bd15..908f4c8e 100644 --- a/src/upgrade/upgradeManager.ts +++ b/src/upgrade/upgradeManager.ts @@ -80,7 +80,7 @@ class UpgradeManager { const issues = await assessmentManager.getProjectIssues(projectNode); projectIssues.push(...issues); sendInfo(operationId, { - issuesFoundForPackageId: projectIssues.map(x => x.packageId).join(","), + issuesFoundForPackageId: projectIssues.map(x => `${x.packageId}:${x.currentVersion}`).join(","), }); })); From c2c4cf65d15547420af89c904aa66bf86644b85a Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Fri, 12 Sep 2025 17:35:35 +0800 Subject: [PATCH 47/73] chore: restore formatting --- package.nls.json | 10 +++++----- src/upgrade/type.ts | 1 + 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/package.nls.json b/package.nls.json index 8857731a..e29c95f4 100644 --- a/package.nls.json +++ b/package.nls.json @@ -12,10 +12,10 @@ "contributes.commands.java.project.update": "Reload Project", "contributes.commands.java.project.reloadProjectFromActiveFile": "Reload Java Project", "contributes.commands.java.view.package.revealInProjectExplorer": "Reveal in Java Project Explorer", - "contributes.commands.java.view.package.changeToFlatPackageView": "Flat View", - "contributes.commands.java.view.package.changeToHierarchicalPackageView": "Hierarchical View", - "contributes.commands.java.view.package.linkWithFolderExplorer": "Link with Editor", - "contributes.commands.java.view.package.unlinkWithFolderExplorer": "Unlink with Editor", + "contributes.commands.java.view.package.changeToFlatPackageView":"Flat View", + "contributes.commands.java.view.package.changeToHierarchicalPackageView":"Hierarchical View", + "contributes.commands.java.view.package.linkWithFolderExplorer":"Link with Editor", + "contributes.commands.java.view.package.unlinkWithFolderExplorer":"Unlink with Editor", "contributes.commands.java.project.explorer.showNonJavaResources": "Show Non-Java Resources", "contributes.commands.java.project.explorer.hideNonJavaResources": "Hide Non-Java Resources", "contributes.commands.java.view.package.revealFileInOS": "Reveal in Explorer", @@ -66,4 +66,4 @@ "viewsWelcome.workbench.importFailed": "Oops, something went wrong when opening Java projects. Please use the following action for troubleshooting:\n[Open Problems View](command:workbench.panel.markers.view.focus)", "viewsWelcome.workbench.inLightWeightMode": "To view the projects, you can import the projects into workspace.\n[Import Projects](command:java.server.mode.switch?%5B%22Standard%22,true%5D)", "viewsWelcome.workbench.installLanguageSupport": "The Java Projects explorer requires [Extension Pack for Java](command:extension.open?%5B%22vscjava.vscode-java-pack%22%5D) to provide full features.\n[Install](command:java.project.installExtension?%5B%22vscjava.vscode-java-pack%22%5D)" -} \ No newline at end of file +} diff --git a/src/upgrade/type.ts b/src/upgrade/type.ts index edf99789..1e14d0b0 100644 --- a/src/upgrade/type.ts +++ b/src/upgrade/type.ts @@ -1,5 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. + export type DependencyCheckItemBase = { name: string, reason: UpgradeReason }; export type DependencyCheckItemEol = DependencyCheckItemBase & { reason: UpgradeReason.END_OF_LIFE | UpgradeReason.JRE_TOO_OLD, supportedVersion: string, suggestedVersion: string }; export type DependencyCheckItemDeprecated = DependencyCheckItemBase & { reason: UpgradeReason.DEPRECATED, alternative: string }; From 1c1fef658500e6d2149772e0459b78c8f8b6bc54 Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Fri, 12 Sep 2025 18:13:55 +0800 Subject: [PATCH 48/73] fix: pass `suggestedVersion` to `UpgradeIssue` --- src/upgrade/assessmentManager.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/upgrade/assessmentManager.ts b/src/upgrade/assessmentManager.ts index a15b4173..302f0d5c 100644 --- a/src/upgrade/assessmentManager.ts +++ b/src/upgrade/assessmentManager.ts @@ -49,6 +49,7 @@ function getUpgrade(versionString: string, supportedVersionDefinition: Dependenc packageDisplayName: supportedVersionDefinition.name, reason, currentVersion: versionString, + suggestedVersion: supportedVersionDefinition.suggestedVersion, } } } From a3702927c76ff4af58de6358ef8c9d14772fba79 Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Mon, 15 Sep 2025 10:08:27 +0800 Subject: [PATCH 49/73] feat: update dependency data definition * Fix Spring Boot/Framework target version * Add Spring Security * Merge javax:{javaee-api,javaee-web-api} to javax:* (this adds `javax:javaee-endorsed-api` which is also Java EE) --- src/upgrade/dependency.data.ts | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/upgrade/dependency.data.ts b/src/upgrade/dependency.data.ts index 40450fdd..9104a54b 100644 --- a/src/upgrade/dependency.data.ts +++ b/src/upgrade/dependency.data.ts @@ -18,20 +18,21 @@ const DEPENDENCIES_TO_SCAN: DependencyCheckMetadata = { "reason": UpgradeReason.END_OF_LIFE, "name": "Spring Boot", "supportedVersion": "2.7.x || >=3.2.x", - "suggestedVersion": "6.2", + "suggestedVersion": "3.5", }, "org.springframework:*": { "reason": UpgradeReason.END_OF_LIFE, "name": "Spring Framework", "supportedVersion": "5.3.x || >=6.2.x", - "suggestedVersion": "3.5" + "suggestedVersion": "6.2" }, - "javax:javaee-api": { - "reason": UpgradeReason.DEPRECATED, - "name": "Java EE", - "alternative": "Jakarta EE 10", + "org.springframework.security:*": { + "reason": UpgradeReason.END_OF_LIFE, + "name": "Spring Security", + "supportedVersion": "5.7.x || 5.8.x || >=6.2.x", + "suggestedVersion": "6.5" }, - "javax:javaee-web-api": { + "javax:*": { "reason": UpgradeReason.DEPRECATED, "name": "Java EE", "alternative": "Jakarta EE 10", From 03c85fbfa68bd1def3d40cbb24a94ea877a9ff30 Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Mon, 15 Sep 2025 10:10:40 +0800 Subject: [PATCH 50/73] chore: update event names --- src/upgrade/display/notificationManager.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/upgrade/display/notificationManager.ts b/src/upgrade/display/notificationManager.ts index 6132fea5..4dcccab3 100644 --- a/src/upgrade/display/notificationManager.ts +++ b/src/upgrade/display/notificationManager.ts @@ -27,7 +27,7 @@ class NotificationManager implements DisplayInterface { async render(issues: UpgradeIssue[]) { return (instrumentOperation( - "notificationManager.render", + "java.dependency.showUpgradeNotification", async (operationId: string) => { if (issues.length === 0) { return; @@ -57,21 +57,21 @@ class NotificationManager implements DisplayInterface { case BUTTON_TEXT_UPGRADE: { commands.executeCommand(Commands.JAVA_UPGRADE_WITH_COPILOT, prompt); sendInfo(operationId, { - __event_name__: "javaDependency.notificationManager.runUpgrade", + __event_name__: "java.dependency.upgradeNotification.runUpgrade", }); break; } case BUTTON_TEXT_NOT_NOW: { this.setSessionCount(-1 * SESSION_COUNT_BEFORE_NOTIFICATION_RESHOW); sendInfo(operationId, { - __event_name__: "javaDependency.notificationManager.notNow", + __event_name__: "java.dependency.upgradeNotification.notNow", }); break; } case BUTTON_TEXT_DONT_SHOW_AGAIN: { Settings.disableWorkspaceDependencyDiagnostics(); sendInfo(operationId, { - __event_name__: "javaDependency.notificationManager.dontShowAgain", + __event_name__: "java.dependency.upgradeNotification.dontShowAgain", }); break; } From daf65c5f24661e3a5bf26927c85d3de58cc1f5ba Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Mon, 15 Sep 2025 10:46:57 +0800 Subject: [PATCH 51/73] chore(assessmentManager): refactor --- src/upgrade/assessmentManager.ts | 46 +++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/src/upgrade/assessmentManager.ts b/src/upgrade/assessmentManager.ts index 302f0d5c..497033a8 100644 --- a/src/upgrade/assessmentManager.ts +++ b/src/upgrade/assessmentManager.ts @@ -9,6 +9,7 @@ import { DEPENDENCY_JAVA_RUNTIME } from "./dependency.data"; import { Upgrade } from '../constants'; import { buildPackageId } from './utility'; import metadataManager from './metadataManager'; +import { sendInfo } from 'vscode-extension-telemetry-wrapper'; function getJavaIssues(data: INodeData): UpgradeIssue[] { const javaVersion = data.metaData?.MaxSourceVersion as number | undefined; @@ -59,29 +60,27 @@ function getUpgrade(versionString: string, supportedVersionDefinition: Dependenc return null; } -function getDependencyIssues(data: INodeData): UpgradeIssue[] { +function checkDependencyIssue(data: INodeData): UpgradeIssue | null { const versionString = data.metaData?.["maven.version"]; const groupId = data.metaData?.["maven.groupId"]; const artifactId = data.metaData?.["maven.artifactId"]; const packageId = buildPackageId(groupId, artifactId); const supportedVersionDefinition = metadataManager.getMetadataById(packageId); if (!versionString || !groupId || !supportedVersionDefinition) { - return []; + return null; } const upgrade = getUpgrade(versionString, supportedVersionDefinition); if (upgrade) { - return [{ ...upgrade, packageId }]; + return { ...upgrade, packageId }; } - return []; + return null; } -async function getProjectIssues(projectNode: INodeData): Promise { - const issues: UpgradeIssue[] = []; - issues.push(...getJavaIssues(projectNode)); - const packageData = await Jdtls.getPackageData({ kind: NodeKind.Project, projectUri: projectNode.uri }); - await Promise.allSettled( - packageData +async function getDependencyIssues(projectNode: INodeData): Promise { + const projectStructureData = await Jdtls.getPackageData({ kind: NodeKind.Project, projectUri: projectNode.uri }); + const packageContainerIssues = await Promise.allSettled( + projectStructureData .filter(x => x.kind === NodeKind.Container) .map(async (packageContainer) => { const packages = await Jdtls.getPackageData({ @@ -89,13 +88,30 @@ async function getProjectIssues(projectNode: INodeData): Promise projectUri: projectNode.uri, path: packageContainer.path, }); - packages.forEach( - (pkg) => { - issues.push(...getDependencyIssues(pkg)) - } - ); + + return packages.map(checkDependencyIssue).filter((x): x is UpgradeIssue => Boolean(x)); }) ); + + return packageContainerIssues + .map(x => { + if (x.status === "fulfilled") { + return x.value; + } + + sendInfo("", { + operationName: "java.dependency.assessmentManager.getDependencyIssues", + failureReason: String(x.reason), + }); + return []; + }) + .reduce((a, b) => [...a, ...b]); +} + +async function getProjectIssues(projectNode: INodeData): Promise { + const issues: UpgradeIssue[] = []; + issues.push(...getJavaIssues(projectNode)); + issues.push(...(await getDependencyIssues(projectNode))); return issues; } From 12f8a9bfcfc31feaa3d599ea253bb6f55e7c08bb Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Mon, 15 Sep 2025 10:48:49 +0800 Subject: [PATCH 52/73] chore(notificationManager): merge code to send choice --- src/upgrade/display/notificationManager.ts | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/upgrade/display/notificationManager.ts b/src/upgrade/display/notificationManager.ts index 4dcccab3..d292a47f 100644 --- a/src/upgrade/display/notificationManager.ts +++ b/src/upgrade/display/notificationManager.ts @@ -52,27 +52,22 @@ class NotificationManager implements DisplayInterface { BUTTON_TEXT_UPGRADE, BUTTON_TEXT_NOT_NOW, BUTTON_TEXT_DONT_SHOW_AGAIN); + sendInfo(operationId, { + operationName: "java.dependency.upgradeNotification.runUpgrade", + choice: selection ?? "", + }); switch (selection) { case BUTTON_TEXT_UPGRADE: { commands.executeCommand(Commands.JAVA_UPGRADE_WITH_COPILOT, prompt); - sendInfo(operationId, { - __event_name__: "java.dependency.upgradeNotification.runUpgrade", - }); break; } case BUTTON_TEXT_NOT_NOW: { this.setSessionCount(-1 * SESSION_COUNT_BEFORE_NOTIFICATION_RESHOW); - sendInfo(operationId, { - __event_name__: "java.dependency.upgradeNotification.notNow", - }); break; } case BUTTON_TEXT_DONT_SHOW_AGAIN: { Settings.disableWorkspaceDependencyDiagnostics(); - sendInfo(operationId, { - __event_name__: "java.dependency.upgradeNotification.dontShowAgain", - }); break; } } From 4bec02348610b94d1ff449caade464d672fb19a5 Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Mon, 15 Sep 2025 10:50:25 +0800 Subject: [PATCH 53/73] chore: refactor method names --- src/upgrade/assessmentManager.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/upgrade/assessmentManager.ts b/src/upgrade/assessmentManager.ts index 497033a8..e1adca21 100644 --- a/src/upgrade/assessmentManager.ts +++ b/src/upgrade/assessmentManager.ts @@ -31,7 +31,7 @@ function getJavaIssues(data: INodeData): UpgradeIssue[] { return []; } -function getUpgrade(versionString: string, supportedVersionDefinition: DependencyCheckItem): Omit | null { +function getUpgradeForDependency(versionString: string, supportedVersionDefinition: DependencyCheckItem): Omit | null { const { reason } = supportedVersionDefinition; switch (reason) { case UpgradeReason.DEPRECATED: { @@ -60,7 +60,7 @@ function getUpgrade(versionString: string, supportedVersionDefinition: Dependenc return null; } -function checkDependencyIssue(data: INodeData): UpgradeIssue | null { +function getDependencyIssue(data: INodeData): UpgradeIssue | null { const versionString = data.metaData?.["maven.version"]; const groupId = data.metaData?.["maven.groupId"]; const artifactId = data.metaData?.["maven.artifactId"]; @@ -70,7 +70,7 @@ function checkDependencyIssue(data: INodeData): UpgradeIssue | null { return null; } - const upgrade = getUpgrade(versionString, supportedVersionDefinition); + const upgrade = getUpgradeForDependency(versionString, supportedVersionDefinition); if (upgrade) { return { ...upgrade, packageId }; } @@ -89,7 +89,7 @@ async function getDependencyIssues(projectNode: INodeData): Promise Boolean(x)); + return packages.map(getDependencyIssue).filter((x): x is UpgradeIssue => Boolean(x)); }) ); From f7f2d29fec298f4f270eba26745ab1d1affc317a Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Mon, 15 Sep 2025 10:51:02 +0800 Subject: [PATCH 54/73] chore: rename --- src/upgrade/assessmentManager.ts | 2 +- src/upgrade/{dependency.data.ts => dependency.metadata.ts} | 0 src/upgrade/metadataManager.ts | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename src/upgrade/{dependency.data.ts => dependency.metadata.ts} (100%) diff --git a/src/upgrade/assessmentManager.ts b/src/upgrade/assessmentManager.ts index e1adca21..cd2c7053 100644 --- a/src/upgrade/assessmentManager.ts +++ b/src/upgrade/assessmentManager.ts @@ -5,7 +5,7 @@ import * as semver from 'semver'; import { Jdtls } from "../java/jdtls"; import { NodeKind, type INodeData } from "../java/nodeData"; import { type DependencyCheckItem, UpgradeReason, type UpgradeIssue } from "./type"; -import { DEPENDENCY_JAVA_RUNTIME } from "./dependency.data"; +import { DEPENDENCY_JAVA_RUNTIME } from "./dependency.metadata"; import { Upgrade } from '../constants'; import { buildPackageId } from './utility'; import metadataManager from './metadataManager'; diff --git a/src/upgrade/dependency.data.ts b/src/upgrade/dependency.metadata.ts similarity index 100% rename from src/upgrade/dependency.data.ts rename to src/upgrade/dependency.metadata.ts diff --git a/src/upgrade/metadataManager.ts b/src/upgrade/metadataManager.ts index 81fb7f21..f9f79dfd 100644 --- a/src/upgrade/metadataManager.ts +++ b/src/upgrade/metadataManager.ts @@ -3,7 +3,7 @@ import { type DependencyCheckMetadata, type DependencyCheckItem } from "./type"; import { buildPackageId } from "./utility"; -import DEPENDENCIES_TO_SCAN from "./dependency.data"; +import DEPENDENCIES_TO_SCAN from "./dependency.metadata"; class MetadataManager { private static dependencyCheckMetadata: DependencyCheckMetadata = DEPENDENCIES_TO_SCAN; From 6af31226e6d042e514cdd068cc6920557c04c43e Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Mon, 15 Sep 2025 10:52:08 +0800 Subject: [PATCH 55/73] chore: rename the interface --- src/upgrade/display/notificationManager.ts | 4 ++-- src/upgrade/type.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/upgrade/display/notificationManager.ts b/src/upgrade/display/notificationManager.ts index d292a47f..cf75531f 100644 --- a/src/upgrade/display/notificationManager.ts +++ b/src/upgrade/display/notificationManager.ts @@ -2,7 +2,7 @@ // Licensed under the MIT license. import { commands, ExtensionContext, window } from "vscode"; -import type { DisplayInterface, UpgradeIssue } from "../type"; +import type { IUpgradeIssuesRenderer, UpgradeIssue } from "../type"; import { buildFixPrompt, buildNotificationMessage } from "../utility"; import { Commands } from "../../commands"; import { Settings } from "../../settings"; @@ -17,7 +17,7 @@ const BUTTON_TEXT_DONT_SHOW_AGAIN = "Don't Show Again"; const SESSION_COUNT_BEFORE_NOTIFICATION_RESHOW = 3; -class NotificationManager implements DisplayInterface { +class NotificationManager implements IUpgradeIssuesRenderer { private hasShown = false; private context?: ExtensionContext; diff --git a/src/upgrade/type.ts b/src/upgrade/type.ts index 1e14d0b0..0d2758f2 100644 --- a/src/upgrade/type.ts +++ b/src/upgrade/type.ts @@ -22,6 +22,6 @@ export type UpgradeIssue = { suggestedVersion?: string; }; -export interface DisplayInterface { +export interface IUpgradeIssuesRenderer { render(issues: UpgradeIssue[]): void; } \ No newline at end of file From a64a3c84446fa79e3759cc4840d8cf99e68babe2 Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Mon, 15 Sep 2025 14:45:26 +0800 Subject: [PATCH 56/73] fix: stringify the telemetry --- src/upgrade/upgradeManager.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/upgrade/upgradeManager.ts b/src/upgrade/upgradeManager.ts index 908f4c8e..268059ba 100644 --- a/src/upgrade/upgradeManager.ts +++ b/src/upgrade/upgradeManager.ts @@ -80,7 +80,7 @@ class UpgradeManager { const issues = await assessmentManager.getProjectIssues(projectNode); projectIssues.push(...issues); sendInfo(operationId, { - issuesFoundForPackageId: projectIssues.map(x => `${x.packageId}:${x.currentVersion}`).join(","), + issuesFoundForPackageId: JSON.stringify(projectIssues.map(x => `${x.packageId}:${x.currentVersion}`)), }); })); From 1386bfb16a5269f5b7411aa1458896d217750fd0 Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Mon, 15 Sep 2025 14:46:05 +0800 Subject: [PATCH 57/73] chore(upgradeManager): no need to check command --- src/upgrade/upgradeManager.ts | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/src/upgrade/upgradeManager.ts b/src/upgrade/upgradeManager.ts index 268059ba..92f5ff38 100644 --- a/src/upgrade/upgradeManager.ts +++ b/src/upgrade/upgradeManager.ts @@ -21,14 +21,6 @@ function shouldCheckUpgrade() { && !!extensions.getExtension(ExtensionName.APP_MODERNIZATION_UPGRADE_FOR_JAVA); } -async function runUpgrade(promptText: string) { - await commands.executeCommand('workbench.action.chat.open'); - await commands.executeCommand('workbench.action.chat.newEditSession', { - agentMode: true, - inputValue: promptText, - }); -} - class UpgradeManager { public static initialize(context: ExtensionContext) { notificationManager.initialize(context); @@ -36,13 +28,7 @@ class UpgradeManager { // Commands to be used context.subscriptions.push(instrumentOperationAsVsCodeCommand(Commands.JAVA_UPGRADE_WITH_COPILOT, async (promptText?: string) => { const promptToUse = promptText ?? DEFAULT_UPGRADE_PROMPT; - // The command should typically exist as we checked for the extension before. - const hasAgentModeCommand = (await commands.getCommands(true).then(cmds => cmds.includes(Commands.GOTO_AGENT_MODE))); - if (hasAgentModeCommand) { - await commands.executeCommand(Commands.GOTO_AGENT_MODE, { prompt: promptToUse }); - } else { - await runUpgrade(promptToUse); - } + await commands.executeCommand(Commands.GOTO_AGENT_MODE, { prompt: promptToUse }); })); commands.executeCommand('setContext', 'isModernizationExtensionInstalled', !!extensions.getExtension(ExtensionName.APP_MODERNIZATION_FOR_JAVA)); From fa0fe9e22759f27615757d6bd6ac245c7fe6d1cd Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Mon, 15 Sep 2025 14:52:16 +0800 Subject: [PATCH 58/73] chore: split `getWorkspaceIssues` --- src/upgrade/assessmentManager.ts | 27 ++++++++++++++++++++++++++- src/upgrade/upgradeManager.ts | 19 +++++-------------- 2 files changed, 31 insertions(+), 15 deletions(-) diff --git a/src/upgrade/assessmentManager.ts b/src/upgrade/assessmentManager.ts index cd2c7053..1036c38f 100644 --- a/src/upgrade/assessmentManager.ts +++ b/src/upgrade/assessmentManager.ts @@ -115,6 +115,31 @@ async function getProjectIssues(projectNode: INodeData): Promise return issues; } +async function getWorkspaceIssues(workspaceUri: string): Promise { + const projects = await Jdtls.getProjects(workspaceUri); + const projectsIssues = await Promise.allSettled(projects.map(async (projectNode) => { + const issues = await getProjectIssues(projectNode); + sendInfo("", { + issuesFoundForPackageId: JSON.stringify(issues.map(x => `${x.packageId}:${x.currentVersion}`)), + }); + return issues; + })); + + const workspaceIssues = projectsIssues.map(x => { + if (x.status === "fulfilled") { + return x.value; + } + + sendInfo("", { + operationName: "java.dependency.assessmentManager.getWorkspaceIssues", + failureReason: String(x.reason), + }); + return []; + }).reduce((a, b) => [...a, ...b]); + + return workspaceIssues; +} + export default { - getProjectIssues + getWorkspaceIssues, }; \ No newline at end of file diff --git a/src/upgrade/upgradeManager.ts b/src/upgrade/upgradeManager.ts index 92f5ff38..0b49a507 100644 --- a/src/upgrade/upgradeManager.ts +++ b/src/upgrade/upgradeManager.ts @@ -6,8 +6,7 @@ import { commands, type ExtensionContext, extensions, workspace, type WorkspaceF import { Jdtls } from "../java/jdtls"; import { languageServerApiManager } from "../languageServerApi/languageServerApiManager"; import { ExtensionName } from "../constants"; -import { UpgradeIssue } from "./type"; -import { instrumentOperation, instrumentOperationAsVsCodeCommand, sendInfo } from "vscode-extension-telemetry-wrapper"; +import { instrumentOperation, instrumentOperationAsVsCodeCommand } from "vscode-extension-telemetry-wrapper"; import { Commands } from "../commands"; import notificationManager from "./display/notificationManager"; import { Settings } from "../settings"; @@ -50,7 +49,7 @@ class UpgradeManager { private static async checkUpgradableComponents(folder: WorkspaceFolder) { return (instrumentOperation("upgradeManager.checkUpgradableComponents", - async (operationId: string) => { + async () => { if (!await languageServerApiManager.ready()) { return; } @@ -59,20 +58,12 @@ class UpgradeManager { return; } - const projectIssues: UpgradeIssue[] = []; const uri = folder.uri.toString(); - const projects = await Jdtls.getProjects(uri); - await Promise.allSettled(projects.map(async (projectNode) => { - const issues = await assessmentManager.getProjectIssues(projectNode); - projectIssues.push(...issues); - sendInfo(operationId, { - issuesFoundForPackageId: JSON.stringify(projectIssues.map(x => `${x.packageId}:${x.currentVersion}`)), - }); - })); + const workspaceIssues = await assessmentManager.getWorkspaceIssues(uri); - if (projectIssues.length > 0) { + if (workspaceIssues.length > 0) { // only show one issue in notifications - notificationManager.render(projectIssues); + notificationManager.render(workspaceIssues); } } ))() From 5e0f4b0d587800526f4a3f872446a65ac5fd7bc7 Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Mon, 15 Sep 2025 15:15:30 +0800 Subject: [PATCH 59/73] chore: telemetry operation name --- src/upgrade/upgradeManager.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/upgrade/upgradeManager.ts b/src/upgrade/upgradeManager.ts index 0b49a507..6d388d8f 100644 --- a/src/upgrade/upgradeManager.ts +++ b/src/upgrade/upgradeManager.ts @@ -48,7 +48,7 @@ class UpgradeManager { } private static async checkUpgradableComponents(folder: WorkspaceFolder) { - return (instrumentOperation("upgradeManager.checkUpgradableComponents", + return (instrumentOperation("java.dependency.diagnoseDependencyIssues", async () => { if (!await languageServerApiManager.ready()) { return; From 9fa24f97904b4cc65d285b15cc9ff546761f42de Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Mon, 15 Sep 2025 15:28:07 +0800 Subject: [PATCH 60/73] chore: rename `java.dependency.enableDependencyDiagnostics` ... to java.dependency.enableDependencyCheckup` as `Diagnostics` is used as a VSCode-specific concept --- package.json | 4 ++-- package.nls.json | 2 +- src/settings.ts | 8 ++++---- src/upgrade/display/notificationManager.ts | 4 ++-- src/upgrade/upgradeManager.ts | 12 ++++++------ 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/package.json b/package.json index d7ddd7a1..49ee6239 100644 --- a/package.json +++ b/package.json @@ -333,9 +333,9 @@ "description": "%configuration.java.dependency.packagePresentation%", "default": "flat" }, - "java.dependency.enableDependencyDiagnostics": { + "java.dependency.enableDependencyCheckup": { "type": "boolean", - "description": "%configuration.java.dependency.enableDependencyDiagnostics%", + "description": "%configuration.java.dependency.enableDependencyCheckup%", "default": true }, "java.project.exportJar.targetPath": { diff --git a/package.nls.json b/package.nls.json index e29c95f4..95052e18 100644 --- a/package.nls.json +++ b/package.nls.json @@ -45,7 +45,7 @@ "configuration.java.dependency.autoRefresh": "Synchronize Java Projects explorer with changes", "configuration.java.dependency.refreshDelay": "The delay time (ms) the auto refresh is invoked when changes are detected", "configuration.java.dependency.packagePresentation": "Package presentation mode: flat or hierarchical", - "configuration.java.dependency.enableDependencyDiagnostics": "Show reminders when your Java runtimes or dependencies need an upgrade.", + "configuration.java.dependency.enableDependencyCheckup": "Show reminders when your Java runtimes or dependencies need an upgrade.", "configuration.java.project.explorer.showNonJavaResources": "When enabled, the explorer shows non-Java resources.", "configuration.java.project.exportJar.targetPath.customization": "The output path of the exported jar. Leave it empty if you want to manually pick the output location.", "configuration.java.project.exportJar.targetPath.workspaceFolder": "Export the jar file into the workspace folder. Its name is the same as the folder's.", diff --git a/src/settings.ts b/src/settings.ts index 4ea7edb3..f3ab01b8 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -58,8 +58,8 @@ export class Settings { workspace.getConfiguration("java.dependency").update("packagePresentation", PackagePresentation.Hierarchical, false); } - public static disableWorkspaceDependencyDiagnostics() { - return workspace.getConfiguration("java.dependency").update("enableDependencyDiagnostics", false, ConfigurationTarget.Workspace); + public static disableWorkspaceDependencyCheckup() { + return workspace.getConfiguration("java.dependency").update("enableDependencyCheckup", false, ConfigurationTarget.Workspace); } public static switchNonJavaResourceFilter(enabled: boolean): void { @@ -112,8 +112,8 @@ export class Settings { return workspace.getConfiguration("java.dependency").get("refreshDelay", 2000); } - public static getEnableDependencyDiagnostics() { - return workspace.getConfiguration("java.dependency").get("enableDependencyDiagnostics", true); + public static getEnableDependencyCheckup() { + return workspace.getConfiguration("java.dependency").get("enableDependencyCheckup", true); } public static getExportJarTargetPath(): string { diff --git a/src/upgrade/display/notificationManager.ts b/src/upgrade/display/notificationManager.ts index cf75531f..b413ff7d 100644 --- a/src/upgrade/display/notificationManager.ts +++ b/src/upgrade/display/notificationManager.ts @@ -67,7 +67,7 @@ class NotificationManager implements IUpgradeIssuesRenderer { break; } case BUTTON_TEXT_DONT_SHOW_AGAIN: { - Settings.disableWorkspaceDependencyDiagnostics(); + Settings.disableWorkspaceDependencyCheckup(); break; } } @@ -76,7 +76,7 @@ class NotificationManager implements IUpgradeIssuesRenderer { } private shouldShow() { - return Settings.getEnableDependencyDiagnostics() + return Settings.getEnableDependencyCheckup() && ((this.getSessionCount() ?? 0) >= 0); } diff --git a/src/upgrade/upgradeManager.ts b/src/upgrade/upgradeManager.ts index 6d388d8f..5fac4188 100644 --- a/src/upgrade/upgradeManager.ts +++ b/src/upgrade/upgradeManager.ts @@ -15,8 +15,8 @@ import assessmentManager from "./assessmentManager"; const DEFAULT_UPGRADE_PROMPT = "Upgrade Java project dependency to latest version."; -function shouldCheckUpgrade() { - return Settings.getEnableDependencyDiagnostics() +function shouldRunCheckup() { + return Settings.getEnableDependencyCheckup() && !!extensions.getExtension(ExtensionName.APP_MODERNIZATION_UPGRADE_FOR_JAVA); } @@ -39,17 +39,17 @@ class UpgradeManager { } public static scan() { - if (!shouldCheckUpgrade()) { + if (!shouldRunCheckup()) { return; } workspace.workspaceFolders?.forEach((folder) => - UpgradeManager.checkUpgradableComponents(folder) + UpgradeManager.runDependencyCheckup(folder) ); } - private static async checkUpgradableComponents(folder: WorkspaceFolder) { + private static async runDependencyCheckup(folder: WorkspaceFolder) { return (instrumentOperation("java.dependency.diagnoseDependencyIssues", - async () => { + async (_operationId: string) => { if (!await languageServerApiManager.ready()) { return; } From 1456262d9e4e22e585397ccf47d1135d860b7e1f Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Mon, 15 Sep 2025 15:30:01 +0800 Subject: [PATCH 61/73] chore: add `operationName` in telemetry --- src/upgrade/assessmentManager.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/upgrade/assessmentManager.ts b/src/upgrade/assessmentManager.ts index 1036c38f..ee764701 100644 --- a/src/upgrade/assessmentManager.ts +++ b/src/upgrade/assessmentManager.ts @@ -120,6 +120,7 @@ async function getWorkspaceIssues(workspaceUri: string): Promise const projectsIssues = await Promise.allSettled(projects.map(async (projectNode) => { const issues = await getProjectIssues(projectNode); sendInfo("", { + operationName: "java.dependency.assessmentManager.getWorkspaceIssues", issuesFoundForPackageId: JSON.stringify(issues.map(x => `${x.packageId}:${x.currentVersion}`)), }); return issues; From efdff835c88bf0d2112c087796b54d046fb4475f Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Mon, 15 Sep 2025 15:30:25 +0800 Subject: [PATCH 62/73] chore: don't collect `failureReason` --- src/upgrade/assessmentManager.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/upgrade/assessmentManager.ts b/src/upgrade/assessmentManager.ts index ee764701..ea0c9086 100644 --- a/src/upgrade/assessmentManager.ts +++ b/src/upgrade/assessmentManager.ts @@ -101,7 +101,6 @@ async function getDependencyIssues(projectNode: INodeData): Promise sendInfo("", { operationName: "java.dependency.assessmentManager.getWorkspaceIssues", - failureReason: String(x.reason), }); return []; }).reduce((a, b) => [...a, ...b]); From 2578194dedd491fdde1be8a2903ef8bdf642223b Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Mon, 15 Sep 2025 15:52:46 +0800 Subject: [PATCH 63/73] chore: rename --- src/upgrade/upgradeManager.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/upgrade/upgradeManager.ts b/src/upgrade/upgradeManager.ts index 5fac4188..240a1871 100644 --- a/src/upgrade/upgradeManager.ts +++ b/src/upgrade/upgradeManager.ts @@ -48,7 +48,7 @@ class UpgradeManager { } private static async runDependencyCheckup(folder: WorkspaceFolder) { - return (instrumentOperation("java.dependency.diagnoseDependencyIssues", + return (instrumentOperation("java.dependency.runDependencyCheckup", async (_operationId: string) => { if (!await languageServerApiManager.ready()) { return; From 731d86a1eca55efe7ff90bcbb685fcf1abf2c547 Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Mon, 15 Sep 2025 16:18:46 +0800 Subject: [PATCH 64/73] chore: don't show the commands in CP --- package.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/package.json b/package.json index 49ee6239..6003c338 100644 --- a/package.json +++ b/package.json @@ -565,6 +565,14 @@ { "command": "_java.project.create.from.javaprojectexplorer", "when": "false" + }, + { + "command": "_java.view.modernizeJavaProject", + "when": "false" + }, + { + "command": "_java.upgradeWithCopilot", + "when": "false" } ], "explorer/context": [ From 803be9b99f8e4c0d84aeae582158029f4d9c5fba Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Mon, 15 Sep 2025 16:34:35 +0800 Subject: [PATCH 65/73] chore: fix lint --- src/upgrade/assessmentManager.ts | 4 ++-- src/upgrade/display/notificationManager.ts | 2 +- src/upgrade/type.ts | 5 +++-- src/upgrade/upgradeManager.ts | 2 +- src/upgrade/utility.ts | 4 ++-- 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/upgrade/assessmentManager.ts b/src/upgrade/assessmentManager.ts index ea0c9086..04f902e8 100644 --- a/src/upgrade/assessmentManager.ts +++ b/src/upgrade/assessmentManager.ts @@ -41,7 +41,7 @@ function getUpgradeForDependency(versionString: string, supportedVersionDefiniti reason, currentVersion: versionString, suggestedVersion: alternative, - } + }; } case UpgradeReason.END_OF_LIFE: { const currentSemVer = semver.coerce(versionString); @@ -51,7 +51,7 @@ function getUpgradeForDependency(versionString: string, supportedVersionDefiniti reason, currentVersion: versionString, suggestedVersion: supportedVersionDefinition.suggestedVersion, - } + }; } } diff --git a/src/upgrade/display/notificationManager.ts b/src/upgrade/display/notificationManager.ts index b413ff7d..64419d8e 100644 --- a/src/upgrade/display/notificationManager.ts +++ b/src/upgrade/display/notificationManager.ts @@ -72,7 +72,7 @@ class NotificationManager implements IUpgradeIssuesRenderer { } } } - ))() + ))(); } private shouldShow() { diff --git a/src/upgrade/type.ts b/src/upgrade/type.ts index 0d2758f2..34ca4b63 100644 --- a/src/upgrade/type.ts +++ b/src/upgrade/type.ts @@ -2,7 +2,8 @@ // Licensed under the MIT license. export type DependencyCheckItemBase = { name: string, reason: UpgradeReason }; -export type DependencyCheckItemEol = DependencyCheckItemBase & { reason: UpgradeReason.END_OF_LIFE | UpgradeReason.JRE_TOO_OLD, supportedVersion: string, suggestedVersion: string }; +export type DependencyCheckItemEol = DependencyCheckItemBase + & { reason: UpgradeReason.END_OF_LIFE | UpgradeReason.JRE_TOO_OLD, supportedVersion: string, suggestedVersion: string }; export type DependencyCheckItemDeprecated = DependencyCheckItemBase & { reason: UpgradeReason.DEPRECATED, alternative: string }; export type DependencyCheckItem = (DependencyCheckItemEol | DependencyCheckItemDeprecated); export type DependencyCheckMetadata = Record; @@ -12,7 +13,7 @@ export enum UpgradeReason { DEPRECATED, CVE, JRE_TOO_OLD, -}; +} export type UpgradeIssue = { packageId: string; diff --git a/src/upgrade/upgradeManager.ts b/src/upgrade/upgradeManager.ts index 240a1871..60e270e4 100644 --- a/src/upgrade/upgradeManager.ts +++ b/src/upgrade/upgradeManager.ts @@ -66,7 +66,7 @@ class UpgradeManager { notificationManager.render(workspaceIssues); } } - ))() + ))(); } } diff --git a/src/upgrade/utility.ts b/src/upgrade/utility.ts index ff33c19b..91232c4a 100644 --- a/src/upgrade/utility.ts +++ b/src/upgrade/utility.ts @@ -10,11 +10,11 @@ export function buildNotificationMessage(issue: UpgradeIssue): string { const name = packageDisplayName ?? packageId; if (packageId === Upgrade.PACKAGE_ID_FOR_JAVA_RUNTIME) { - return `The current project is using an older runtime (Java ${currentVersion}). Do you want to upgrade to the latest LTS version${suggestedVersion ? ` (${suggestedVersion})` : ""}?` + return `The current project is using an older runtime (Java ${currentVersion}). Do you want to upgrade to the latest LTS version${suggestedVersion ? ` (${suggestedVersion})` : ""}?`; } return `The current project is using ${name} ${currentVersion}, which has reached end of life. Do you want to upgrade to ${suggestedVersion ? ` ${suggestedVersion}` : "the latest version" - }?` + }?`; } export function buildFixPrompt(issue: UpgradeIssue): string { From aea445f1d659877ab2aedfad664d5704c1247c72 Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Tue, 16 Sep 2025 11:50:17 +0800 Subject: [PATCH 66/73] feat: show reasons for the versions we choose --- src/upgrade/dependency.metadata.ts | 26 +++++++++++++++++++++----- src/upgrade/type.ts | 9 +++++---- src/upgrade/utility.ts | 28 +++++++++++++++++----------- 3 files changed, 43 insertions(+), 20 deletions(-) diff --git a/src/upgrade/dependency.metadata.ts b/src/upgrade/dependency.metadata.ts index 9104a54b..c60c784b 100644 --- a/src/upgrade/dependency.metadata.ts +++ b/src/upgrade/dependency.metadata.ts @@ -10,7 +10,10 @@ export const DEPENDENCY_JAVA_RUNTIME = { "name": "Java Runtime", "reason": UpgradeReason.JRE_TOO_OLD, "supportedVersion": `>=${LATEST_JAVA_LTS_VESRION}`, - "suggestedVersion": String(LATEST_JAVA_LTS_VESRION), + "suggestedVersion": { + "name": String(LATEST_JAVA_LTS_VESRION), + "description": "latest LTS version", + }, } as const; const DEPENDENCIES_TO_SCAN: DependencyCheckMetadata = { @@ -18,24 +21,37 @@ const DEPENDENCIES_TO_SCAN: DependencyCheckMetadata = { "reason": UpgradeReason.END_OF_LIFE, "name": "Spring Boot", "supportedVersion": "2.7.x || >=3.2.x", - "suggestedVersion": "3.5", + "suggestedVersion": { + "name": "3.5", + "description": "latest stable release", + }, }, "org.springframework:*": { "reason": UpgradeReason.END_OF_LIFE, "name": "Spring Framework", "supportedVersion": "5.3.x || >=6.2.x", - "suggestedVersion": "6.2" + "suggestedVersion": { + "name": "3.5", + "description": "latest stable release", + }, }, "org.springframework.security:*": { "reason": UpgradeReason.END_OF_LIFE, "name": "Spring Security", "supportedVersion": "5.7.x || 5.8.x || >=6.2.x", - "suggestedVersion": "6.5" + "suggestedVersion": { + "name": "3.5", + "description": "latest stable release", + }, }, "javax:*": { "reason": UpgradeReason.DEPRECATED, "name": "Java EE", - "alternative": "Jakarta EE 10", + "alternative": { + "name": "Jakarta EE 10", + "description": "latest release with wide Java runtime version support", + + }, }, [Upgrade.PACKAGE_ID_FOR_JAVA_RUNTIME]: DEPENDENCY_JAVA_RUNTIME, }; diff --git a/src/upgrade/type.ts b/src/upgrade/type.ts index 34ca4b63..9ae2c50c 100644 --- a/src/upgrade/type.ts +++ b/src/upgrade/type.ts @@ -1,10 +1,11 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +export type UpgradeTarget = { name: string; description: string }; export type DependencyCheckItemBase = { name: string, reason: UpgradeReason }; export type DependencyCheckItemEol = DependencyCheckItemBase - & { reason: UpgradeReason.END_OF_LIFE | UpgradeReason.JRE_TOO_OLD, supportedVersion: string, suggestedVersion: string }; -export type DependencyCheckItemDeprecated = DependencyCheckItemBase & { reason: UpgradeReason.DEPRECATED, alternative: string }; + & { reason: UpgradeReason.END_OF_LIFE | UpgradeReason.JRE_TOO_OLD, supportedVersion: string, suggestedVersion: UpgradeTarget }; +export type DependencyCheckItemDeprecated = DependencyCheckItemBase & { reason: UpgradeReason.DEPRECATED, alternative: UpgradeTarget }; export type DependencyCheckItem = (DependencyCheckItemEol | DependencyCheckItemDeprecated); export type DependencyCheckMetadata = Record; @@ -17,10 +18,10 @@ export enum UpgradeReason { export type UpgradeIssue = { packageId: string; - packageDisplayName?: string; + packageDisplayName: string; reason: UpgradeReason; currentVersion: string; - suggestedVersion?: string; + suggestedVersion: UpgradeTarget; }; export interface IUpgradeIssuesRenderer { diff --git a/src/upgrade/utility.ts b/src/upgrade/utility.ts index 91232c4a..94e27b10 100644 --- a/src/upgrade/utility.ts +++ b/src/upgrade/utility.ts @@ -6,31 +6,37 @@ import { UpgradeReason, type UpgradeIssue } from "./type"; import { Upgrade } from "../constants"; export function buildNotificationMessage(issue: UpgradeIssue): string { - const { packageId, currentVersion, suggestedVersion, packageDisplayName } = issue; - const name = packageDisplayName ?? packageId; + const { packageId, currentVersion, reason, suggestedVersion: { name: suggestedVersionName, description: suggestedVersionDescription }, packageDisplayName } = issue; if (packageId === Upgrade.PACKAGE_ID_FOR_JAVA_RUNTIME) { - return `The current project is using an older runtime (Java ${currentVersion}). Do you want to upgrade to the latest LTS version${suggestedVersion ? ` (${suggestedVersion})` : ""}?`; + return `The current project is using an older Java runtime (${currentVersion}). Do you want to upgrade to the latest LTS version ${suggestedVersionName}?`; } - return `The current project is using ${name} ${currentVersion}, which has reached end of life. Do you want to upgrade to ${suggestedVersion ? ` ${suggestedVersion}` : "the latest version" - }?`; + switch (reason) { + case UpgradeReason.CVE: { + return `The current project is using ${packageDisplayName} ${currentVersion}, which has CVE issues. Do you want to upgrade to ${suggestedVersionName} (${suggestedVersionDescription})?`; + } + case UpgradeReason.DEPRECATED: + case UpgradeReason.END_OF_LIFE: + default: { + return `The current project is using ${packageDisplayName} ${currentVersion}, which has reached end of life. Do you want to upgrade to ${suggestedVersionName} (${suggestedVersionDescription})?`; + } + } } + export function buildFixPrompt(issue: UpgradeIssue): string { - const { packageId, packageDisplayName, reason, suggestedVersion } = issue; - const name = packageDisplayName ?? packageId; + const { packageDisplayName, reason, suggestedVersion: { name: suggestedVersionName } } = issue; switch (reason) { case UpgradeReason.CVE: { - return `upgrade package ${name} to ${suggestedVersion ?? "the latest version"} to address CVE issues using java upgrade tools`; + return `upgrade ${packageDisplayName} to ${suggestedVersionName} to address CVE issues using java upgrade tools`; } case UpgradeReason.JRE_TOO_OLD: { - return `upgrade java runtime to latest LTS version${suggestedVersion ? ` (${suggestedVersion})` : "" - } using java upgrade tools`; + return `upgrade java runtime to the latest LTS version ${suggestedVersionName} using java upgrade tools`; } default: { - return `upgrade package ${name} to ${suggestedVersion ?? "the latest version"} using java upgrade tools`; + return `upgrade ${packageDisplayName} to ${suggestedVersionName} using java upgrade tools`; } } } From 430f7e8f4c7fc6f3e353a1b43c769e7b72f23073 Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Tue, 16 Sep 2025 11:54:05 +0800 Subject: [PATCH 67/73] feat: update notification display UX --- src/settings.ts | 4 ---- src/upgrade/display/notificationManager.ts | 27 +++++++++------------- 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/src/settings.ts b/src/settings.ts index f3ab01b8..60bde619 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -58,10 +58,6 @@ export class Settings { workspace.getConfiguration("java.dependency").update("packagePresentation", PackagePresentation.Hierarchical, false); } - public static disableWorkspaceDependencyCheckup() { - return workspace.getConfiguration("java.dependency").update("enableDependencyCheckup", false, ConfigurationTarget.Workspace); - } - public static switchNonJavaResourceFilter(enabled: boolean): void { workspace.getConfiguration("java.project.explorer").update( "showNonJavaResources", diff --git a/src/upgrade/display/notificationManager.ts b/src/upgrade/display/notificationManager.ts index 64419d8e..4e42c25b 100644 --- a/src/upgrade/display/notificationManager.ts +++ b/src/upgrade/display/notificationManager.ts @@ -9,13 +9,13 @@ import { Settings } from "../../settings"; import { instrumentOperation, sendInfo } from "vscode-extension-telemetry-wrapper"; const KEY_PREFIX = 'javaupgrade.notificationManager'; -const SESSION_COUNT_KEY = `${KEY_PREFIX}.sessionCount`; +const NEXT_SHOW_TS_KEY = `${KEY_PREFIX}.nextShowTs`; const BUTTON_TEXT_UPGRADE = "Upgrade Now"; const BUTTON_TEXT_NOT_NOW = "Not Now"; -const BUTTON_TEXT_DONT_SHOW_AGAIN = "Don't Show Again"; -const SESSION_COUNT_BEFORE_NOTIFICATION_RESHOW = 3; +const SECONDS_IN_A_DAY = 24 * 60 * 60; +const SECONDS_COUNT_BEFORE_NOTIFICATION_RESHOW = 10 * SECONDS_IN_A_DAY; class NotificationManager implements IUpgradeIssuesRenderer { private hasShown = false; @@ -39,7 +39,7 @@ class NotificationManager implements IUpgradeIssuesRenderer { } this.hasShown = true; - this.setSessionCount((this.getSessionCount() ?? 0) + 1); + this.setNextShowTs((Number(new Date()) / 1000) + SECONDS_COUNT_BEFORE_NOTIFICATION_RESHOW); if (!this.shouldShow()) { return; @@ -50,8 +50,7 @@ class NotificationManager implements IUpgradeIssuesRenderer { const selection = await window.showInformationMessage( notificationMessage, BUTTON_TEXT_UPGRADE, - BUTTON_TEXT_NOT_NOW, - BUTTON_TEXT_DONT_SHOW_AGAIN); + BUTTON_TEXT_NOT_NOW); sendInfo(operationId, { operationName: "java.dependency.upgradeNotification.runUpgrade", choice: selection ?? "", @@ -63,11 +62,7 @@ class NotificationManager implements IUpgradeIssuesRenderer { break; } case BUTTON_TEXT_NOT_NOW: { - this.setSessionCount(-1 * SESSION_COUNT_BEFORE_NOTIFICATION_RESHOW); - break; - } - case BUTTON_TEXT_DONT_SHOW_AGAIN: { - Settings.disableWorkspaceDependencyCheckup(); + this.setNextShowTs(-1 * SECONDS_COUNT_BEFORE_NOTIFICATION_RESHOW); break; } } @@ -77,15 +72,15 @@ class NotificationManager implements IUpgradeIssuesRenderer { private shouldShow() { return Settings.getEnableDependencyCheckup() - && ((this.getSessionCount() ?? 0) >= 0); + && ((this.getNextShowTs() ?? 0) <= (Number(new Date()) / 1000)); } - private getSessionCount() { - return this.context?.globalState.get(SESSION_COUNT_KEY); + private getNextShowTs() { + return this.context?.globalState.get(NEXT_SHOW_TS_KEY); } - private setSessionCount(num: number) { - return this.context?.globalState.update(SESSION_COUNT_KEY, num); + private setNextShowTs(num: number) { + return this.context?.globalState.update(NEXT_SHOW_TS_KEY, num); } } From 440e92e997a30673ab78b60716cdc8eb70640f60 Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Tue, 16 Sep 2025 13:56:43 +0800 Subject: [PATCH 68/73] chore: merge `getNowTs()` --- src/upgrade/display/notificationManager.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/upgrade/display/notificationManager.ts b/src/upgrade/display/notificationManager.ts index 4e42c25b..d828fb6e 100644 --- a/src/upgrade/display/notificationManager.ts +++ b/src/upgrade/display/notificationManager.ts @@ -17,6 +17,10 @@ const BUTTON_TEXT_NOT_NOW = "Not Now"; const SECONDS_IN_A_DAY = 24 * 60 * 60; const SECONDS_COUNT_BEFORE_NOTIFICATION_RESHOW = 10 * SECONDS_IN_A_DAY; +function getNowTs() { + return Number(new Date()) / 1000; +} + class NotificationManager implements IUpgradeIssuesRenderer { private hasShown = false; private context?: ExtensionContext; @@ -39,8 +43,6 @@ class NotificationManager implements IUpgradeIssuesRenderer { } this.hasShown = true; - this.setNextShowTs((Number(new Date()) / 1000) + SECONDS_COUNT_BEFORE_NOTIFICATION_RESHOW); - if (!this.shouldShow()) { return; } @@ -62,7 +64,7 @@ class NotificationManager implements IUpgradeIssuesRenderer { break; } case BUTTON_TEXT_NOT_NOW: { - this.setNextShowTs(-1 * SECONDS_COUNT_BEFORE_NOTIFICATION_RESHOW); + this.setNextShowTs(getNowTs() + SECONDS_COUNT_BEFORE_NOTIFICATION_RESHOW); break; } } @@ -72,7 +74,7 @@ class NotificationManager implements IUpgradeIssuesRenderer { private shouldShow() { return Settings.getEnableDependencyCheckup() - && ((this.getNextShowTs() ?? 0) <= (Number(new Date()) / 1000)); + && ((this.getNextShowTs() ?? 0) <= getNowTs()); } private getNextShowTs() { From 478d871575deca71c404cbab22c811bb9ab76217 Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Tue, 16 Sep 2025 15:53:59 +0800 Subject: [PATCH 69/73] chore(notificationManager): tweak order of `shouldShow` and `hasShown` --- src/upgrade/display/notificationManager.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/upgrade/display/notificationManager.ts b/src/upgrade/display/notificationManager.ts index d828fb6e..1b6c98d0 100644 --- a/src/upgrade/display/notificationManager.ts +++ b/src/upgrade/display/notificationManager.ts @@ -38,14 +38,14 @@ class NotificationManager implements IUpgradeIssuesRenderer { } const issue = issues[0]; - if (this.hasShown) { + if (!this.shouldShow()) { return; } - this.hasShown = true; - if (!this.shouldShow()) { + if (this.hasShown) { return; } + this.hasShown = true; const prompt = buildFixPrompt(issue); const notificationMessage = buildNotificationMessage(issue); From 4397ccce8929635799d8b73d13f3666be931093a Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Tue, 16 Sep 2025 16:52:37 +0800 Subject: [PATCH 70/73] chore: `workspaceUri` -> `workspaceFolderUri` --- src/upgrade/assessmentManager.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/upgrade/assessmentManager.ts b/src/upgrade/assessmentManager.ts index 04f902e8..63e22bda 100644 --- a/src/upgrade/assessmentManager.ts +++ b/src/upgrade/assessmentManager.ts @@ -114,8 +114,8 @@ async function getProjectIssues(projectNode: INodeData): Promise return issues; } -async function getWorkspaceIssues(workspaceUri: string): Promise { - const projects = await Jdtls.getProjects(workspaceUri); +async function getWorkspaceIssues(workspaceFolderUri: string): Promise { + const projects = await Jdtls.getProjects(workspaceFolderUri); const projectsIssues = await Promise.allSettled(projects.map(async (projectNode) => { const issues = await getProjectIssues(projectNode); sendInfo("", { From a0abeb922cba034e6bfa7c603d4be762de35e59c Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Tue, 16 Sep 2025 17:00:39 +0800 Subject: [PATCH 71/73] chore: lint --- src/upgrade/utility.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/upgrade/utility.ts b/src/upgrade/utility.ts index 94e27b10..09a34594 100644 --- a/src/upgrade/utility.ts +++ b/src/upgrade/utility.ts @@ -6,7 +6,14 @@ import { UpgradeReason, type UpgradeIssue } from "./type"; import { Upgrade } from "../constants"; export function buildNotificationMessage(issue: UpgradeIssue): string { - const { packageId, currentVersion, reason, suggestedVersion: { name: suggestedVersionName, description: suggestedVersionDescription }, packageDisplayName } = issue; + const { + packageId, + currentVersion, + reason, + suggestedVersion: { name: suggestedVersionName, description: suggestedVersionDescription }, + packageDisplayName + } = issue; + 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}?`; From 4d271c153fe3d9d88d1376b919cb324e88ab5f1d Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Tue, 16 Sep 2025 17:39:57 +0800 Subject: [PATCH 72/73] feat: add EOL date to notification --- src/upgrade/assessmentManager.ts | 21 +++++-------- src/upgrade/dependency.metadata.ts | 50 +++++++++++++++++++++++++++++- src/upgrade/type.ts | 14 ++++----- src/upgrade/utility.ts | 38 +++++++++++++++++------ 4 files changed, 91 insertions(+), 32 deletions(-) diff --git a/src/upgrade/assessmentManager.ts b/src/upgrade/assessmentManager.ts index 63e22bda..1a361460 100644 --- a/src/upgrade/assessmentManager.ts +++ b/src/upgrade/assessmentManager.ts @@ -13,48 +13,47 @@ import { sendInfo } from 'vscode-extension-telemetry-wrapper'; function getJavaIssues(data: INodeData): UpgradeIssue[] { const javaVersion = data.metaData?.MaxSourceVersion as number | undefined; - const { name, reason, supportedVersion, suggestedVersion } = DEPENDENCY_JAVA_RUNTIME; + const { name, supportedVersion } = DEPENDENCY_JAVA_RUNTIME; if (!javaVersion) { return []; } const currentSemVer = semver.coerce(javaVersion); if (currentSemVer && !semver.satisfies(currentSemVer, supportedVersion)) { return [{ + ...DEPENDENCY_JAVA_RUNTIME, packageId: Upgrade.PACKAGE_ID_FOR_JAVA_RUNTIME, packageDisplayName: name, currentVersion: String(javaVersion), - reason, - suggestedVersion, }]; } return []; } -function getUpgradeForDependency(versionString: string, supportedVersionDefinition: DependencyCheckItem): Omit | null { +function getUpgradeForDependency(versionString: string, supportedVersionDefinition: DependencyCheckItem, packageId: string): UpgradeIssue | null { const { reason } = supportedVersionDefinition; switch (reason) { case UpgradeReason.DEPRECATED: { - const { alternative } = supportedVersionDefinition; return { + ...supportedVersionDefinition, packageDisplayName: supportedVersionDefinition.name, reason, currentVersion: versionString, - suggestedVersion: alternative, + packageId, }; } case UpgradeReason.END_OF_LIFE: { const currentSemVer = semver.coerce(versionString); if (currentSemVer && !semver.satisfies(currentSemVer, supportedVersionDefinition.supportedVersion)) { return { + ...supportedVersionDefinition, packageDisplayName: supportedVersionDefinition.name, reason, currentVersion: versionString, - suggestedVersion: supportedVersionDefinition.suggestedVersion, + packageId, }; } } - } return null; @@ -70,11 +69,7 @@ function getDependencyIssue(data: INodeData): UpgradeIssue | null { return null; } - const upgrade = getUpgradeForDependency(versionString, supportedVersionDefinition); - if (upgrade) { - return { ...upgrade, packageId }; - } - return null; + return getUpgradeForDependency(versionString, supportedVersionDefinition, packageId); } async function getDependencyIssues(projectNode: INodeData): Promise { diff --git a/src/upgrade/dependency.metadata.ts b/src/upgrade/dependency.metadata.ts index c60c784b..8b31b04f 100644 --- a/src/upgrade/dependency.metadata.ts +++ b/src/upgrade/dependency.metadata.ts @@ -21,6 +21,24 @@ const DEPENDENCIES_TO_SCAN: DependencyCheckMetadata = { "reason": UpgradeReason.END_OF_LIFE, "name": "Spring Boot", "supportedVersion": "2.7.x || >=3.2.x", + "eolDate": { + "4.0.x": "2027-12", + "3.5.x": "2032-06", + "3.4.x": "2026-12", + "3.3.x": "2026-06", + "3.2.x": "2025-12", + "3.1.x": "2025-06", + "3.0.x": "2024-12", + "2.7.x": "2029-06", + "2.6.x": "2024-02", + "2.5.x": "2023-08", + "2.4.x": "2023-02", + "2.3.x": "2022-08", + "2.2.x": "2022-01", + "2.1.x": "2021-01", + "2.0.x": "2020-06", + "1.5.x": "2020-11", + }, "suggestedVersion": { "name": "3.5", "description": "latest stable release", @@ -30,6 +48,17 @@ const DEPENDENCIES_TO_SCAN: DependencyCheckMetadata = { "reason": UpgradeReason.END_OF_LIFE, "name": "Spring Framework", "supportedVersion": "5.3.x || >=6.2.x", + "eolDate": { + "7.0.x": "2028-06", + "6.2.x": "2032-06", + "6.1.x": "2026-06", + "6.0.x": "2025-08", + "5.3.x": "2029-06", + "5.2.x": "2023-12", + "5.1.x": "2022-12", + "5.0.x": "2022-12", + "4.3.x": "2020-12", + }, "suggestedVersion": { "name": "3.5", "description": "latest stable release", @@ -39,6 +68,25 @@ const DEPENDENCIES_TO_SCAN: DependencyCheckMetadata = { "reason": UpgradeReason.END_OF_LIFE, "name": "Spring Security", "supportedVersion": "5.7.x || 5.8.x || >=6.2.x", + "eolDate": { + "7.0.x": "2027-12", + "6.5.x": "2032-06", + "6.4.x": "2026-12", + "6.3.x": "2026-06", + "6.2.x": "2025-12", + "6.1.x": "2025-06", + "6.0.x": "2024-12", + "5.8.x": "2029-06", + "5.7.x": "2029-06", + "5.6.x": "2024-02", + "5.5.x": "2023-08", + "5.4.x": "2023-02", + "5.3.x": "2022-08", + "5.2.x": "2022-01", + "5.1.x": "2021-01", + "5.0.x": "2020-06", + "4.2.x": "2020-11", + }, "suggestedVersion": { "name": "3.5", "description": "latest stable release", @@ -47,7 +95,7 @@ const DEPENDENCIES_TO_SCAN: DependencyCheckMetadata = { "javax:*": { "reason": UpgradeReason.DEPRECATED, "name": "Java EE", - "alternative": { + "suggestedVersion": { "name": "Jakarta EE 10", "description": "latest release with wide Java runtime version support", diff --git a/src/upgrade/type.ts b/src/upgrade/type.ts index 9ae2c50c..add29f1d 100644 --- a/src/upgrade/type.ts +++ b/src/upgrade/type.ts @@ -2,11 +2,11 @@ // Licensed under the MIT license. export type UpgradeTarget = { name: string; description: string }; -export type DependencyCheckItemBase = { name: string, reason: UpgradeReason }; -export type DependencyCheckItemEol = DependencyCheckItemBase - & { reason: UpgradeReason.END_OF_LIFE | UpgradeReason.JRE_TOO_OLD, supportedVersion: string, suggestedVersion: UpgradeTarget }; -export type DependencyCheckItemDeprecated = DependencyCheckItemBase & { reason: UpgradeReason.DEPRECATED, alternative: UpgradeTarget }; -export type DependencyCheckItem = (DependencyCheckItemEol | DependencyCheckItemDeprecated); +export type DependencyCheckItemBase = { name: string, reason: UpgradeReason, suggestedVersion: UpgradeTarget }; +export type DependencyCheckItemEol = DependencyCheckItemBase & { reason: UpgradeReason.END_OF_LIFE, supportedVersion: string, eolDate: Record }; +export type DependencyCheckItemJreTooOld = DependencyCheckItemBase & { reason: UpgradeReason.JRE_TOO_OLD }; +export type DependencyCheckItemDeprecated = DependencyCheckItemBase & { reason: UpgradeReason.DEPRECATED }; +export type DependencyCheckItem = (DependencyCheckItemEol | DependencyCheckItemJreTooOld | DependencyCheckItemDeprecated); export type DependencyCheckMetadata = Record; export enum UpgradeReason { @@ -19,10 +19,8 @@ export enum UpgradeReason { export type UpgradeIssue = { packageId: string; packageDisplayName: string; - reason: UpgradeReason; currentVersion: string; - suggestedVersion: UpgradeTarget; -}; +} & DependencyCheckItem; export interface IUpgradeIssuesRenderer { render(issues: UpgradeIssue[]): void; diff --git a/src/upgrade/utility.ts b/src/upgrade/utility.ts index 09a34594..1735f599 100644 --- a/src/upgrade/utility.ts +++ b/src/upgrade/utility.ts @@ -2,9 +2,24 @@ // Licensed under the MIT license. import { Uri } from "vscode"; +import * as semver from "semver"; import { UpgradeReason, type UpgradeIssue } from "./type"; import { Upgrade } from "../constants"; + +function findEolDate(currentVersion: string, eolDate: Record): string | null { + const currentVersionSemVer = semver.coerce(currentVersion); + if (!currentVersionSemVer) { + return null; + } + for (const [versionRange, date] of Object.entries(eolDate)) { + if (semver.satisfies(currentVersionSemVer, versionRange)) { + return date; + } + } + return null; +} + export function buildNotificationMessage(issue: UpgradeIssue): string { const { packageId, @@ -20,29 +35,31 @@ export function buildNotificationMessage(issue: UpgradeIssue): string { } switch (reason) { - case UpgradeReason.CVE: { - return `The current project is using ${packageDisplayName} ${currentVersion}, which has CVE issues. Do you want to upgrade to ${suggestedVersionName} (${suggestedVersionDescription})?`; + 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})?`; } case UpgradeReason.DEPRECATED: - case UpgradeReason.END_OF_LIFE: default: { - return `The current project is using ${packageDisplayName} ${currentVersion}, which has reached end of life. Do you want to upgrade to ${suggestedVersionName} (${suggestedVersionDescription})?`; + return `The current project is using ${packageDisplayName} ${currentVersion}, which has been deprecated. Do you want to upgrade to ${suggestedVersionName} (${suggestedVersionDescription})?`; } } } export function buildFixPrompt(issue: UpgradeIssue): string { - const { packageDisplayName, reason, suggestedVersion: { name: suggestedVersionName } } = issue; + const { packageDisplayName, reason } = issue; switch (reason) { - case UpgradeReason.CVE: { - return `upgrade ${packageDisplayName} to ${suggestedVersionName} to address CVE issues using java upgrade tools`; - } case UpgradeReason.JRE_TOO_OLD: { + const { suggestedVersion: { name: suggestedVersionName } } = issue; return `upgrade java runtime to the latest LTS version ${suggestedVersionName} using java upgrade tools`; } - default: { + case UpgradeReason.END_OF_LIFE: + case UpgradeReason.DEPRECATED: { + const { suggestedVersion: { name: suggestedVersionName } } = issue; return `upgrade ${packageDisplayName} to ${suggestedVersionName} using java upgrade tools`; } } @@ -54,4 +71,5 @@ export function buildPackageId(groupId: string, artifactId: string): string { export function normalizePath(path: string): string { return Uri.parse(path).toString(); -} \ No newline at end of file +} + From 3b09680877bc46c42f824172176849d7e1daebf8 Mon Sep 17 00:00:00 2001 From: FluoriteCafe-work <202210574+FluoriteCafe-work@users.noreply.github.com> Date: Tue, 16 Sep 2025 17:42:51 +0800 Subject: [PATCH 73/73] chore: lint --- src/upgrade/type.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/upgrade/type.ts b/src/upgrade/type.ts index add29f1d..82105fb0 100644 --- a/src/upgrade/type.ts +++ b/src/upgrade/type.ts @@ -3,7 +3,11 @@ export type UpgradeTarget = { name: string; description: string }; export type DependencyCheckItemBase = { name: string, reason: UpgradeReason, suggestedVersion: UpgradeTarget }; -export type DependencyCheckItemEol = DependencyCheckItemBase & { reason: UpgradeReason.END_OF_LIFE, supportedVersion: string, eolDate: Record }; +export type DependencyCheckItemEol = DependencyCheckItemBase & { + reason: UpgradeReason.END_OF_LIFE, + supportedVersion: string, + eolDate: Record +}; export type DependencyCheckItemJreTooOld = DependencyCheckItemBase & { reason: UpgradeReason.JRE_TOO_OLD }; export type DependencyCheckItemDeprecated = DependencyCheckItemBase & { reason: UpgradeReason.DEPRECATED }; export type DependencyCheckItem = (DependencyCheckItemEol | DependencyCheckItemJreTooOld | DependencyCheckItemDeprecated);