Skip to content

Commit

Permalink
Auto-Reload and safer Plugin-Repositories
Browse files Browse the repository at this point in the history
- Allow "auto-reload"-Settings to be configured
- Improved #1: Added a separate "safer" way to configure plugin repositories for a project. Using the new provider plugin repositories are not added to the global plugin repository list but are rather used for update checking and checking required plugins whenever the project is open and the plugin is loaded.
  • Loading branch information
nailujx86 committed May 17, 2024
1 parent 5bbca67 commit 58c0c11
Show file tree
Hide file tree
Showing 8 changed files with 161 additions and 71 deletions.
4 changes: 4 additions & 0 deletions .idea/codeStyles/Project.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

58 changes: 29 additions & 29 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
plugins {
id 'org.jetbrains.intellij' version '1.17.3'
id 'java'
id 'org.jetbrains.intellij' version '1.17.3'
id 'java'
id "org.jsonschema2pojo" version "1.2.1"
}

Expand All @@ -17,33 +17,33 @@ allprojects {
jUnitJupiterVersion = '5.10.1'
intellijType = 'IC' // IC: Community Edition, IU: Ultimate Edition.
intellijVersion = '2024.1' // https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html
intellijSinceBuild = '231.1'
intellijSinceBuild = '232.1'
}
}

repositories {
mavenCentral()
mavenCentral()
}

// Must match Groovy version bundled with IntelliJ (see IJ/Contents/lib/groovy.jar/META-INF/org.codehaus.groovy.runtime.ExtensionModule)
ext.groovyVersion = "3.0.19"

intellij {
// Available IDE versions: https://www.jetbrains.com/intellij-repository/releases and https://www.jetbrains.com/intellij-repository/snapshots
version = System.getenv().getOrDefault("IJ_VERSION",
"2024.1"
)
pluginName = "AutoConfigPlugin"
downloadSources = true
updateSinceUntilBuild = false
instrumentCode = false
plugins = [
"java",
"Git4Idea",
"junit",
"org.jetbrains.plugins.yaml",
"org.jetbrains.idea.maven"
]
// Available IDE versions: https://www.jetbrains.com/intellij-repository/releases and https://www.jetbrains.com/intellij-repository/snapshots
version = System.getenv().getOrDefault("IJ_VERSION",
"2024.1"
)
pluginName = "AutoConfigPlugin"
downloadSources = true
updateSinceUntilBuild = false
instrumentCode = false
plugins = [
"java",
"Git4Idea",
"junit",
"org.jetbrains.plugins.yaml",
"org.jetbrains.idea.maven"
]
}
buildSearchableOptions.enabled = false // Disable because it takes a long time and the plugin doesn't need it
runIde.jbrVariant.set("jcef") // JVM with Java Chromium Embedded Framework because why not (see also https://github.com/JetBrains/gradle-intellij-plugin#running-dsl)
Expand Down Expand Up @@ -271,18 +271,18 @@ jsonSchema2Pojo {
}

sourceSets {
// Keep Groovy and Kotlin API source code in separate source sets, otherwise
// compilation fails because of inter-dependencies between Kotlin and Groovy files which confuse compiler,
// even though overall dependencies are unidirectional: pluginApiKotlin -> pluginApiGroovy -> main.

main {
java { srcDir "src/main" }
resources { srcDir "resources" }
}
// Keep Groovy and Kotlin API source code in separate source sets, otherwise
// compilation fails because of inter-dependencies between Kotlin and Groovy files which confuse compiler,
// even though overall dependencies are unidirectional: pluginApiKotlin -> pluginApiGroovy -> main.

main {
java { srcDir "src/main" }
resources { srcDir "resources" }
}
}

compileJava {
sourceCompatibility = "17"
targetCompatibility = "17"
sourceCompatibility = "17"
targetCompatibility = "17"
}

46 changes: 23 additions & 23 deletions src/main/java/de/gebit/intellij/autoconfig/AutoconfigStartup.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,35 +24,35 @@
import static de.gebit.intellij.autoconfig.util.Notifications.showInfo;

