1+ // Copyright (c) Microsoft Corporation. All rights reserved.
2+ // Licensed under the MIT license.
3+
4+ import { commands , type ExtensionContext , workspace , type WorkspaceFolder } from "vscode" ;
5+ import * as semver from 'semver'
6+ import { Jdtls } from "../java/jdtls" ;
7+ import { languageServerApiManager } from "../languageServerApi/languageServerApiManager" ;
8+ import { NodeKind , type INodeData } from "../java/nodeData" ;
9+ import { Upgrade } from "../constants" ;
10+ import { UpgradeIssue , UpgradeReason } from "./type" ;
11+ import { instrumentOperationAsVsCodeCommand } from "vscode-extension-telemetry-wrapper" ;
12+ import { Commands } from "../commands" ;
13+ import metadataManager from "./metadataManager" ;
14+ import { buildPackageId } from "./utility" ;
15+
16+ const DEFAULT_UPGRADE_PROMPT = "Upgrade Java project dependency" ;
17+
18+ function getJavaIssues ( data : INodeData ) : UpgradeIssue [ ] {
19+ const javaVersion = data . metaData ?. MaxSourceVersion as number | undefined ;
20+ if ( ! javaVersion ) {
21+ return [ ] ;
22+ }
23+ if ( javaVersion < Upgrade . LATEST_JAVA_LTS_VESRION ) {
24+ return [ {
25+ packageId : buildPackageId ( Upgrade . DIAGNOSTICS_GROUP_ID_FOR_JAVA_ENGINE , "*" ) ,
26+ reason : UpgradeReason . ENGINE_TOO_OLD ,
27+ currentVersion : String ( javaVersion ) ,
28+ suggestedVersion : String ( Upgrade . LATEST_JAVA_LTS_VESRION ) ,
29+ } ] ;
30+ }
31+
32+ return [ ] ;
33+ }
34+
35+ function getDependencyIssues ( data : INodeData ) : UpgradeIssue [ ] {
36+ const versionString = data . metaData ?. [ "maven.version" ] ;
37+ const groupId = data . metaData ?. [ "maven.groupId" ] ;
38+ const artifactId = data . metaData ?. [ "maven.artifactId" ] ;
39+ const packageId = buildPackageId ( groupId , artifactId ) ;
40+ const supportedVersionDefinition = metadataManager . getMetadataById ( packageId ) ;
41+ if ( ! versionString || ! groupId || ! supportedVersionDefinition ) {
42+ return [ ] ;
43+ }
44+ const currentVersion = semver . coerce ( versionString ) ;
45+ if ( ! currentVersion ) {
46+ return [ ] ;
47+ }
48+ if ( ! semver . satisfies ( currentVersion , supportedVersionDefinition . supportedVersion ) ) {
49+ return [ {
50+ packageId,
51+ packageDisplayName : supportedVersionDefinition . name ,
52+ reason : UpgradeReason . END_OF_LIFE ,
53+ currentVersion : versionString ,
54+ suggestedVersion : "latest" , // TODO
55+ } ] ;
56+ }
57+ return [ ] ;
58+ }
59+
60+ async function getProjectIssues ( projectNode : INodeData ) : Promise < UpgradeIssue [ ] > {
61+ const pomPath = projectNode . metaData ?. PomPath as string | undefined ;
62+ if ( ! pomPath ) {
63+ return [ ] ;
64+ }
65+ const issues : UpgradeIssue [ ] = [ ] ;
66+ issues . push ( ...getJavaIssues ( projectNode ) ) ;
67+ const packageData = await Jdtls . getPackageData ( { kind : NodeKind . Project , projectUri : projectNode . uri } ) ;
68+ packageData
69+ . filter ( x => x . kind === NodeKind . Container )
70+ . forEach ( async ( packageContainer ) => {
71+ const packages = await Jdtls . getPackageData ( {
72+ kind : NodeKind . Container ,
73+ projectUri : projectNode . uri ,
74+ path : packageContainer . path ,
75+ } ) ;
76+ packages . forEach (
77+ ( pkg ) => {
78+ issues . push ( ...getDependencyIssues ( pkg ) )
79+ }
80+ ) ;
81+ } ) ;
82+ return issues ;
83+ }
84+
85+ class UpgradeManager {
86+ public initialize ( context : ExtensionContext ) {
87+ // Command to be used
88+ context . subscriptions . push ( instrumentOperationAsVsCodeCommand ( Commands . VIEW_TRIGGER_JAVA_UPGRADE_TOOL , ( promptText ?: string ) => {
89+ this . runUpgrade ( promptText ?? DEFAULT_UPGRADE_PROMPT ) ;
90+ } ) ) ;
91+
92+ upgradeManager . scan ( ) ;
93+ }
94+
95+ public scan ( ) {
96+ workspace . workspaceFolders ?. forEach ( ( folder ) =>
97+ this . checkUpgradableComponents ( folder )
98+ ) ;
99+ }
100+
101+ private async checkUpgradableComponents ( folder : WorkspaceFolder ) {
102+ if ( ! await languageServerApiManager . ready ( ) ) {
103+ return ;
104+ }
105+ const hasJavaError : boolean = await Jdtls . checkImportStatus ( ) ;
106+ if ( hasJavaError ) {
107+ return ;
108+ }
109+
110+ const projectIssues : Record < /* pomPath */ string , UpgradeIssue [ ] > = { } ;
111+ const uri = folder . uri . toString ( ) ;
112+ const projects = await Jdtls . getProjects ( uri ) ;
113+ projects . forEach ( async ( projectNode ) => {
114+ const pomPath = projectNode . metaData ?. PomPath as string | undefined ;
115+ if ( ! pomPath ) {
116+ return ;
117+ }
118+
119+ const issues = await getProjectIssues ( projectNode ) ;
120+ projectIssues [ pomPath ] = issues ;
121+ } ) ;
122+
123+ // TODO: show notification
124+ }
125+
126+
127+ private async runUpgrade ( promptText : string ) {
128+ await commands . executeCommand ( "workbench.action.chat.open" , {
129+ query : promptText ,
130+ isPartialQuery : true
131+ } ) ;
132+ }
133+ }
134+
135+ const upgradeManager = new UpgradeManager ( ) ;
136+ export default upgradeManager ;
0 commit comments