diff --git a/plugin-modernizer-core/src/main/java/io/jenkins/tools/pluginmodernizer/core/extractor/MetadataFlag.java b/plugin-modernizer-core/src/main/java/io/jenkins/tools/pluginmodernizer/core/extractor/MetadataFlag.java index cc7aaf0d..ee26ef61 100644 --- a/plugin-modernizer-core/src/main/java/io/jenkins/tools/pluginmodernizer/core/extractor/MetadataFlag.java +++ b/plugin-modernizer-core/src/main/java/io/jenkins/tools/pluginmodernizer/core/extractor/MetadataFlag.java @@ -1,8 +1,13 @@ package io.jenkins.tools.pluginmodernizer.core.extractor; +import io.jenkins.tools.pluginmodernizer.core.model.Plugin; +import io.jenkins.tools.pluginmodernizer.core.utils.UpdateCenterService; import java.util.Optional; +import java.util.function.BiPredicate; import java.util.function.Predicate; import org.openrewrite.xml.tree.Xml; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Flag for metadata @@ -12,69 +17,94 @@ public enum MetadataFlag { /** * If the SCM URL uses HTTPS */ - SCM_HTTPS(tag -> { - if ("scm".equals(tag.getName())) { - Optional connection = tag.getChildValue("connection"); - return connection.isPresent() && connection.get().startsWith("scm:git:https"); - } - return false; - }), + SCM_HTTPS( + tag -> { + if ("scm".equals(tag.getName())) { + Optional connection = tag.getChildValue("connection"); + return connection.isPresent() && connection.get().startsWith("scm:git:https"); + } + return false; + }, + null), /** * If the plugin uses HTTPS for all its repositories */ - MAVEN_REPOSITORIES_HTTPS(tag -> { - if ("repositories".equals(tag.getName())) { - return tag.getChildren().stream() - .filter(c -> "repository".equals(c.getName())) - .map(Xml.Tag.class::cast) - .map(r -> r.getChildValue("url").orElseThrow()) - .allMatch(url -> url.startsWith("https")); - } - return false; - }), + MAVEN_REPOSITORIES_HTTPS( + tag -> { + if ("repositories".equals(tag.getName())) { + return tag.getChildren().stream() + .filter(c -> "repository".equals(c.getName())) + .map(Xml.Tag.class::cast) + .map(r -> r.getChildValue("url").orElseThrow()) + .allMatch(url -> url.startsWith("https")); + } + return false; + }, + null), /** * If the license block is set */ - LICENSE_SET(tag -> { - if ("licenses".equals(tag.getName())) { - return tag.getChildren().stream() - .filter(c -> "license".equals(c.getName())) - .map(Xml.Tag.class::cast) - .map(r -> r.getChildValue("name").orElseThrow()) - .findAny() - .isPresent(); - } - return false; - }), + LICENSE_SET( + tag -> { + if ("licenses".equals(tag.getName())) { + return tag.getChildren().stream() + .filter(c -> "license".equals(c.getName())) + .map(Xml.Tag.class::cast) + .map(r -> r.getChildValue("name").orElseThrow()) + .findAny() + .isPresent(); + } + return false; + }, + null), /** * If the develop block is set */ - DEVELOPER_SET(tag -> { - if ("developers".equals(tag.getName())) { - return tag.getChildren().stream() - .filter(c -> "developer".equals(c.getName())) - .map(Xml.Tag.class::cast) - .map(r -> r.getChildValue("id").orElseThrow()) - .findAny() - .isPresent(); - } - return false; - }); + DEVELOPER_SET( + tag -> { + if ("developers".equals(tag.getName())) { + return tag.getChildren().stream() + .filter(c -> "developer".equals(c.getName())) + .map(Xml.Tag.class::cast) + .map(r -> r.getChildValue("id").orElseThrow()) + .findAny() + .isPresent(); + } + return false; + }, + null), + + /** + * If the plugin is an API plugin + */ + IS_API_PLUGIN(null, (plugin, updateCenterService) -> updateCenterService.isApiPlugin(plugin)), + + /** + * If the plugin is deprecated + */ + IS_DEPRECATED(null, (plugin, updateCenterService) -> updateCenterService.isDeprecated(plugin)), + ; /** * Function to check if the flag is applicable for the given XML tag */ - private final Predicate isApplicable; + private final Predicate isApplicableTag; + + /** + * Function to check if the flag is applicable for the given plugin + */ + private final BiPredicate isApplicablePlugin; /** * Constructor - * @param isApplicable Predicate to check if the flag is applicable for the given XML tag + * @param isApplicableTag Predicate to check if the flag is applicable for the given XML tag */ - MetadataFlag(Predicate isApplicable) { - this.isApplicable = isApplicable; + MetadataFlag(Predicate isApplicableTag, BiPredicate isApplicablePlugin) { + this.isApplicableTag = isApplicableTag; + this.isApplicablePlugin = isApplicablePlugin; } /** @@ -83,6 +113,34 @@ public enum MetadataFlag { * @return true if the flag is applicable */ public boolean isApplicable(Xml.Tag tag) { - return isApplicable.test(tag); + if (isApplicableTag == null) { + return false; + } + return isApplicableTag.test(tag); } + + /** + * Check if the flag is applicable for the given plugin + * @param plugin Plugin + * @return true if the flag is applicable + */ + public boolean isApplicable(Plugin plugin, UpdateCenterService updateCenterService) { + if (plugin.getMetadata() == null) { + LOG.debug("Metadata not found for plugin {}", plugin.getName()); + return false; + } + if (plugin.getMetadata().hasFlag(this)) { + LOG.debug("Flag {} already set for plugin {}", this, plugin.getName()); + return true; + } + if (isApplicablePlugin == null) { + LOG.debug("No applicable plugin check for flag {}", this); + return false; + } + boolean result = isApplicablePlugin.test(plugin, updateCenterService); + LOG.debug("Flag {} applicable for plugin {}: {}", this, plugin.getName(), result); + return result; + } + + private static final Logger LOG = LoggerFactory.getLogger(MetadataFlag.class); } diff --git a/plugin-modernizer-core/src/main/java/io/jenkins/tools/pluginmodernizer/core/extractor/PluginMetadata.java b/plugin-modernizer-core/src/main/java/io/jenkins/tools/pluginmodernizer/core/extractor/PluginMetadata.java index 33c9f726..8b642130 100644 --- a/plugin-modernizer-core/src/main/java/io/jenkins/tools/pluginmodernizer/core/extractor/PluginMetadata.java +++ b/plugin-modernizer-core/src/main/java/io/jenkins/tools/pluginmodernizer/core/extractor/PluginMetadata.java @@ -8,6 +8,7 @@ import java.io.Serializable; import java.nio.file.Path; import java.util.Collections; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -112,11 +113,21 @@ public void setFlags(Set flags) { this.flags = flags; } + public void addFlag(MetadataFlag flag) { + if (flags == null) { + flags = new HashSet<>(); + } + flags.add(flag); + } + public boolean hasFlag(MetadataFlag flag) { - return flags.contains(flag); + return flags != null && flags.contains(flag); } public Set getErrors() { + if (errors == null) { + errors = new HashSet<>(); + } return Collections.unmodifiableSet(errors); } diff --git a/plugin-modernizer-core/src/main/java/io/jenkins/tools/pluginmodernizer/core/impl/CacheManager.java b/plugin-modernizer-core/src/main/java/io/jenkins/tools/pluginmodernizer/core/impl/CacheManager.java index 53a78582..dc0e86ab 100644 --- a/plugin-modernizer-core/src/main/java/io/jenkins/tools/pluginmodernizer/core/impl/CacheManager.java +++ b/plugin-modernizer-core/src/main/java/io/jenkins/tools/pluginmodernizer/core/impl/CacheManager.java @@ -159,6 +159,18 @@ public > T move( return entry.move(cacheManager, newPath, newKey); } + /** + * Copy a cache entry to the new cache manager + * @param cacheManager The cache manager + * @param newPath The new path + * @param newKey The new key + * @param entry The cache entry to move + */ + public > T copy( + CacheManager cacheManager, Path newPath, String newKey, CacheEntry entry) { + return entry.copy(cacheManager, newPath, newKey); + } + /** * Get the location of the cache * @return The location diff --git a/plugin-modernizer-core/src/main/java/io/jenkins/tools/pluginmodernizer/core/impl/PluginModernizer.java b/plugin-modernizer-core/src/main/java/io/jenkins/tools/pluginmodernizer/core/impl/PluginModernizer.java index 42a5c1d3..be0e6adf 100644 --- a/plugin-modernizer-core/src/main/java/io/jenkins/tools/pluginmodernizer/core/impl/PluginModernizer.java +++ b/plugin-modernizer-core/src/main/java/io/jenkins/tools/pluginmodernizer/core/impl/PluginModernizer.java @@ -140,9 +140,12 @@ private void process(Plugin plugin) { plugin.withJDK(JDK.JAVA_17); // Collect metadata and move metadata from the target directory of the plugin to the common cache - if (!plugin.hasMetadata()) { + if (!plugin.hasMetadata() || config.isFetchMetadataOnly()) { plugin.collectMetadata(mavenInvoker); plugin.moveMetadata(cacheManager); + plugin.loadMetadata(cacheManager); + plugin.enrichMetadata(updateCenterService); + } else { LOG.debug("Metadata already computed for plugin {}. Using cached metadata.", plugin.getName()); } @@ -165,8 +168,12 @@ private void process(Plugin plugin) { }); // Retry to collect metadata after remediation to get up-to-date results - plugin.collectMetadata(mavenInvoker); - plugin.moveMetadata(cacheManager); + if (!config.isFetchMetadataOnly()) { + plugin.collectMetadata(mavenInvoker); + plugin.moveMetadata(cacheManager); + plugin.loadMetadata(cacheManager); + plugin.enrichMetadata(updateCenterService); + } } // Check if we still have errors and abort if not remediation is possible @@ -201,19 +208,22 @@ private void process(Plugin plugin) { } // Recollect metadata after modernization - plugin.collectMetadata(mavenInvoker); - PluginMetadata metadata = plugin.readTargetMetadata(); - LOG.debug( - "Plugin {} metadata before modernization: {}", - plugin.getName(), - plugin.getMetadata().toJson()); - LOG.debug("Plugin {} metadata after modernization: {}", plugin.getName(), metadata.toJson()); - - plugin.commit(ghService); - plugin.push(ghService); - plugin.openPullRequest(ghService); - if (config.isRemoveForks()) { - plugin.deleteFork(ghService); + if (!config.isFetchMetadataOnly()) { + plugin.collectMetadata(mavenInvoker); + plugin.moveMetadata(cacheManager); + plugin.loadMetadata(cacheManager); + plugin.enrichMetadata(updateCenterService); + LOG.debug( + "Plugin {} metadata after modernization: {}", + plugin.getName(), + plugin.getMetadata().toJson()); + + plugin.commit(ghService); + plugin.push(ghService); + plugin.openPullRequest(ghService); + if (config.isRemoveForks()) { + plugin.deleteFork(ghService); + } } } diff --git a/plugin-modernizer-core/src/main/java/io/jenkins/tools/pluginmodernizer/core/model/CacheEntry.java b/plugin-modernizer-core/src/main/java/io/jenkins/tools/pluginmodernizer/core/model/CacheEntry.java index d448012d..1c94ae85 100644 --- a/plugin-modernizer-core/src/main/java/io/jenkins/tools/pluginmodernizer/core/model/CacheEntry.java +++ b/plugin-modernizer-core/src/main/java/io/jenkins/tools/pluginmodernizer/core/model/CacheEntry.java @@ -95,6 +95,19 @@ public final T refresh() { * @return The refreshed object copied */ public final T move(CacheManager newCacheManager, Path newPath, String newKey) { + return move(newCacheManager, newPath, newKey, false); + } + + /** + * Return a copy of this object copied to another cache manager + * @param newCacheManager The new cache manager + * @return The refreshed object copied + */ + public final T copy(CacheManager newCacheManager, Path newPath, String newKey) { + return move(newCacheManager, newPath, newKey, true); + } + + private T move(CacheManager newCacheManager, Path newPath, String newKey, boolean copy) { LOG.debug( "Moving object from {} to {}", cacheManager.getLocation().resolve(path).resolve(key), @@ -106,7 +119,9 @@ public final T move(CacheManager newCacheManager, Path newPath, String newKey) { refreshedObject.setCacheManager(newCacheManager); newCacheManager.put(refreshedObject); LOG.debug(refreshedObject.getCacheManager().getLocation().toString()); - this.delete(); + if (!copy) { + this.delete(); + } return newCacheManager.get(newPath, newKey, clazz); } diff --git a/plugin-modernizer-core/src/main/java/io/jenkins/tools/pluginmodernizer/core/model/Plugin.java b/plugin-modernizer-core/src/main/java/io/jenkins/tools/pluginmodernizer/core/model/Plugin.java index 052d5bc9..82ceed22 100644 --- a/plugin-modernizer-core/src/main/java/io/jenkins/tools/pluginmodernizer/core/model/Plugin.java +++ b/plugin-modernizer-core/src/main/java/io/jenkins/tools/pluginmodernizer/core/model/Plugin.java @@ -2,6 +2,7 @@ import io.jenkins.tools.pluginmodernizer.core.config.Config; import io.jenkins.tools.pluginmodernizer.core.config.Settings; +import io.jenkins.tools.pluginmodernizer.core.extractor.MetadataFlag; import io.jenkins.tools.pluginmodernizer.core.extractor.PluginMetadata; import io.jenkins.tools.pluginmodernizer.core.github.GHService; import io.jenkins.tools.pluginmodernizer.core.impl.CacheManager; @@ -492,6 +493,21 @@ public void format(MavenInvoker maven) { LOG.info("Done"); } + /** + * Enrich the metadata of the plugin and save it + * @param updateCenterService The update center service + */ + public void enrichMetadata(UpdateCenterService updateCenterService) { + LOG.debug("Setting extra flags for plugin {}", name); + if (metadata == null) { + throw new IllegalStateException("Metadata not found for plugin " + name); + } + Arrays.stream(MetadataFlag.values()) + .filter(flag -> flag.isApplicable(this, updateCenterService)) + .forEach(metadata::addFlag); + this.metadata.save(); + } + /** * Collect plugin metadata * @param maven The maven invoker instance @@ -580,20 +596,38 @@ public boolean isArchived(GHService service) { /** * Return if this plugin is deprecated in the update center + * @param updateCenterService The update center service * @return True if the plugin is deprecated */ public boolean isDeprecated(UpdateCenterService updateCenterService) { return updateCenterService.isDeprecated(this); } + /** + * Return if this plugin is deprecated in the update center + * @return True if the plugin is deprecated + */ + public boolean isDeprecated() { + return hasMetadata() && metadata.hasFlag(MetadataFlag.IS_DEPRECATED); + } + /** * Return if this plugin is an API plugin + * @param updateCenterService The update center service * @return True if the plugin is an API plugin */ public boolean isApiPlugin(UpdateCenterService updateCenterService) { return updateCenterService.isApiPlugin(this); } + /** + * Return if this plugin is an API plugin + * @return True if the plugin is an API plugin + */ + public boolean isApiPlugin() { + return hasMetadata() && metadata.hasFlag(MetadataFlag.IS_API_PLUGIN); + } + /** * Delete the plugin fork * @param service The GitHub service diff --git a/plugin-modernizer-core/src/main/java/io/jenkins/tools/pluginmodernizer/core/utils/UpdateCenterService.java b/plugin-modernizer-core/src/main/java/io/jenkins/tools/pluginmodernizer/core/utils/UpdateCenterService.java index 82892912..7d381e26 100644 --- a/plugin-modernizer-core/src/main/java/io/jenkins/tools/pluginmodernizer/core/utils/UpdateCenterService.java +++ b/plugin-modernizer-core/src/main/java/io/jenkins/tools/pluginmodernizer/core/utils/UpdateCenterService.java @@ -66,6 +66,11 @@ public boolean isDeprecated(Plugin plugin) { && updateCenterPlugin.labels().contains("deprecated"); } + /** + * Check if a plugin is an API plugin + * @param plugin Plugin + * @return True if API plugin + */ public boolean isApiPlugin(Plugin plugin) { UpdateCenterData updateCenterData = get(); UpdateCenterData.UpdateCenterPlugin updateCenterPlugin =