/**
* Entry point for the opening of a project. The yaml configuration file is read here, the resulting configuration options object is passed to the CommonConfigurationHandler.
* At the end, a message is composed, displaying a list of all updated configuration options.
* Entry point for the opening of a project. The yaml configuration file is read here, the resulting configuration options object is passed to the
* CommonConfigurationHandler. At the end, a message is composed, displaying a list of all updated configuration options.
*/
public class AutoconfigStartup implements ProjectActivity {
private static final com.intellij.openapi.diagnostic.Logger LOG = Logger.getInstance(AutoconfigStartup.class);
private static final com.intellij.openapi.diagnostic.Logger LOG = Logger.getInstance(AutoconfigStartup.class);

public static final ExtensionPointName<UpdateHandler<?>>
EP_NAME = ExtensionPointName.create("de.gebit.intellij.autoconfig.configurationUpdater");
public static final ExtensionPointName<UpdateHandler<?>>
EP_NAME = ExtensionPointName.create("de.gebit.intellij.autoconfig.configurationUpdater");

@Nullable
@Override
public Object execute(@NotNull Project project, @NotNull Continuation<? super Unit> continuation) {
ConfigurationLoaderService projectService = project.getService(ConfigurationLoaderService.class);
if (projectService == null) {
return null;
}
@Nullable
@Override
public Object execute(@NotNull Project project, @NotNull Continuation<? super Unit> continuation) {
ConfigurationLoaderService projectService = project.getService(ConfigurationLoaderService.class);
if (projectService == null) {
return null;
}

List<String> changedConfigs = new ArrayList<>();
List<String> changedConfigs = new ArrayList<>();

for (UpdateHandler updateHandler : EP_NAME.getExtensionList()) {
Optional<Object> extensionConfiguration = projectService.getConfiguration(updateHandler.getConfigurationClass(), updateHandler.getFileName());
extensionConfiguration.ifPresentOrElse(config -> changedConfigs.addAll(updateHandler.updateConfiguration(config, project)), () -> LOG.info("No configuration for " + updateHandler.getUpdaterName() + " found."));
}
for (UpdateHandler updateHandler : EP_NAME.getExtensionList()) {
Optional<Object> extensionConfiguration = projectService.getConfiguration(updateHandler.getConfigurationClass(), updateHandler.getFileName());
extensionConfiguration.ifPresentOrElse(config -> changedConfigs.addAll(updateHandler.updateConfiguration(config, project)), () -> LOG.info("No configuration for " + updateHandler.getUpdaterName() + " found."));
}

if (!changedConfigs.isEmpty()) {
String notification = String.join(", ", changedConfigs);
showInfo("New project configurations applied: " + notification, project);
}
if (!changedConfigs.isEmpty()) {
String notification = String.join(", ", changedConfigs);
showInfo("New project configurations applied: " + notification, project);
}

return changedConfigs;
}
return changedConfigs;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public<T> Optional<T> getConfiguration(Class<T> objectClass, String configFileNa
T configObject = null;
Object o = configurationOptions.get(objectClass.getCanonicalName());
if (o != null && o.getClass().isAssignableFrom(objectClass)) {
//noinspection unchecked
configObject = (T) o;
}
if (configObject != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,13 @@
import com.intellij.codeInsight.actions.onSave.OptimizeImportsOnSaveOptions;
import com.intellij.externalDependencies.ExternalDependenciesManager;
import com.intellij.externalDependencies.impl.ExternalDependenciesManagerImpl;
import com.intellij.openapi.externalSystem.autoimport.ExternalSystemProjectTrackerSettings;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.updateSettings.impl.UpdateSettings;
import com.intellij.openapi.vcs.IssueNavigationConfiguration;
import com.intellij.openapi.vcs.IssueNavigationLink;
import de.gebit.intellij.autoconfig.UpdateHandler;
import de.gebit.intellij.autoconfig.model.Formatting;
import de.gebit.intellij.autoconfig.model.GeneralConfiguration;
import de.gebit.intellij.autoconfig.model.IssueNavigation;
import de.gebit.intellij.autoconfig.model.OnSave;
import de.gebit.intellij.autoconfig.model.*;
import de.gebit.intellij.autoconfig.state.TransientPluginStateService;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.Nullable;
Expand All @@ -38,6 +36,8 @@ public class CommonConfigurationHandler extends AbstractHandler implements Updat

public static final @NonNls String CONFIG_FILE_NAME = "autoconfig.yaml";

public static final @NonNls Class<GeneralConfiguration> CONFIGURATION_CLASS = GeneralConfiguration.class;

@Override
public String getFileName() {
return CONFIG_FILE_NAME;
Expand All @@ -55,18 +55,34 @@ public String getUpdaterName() {

@Override
public Class<GeneralConfiguration> getConfigurationClass() {
return GeneralConfiguration.class;
return CONFIGURATION_CLASS;
}

@Override
public List<String> updateConfiguration(GeneralConfiguration options, Project project) {
List<String> updatedConfigs = new ArrayList<>();
applyIssueNavigationConfiguration(options.getIssueNavigation(), project, updatedConfigs);
applyPluginHosts(options.getPluginRepositories(), project, updatedConfigs);
applyPluginHosts(options.getGlobalPluginRepositories(), project, updatedConfigs);
applyOnSaveOptions(options.getOnSave(), project, updatedConfigs);
applyReloadConfiguration(options.getReloadProjectAutomatically(), project, updatedConfigs);
return updatedConfigs;
}

private void applyReloadConfiguration(ReloadProjectAutomatically reloadProjectAutomatically, Project project, List<String> updatedConfigs) {
if (reloadProjectAutomatically != null) {
final ExternalSystemProjectTrackerSettings instance = ExternalSystemProjectTrackerSettings.getInstance(project);
if (Boolean.FALSE.equals(reloadProjectAutomatically.getEnabled())) {
applySetting(ExternalSystemProjectTrackerSettings.AutoReloadType.NONE, instance.getAutoReloadType(), instance::setAutoReloadType, updatedConfigs, "Automatic project reload deactivated");
instance.setAutoReloadType(ExternalSystemProjectTrackerSettings.AutoReloadType.NONE);
} else if (reloadProjectAutomatically.getMode() != null) {
applySetting(switch (reloadProjectAutomatically.getMode()) {
case ANY_CHANGES -> ExternalSystemProjectTrackerSettings.AutoReloadType.ALL;
case EXTERNAL_CHANGES -> ExternalSystemProjectTrackerSettings.AutoReloadType.SELECTIVE;
}, instance.getAutoReloadType(), instance::setAutoReloadType, updatedConfigs, "Automatic project reload activated");
}
}
}

private void applyIssueNavigationConfiguration(List<IssueNavigation> issueNavigationConfig, Project aProject, List<String> updatedConfigs) {
if (issueNavigationConfig != null) {
var issueNavigationSettings = IssueNavigationConfiguration.getInstance(aProject);
Expand Down Expand Up @@ -103,6 +119,7 @@ private List<String> getFileTypes(@Nullable Formatting formattingOptions) {
}

private void applyPluginHosts(List<String> pluginHosts, Project aProject, List<String> changedConfigs) {
// Maybe ask the user before applying new Plugin-Hosts? This could be a possible attack vector otherwise.
if (pluginHosts != null) {
var updateSettings = UpdateSettings.getInstance();
var storedPluginHosts = updateSettings.getStoredPluginHosts();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package de.gebit.intellij.autoconfig.plugins;

import com.intellij.openapi.updateSettings.impl.UpdateSettingsProvider;
import de.gebit.intellij.autoconfig.ConfigurationLoaderService;
import de.gebit.intellij.autoconfig.handlers.CommonConfigurationHandler;
import de.gebit.intellij.autoconfig.model.GeneralConfiguration;
import org.jetbrains.annotations.NotNull;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
* "Safer" Plugin-Repository Provider which does not persist the configured plugin repository. This provider is used when checking for required
* plugins and when checking for plugin updates.
*/
public class AutoConfigUpdateSettingsProvider implements UpdateSettingsProvider {

@NotNull
@Override
public List<String> getPluginRepositories() {
List<String> pluginRepositories = new ArrayList<>();
com.intellij.openapi.project.ProjectUtil.getOpenedProjects().iterator().forEachRemaining(project -> {
ConfigurationLoaderService projectService = project.getService(ConfigurationLoaderService.class);
final Optional<GeneralConfiguration> configuration = projectService.getConfiguration(CommonConfigurationHandler.CONFIGURATION_CLASS, CommonConfigurationHandler.CONFIG_FILE_NAME);
configuration.map(GeneralConfiguration::getPluginRepositories).ifPresent(pluginRepositories::addAll);
});
return pluginRepositories;
}
}
9 changes: 4 additions & 5 deletions src/main/resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
<idea-plugin url="https://gitlab.local.gebit.de/intellij/trend-tools">
<id>de.gebit.intellij.autoconfig</id>
<name>Autoconfig</name>
<vendor email="info@gebit.de" url="https://www.gebit.de">GEBIT Solutions GmbH</vendor>
<vendor email="jetbrains@gebit.de" url="https://github.com/GEBIT/autoconfig-intellij-plugin">GEBIT Solutions GmbH</vendor>

<version>0.0.0</version>
<idea-version since-build="231.1"/>
<vendor url="https://github.com/GEBIT/autoconfig-intellij-plugin"
email="[email protected]">GEBIT Solutions GmbH</vendor>
<version>0.0.1</version>
<idea-version since-build="232.1"/>
<description><![CDATA[
TODO: HTML text describing the autoconfig plugin functionality.
]]>
Expand All @@ -33,6 +31,7 @@
<postStartupActivity implementation="de.gebit.intellij.autoconfig.AutoconfigStartup"/>
<notificationGroup displayType="BALLOON" id="Autoconfig"/>
<formatOnSaveOptions.defaultsProvider implementation="de.gebit.intellij.autoconfig.FormatOnSaveOptionsDefaultsProvider"/>
<updateSettingsProvider implementation="de.gebit.intellij.autoconfig.plugins.AutoConfigUpdateSettingsProvider"/>
</extensions>
<extensions defaultExtensionNs="JavaScript.JsonSchema">
<ProviderFactory implementation="de.gebit.intellij.autoconfig.json.ConfigurationJsonSchemeProviderFactory"/>
Expand Down
55 changes: 47 additions & 8 deletions src/main/resources/schema/config.schema.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"$id": "https://www.gebit.de/autoconfig-intellij-plugin/config.schema.json",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "General configuration",
"definitions": {
"formatting": {
Expand All @@ -15,6 +15,13 @@
}
}
}
},
"pluginRepositories": {
"type": "array",
"description": "List of additional plugin repositories.",
"items": {
"type": "string"
}
}
},
"type": "object",
Expand All @@ -23,8 +30,12 @@
"type": "object",
"description": "Actions on save settings.",
"properties": {
"format": { "$ref": "#/definitions/formatting" },
"optimizeImports": { "$ref": "#/definitions/formatting" }
"format": {
"$ref": "#/definitions/formatting"
},
"optimizeImports": {
"$ref": "#/definitions/formatting"
}
}
},
"issueNavigation": {
Expand All @@ -48,12 +59,40 @@
}
}
},
"globalPluginRepositories": {
"description": "List of plugin repositories to be configured globally (cross project).",
"$ref": "#/definitions/pluginRepositories"
},
"pluginRepositories": {
"type": "array",
"description": "List of additional plugin repositories.",
"items": {
"type": "string"
"description": "List of plugin repositories to be used when this project is open.",
"$ref": "#/definitions/pluginRepositories"
},
"reloadProjectAutomatically": {
"type": "object",
"description": "Automatically reload the project after the configuration has been changed.",
"properties": {
"enabled": {
"type": "boolean",
"description": "Enable automatic reload of the project"
},
"mode": {
"type": "string",
"description": "Reload on any changes or only reload on external changes e.g. from version control?",
"enum": [
"any-changes",
"external-changes"
],
"default": "external-changes",
"x-intellij-enum-metadata": {
"any-changes": {
"description": "Reload on any changes on project configuration files"
},
"external-changes": {
"description": "Reload on external changes on project configuration files e.g. from version control"
}
}
}
}
}
}
}
}

0 comments on commit 58c0c11

Please sign in to comment.