Skip to content

Commit 2c37251

Browse files
andxuAndy Xu(devdiv)
andauthored
Handle the dependency update due to spring boot 2.3.0-RELEASE (#4589)
* Handle the dependency update due to spring boot 2.3.0-RELEASE * Update maven project if it is dirty, since idea introduces a new way of Maven and Gradle importing :https://blog.jetbrains.com/idea/2020/01/intellij-idea-2020-1-eap/#maven_and_gradle_importing_updates Co-authored-by: Andy Xu(devdiv) <andxu@microsoft>
1 parent e6b76ec commit 2c37251

File tree

2 files changed

+174
-113
lines changed

2 files changed

+174
-113
lines changed

PluginsAndFeatures/azure-toolkit-for-intellij/src/com/microsoft/azure/springcloud/dependency/action/AddAzureDependencyAction.java

Lines changed: 140 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,16 @@
2222

2323
package com.microsoft.azure.springcloud.dependency.action;
2424

25+
import com.google.common.util.concurrent.SettableFuture;
2526
import com.intellij.openapi.actionSystem.AnActionEvent;
2627
import com.intellij.openapi.actionSystem.CommonDataKeys;
2728
import com.intellij.openapi.actionSystem.LangDataKeys;
2829
import com.intellij.openapi.actionSystem.Presentation;
2930
import com.intellij.openapi.application.ApplicationManager;
3031
import com.intellij.openapi.editor.Editor;
3132
import com.intellij.openapi.editor.EditorKind;
33+
import com.intellij.openapi.externalSystem.autoimport.ExternalSystemProjectTracker;
34+
import com.intellij.openapi.externalSystem.autoimport.ProjectNotificationAware;
3235
import com.intellij.openapi.fileEditor.FileEditorManager;
3336
import com.intellij.openapi.module.Module;
3437
import com.intellij.openapi.module.ModuleTypeId;
@@ -60,16 +63,15 @@
6063

6164
import java.io.File;
6265
import 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

6869
public 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

Comments
 (0)