diff --git a/changelog/@unreleased/pr-410.v2.yml b/changelog/@unreleased/pr-410.v2.yml new file mode 100644 index 00000000..954ee529 --- /dev/null +++ b/changelog/@unreleased/pr-410.v2.yml @@ -0,0 +1,6 @@ +type: improvement +improvement: + description: '[Intellij plugin] Prompt user to update plugin when installed version + is lower than minVersion' + links: + - https://github.com/palantir/gradle-jdks/pull/410 diff --git a/gradle-jdks/src/main/java/com/palantir/gradle/jdks/PalantirGradleJdksIdeaPlugin.java b/gradle-jdks/src/main/java/com/palantir/gradle/jdks/PalantirGradleJdksIdeaPlugin.java index 838887cc..2d228d43 100644 --- a/gradle-jdks/src/main/java/com/palantir/gradle/jdks/PalantirGradleJdksIdeaPlugin.java +++ b/gradle-jdks/src/main/java/com/palantir/gradle/jdks/PalantirGradleJdksIdeaPlugin.java @@ -25,7 +25,7 @@ public class PalantirGradleJdksIdeaPlugin implements Plugin { private static final Logger logger = Logging.getLogger(ToolchainsPlugin.class); - private static final String MIN_IDEA_PLUGIN_VERSION = "0.44.0"; + protected static final String MIN_IDEA_PLUGIN_VERSION = "0.44.0"; @Override public final void apply(Project rootProject) { diff --git a/gradle-jdks/src/test/java/com/palantir/gradle/jdks/IntellijPluginCheckerTest.java b/gradle-jdks/src/test/java/com/palantir/gradle/jdks/IntellijPluginCheckerTest.java new file mode 100644 index 00000000..39ffc784 --- /dev/null +++ b/gradle-jdks/src/test/java/com/palantir/gradle/jdks/IntellijPluginCheckerTest.java @@ -0,0 +1,63 @@ +/* + * (c) Copyright 2024 Palantir Technologies Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.palantir.gradle.jdks; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.URL; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import org.junit.jupiter.api.Test; +import org.spockframework.util.VersionNumber; +import org.w3c.dom.Document; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; + +public class IntellijPluginCheckerTest { + + @Test + public void minimum_version_intellij_plugin_exists() + throws IOException, ParserConfigurationException, SAXException { + URL url = new URL("https://plugins.jetbrains.com/plugins/list?pluginId=24776"); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setRequestMethod("GET"); + assertThat(conn.getResponseCode()) + .isEqualTo(HttpURLConnection.HTTP_OK) + .describedAs("Failed to query plugin version", conn.getResponseCode()); + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); + DocumentBuilder builder = factory.newDocumentBuilder(); + Document document = builder.parse(conn.getInputStream()); + document.getDocumentElement().normalize(); + NodeList versionList = document.getElementsByTagName("version"); + assertThat(versionList.getLength()).isGreaterThan(0); + String version = versionList.item(0).getTextContent(); + assertThat(compareVersions(version, PalantirGradleJdksIdeaPlugin.MIN_IDEA_PLUGIN_VERSION)) + .as( + "If this test fails, then the minimum required Intellij plugin version is not " + + "yet published. version=%s, expected_min_version=%s", + version, PalantirGradleJdksIdeaPlugin.MIN_IDEA_PLUGIN_VERSION) + .isGreaterThan(0); + } + + private static int compareVersions(String version1, String version2) { + return VersionNumber.parse(version1).compareTo(VersionNumber.parse(version2)); + } +} diff --git a/idea-plugin/build.gradle b/idea-plugin/build.gradle index 608a37c8..81fd581e 100644 --- a/idea-plugin/build.gradle +++ b/idea-plugin/build.gradle @@ -17,7 +17,7 @@ patchPluginXml { dependencies { implementation project(':gradle-jdks-setup-common') implementation project(':gradle-jdks-enablement') - + testImplementation 'org.assertj:assertj-core' testImplementation 'org.junit.jupiter:junit-jupiter' } diff --git a/idea-plugin/src/main/java/com/palantir/gradle/jdks/GradleJdksExternalSystemTaskNotificationListener.java b/idea-plugin/src/main/java/com/palantir/gradle/jdks/GradleJdksExternalSystemTaskNotificationListener.java index 6be5cebb..4a199782 100644 --- a/idea-plugin/src/main/java/com/palantir/gradle/jdks/GradleJdksExternalSystemTaskNotificationListener.java +++ b/idea-plugin/src/main/java/com/palantir/gradle/jdks/GradleJdksExternalSystemTaskNotificationListener.java @@ -33,6 +33,7 @@ public void onStart(@NotNull ExternalSystemTaskId id, String _workingDir) { || id.getType() == ExternalSystemTaskType.EXECUTE_TASK)) { Project project = id.findProject(); if (project != null) { + project.getService(PluginUpdateCheckerService.class).checkPluginVersion(); project.getService(GradleJdksProjectService.class).maybeSetupGradleJdks(); } } diff --git a/idea-plugin/src/main/java/com/palantir/gradle/jdks/GradleJdksProjectService.java b/idea-plugin/src/main/java/com/palantir/gradle/jdks/GradleJdksProjectService.java index cba27ccf..1cdb9914 100644 --- a/idea-plugin/src/main/java/com/palantir/gradle/jdks/GradleJdksProjectService.java +++ b/idea-plugin/src/main/java/com/palantir/gradle/jdks/GradleJdksProjectService.java @@ -36,6 +36,7 @@ import com.intellij.openapi.wm.ToolWindow; import com.intellij.openapi.wm.ToolWindowAnchor; import com.intellij.openapi.wm.ToolWindowManager; +import com.intellij.platform.ide.progress.TaskCancellation; import com.intellij.platform.ide.progress.TasksKt; import com.intellij.platform.util.progress.StepsKt; import com.intellij.ui.content.Content; @@ -111,6 +112,7 @@ public void maybeSetupGradleJdks() { TasksKt.withBackgroundProgress( project, "Gradle JDK Setup", + TaskCancellation.nonCancellable(), (_coroutineScope, continuation) -> { StepsKt.withProgressText( "`Gradle JDK Setup` is running. Logs in the `Gradle JDK Setup` window ...", diff --git a/idea-plugin/src/main/java/com/palantir/gradle/jdks/PluginUpdateCheckerService.java b/idea-plugin/src/main/java/com/palantir/gradle/jdks/PluginUpdateCheckerService.java new file mode 100644 index 00000000..f661eccb --- /dev/null +++ b/idea-plugin/src/main/java/com/palantir/gradle/jdks/PluginUpdateCheckerService.java @@ -0,0 +1,78 @@ +/* + * (c) Copyright 2024 Palantir Technologies Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.palantir.gradle.jdks; + +import com.intellij.externalDependencies.DependencyOnPlugin; +import com.intellij.externalDependencies.ExternalDependenciesManager; +import com.intellij.ide.plugins.IdeaPluginDescriptor; +import com.intellij.ide.plugins.PluginManagerCore; +import com.intellij.notification.Notification; +import com.intellij.notification.NotificationGroupManager; +import com.intellij.notification.NotificationType; +import com.intellij.openapi.components.Service; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.extensions.PluginId; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.updateSettings.impl.pluginsAdvertisement.PluginsAdvertiser; +import com.intellij.util.text.VersionComparatorUtil; +import java.util.Optional; +import java.util.Set; + +@Service(Service.Level.PROJECT) +public final class PluginUpdateCheckerService { + + private static final String PLUGIN_ID = "palantir-gradle-jdks"; + + private final Logger logger = Logger.getInstance(PluginUpdateCheckerService.class); + private final Project project; + + public PluginUpdateCheckerService(Project project) { + this.project = project; + } + + public void checkPluginVersion() { + PluginId pluginId = PluginId.getId(PLUGIN_ID); + IdeaPluginDescriptor pluginDescriptor = PluginManagerCore.getPlugin(pluginId); + if (pluginDescriptor == null) { + logger.info("Plugin " + pluginId + " not found"); + return; + } + Optional maybeMinVersion = + ExternalDependenciesManager.getInstance(project).getDependencies(DependencyOnPlugin.class).stream() + .filter(dependencyOnPlugin -> + dependencyOnPlugin.getPluginId().equals(pluginId.getIdString())) + .map(DependencyOnPlugin::getMinVersion) + .filter(version -> Optional.ofNullable(version).isPresent()) + .max(VersionComparatorUtil::compare); + boolean isPluginUpToDate = maybeMinVersion + .map(minVersion -> VersionComparatorUtil.compare(pluginDescriptor.getVersion(), minVersion) > 0) + .orElse(true); + if (isPluginUpToDate) { + return; + } + Notification notification = NotificationGroupManager.getInstance() + .getNotificationGroup("Update Palantir plugins") + .createNotification( + "Update palantir-gradle-jdks plugin", + String.format( + "Please update the plugin in the Settings window to a version higher than '%s'", + maybeMinVersion.get()), + NotificationType.ERROR); + notification.notify(project); + PluginsAdvertiser.installAndEnablePlugins(Set.of(PLUGIN_ID), notification::expire); + } +} diff --git a/idea-plugin/src/main/resources/META-INF/plugin.xml b/idea-plugin/src/main/resources/META-INF/plugin.xml index daddf16f..33b18895 100644 --- a/idea-plugin/src/main/resources/META-INF/plugin.xml +++ b/idea-plugin/src/main/resources/META-INF/plugin.xml @@ -12,8 +12,11 @@ - + +