From e82d377938d9903ea062b8bb1fd000fd86ecce5e Mon Sep 17 00:00:00 2001 From: Frank Liu Date: Wed, 27 May 2026 19:07:01 +0800 Subject: [PATCH 1/2] fix(upgrade): check extension version and add comprehensive telemetry - Check appmod extension version (>= 1.15.0) before calling gotoAgentMode, fixing 67% of upgrade failures caused by outdated extensions - Add extensionState (up-to-date/outdated/not-installed) and issueType (cve/upgrade) dimensions to all telemetry events for funnel analysis - Distinguish notification button text and message body based on extension state (Upgrade Now / Update Extension and Upgrade / Install Extension and Upgrade) - Track extension install/update success rate and reload prompt engagement - Extract pure functions (getExtensionState, buildNotificationContent) for unit testability - Centralize telemetry operation names in telemetryConstants.ts Co-Authored-By: Claude Opus 4 --- src/constants.ts | 4 +- src/upgrade/display/notificationManager.ts | 104 +++++++++++---- src/upgrade/telemetryConstants.ts | 13 ++ src/upgrade/upgradeManager.ts | 27 +++- src/upgrade/utility.ts | 61 ++++++++- test/suite/notificationContent.test.ts | 143 +++++++++++++++++++++ 6 files changed, 313 insertions(+), 39 deletions(-) create mode 100644 src/upgrade/telemetryConstants.ts create mode 100644 test/suite/notificationContent.test.ts diff --git a/src/constants.ts b/src/constants.ts index 0345b5a0..4ca69ac1 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -36,11 +36,13 @@ export namespace ExtensionName { export const APP_MODERNIZATION_FOR_JAVA = "vscjava.migrate-java-to-azure"; // Java upgrade extension is merged into app modernization extension export const APP_MODERNIZATION_UPGRADE_FOR_JAVA = APP_MODERNIZATION_FOR_JAVA; - export const APP_MODERNIZATION_EXTENSION_NAME = "GitHub Copilot app modernization"; + export const APP_MODERNIZATION_EXTENSION_NAME = "GitHub Copilot modernization"; } export namespace Upgrade { export const PACKAGE_ID_FOR_JAVA_RUNTIME = "java:*"; + /** Minimum version of the appmod extension that supports gotoAgentMode command */ + export const MIN_APPMOD_VERSION = "1.15.0"; } /** diff --git a/src/upgrade/display/notificationManager.ts b/src/upgrade/display/notificationManager.ts index 524184b5..b0ae43b1 100644 --- a/src/upgrade/display/notificationManager.ts +++ b/src/upgrade/display/notificationManager.ts @@ -2,13 +2,15 @@ // Licensed under the MIT license. import { commands, ExtensionContext, extensions, window } from "vscode"; +import * as semver from "semver"; import { UpgradeReason, type IUpgradeIssuesRenderer, type UpgradeIssue } from "../type"; -import { buildCVENotificationMessage, buildFixPrompt, buildNotificationMessage } from "../utility"; +import { buildCVENotificationMessage, buildFixPrompt, buildNotificationMessage, type ExtensionState } from "../utility"; import { Commands } from "../../commands"; import { Settings } from "../../settings"; import { instrumentOperation, sendInfo } from "vscode-extension-telemetry-wrapper"; -import { ExtensionName } from "../../constants"; +import { ExtensionName, Upgrade } from "../../constants"; import { CveUpgradeIssue } from "../cve"; +import { UpgradeTelemetry } from "../telemetryConstants"; const KEY_PREFIX = 'javaupgrade.notificationManager'; const NEXT_SHOW_TS_KEY = `${KEY_PREFIX}.nextShowTs`; @@ -17,6 +19,8 @@ const BUTTON_TEXT_UPGRADE = "Upgrade Now"; const BUTTON_TEXT_FIX_CVE = "Fix Now"; const BUTTON_TEXT_INSTALL_AND_UPGRADE = "Install Extension and Upgrade"; const BUTTON_TEXT_INSTALL_AND_FIX_CVE = "Install Extension and Fix"; +const BUTTON_TEXT_UPDATE_AND_UPGRADE = "Update Extension and Upgrade"; +const BUTTON_TEXT_UPDATE_AND_FIX_CVE = "Update Extension and Fix"; const BUTTON_TEXT_NOT_NOW = "Not Now"; const SECONDS_IN_A_DAY = 24 * 60 * 60; @@ -26,6 +30,61 @@ function getNowTs() { return Number(new Date()) / 1000; } +export type { ExtensionState } from "../utility"; + +export interface NotificationContent { + message: string; + upgradeButtonText: string; + fixCVEButtonText: string; +} + +export function getExtensionState(extensionVersion: string | undefined): ExtensionState { + if (!extensionVersion) { + return "not-installed"; + } + if (semver.gte(extensionVersion, Upgrade.MIN_APPMOD_VERSION)) { + return "up-to-date"; + } + return "outdated"; +} + +export function buildNotificationContent( + issues: UpgradeIssue[], + extensionState: ExtensionState, +): NotificationContent { + const cveIssues = issues.filter( + (i): i is CveUpgradeIssue => i.reason === UpgradeReason.CVE + ); + const nonCVEIssues = issues.filter( + (i) => i.reason !== UpgradeReason.CVE + ); + const hasCVEIssue = cveIssues.length > 0; + + const message = hasCVEIssue + ? buildCVENotificationMessage(cveIssues, extensionState) + : buildNotificationMessage(nonCVEIssues[0], extensionState); + + let upgradeButtonText: string; + let fixCVEButtonText: string; + + switch (extensionState) { + case "up-to-date": + upgradeButtonText = BUTTON_TEXT_UPGRADE; + fixCVEButtonText = BUTTON_TEXT_FIX_CVE; + break; + case "outdated": + upgradeButtonText = BUTTON_TEXT_UPDATE_AND_UPGRADE; + fixCVEButtonText = BUTTON_TEXT_UPDATE_AND_FIX_CVE; + break; + case "not-installed": + upgradeButtonText = BUTTON_TEXT_INSTALL_AND_UPGRADE; + fixCVEButtonText = BUTTON_TEXT_INSTALL_AND_FIX_CVE; + break; + } + + return { message, upgradeButtonText, fixCVEButtonText }; +} + class NotificationManager implements IUpgradeIssuesRenderer { private hasShown = false; private context?: ExtensionContext; @@ -42,16 +101,6 @@ class NotificationManager implements IUpgradeIssuesRenderer { return; } - // Filter to only CVE issues and cast to CveUpgradeIssue[] - const cveIssues = issues.filter( - (i): i is CveUpgradeIssue => i.reason === UpgradeReason.CVE - ); - const nonCVEIssues = issues.filter( - (i) => i.reason !== UpgradeReason.CVE - ); - const hasCVEIssue = cveIssues.length > 0; - const issue = hasCVEIssue ? cveIssues[0] : nonCVEIssues[0]; - if (!this.shouldShow()) { return; } @@ -61,20 +110,21 @@ class NotificationManager implements IUpgradeIssuesRenderer { } this.hasShown = true; - const hasExtension = !!extensions.getExtension(ExtensionName.APP_MODERNIZATION_UPGRADE_FOR_JAVA); - const prompt = buildFixPrompt(issue); + const ext = extensions.getExtension(ExtensionName.APP_MODERNIZATION_UPGRADE_FOR_JAVA); + const extensionState = getExtensionState(ext?.packageJSON?.version); + const { message, upgradeButtonText, fixCVEButtonText } = buildNotificationContent(issues, extensionState); - let notificationMessage = ""; + const hasCVEIssue = issues.some(i => i.reason === UpgradeReason.CVE); + const issueType = hasCVEIssue ? "cve" : "upgrade"; + const issue = hasCVEIssue + ? issues.find((i): i is CveUpgradeIssue => i.reason === UpgradeReason.CVE)! + : issues.find(i => i.reason !== UpgradeReason.CVE)!; + const prompt = buildFixPrompt(issue); - if (hasCVEIssue) { - notificationMessage = buildCVENotificationMessage(cveIssues, hasExtension); - } else { - notificationMessage = buildNotificationMessage(issue, hasExtension); - } - const upgradeButtonText = hasExtension ? BUTTON_TEXT_UPGRADE : BUTTON_TEXT_INSTALL_AND_UPGRADE; - const fixCVEButtonText = hasExtension ? BUTTON_TEXT_FIX_CVE : BUTTON_TEXT_INSTALL_AND_FIX_CVE; sendInfo(operationId, { - operationName: "java.dependency.upgradeNotification.show", + operationName: UpgradeTelemetry.NOTIFICATION_SHOW, + extensionState, + issueType, }); const buttons = hasCVEIssue @@ -82,18 +132,20 @@ class NotificationManager implements IUpgradeIssuesRenderer { : [upgradeButtonText, BUTTON_TEXT_NOT_NOW]; const selection = await window.showInformationMessage( - notificationMessage, + message, ...buttons ); sendInfo(operationId, { - operationName: "java.dependency.upgradeNotification.runUpgrade", + operationName: UpgradeTelemetry.NOTIFICATION_CLICK, + extensionState, + issueType, choice: selection ?? "", }); switch (selection) { case fixCVEButtonText: case upgradeButtonText: { - commands.executeCommand(Commands.JAVA_UPGRADE_WITH_COPILOT, prompt); + commands.executeCommand(Commands.JAVA_UPGRADE_WITH_COPILOT, prompt, issueType, extensionState); break; } case BUTTON_TEXT_NOT_NOW: { diff --git a/src/upgrade/telemetryConstants.ts b/src/upgrade/telemetryConstants.ts new file mode 100644 index 00000000..46d220c5 --- /dev/null +++ b/src/upgrade/telemetryConstants.ts @@ -0,0 +1,13 @@ +/** + * Telemetry operation names for the upgrade flow. + */ +export const UpgradeTelemetry = { + NOTIFICATION_SHOW: "java.dependency.upgradeNotification.show", + NOTIFICATION_CLICK: "java.dependency.upgradeNotification.runUpgrade", + EXECUTE_START: "java.dependency.upgrade.execute.start", + EXECUTE_END: "java.dependency.upgrade.execute.end", + EXTENSION_INSTALL_START: "java.dependency.upgrade.extensionInstall.start", + EXTENSION_INSTALL_END: "java.dependency.upgrade.extensionInstall.end", + RELOAD_PROMPT_SHOW: "java.dependency.upgrade.reloadPrompt.show", + RELOAD_PROMPT_CLICK: "java.dependency.upgrade.reloadPrompt.click", +} as const; diff --git a/src/upgrade/upgradeManager.ts b/src/upgrade/upgradeManager.ts index 1f9f1d3a..4a25aa85 100644 --- a/src/upgrade/upgradeManager.ts +++ b/src/upgrade/upgradeManager.ts @@ -12,8 +12,9 @@ import notificationManager from "./display/notificationManager"; import { Settings } from "../settings"; import assessmentManager, { getDirectDependencies } from "./assessmentManager"; import { checkOrInstallAppModExtensionForUpgrade, checkOrPopupToInstallAppModExtensionForModernization } from "./utility"; +import { UpgradeTelemetry } from "./telemetryConstants"; -const DEFAULT_UPGRADE_PROMPT = "Upgrade Java project dependency to latest version."; +const DEFAULT_UPGRADE_PROMPT = "Upgrade Java runtime and frameworks to the latest stable version."; function shouldRunCheckup() { @@ -25,10 +26,26 @@ class UpgradeManager { notificationManager.initialize(context); // Upgrade project - context.subscriptions.push(instrumentOperationAsVsCodeCommand(Commands.JAVA_UPGRADE_WITH_COPILOT, async (promptText?: string) => { - await checkOrInstallAppModExtensionForUpgrade(ExtensionName.APP_MODERNIZATION_UPGRADE_FOR_JAVA); - const promptToUse = promptText ?? DEFAULT_UPGRADE_PROMPT; - await commands.executeCommand(Commands.GOTO_AGENT_MODE, { prompt: promptToUse, useCustomAgent: true }); + context.subscriptions.push(instrumentOperationAsVsCodeCommand(Commands.JAVA_UPGRADE_WITH_COPILOT, async (promptText?: string, issueType?: string, extensionState?: string) => { + const dimensions = { + issueType: issueType ?? "unknown", + extensionState: extensionState ?? "unknown", + }; + sendInfo("", { operationName: UpgradeTelemetry.EXECUTE_START, ...dimensions }); + try { + await checkOrInstallAppModExtensionForUpgrade(ExtensionName.APP_MODERNIZATION_UPGRADE_FOR_JAVA); + const promptToUse = promptText ?? DEFAULT_UPGRADE_PROMPT; + await commands.executeCommand(Commands.GOTO_AGENT_MODE, { prompt: promptToUse, useCustomAgent: true }); + sendInfo("", { operationName: UpgradeTelemetry.EXECUTE_END, ...dimensions, result: "success" }); + } catch (e) { + sendInfo("", { + operationName: UpgradeTelemetry.EXECUTE_END, + ...dimensions, + result: "failure", + error: e instanceof Error ? e.message : String(e), + }); + throw e; + } })); // Show modernization view diff --git a/src/upgrade/utility.ts b/src/upgrade/utility.ts index 40fb2de2..ec69d368 100644 --- a/src/upgrade/utility.ts +++ b/src/upgrade/utility.ts @@ -7,6 +7,7 @@ import { UpgradeReason, type UpgradeIssue } from "./type"; import { ExtensionName, Upgrade } from "../constants"; import { instrumentOperation, sendInfo } from "vscode-extension-telemetry-wrapper"; import { CveUpgradeIssue } from "./cve"; +import { UpgradeTelemetry } from "./telemetryConstants"; function findEolDate(currentVersion: string, eolDate: Record): string | null { @@ -22,7 +23,20 @@ function findEolDate(currentVersion: string, eolDate: Record): s return null; } -export function buildNotificationMessage(issue: UpgradeIssue, hasExtension: boolean): string { +export type ExtensionState = "up-to-date" | "outdated" | "not-installed"; + +function getActionWord(extensionState: ExtensionState, verb: string): string { + switch (extensionState) { + case "up-to-date": + return verb; + case "outdated": + return `update ${ExtensionName.APP_MODERNIZATION_EXTENSION_NAME} extension and ${verb}`; + case "not-installed": + return `install ${ExtensionName.APP_MODERNIZATION_EXTENSION_NAME} extension and ${verb}`; + } +} + +export function buildNotificationMessage(issue: UpgradeIssue, extensionState: ExtensionState): string { const { packageId, currentVersion, @@ -31,7 +45,7 @@ export function buildNotificationMessage(issue: UpgradeIssue, hasExtension: bool packageDisplayName } = issue; - const upgradeWord = hasExtension ? "upgrade" : `install ${ExtensionName.APP_MODERNIZATION_EXTENSION_NAME} extension and upgrade`; + const upgradeWord = getActionWord(extensionState, "upgrade"); if (packageId === Upgrade.PACKAGE_ID_FOR_JAVA_RUNTIME) { return `This project is using an older Java runtime (${currentVersion}). Would you like to ${upgradeWord} it to the latest LTS version?`; @@ -51,7 +65,7 @@ export function buildNotificationMessage(issue: UpgradeIssue, hasExtension: bool } } -export function buildCVENotificationMessage(issues: CveUpgradeIssue[], hasExtension: boolean): string { +export function buildCVENotificationMessage(issues: CveUpgradeIssue[], extensionState: ExtensionState): string { if (issues.length === 0) { return "No CVE issues found."; @@ -81,7 +95,7 @@ export function buildCVENotificationMessage(issues: CveUpgradeIssue[], hasExtens CVESeverityDistribution: severityText, }); - const fixWord = hasExtension ? "fix" : `install ${ExtensionName.APP_MODERNIZATION_EXTENSION_NAME} extension and fix`; + const fixWord = getActionWord(extensionState, "fix"); if (issues.length === 1) { return `${severityText} CVE vulnerability is detected in this project. Would you like to ${fixWord} it now?`; @@ -102,7 +116,7 @@ export function buildFixPrompt(issue: UpgradeIssue): string { return `upgrade ${packageDisplayName} to ${suggestedVersionName}`; } case UpgradeReason.CVE: { - return `fix all critical and high-severity CVE vulnerabilities in this project by invoking #appmod-validate-cves-for-java`; + return `fix all CVE vulnerabilities in this project`; } } } @@ -155,10 +169,43 @@ export async function checkOrPopupToInstallAppModExtensionForModernization( export async function checkOrInstallAppModExtensionForUpgrade( extensionIdToCheck: string): Promise { - if (extensions.getExtension(extensionIdToCheck)) { + const ext = extensions.getExtension(extensionIdToCheck); + + if (ext) { + const installedVersion = ext.packageJSON?.version; + if (installedVersion && semver.gte(installedVersion, Upgrade.MIN_APPMOD_VERSION)) { + return; + } + } + + const action = ext ? "update" : "install"; + sendInfo("", { operationName: UpgradeTelemetry.EXTENSION_INSTALL_START, action }); + try { + await commands.executeCommand("workbench.extensions.installExtension", ExtensionName.APP_MODERNIZATION_FOR_JAVA); + sendInfo("", { operationName: UpgradeTelemetry.EXTENSION_INSTALL_END, action, result: "success" }); + } catch (e) { + sendInfo("", { + operationName: UpgradeTelemetry.EXTENSION_INSTALL_END, + action, + result: "failure", + error: e instanceof Error ? e.message : String(e), + }); + throw e; + } + + if (action === "update") { + // Reload is required for the updated extension to take effect + sendInfo("", { operationName: UpgradeTelemetry.RELOAD_PROMPT_SHOW }); + const reload = await window.showInformationMessage( + "GitHub Copilot modernization extension has been updated. Reload VS Code to start the modernize experience.", + "Reload Now" + ); + sendInfo("", { operationName: UpgradeTelemetry.RELOAD_PROMPT_CLICK, choice: reload ?? "dismissed" }); + if (reload === "Reload Now") { + await commands.executeCommand("workbench.action.reloadWindow"); + } return; } - await commands.executeCommand("workbench.extensions.installExtension", ExtensionName.APP_MODERNIZATION_FOR_JAVA); await checkOrPromptToEnableAppModExtension("upgrade"); } \ No newline at end of file diff --git a/test/suite/notificationContent.test.ts b/test/suite/notificationContent.test.ts new file mode 100644 index 00000000..f2aaa76c --- /dev/null +++ b/test/suite/notificationContent.test.ts @@ -0,0 +1,143 @@ +import * as assert from "assert"; +import { getExtensionState, buildNotificationContent } from "../../src/upgrade/display/notificationManager"; +import { UpgradeReason, type UpgradeIssue } from "../../src/upgrade/type"; +import { Upgrade } from "../../src/constants"; + +suite("notificationManager pure functions", () => { + + suite("getExtensionState", () => { + test("returns 'not-installed' when version is undefined", () => { + assert.strictEqual(getExtensionState(undefined), "not-installed"); + }); + + // Real release versions that are below MIN_APPMOD_VERSION (1.13.0) + const outdatedVersions = [ + "1.14.1", + "1.14.2026033101", + "1.14.0", + "1.13.0", + "1.13.2026031003", + "1.13.2026030905", + "1.12.26021301", + "1.11.0", + "1.11.26012301", + "1.10.1", + "1.10.0", + "1.9.1", + "1.0.0", + "0.5.2025061701", + ]; + + for (const version of outdatedVersions) { + test(`returns 'outdated' for version ${version}`, () => { + assert.strictEqual(getExtensionState(version), "outdated"); + }); + } + + // Real release versions that are >= MIN_APPMOD_VERSION (1.13.0) + const upToDateVersions = [ + "1.15.0", // exact minimum + "1.15.3", + "1.16.0", + "1.17.0", + "1.17.1", + "1.18.0", + "1.19.0", + "1.19.1", + "1.19.2", + "1.20.26052601", // latest + ]; + + for (const version of upToDateVersions) { + test(`returns 'up-to-date' for version ${version}`, () => { + assert.strictEqual(getExtensionState(version), "up-to-date"); + }); + } + + test("MIN_APPMOD_VERSION is 1.15.0", () => { + assert.strictEqual(Upgrade.MIN_APPMOD_VERSION, "1.15.0"); + }); + }); + + suite("buildNotificationContent", () => { + const upgradeIssue: UpgradeIssue = { + packageId: "org.springframework.boot:spring-boot-starter", + packageDisplayName: "Spring Boot", + currentVersion: "2.7.0", + name: "spring-boot-starter", + reason: UpgradeReason.DEPRECATED, + suggestedVersion: { name: "3.2.0", description: "latest stable" }, + }; + + const cveIssue: UpgradeIssue = { + packageId: "org.apache.logging.log4j:log4j-core", + packageDisplayName: "Log4j", + currentVersion: "2.14.0", + name: "log4j-core", + reason: UpgradeReason.CVE, + suggestedVersion: { name: "2.17.1", description: "patched" }, + severity: "critical", + description: "Remote code execution", + link: "https://nvd.nist.gov/vuln/detail/CVE-2021-44228", + }; + + suite("button text", () => { + test("shows 'Upgrade Now' / 'Fix Now' when extension is up-to-date", () => { + const result = buildNotificationContent([upgradeIssue], "up-to-date"); + assert.strictEqual(result.upgradeButtonText, "Upgrade Now"); + assert.strictEqual(result.fixCVEButtonText, "Fix Now"); + }); + + test("shows 'Update Extension and Upgrade/Fix' when extension is outdated", () => { + const result = buildNotificationContent([upgradeIssue], "outdated"); + assert.strictEqual(result.upgradeButtonText, "Update Extension and Upgrade"); + assert.strictEqual(result.fixCVEButtonText, "Update Extension and Fix"); + }); + + test("shows 'Install Extension and Upgrade/Fix' when extension is not installed", () => { + const result = buildNotificationContent([upgradeIssue], "not-installed"); + assert.strictEqual(result.upgradeButtonText, "Install Extension and Upgrade"); + assert.strictEqual(result.fixCVEButtonText, "Install Extension and Fix"); + }); + }); + + suite("message body", () => { + test("up-to-date: message says 'upgrade'", () => { + const result = buildNotificationContent([upgradeIssue], "up-to-date"); + assert.ok(result.message.includes("upgrade")); + assert.ok(!result.message.includes("install")); + assert.ok(!result.message.includes("update")); + }); + + test("outdated: message says 'update ... extension and upgrade'", () => { + const result = buildNotificationContent([upgradeIssue], "outdated"); + assert.ok(result.message.includes("update")); + assert.ok(result.message.includes("extension and upgrade")); + }); + + test("not-installed: message says 'install ... extension and upgrade'", () => { + const result = buildNotificationContent([upgradeIssue], "not-installed"); + assert.ok(result.message.includes("install")); + assert.ok(result.message.includes("extension and upgrade")); + }); + + test("CVE up-to-date: message says 'fix'", () => { + const result = buildNotificationContent([cveIssue], "up-to-date"); + assert.ok(result.message.includes("fix")); + assert.ok(result.message.includes("CVE")); + }); + + test("CVE outdated: message says 'update ... extension and fix'", () => { + const result = buildNotificationContent([cveIssue], "outdated"); + assert.ok(result.message.includes("update")); + assert.ok(result.message.includes("extension and fix")); + }); + + test("CVE not-installed: message says 'install ... extension and fix'", () => { + const result = buildNotificationContent([cveIssue], "not-installed"); + assert.ok(result.message.includes("install")); + assert.ok(result.message.includes("extension and fix")); + }); + }); + }); +}); From a8c104ce9e77ce065ce6c6dadc01dd7bacb17a32 Mon Sep 17 00:00:00 2001 From: Frank Liu Date: Wed, 27 May 2026 19:22:59 +0800 Subject: [PATCH 2/2] fix(telemetry): link execute events with operationId and notification correlation - Replace instrumentOperationAsVsCodeCommand with instrumentOperation + registerCommand to get operationId for execute.start/end events - Pass notification's operationId to the upgrade command as notificationOperationId, enabling cross-step funnel join Co-Authored-By: Claude Opus 4 --- src/upgrade/display/notificationManager.ts | 2 +- src/upgrade/upgradeManager.ts | 43 ++++++++++++---------- 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/src/upgrade/display/notificationManager.ts b/src/upgrade/display/notificationManager.ts index b0ae43b1..d4f1478b 100644 --- a/src/upgrade/display/notificationManager.ts +++ b/src/upgrade/display/notificationManager.ts @@ -145,7 +145,7 @@ class NotificationManager implements IUpgradeIssuesRenderer { switch (selection) { case fixCVEButtonText: case upgradeButtonText: { - commands.executeCommand(Commands.JAVA_UPGRADE_WITH_COPILOT, prompt, issueType, extensionState); + commands.executeCommand(Commands.JAVA_UPGRADE_WITH_COPILOT, prompt, issueType, extensionState, operationId); break; } case BUTTON_TEXT_NOT_NOW: { diff --git a/src/upgrade/upgradeManager.ts b/src/upgrade/upgradeManager.ts index 4a25aa85..a2493ab5 100644 --- a/src/upgrade/upgradeManager.ts +++ b/src/upgrade/upgradeManager.ts @@ -26,26 +26,29 @@ class UpgradeManager { notificationManager.initialize(context); // Upgrade project - context.subscriptions.push(instrumentOperationAsVsCodeCommand(Commands.JAVA_UPGRADE_WITH_COPILOT, async (promptText?: string, issueType?: string, extensionState?: string) => { - const dimensions = { - issueType: issueType ?? "unknown", - extensionState: extensionState ?? "unknown", - }; - sendInfo("", { operationName: UpgradeTelemetry.EXECUTE_START, ...dimensions }); - try { - await checkOrInstallAppModExtensionForUpgrade(ExtensionName.APP_MODERNIZATION_UPGRADE_FOR_JAVA); - const promptToUse = promptText ?? DEFAULT_UPGRADE_PROMPT; - await commands.executeCommand(Commands.GOTO_AGENT_MODE, { prompt: promptToUse, useCustomAgent: true }); - sendInfo("", { operationName: UpgradeTelemetry.EXECUTE_END, ...dimensions, result: "success" }); - } catch (e) { - sendInfo("", { - operationName: UpgradeTelemetry.EXECUTE_END, - ...dimensions, - result: "failure", - error: e instanceof Error ? e.message : String(e), - }); - throw e; - } + context.subscriptions.push(commands.registerCommand(Commands.JAVA_UPGRADE_WITH_COPILOT, (promptText?: string, issueType?: string, extensionState?: string, notificationOperationId?: string) => { + return instrumentOperation(Commands.JAVA_UPGRADE_WITH_COPILOT, async (operationId: string) => { + const dimensions = { + issueType: issueType ?? "unknown", + extensionState: extensionState ?? "unknown", + notificationOperationId: notificationOperationId ?? "", + }; + sendInfo(operationId, { operationName: UpgradeTelemetry.EXECUTE_START, ...dimensions }); + try { + await checkOrInstallAppModExtensionForUpgrade(ExtensionName.APP_MODERNIZATION_UPGRADE_FOR_JAVA); + const promptToUse = promptText ?? DEFAULT_UPGRADE_PROMPT; + await commands.executeCommand(Commands.GOTO_AGENT_MODE, { prompt: promptToUse, useCustomAgent: true }); + sendInfo(operationId, { operationName: UpgradeTelemetry.EXECUTE_END, ...dimensions, result: "success" }); + } catch (e) { + sendInfo(operationId, { + operationName: UpgradeTelemetry.EXECUTE_END, + ...dimensions, + result: "failure", + error: e instanceof Error ? e.message : String(e), + }); + throw e; + } + })(); })); // Show modernization view