Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
dependencies {
implementation(project(":azure-intellij-plugin-lib"))
implementation(project(":azure-intellij-plugin-lib-java"))
// runtimeOnly project(path: ":azure-intellij-plugin-lib", configuration: "instrumentedJar")
implementation("com.microsoft.azure:azure-toolkit-ide-common-lib")
intellijPlatform {
// Plugin Dependencies. Uses `platformBundledPlugins` property from the gradle.properties file for bundled IntelliJ Platform plugins.
bundledPlugin("com.intellij.java")
bundledPlugin("org.jetbrains.idea.maven")
// bundledPlugin("org.jetbrains.idea.maven.model")
bundledPlugin("com.intellij.gradle")
// Copilot plugin for Java upgrade integration
plugin("com.github.copilot:1.5.59-243")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*/

package com.microsoft.azure.toolkit.intellij.appmod.common;

import com.intellij.ide.plugins.IdeaPluginDescriptor;
import com.intellij.ide.plugins.PluginManagerCore;
import com.intellij.openapi.extensions.PluginId;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.updateSettings.impl.pluginsAdvertisement.PluginsAdvertiser;
import com.microsoft.azure.toolkit.lib.common.task.AzureTaskManager;
import com.microsoft.azure.toolkit.intellij.appmod.utils.AppModUtils;

import javax.annotation.Nonnull;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;

/**
* Utility class for managing App Modernization plugin installation.
* This centralizes all plugin detection and installation logic to avoid code duplication
* between MigrateToAzureNode and MigrateToAzureAction.
*/
public class AppModPluginInstaller {
private static final String PLUGIN_ID = "com.github.copilot.appmod";
private static final String COPILOT_PLUGIN_ID = "com.github.copilot";
public static final String TO_INSTALL_APP_MODE_PLUGIN = " (Install Github Copilot app modernization)";
private AppModPluginInstaller() {
// Utility class - prevent instantiation
}

/**
* Checks if the App Modernization plugin is installed and enabled.
*/
public static boolean isAppModPluginInstalled() {
try {
final PluginId pluginId = PluginId.getId(PLUGIN_ID);
final IdeaPluginDescriptor plugin = PluginManagerCore.getPlugin(pluginId);
return plugin != null && plugin.isEnabled();
} catch (Exception e) {
return false;
}
}

/**
* Checks if GitHub Copilot plugin is installed and enabled.
*/
public static boolean isCopilotInstalled() {
try {
final PluginId pluginId = PluginId.getId(COPILOT_PLUGIN_ID);
final IdeaPluginDescriptor plugin = PluginManagerCore.getPlugin(pluginId);
return plugin != null && plugin.isEnabled();
} catch (Exception e) {
return false;
}
}

/**
* Detects if running in development mode (runIde task).
* This helps determine whether to show restart options or dev-mode instructions.
*/
public static boolean isRunningInDevMode() {
try {
final PluginId azureToolkitId = PluginId.getId("com.microsoft.tooling.msservices.intellij.azure");
final IdeaPluginDescriptor descriptor = PluginManagerCore.getPlugin(azureToolkitId);
if (descriptor != null) {
final String path = descriptor.getPluginPath().toString();
return path.contains("build") || path.contains("sandbox") || path.contains("out");
}
} catch (Exception ex) {
// If we can't determine, assume production mode (safer)
}
return false;
}

/**
* Shows a confirmation dialog for plugin installation.
*
* @param project The current project
* @param onConfirm Callback to execute when user confirms installation
*/
public static void showInstallConfirmation(@Nonnull Project project, @Nonnull Runnable onConfirm) {
final boolean copilotInstalled = isCopilotInstalled();

final String title = copilotInstalled
? "Install Github Copilot app modernization"
: "Install GitHub Copilot and app modernization";

final String message = copilotInstalled
? "Install this plugin to automate migrating your apps to Azure with Copilot."
: "To migrate to Azure, you'll need two plugins: GitHub Copilot and app modernization.";

if (Messages.showOkCancelDialog(project, message, title, "Install", "Cancel", Messages.getQuestionIcon()) == Messages.OK) {
onConfirm.run();
}
}

public static void showAppModInstallationConfirmation(@Nonnull Project project) {
final boolean copilotInstalled = isCopilotInstalled();

final String title = copilotInstalled
? "Install Github Copilot app modernization"
: "Install GitHub Copilot and app modernization";

final String message = copilotInstalled
? "Install this plugin to upgrade your apps with Copilot."
: "To upgrade your apps, you'll need two plugins: GitHub Copilot and app modernization.";

if (Messages.showOkCancelDialog(project, message, title, "Install", "Cancel", Messages.getQuestionIcon()) == Messages.OK) {
installPlugin(project);
}
}
/**
* Installs the App Modernization plugin.
* IntelliJ platform will automatically install Copilot as a dependency if AppMod declares it.
*
* @param project The current project
*/
public static void installPlugin(@Nonnull Project project) {
final boolean appModInstalled = isAppModPluginInstalled();

// If already installed, nothing to do
if (appModInstalled) {
AppModUtils.logTelemetryEvent("plugin.install-skipped", Map.of("reason", "already-installed"));
return;
}

// Only pass AppMod ID - IntelliJ will automatically install Copilot as dependency
// (AppMod's plugin.xml should declare <depends>com.github.copilot</depends>)
final Set<PluginId> pluginsToInstall = new LinkedHashSet<>();
pluginsToInstall.add(PluginId.getId(PLUGIN_ID));

// Use PluginsAdvertiser.installAndEnable - IntelliJ handles the rest
// The platform will show plugin selection dialog, download, install, and prompt for restart
AzureTaskManager.getInstance().runAndWait(() -> {
PluginsAdvertiser.installAndEnable(
project,
pluginsToInstall,
true, // showDialog
true, // selectAllInDialog - pre-select all plugins
null, // modalityState
() -> {
AppModUtils.logTelemetryEvent("plugin.install-complete");
}
);
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*/

package com.microsoft.azure.toolkit.intellij.appmod.javamigration;

import com.intellij.openapi.project.Project;

import javax.annotation.Nonnull;
import java.util.List;

/**
* Extension point interface for providing migration nodes.
*
* Implementations of this interface will be discovered via IntelliJ's extension point mechanism
* and used to dynamically construct the migration options tree in:
* - Service Explorer (MigrateToAzureNode)
* - Context Menu (MigrateToAzureAction)
* - Project Explorer (MigrateToAzureFacetNode)
*
* Example implementation:
* <pre>
* public class MyMigrationProvider implements IMigrateOptionProvider {
* @Override
* public List&lt;MigrateNodeData&gt; createNodeData(@Nonnull Project project) {
* return List.of(
* MigrateNodeData.builder("My Migration Option")
* .onClick(() -> performMigration(project))
* .build()
* );
* }
* }
* </pre>
*
* Registration in plugin.xml:
* <pre>
* &lt;extensions defaultExtensionNs="com.microsoft.tooling.msservices.intellij.azure"&gt;
* &lt;migrateOptionProvider implementation="your.package.MyMigrationProvider"/&gt;
* &lt;/extensions&gt;
* </pre>
*/
public interface IMigrateOptionProvider {

/**
* Creates migration node data for the Migrate to Azure section.
*
* This method is called each time the migration menu/tree is constructed.
* The returned list can contain multiple MigrateNodeData instances,
* each representing a single action or a group of options.
*
* @param project The current IntelliJ project
* @return A list of MigrateNodeData instances representing the migration option(s)
*/
@Nonnull
List<MigrateNodeData> createNodeData(@Nonnull Project project);

/**
* Returns the priority/order of this node provider.
* Nodes will be displayed in ascending order of priority.
* Lower numbers appear first.
*
* @return Priority value (default: 100)
*/
default int getPriority() {
return 100;
}

/**
* Determines whether this provider should create a node.
* Can be used to conditionally show/hide migration options based on context.
*
* @param project The current IntelliJ project
* @return true if this provider should contribute a node, false otherwise
*/
default boolean isApplicable(@Nonnull Project project) {
return true;
}
}
Loading