2222
2323package com .microsoft .azure .springcloud .dependency .action ;
2424
25+ import com .google .common .util .concurrent .SettableFuture ;
2526import com .intellij .openapi .actionSystem .AnActionEvent ;
2627import com .intellij .openapi .actionSystem .CommonDataKeys ;
2728import com .intellij .openapi .actionSystem .LangDataKeys ;
2829import com .intellij .openapi .actionSystem .Presentation ;
2930import com .intellij .openapi .application .ApplicationManager ;
3031import com .intellij .openapi .editor .Editor ;
3132import com .intellij .openapi .editor .EditorKind ;
33+ import com .intellij .openapi .externalSystem .autoimport .ExternalSystemProjectTracker ;
34+ import com .intellij .openapi .externalSystem .autoimport .ProjectNotificationAware ;
3235import com .intellij .openapi .fileEditor .FileEditorManager ;
3336import com .intellij .openapi .module .Module ;
3437import com .intellij .openapi .module .ModuleTypeId ;
6063
6164import java .io .File ;
6265import java .io .IOException ;
63- import java .util .ArrayList ;
64- import java .util .Collections ;
65- import java .util .List ;
66- import java .util .Map ;
66+ import java .util .*;
67+ import java .util .concurrent .ExecutionException ;
6768
6869public class AddAzureDependencyAction extends AzureAnAction {
6970 public static final String SPRING_CLOUD_GROUP_ID = "org.springframework.cloud" ;
7071 public static final String SPRING_BOOT_GROUP_ID = "org.springframework.boot" ;
7172 private static final String GROUP_ID = "com.microsoft.azure" ;
7273 private static final String ARTIFACT_ID = "spring-cloud-starter-azure-spring-cloud-client" ;
74+ private static final String SPRING_CLOUD_COMMONS_KEY = "org.springframework.cloud:spring-cloud-commons" ;
7375
7476 @ Override
7577 public boolean onActionPerformed (@ NotNull AnActionEvent event , @ Nullable Operation operation ) {
@@ -79,87 +81,83 @@ public boolean onActionPerformed(@NotNull AnActionEvent event, @Nullable Operati
7981 final MavenProject mavenProject = projectsManager .findProject (module );
8082 if (mavenProject == null ) {
8183 PluginUtil .showErrorNotificationProject (project , "Error" ,
82- String .format ("Project '%s' is not a maven project." ,
83- project .getName ()));
84+ String .format ("Project '%s' is not a maven project." ,
85+ project .getName ()));
8486 return true ;
8587 }
8688
87- DefaultLoader .getIdeHelper ().runInBackground (project , "Deleting Docker Host" , false , true , "Update Azure Spring Cloud dependencies" , () -> {
88- ProgressIndicator progressIndicator = ProgressManager .getInstance ().getProgressIndicator ();
89- progressIndicator .setText ("Syncing maven project " + project .getName ());
90- if (projectsManager .hasScheduledProjects ()) {
91- projectsManager .forceUpdateProjects (Collections .singletonList (mavenProject )).get ();
92- }
93- try {
94- progressIndicator .setText ("Check existing dependencies" );
95- final String evaluateEffectivePom = MavenUtils .evaluateEffectivePom (project , mavenProject );
96- ProgressManager .checkCanceled ();
97- if (StringUtils .isEmpty (evaluateEffectivePom )) {
98- PluginUtil .showErrorNotificationProject (project , "Error" , "Failed to evaluate effective pom." );
99- return ;
100- }
101- final String springBootVer = getMavenLibraryVersion (mavenProject , SPRING_BOOT_GROUP_ID , "spring-boot-autoconfigure" );
102- if (StringUtils .isEmpty (springBootVer )) {
103- throw new AzureExecutionException (String .format ("Module %s is not a spring-boot application." , module .getName ()));
104- }
105- progressIndicator .setText ("Get latest versions ..." );
106- SpringCloudDependencyManager manager = new SpringCloudDependencyManager (evaluateEffectivePom );
107- Map <String , DependencyArtifact > versionMaps = manager .getDependencyVersions ();
108- List <DependencyArtifact > dep = new ArrayList <>();
109- dep .add (getDependencyArtifact (GROUP_ID , ARTIFACT_ID , versionMaps ));
110- dep .add (getDependencyArtifact (SPRING_BOOT_GROUP_ID , "spring-boot-starter-actuator" , versionMaps ));
111- dep .add (getDependencyArtifact (SPRING_CLOUD_GROUP_ID , "spring-cloud-config-client" , versionMaps ));
112- dep .add (getDependencyArtifact (SPRING_CLOUD_GROUP_ID ,
113- "spring-cloud-starter-netflix-eureka-client" ,
114- versionMaps ));
115- dep .add (getDependencyArtifact (SPRING_CLOUD_GROUP_ID , "spring-cloud-starter-zipkin" , versionMaps ));
116- dep .add (getDependencyArtifact (SPRING_CLOUD_GROUP_ID , "spring-cloud-starter-sleuth" , versionMaps ));
117- ProgressManager .checkCanceled ();
118- List <DependencyArtifact > versionChanges = SpringCloudDependencyManager .getCompatibleVersions (dep , springBootVer );
119- if (versionChanges .isEmpty ()) {
120- PluginUtil .showInfoNotificationProject (project , "Your project is update-to-date." ,
121- "No updates are needed." );
122- return ;
123- }
124- progressIndicator .setText ("Applying versions ..." );
125- File pomFile = new File (mavenProject .getFile ().getCanonicalPath ());
126- ProgressManager .checkCanceled ();
127- Map <String , DependencyArtifact > managementVersions = manager .getDependencyManagementVersions ();
128- versionChanges .stream ().filter (change -> managementVersions .containsKey (change .getKey ())).forEach (change -> {
129- String managementVersion = managementVersions .get (change .getKey ()).getCurrentVersion ();
130- if (StringUtils .equals (change .getCompatibleVersion (), managementVersion )
131- || SpringCloudDependencyManager .isCompatibleVersion (managementVersion , springBootVer )) {
132- change .setCompatibleVersion ("" );
133- change .setManagementVersion (managementVersion );
89+ DefaultLoader .getIdeHelper ().runInBackground (project ,
90+ "Update Azure Spring Cloud dependencies" ,
91+ false ,
92+ true ,
93+ "Update Azure Spring Cloud dependencies" ,
94+ () -> {
95+ ProgressIndicator progressIndicator = ProgressManager .getInstance ().getProgressIndicator ();
96+ progressIndicator .setText ("Syncing maven project " + project .getName ());
97+ final SettableFuture <Boolean > isDirty = SettableFuture .create ();
98+
99+ ApplicationManager .getApplication ().invokeAndWait (() -> {
100+ ProjectNotificationAware notificationAware = ProjectNotificationAware .getInstance (project );
101+ isDirty .set (notificationAware .isNotificationVisible ());
102+ if (notificationAware .isNotificationVisible ()) {
103+ ExternalSystemProjectTracker projectTracker = ExternalSystemProjectTracker .getInstance (project );
104+ projectTracker .scheduleProjectRefresh ();
134105 }
135106 });
136- if (!manager .update (pomFile , versionChanges )) {
137- PluginUtil .showInfoNotificationProject (project , "Your project is update-to-date." ,
138- "No updates are needed." );
107+ try {
108+ if (isDirty .get ().booleanValue ()) {
109+ projectsManager .forceUpdateProjects (Collections .singletonList (mavenProject )).get ();
110+ }
111+ } catch (InterruptedException | ExecutionException e ) {
112+ PluginUtil .showErrorNotification ("Error" ,
113+ "Failed to update project due to error: "
114+ + e .getMessage ());
139115 return ;
140116 }
141117
142- final VirtualFile vf = LocalFileSystem .getInstance ().refreshAndFindFileByIoFile (pomFile );
143- RefreshQueue .getInstance ().refresh (true , false , null , new VirtualFile []{vf });
144- ApplicationManager .getApplication ().invokeLater (() -> {
145- FileEditorManager .getInstance (project ).closeFile (vf );
146- FileEditorManager .getInstance (project ).openFile (vf , true , true );
147- if (versionChanges .stream ().anyMatch (t -> StringUtils .isNotEmpty (t .getCurrentVersion ()))) {
148- PluginUtil .showInfoNotificationProject (project ,
149- "Azure Spring Cloud dependencies are updated successfully." ,
150- summaryVersionChanges (versionChanges ));
118+ try {
119+ progressIndicator .setText ("Check existing dependencies" );
120+ final String evaluateEffectivePom = MavenUtils .evaluateEffectivePom (project , mavenProject );
121+ ProgressManager .checkCanceled ();
122+ if (StringUtils .isEmpty (evaluateEffectivePom )) {
123+ PluginUtil .showErrorNotificationProject (project , "Error" , "Failed to evaluate effective pom." );
124+ return ;
125+ }
126+ final String springBootVer = getMavenLibraryVersion (mavenProject , SPRING_BOOT_GROUP_ID , "spring-boot-autoconfigure" );
127+ if (StringUtils .isEmpty (springBootVer )) {
128+ throw new AzureExecutionException (String .format ("Module %s is not a spring-boot application." , module .getName ()));
129+ }
130+ progressIndicator .setText ("Get latest versions ..." );
131+ SpringCloudDependencyManager dependencyManager = new SpringCloudDependencyManager (evaluateEffectivePom );
132+ Map <String , DependencyArtifact > versionMaps = dependencyManager .getDependencyVersions ();
133+ Map <String , DependencyArtifact > managerDependencyVersionsMaps = dependencyManager .getDependencyManagementVersions ();
134+
135+ // given the spring-cloud-commons is greater or equal to 2.2.5.RELEASE, we should not add spring-cloud-starter-azure-spring-cloud-client
136+ // because the code is already merged into spring repo: https://github.com/spring-cloud/spring-cloud-commons/pull/803
137+ boolean noAzureSpringCloudClientDependency = shouldNotAddAzureSpringCloudClientDependency (versionMaps ) ||
138+ shouldNotAddAzureSpringCloudClientDependency (managerDependencyVersionsMaps );
139+
140+ ProgressManager .checkCanceled ();
141+ final List <DependencyArtifact > versionChanges = calculateVersionChanges (springBootVer , noAzureSpringCloudClientDependency , versionMaps );
142+ if (versionChanges .isEmpty ()) {
143+ PluginUtil .showInfoNotificationProject (project , "Your project is update-to-date." ,
144+ "No updates are needed." );
145+ return ;
146+ }
147+ progressIndicator .setText ("Applying versions ..." );
148+ final File pomFile = new File (mavenProject .getFile ().getCanonicalPath ());
149+ ProgressManager .checkCanceled ();
150+ if (applyVersionChanges (dependencyManager , pomFile , springBootVer , managerDependencyVersionsMaps , versionChanges )) {
151+ noticeUserVersionChanges (project , pomFile , versionChanges );
151152 } else {
152- PluginUtil .showInfoNotificationProject (project ,
153- "Azure Spring Cloud dependencies are added to your project successfully." ,
154- summaryVersionChanges (versionChanges ));
153+ PluginUtil .showInfoNotificationProject (project , "Your project is update-to-date." , "No updates are needed." );
155154 }
156- });
157- } catch (DocumentException | IOException | AzureExecutionException | MavenProcessCanceledException e ) {
158- PluginUtil .showErrorNotification ("Error" ,
159- "Failed to update Azure Spring Cloud dependencies due to error: "
160- + e .getMessage ());
161- }
162- });
155+ } catch (DocumentException | IOException | AzureExecutionException | MavenProcessCanceledException e ) {
156+ PluginUtil .showErrorNotification ("Error" ,
157+ "Failed to update Azure Spring Cloud dependencies due to error: "
158+ + e .getMessage ());
159+ }
160+ });
163161
164162 return false ;
165163 }
@@ -207,12 +205,12 @@ private static String summaryVersionChanges(List<DependencyArtifact> changes) {
207205 for (DependencyArtifact change : changes ) {
208206 boolean isUpdate = StringUtils .isNotEmpty (change .getCurrentVersion ());
209207 builder .append (String .format ("%s dependency: Group: %s, Artifact: %s, Version: %s%s \n " ,
210- isUpdate ? "Update" : "Add " ,
211- change .getGroupId (),
212- change .getArtifactId (),
213- isUpdate ? (change .getCurrentVersion () + " -> " ) : "" ,
214- StringUtils .isNotEmpty (change .getCompatibleVersion ()) ? change .getCompatibleVersion () :
215- change .getManagementVersion ()));
208+ isUpdate ? "Update" : "Add " ,
209+ change .getGroupId (),
210+ change .getArtifactId (),
211+ isUpdate ? (change .getCurrentVersion () + " -> " ) : "" ,
212+ StringUtils .isNotEmpty (change .getCompatibleVersion ()) ? change .getCompatibleVersion () :
213+ change .getManagementVersion ()));
216214 }
217215 return builder .toString ();
218216 }
@@ -230,4 +228,65 @@ private static String getMavenLibraryVersion(MavenProject project, String groupI
230228 private static boolean isMatch (MavenArtifact lib , String groupId , String artifactId ) {
231229 return StringUtils .equals (lib .getArtifactId (), artifactId ) && StringUtils .equals (lib .getGroupId (), groupId );
232230 }
231+
232+ private static boolean shouldNotAddAzureSpringCloudClientDependency (Map <String , DependencyArtifact > versionMaps ) {
233+ if (versionMaps .containsKey (SPRING_CLOUD_COMMONS_KEY )) {
234+ String version = versionMaps .get (SPRING_CLOUD_COMMONS_KEY ).getCurrentVersion ();
235+ return SpringCloudDependencyManager .isGreaterOrEqualVersion (version , "2.2.5.RELEASE" );
236+ }
237+ return false ;
238+ }
239+
240+ private static List <DependencyArtifact > calculateVersionChanges (String springBootVer ,
241+ boolean noAzureSpringCloudClientDependency ,
242+ Map <String , DependencyArtifact > versionMaps )
243+ throws AzureExecutionException , DocumentException , IOException {
244+ List <DependencyArtifact > dep = new ArrayList <>();
245+ if (!noAzureSpringCloudClientDependency ) {
246+ dep .add (getDependencyArtifact (GROUP_ID , ARTIFACT_ID , versionMaps ));
247+ }
248+ dep .add (getDependencyArtifact (SPRING_BOOT_GROUP_ID , "spring-boot-starter-actuator" , versionMaps ));
249+ dep .add (getDependencyArtifact (SPRING_CLOUD_GROUP_ID , "spring-cloud-config-client" , versionMaps ));
250+ dep .add (getDependencyArtifact (SPRING_CLOUD_GROUP_ID ,
251+ "spring-cloud-starter-netflix-eureka-client" ,
252+ versionMaps ));
253+ dep .add (getDependencyArtifact (SPRING_CLOUD_GROUP_ID , "spring-cloud-starter-zipkin" , versionMaps ));
254+ dep .add (getDependencyArtifact (SPRING_CLOUD_GROUP_ID , "spring-cloud-starter-sleuth" , versionMaps ));
255+
256+ return SpringCloudDependencyManager .getCompatibleVersions (dep , springBootVer );
257+ }
258+
259+ private static boolean applyVersionChanges (SpringCloudDependencyManager dependencyManager ,
260+ File pomFile ,
261+ String springBootVer ,
262+ Map <String , DependencyArtifact > managerDependencyVersionsMaps ,
263+ List <DependencyArtifact > versionChanges ) throws IOException , DocumentException {
264+ versionChanges .stream ().filter (change -> managerDependencyVersionsMaps .containsKey (change .getKey ())).forEach (change -> {
265+ String managementVersion = managerDependencyVersionsMaps .get (change .getKey ()).getCurrentVersion ();
266+ if (StringUtils .equals (change .getCompatibleVersion (), managementVersion )
267+ || SpringCloudDependencyManager .isCompatibleVersion (managementVersion , springBootVer )) {
268+ change .setCompatibleVersion ("" );
269+ change .setManagementVersion (managementVersion );
270+ }
271+ });
272+ return dependencyManager .update (pomFile , versionChanges );
273+ }
274+
275+ private static void noticeUserVersionChanges (Project project , File pomFile , List <DependencyArtifact > versionChanges ) {
276+ final VirtualFile vf = LocalFileSystem .getInstance ().refreshAndFindFileByIoFile (pomFile );
277+ RefreshQueue .getInstance ().refresh (true , false , null , new VirtualFile []{vf });
278+ ApplicationManager .getApplication ().invokeLater (() -> {
279+ FileEditorManager .getInstance (project ).closeFile (vf );
280+ FileEditorManager .getInstance (project ).openFile (vf , true , true );
281+ if (versionChanges .stream ().anyMatch (t -> StringUtils .isNotEmpty (t .getCurrentVersion ()))) {
282+ PluginUtil .showInfoNotificationProject (project ,
283+ "Azure Spring Cloud dependencies are updated successfully." ,
284+ summaryVersionChanges (versionChanges ));
285+ } else {
286+ PluginUtil .showInfoNotificationProject (project ,
287+ "Azure Spring Cloud dependencies are added to your project successfully." ,
288+ summaryVersionChanges (versionChanges ));
289+ }
290+ });
291+ }
233292}
0 commit comments