Skip to content

Commit 3789b11

Browse files
frankliu20FrankLiu4138Copilotchagong
authored
Prefer Java upgrade over CVE in dependency recommendations (#1033)
When both Java upgrade and CVE issues are detected, surface the Java upgrade recommendation first instead of the CVE fix. The notification selection logic derives its state from a single isCVE flag and uses ExtensionState-keyed lookup tables for button labels. Add a product-style README section describing the upgrade and security (CVE) recommendations powered by the app modernization extension. Co-authored-by: Frank Liu <haital@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Changyong Gong <chagon@microsoft.com>
1 parent efeb509 commit 3789b11

2 files changed

Lines changed: 48 additions & 64 deletions

File tree

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,17 @@ You can tell that the glob pattern is supported. And here's more - you can incl
5555
}
5656
```
5757

58+
### Stay Secure and Up to Date
59+
60+
Project Manager for Java keeps an eye on your project's Java runtime and dependencies, so you don't have to track them yourself. When it spots something worth your attention, it offers a one-click recommendation to fix it:
61+
62+
- **Upgrade recommendations** – Get notified when your Java runtime or libraries are out of date, deprecated, or have reached end of life, along with a suggested target version.
63+
- **Security recommendations** – Get alerted when known vulnerabilities (CVEs) are detected in your dependencies, so you can address them before they become a problem.
64+
65+
When you accept a recommendation, the upgrade or fix is carried out for you by the [GitHub Copilot app modernization](https://marketplace.visualstudio.com/items?itemName=vscjava.migrate-java-to-azure) extension. If the extension isn't installed yet, it will be set up automatically as part of the flow.
66+
67+
You can turn these reminders on or off at any time with the `java.dependency.enableDependencyCheckup` setting.
68+
5869
## Requirements
5970

6071
- VS Code (version 1.95.0+)

src/upgrade/display/notificationManager.ts

Lines changed: 37 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
import { commands, ExtensionContext, window } from "vscode";
55
import { UpgradeReason, type IUpgradeIssuesRenderer, type UpgradeIssue } from "../type";
6-
import { buildCVENotificationMessage, buildFixPrompt, buildNotificationMessage, getExtensionState } from "../utility";
6+
import { buildCVENotificationMessage, buildFixPrompt, buildNotificationMessage, getExtensionState, type ExtensionState } from "../utility";
77
import { Commands } from "../../commands";
88
import { Settings } from "../../settings";
99
import { instrumentOperation, sendInfo } from "vscode-extension-telemetry-wrapper";
@@ -13,14 +13,20 @@ import { CveUpgradeIssue } from "../cve";
1313
const KEY_PREFIX = 'javaupgrade.notificationManager';
1414
const NEXT_SHOW_TS_KEY = `${KEY_PREFIX}.nextShowTs`;
1515

16-
const BUTTON_TEXT_UPGRADE = "Upgrade Now";
17-
const BUTTON_TEXT_FIX_CVE = "Fix Now";
18-
const BUTTON_TEXT_INSTALL_AND_UPGRADE = "Install Extension and Upgrade";
19-
const BUTTON_TEXT_INSTALL_AND_FIX_CVE = "Install Extension and Fix";
20-
const BUTTON_TEXT_UPDATE_AND_UPGRADE = "Update Extension and Upgrade";
21-
const BUTTON_TEXT_UPDATE_AND_FIX_CVE = "Update Extension and Fix";
2216
const BUTTON_TEXT_NOT_NOW = "Not Now";
2317

18+
// Action button label keyed by the install state of the app modernization extension.
19+
const UPGRADE_BUTTON_TEXT: Record<ExtensionState, string> = {
20+
"up-to-date": "Upgrade Now",
21+
"outdated": "Update Extension and Upgrade",
22+
"not-installed": "Install Extension and Upgrade",
23+
};
24+
const FIX_CVE_BUTTON_TEXT: Record<ExtensionState, string> = {
25+
"up-to-date": "Fix Now",
26+
"outdated": "Update Extension and Fix",
27+
"not-installed": "Install Extension and Fix",
28+
};
29+
2430
const SECONDS_IN_A_DAY = 24 * 60 * 60;
2531
const SECONDS_COUNT_BEFORE_NOTIFICATION_RESHOW = 10 * SECONDS_IN_A_DAY;
2632

@@ -44,84 +50,51 @@ class NotificationManager implements IUpgradeIssuesRenderer {
4450
return;
4551
}
4652

47-
// Filter to only CVE issues and cast to CveUpgradeIssue[]
53+
if (!this.shouldShow() || this.hasShown) {
54+
return;
55+
}
56+
this.hasShown = true;
57+
58+
// Prefer Java upgrade recommendations over CVE fixes: only fall back
59+
// to a CVE notification when there is no upgrade issue to recommend.
4860
const cveIssues = issues.filter(
4961
(i): i is CveUpgradeIssue => i.reason === UpgradeReason.CVE
5062
);
51-
const nonCVEIssues = issues.filter(
63+
const upgradeIssues = issues.filter(
5264
(i) => i.reason !== UpgradeReason.CVE
5365
);
54-
const hasCVEIssue = cveIssues.length > 0;
55-
const issue = hasCVEIssue ? cveIssues[0] : nonCVEIssues[0];
56-
57-
if (!this.shouldShow()) {
58-
return;
59-
}
60-
61-
if (this.hasShown) {
62-
return;
63-
}
64-
this.hasShown = true;
66+
const isCVE = upgradeIssues.length === 0;
67+
const issue = isCVE ? cveIssues[0] : upgradeIssues[0];
6568

6669
const extensionState = getExtensionState(ExtensionName.APP_MODERNIZATION_UPGRADE_FOR_JAVA);
67-
const prompt = buildFixPrompt(issue);
68-
69-
let notificationMessage = "";
70+
const source = isCVE ? Upgrade.SOURCE_CVE : Upgrade.SOURCE_JAVA_UPGRADE;
71+
const notificationMessage = isCVE
72+
? buildCVENotificationMessage(cveIssues, extensionState)
73+
: buildNotificationMessage(issue, extensionState);
74+
const actionButtonText = isCVE
75+
? FIX_CVE_BUTTON_TEXT[extensionState]
76+
: UPGRADE_BUTTON_TEXT[extensionState];
7077

71-
if (hasCVEIssue) {
72-
notificationMessage = buildCVENotificationMessage(cveIssues, extensionState);
73-
} else {
74-
notificationMessage = buildNotificationMessage(issue, extensionState);
75-
}
76-
77-
let upgradeButtonText: string;
78-
let fixCVEButtonText: string;
79-
switch (extensionState) {
80-
case "up-to-date":
81-
upgradeButtonText = BUTTON_TEXT_UPGRADE;
82-
fixCVEButtonText = BUTTON_TEXT_FIX_CVE;
83-
break;
84-
case "outdated":
85-
upgradeButtonText = BUTTON_TEXT_UPDATE_AND_UPGRADE;
86-
fixCVEButtonText = BUTTON_TEXT_UPDATE_AND_FIX_CVE;
87-
break;
88-
case "not-installed":
89-
upgradeButtonText = BUTTON_TEXT_INSTALL_AND_UPGRADE;
90-
fixCVEButtonText = BUTTON_TEXT_INSTALL_AND_FIX_CVE;
91-
break;
92-
}
9378
sendInfo(operationId, {
9479
operationName: "java.dependency.upgradeNotification.show",
9580
extensionState,
96-
source: hasCVEIssue ? Upgrade.SOURCE_CVE : Upgrade.SOURCE_JAVA_UPGRADE,
81+
source,
9782
});
9883

99-
const buttons = hasCVEIssue
100-
? [fixCVEButtonText, BUTTON_TEXT_NOT_NOW]
101-
: [upgradeButtonText, BUTTON_TEXT_NOT_NOW];
102-
10384
const selection = await window.showInformationMessage(
10485
notificationMessage,
105-
...buttons
86+
actionButtonText,
87+
BUTTON_TEXT_NOT_NOW
10688
);
10789
sendInfo(operationId, {
10890
operationName: "java.dependency.upgradeNotification.runUpgrade",
10991
choice: selection ?? "",
11092
});
11193

112-
switch (selection) {
113-
case fixCVEButtonText: {
114-
commands.executeCommand(Commands.JAVA_UPGRADE_WITH_COPILOT, prompt, Upgrade.SOURCE_CVE);
115-
break;
116-
}
117-
case upgradeButtonText: {
118-
commands.executeCommand(Commands.JAVA_UPGRADE_WITH_COPILOT, prompt, Upgrade.SOURCE_JAVA_UPGRADE);
119-
break;
120-
}
121-
case BUTTON_TEXT_NOT_NOW: {
122-
this.setNextShowTs(getNowTs() + SECONDS_COUNT_BEFORE_NOTIFICATION_RESHOW);
123-
break;
124-
}
94+
if (selection === actionButtonText) {
95+
commands.executeCommand(Commands.JAVA_UPGRADE_WITH_COPILOT, buildFixPrompt(issue), source);
96+
} else if (selection === BUTTON_TEXT_NOT_NOW) {
97+
this.setNextShowTs(getNowTs() + SECONDS_COUNT_BEFORE_NOTIFICATION_RESHOW);
12598
}
12699
}
127100
))();

0 commit comments

Comments
 (0)