diff --git a/components/sbm-core/pom.xml b/components/sbm-core/pom.xml index f0cd95faa..9b595a4da 100644 --- a/components/sbm-core/pom.xml +++ b/components/sbm-core/pom.xml @@ -154,7 +154,13 @@ tests test - + + com.fasterxml.jackson.dataformat + jackson-dataformat-xml + 2.14.0 + + + diff --git a/components/sbm-core/src/main/java/org/springframework/sbm/build/api/BuildFile.java b/components/sbm-core/src/main/java/org/springframework/sbm/build/api/BuildFile.java index 73a278090..5ad100ee7 100644 --- a/components/sbm-core/src/main/java/org/springframework/sbm/build/api/BuildFile.java +++ b/components/sbm-core/src/main/java/org/springframework/sbm/build/api/BuildFile.java @@ -16,10 +16,12 @@ package org.springframework.sbm.build.api; import org.openrewrite.maven.tree.Scope; + import org.springframework.sbm.project.resource.ProjectResource; import java.nio.file.Path; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.Set; @@ -117,6 +119,8 @@ public interface BuildFile extends ProjectResource { String getProperty(String key); + void deleteProperty(String key); + String print(); /** @@ -165,4 +169,6 @@ public interface BuildFile extends ProjectResource { List getPluginRepositories(); List getDeclaredModules(); + + Optional findPlugin(String groupId, String artifactId); } diff --git a/components/sbm-core/src/main/java/org/springframework/sbm/build/api/Plugin.java b/components/sbm-core/src/main/java/org/springframework/sbm/build/api/Plugin.java index 21d0dc821..6e824b12a 100644 --- a/components/sbm-core/src/main/java/org/springframework/sbm/build/api/Plugin.java +++ b/components/sbm-core/src/main/java/org/springframework/sbm/build/api/Plugin.java @@ -15,47 +15,46 @@ */ package org.springframework.sbm.build.api; -import lombok.*; - -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Null; import java.util.List; +import java.util.Optional; +import java.util.Set; + +public interface Plugin { + + String getGroupId(); + + String getArtifactId(); + + String getVersion(); + + String getDependencies(); + + List getExecutions(); + + Configuration getConfiguration(); + + interface Configuration { + + Optional getDeclaredStringValue(String property); + + String getResolvedStringValue(String property); + + void setDeclaredStringValue(String property, String value); + + Set getPropertyKeys(); + + } + + interface Execution { + + String getId(); + + List getGoals(); + + String getPhase(); + + String getConfiguration(); + + } -@Getter -@Setter -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class Plugin { - - @NotNull - private String groupId; - - @NotNull - private String artifactId; - - private String version; - - @Singular("execution") - private List executions; - - private String configuration; - - private String dependencies; - - @Builder - @Getter - @NoArgsConstructor - @AllArgsConstructor - @Setter - public static class Execution { - @Null - private String id; - @Singular("goal") - private List goals; - @Null - private String phase; - @Null - private String configuration; - } -} +} \ No newline at end of file diff --git a/components/sbm-core/src/main/java/org/springframework/sbm/build/impl/Refactoring.java b/components/sbm-core/src/main/java/org/springframework/sbm/build/impl/MavenBuildFileRefactoring.java similarity index 91% rename from components/sbm-core/src/main/java/org/springframework/sbm/build/impl/Refactoring.java rename to components/sbm-core/src/main/java/org/springframework/sbm/build/impl/MavenBuildFileRefactoring.java index f978d4bec..c3c5bbc89 100644 --- a/components/sbm-core/src/main/java/org/springframework/sbm/build/impl/Refactoring.java +++ b/components/sbm-core/src/main/java/org/springframework/sbm/build/impl/MavenBuildFileRefactoring.java @@ -23,14 +23,13 @@ import org.openrewrite.xml.tree.Xml; import org.springframework.sbm.project.resource.RewriteSourceFileHolder; import org.springframework.sbm.support.openrewrite.GenericOpenRewriteRecipe; -import org.springframework.util.ReflectionUtils; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; @RequiredArgsConstructor -class Refactoring

{ +class MavenBuildFileRefactoring

{ private final RewriteSourceFileHolder pom; @@ -57,7 +56,9 @@ private List executeRecipe(Recipe recipe) { private void processResults(List results) { if (!results.isEmpty()) { - results.forEach(c -> processResult(c)); + // FIXME: Works only on a single POM and does not apply to all other resources + pom.replaceWith((Xml.Document) results.get(0).getAfter()); + // results.forEach(c -> processResult(c)); } } diff --git a/components/sbm-core/src/main/java/org/springframework/sbm/build/impl/OpenRewriteMavenBuildFile.java b/components/sbm-core/src/main/java/org/springframework/sbm/build/impl/OpenRewriteMavenBuildFile.java index 43dc45893..c554caa8b 100644 --- a/components/sbm-core/src/main/java/org/springframework/sbm/build/impl/OpenRewriteMavenBuildFile.java +++ b/components/sbm-core/src/main/java/org/springframework/sbm/build/impl/OpenRewriteMavenBuildFile.java @@ -15,6 +15,7 @@ */ package org.springframework.sbm.build.impl; +import com.fasterxml.jackson.core.JsonProcessingException; import lombok.extern.slf4j.Slf4j; import org.openrewrite.ExecutionContext; import org.openrewrite.Parser; @@ -24,12 +25,16 @@ import org.openrewrite.internal.lang.Nullable; import org.openrewrite.marker.Markers; import org.openrewrite.maven.*; +import org.openrewrite.maven.internal.MavenXmlMapper; import org.openrewrite.maven.tree.MavenResolutionResult; import org.openrewrite.maven.tree.Parent; import org.openrewrite.maven.tree.ResolvedDependency; import org.openrewrite.maven.tree.ResolvedManagedDependency; import org.openrewrite.maven.tree.Scope; +import org.openrewrite.xml.ChangeTagValueVisitor; import org.openrewrite.xml.tree.Xml; +import org.openrewrite.xml.tree.Xml.Tag; + import org.springframework.context.ApplicationEventPublisher; import org.springframework.sbm.build.api.BuildFile; import org.springframework.sbm.build.api.DependenciesChangedEvent; @@ -70,7 +75,8 @@ public class OpenRewriteMavenBuildFile extends RewriteSourceFileHolder implements BuildFile { private final ApplicationEventPublisher eventPublisher; - private PluginRepositoryHandler pluginRepositoryHandler = new PluginRepositoryHandler(); + private final PluginRepositoryHandler pluginRepositoryHandler = new PluginRepositoryHandler(); + private final MavenBuildFileRefactoring refactoring ; // TODO: #7 clarify if RefreshPomModel is still required? // Execute separately since RefreshPomModel caches the refreshed maven files after the first visit @@ -105,7 +111,7 @@ protected List visit(List before, ExecutionContext ctx) for (int i = 0; i < newMavenFiles.size(); i++) { Optional mavenModels = MavenBuildFileUtil.findMavenResolution(mavenFiles.get(i)); Optional newMavenModels = MavenBuildFileUtil.findMavenResolution(newMavenFiles.get(i)); - mavenFiles.get(i).withMarkers(Markers.build(Arrays.asList(newMavenModels.get()))); + mavenFiles.get(i).withMarkers(Markers.build(List.of(newMavenModels.get()))); // FIXME: 497 verify correctness mavenFiles.set(i, newMavenFiles.get(i)); } @@ -143,22 +149,23 @@ public OpenRewriteMavenBuildFile(Path absoluteProjectPath, super(absoluteProjectPath, sourceFile); this.eventPublisher = eventPublisher; this.executionContext = executionContext; + this.refactoring = new MavenBuildFileRefactoring<>(this.getResource()); } public void apply(Recipe recipe) { // FIXME: #7 Make ExecutionContext a Spring Bean and caching configurable, also if the project root is used as workdir it must be added to .gitignore - // FIXME: #7 this made it veeery slow //executionContext.putMessage("org.openrewrite.maven.pomCache", new RocksdbMavenPomCache(this.getAbsoluteProjectDir())); - List result = recipe.run(List.of(getSourceFile()), executionContext).getResults(); - if (!result.isEmpty()) { - replaceWith((Xml.Document) result.get(0).getAfter()); - } + refactoring.execute(recipe); } public MavenResolutionResult getPom() { return MavenBuildFileUtil.findMavenResolution(getSourceFile()).get(); } + public RewriteSourceFileHolder getResource() { + return this; + } + @Override public void addDependency(Dependency dependency) { if (!containsDependency(dependency)) { @@ -263,7 +270,6 @@ public List getDeclaredDependencies(Scope... scopes) { @Override public List getRequestedDependencies() { List requestedDependencies = getPom().getPom().getRequestedDependencies(); - // FIXME: #7 use getPom().getDependencies() instead ? List declaredDependenciesWithEffectiveVersions = requestedDependencies.stream() .map(d -> mapDependency(d)) @@ -312,6 +318,8 @@ public List getRequestedDependencies() { /** * {@inheritDoc} + * + * TODO: #497 Test with declared and transitive dependencies */ @Override public Set getEffectiveDependencies(Scope scope) { @@ -574,22 +582,22 @@ public boolean hasPlugin(Plugin plugin) { @Override public void addPlugin(Plugin plugin) { - apply(new AddMavenPlugin(plugin)); + apply(new AddMavenPlugin((OpenRewriteMavenPlugin) plugin)); } @Override public List getSourceFolders() { - return Arrays.asList(getAbsolutePath().getParent().resolve(JAVA_SOURCE_FOLDER)); + return List.of(getAbsolutePath().getParent().resolve(JAVA_SOURCE_FOLDER)); } @Override public List getResourceFolders() { - return Arrays.asList(getAbsolutePath().getParent().resolve(RESOURCE_FOLDER)); + return List.of(getAbsolutePath().getParent().resolve(RESOURCE_FOLDER)); } @Override public List getTestResourceFolders() { - return Arrays.asList(getAbsolutePath().getParent().resolve(RESOURCE_TEST_FOLDER)); + return List.of(getAbsolutePath().getParent().resolve(RESOURCE_TEST_FOLDER)); } @Override @@ -602,21 +610,23 @@ public List getClasspath() { @Override public List getTestSourceFolders() { - return Arrays.asList(getAbsolutePath().getParent().resolve(JAVA_TEST_SOURCE_FOLDER)); + return List.of(getAbsolutePath().getParent().resolve(JAVA_TEST_SOURCE_FOLDER)); } final public String getProperty(String key) { - return getPom().getPom().getProperties().get(key); + return getPom().getPom().getRequested().getProperties().get(key); } + @Override + final public void deleteProperty(String key){ + apply(new RemoveProperty(key)); + apply(new RefreshPomModel()); + } + final public void setProperty(String key, String value) { - if (value == null) { - apply(new RemoveProperty(key)); - } else { - String current = getProperty(key); - apply(current == null ? new AddProperty(key, value) : new ChangePropertyValue(key, value, false)); - } - apply(new RefreshPomModel()); + String current = getProperty(key); + apply(current == null ? new ChangePropertyValue(key, value, true) : new ChangePropertyValue(key, value, false)); + apply(new RefreshPomModel()); } @Override @@ -654,6 +664,7 @@ public String getArtifactId() { public String getVersion() { return resolve(getPom().getPom().getVersion()); } + @Override public String getCoordinates() { return getGroupId() + ":" + getArtifactId() + ":" + getVersion(); @@ -754,45 +765,9 @@ private boolean anyRegexMatchesCoordinate(Plugin p, String... regex) { @Override public List getPlugins() { - - List plugins = new ArrayList<>(); - - MavenVisitor mavenVisitor = new MavenVisitor() { - - @Override - public Xml.Document visitDocument(Xml.Document maven, ExecutionContext ctx) { - Xml.Tag mavenRoot = maven.getRoot(); - Optional build = mavenRoot.getChild("build"); - if (build.isPresent()) { - Xml.Tag buildTag = build.get(); - Optional pluginTags = buildTag.getChild("plugins"); - if (pluginTags.isPresent()) { - List plugin = pluginTags.get().getChildren("plugin"); - List pluginList = plugin.stream() - .map(this::mapToPlugin) - .collect(Collectors.toList()); - plugins.addAll(pluginList); - } - } - return null; - } - - private Plugin mapToPlugin(Xml.Tag tag) { - String groupId = tag.getChild("groupId").get().getValue().get(); - String artifactId = tag.getChild("artifactId").get().getValue().get(); - Optional versionTag = tag.getChild("version"); - String version = null; - if (versionTag.isPresent()) { - version = versionTag.get().getValue().get(); - } - Plugin plugin = new Plugin(groupId, artifactId, version, List.of(), "", ""); - return plugin; - } - }; - - mavenVisitor.visitDocument(getSourceFile(), executionContext); - - return plugins; + return getPom().getPom().getRequested().getPlugins().stream() + .map(p -> new OpenRewriteMavenPlugin(p, getResource(), refactoring)) + .collect(Collectors.toList()); } /** @@ -830,6 +805,14 @@ public void removePlugins(String... coordinates) { } } + @Override + public Optional findPlugin(String groupId, String artifactId){ + return getPlugins() + .stream() + .filter(plugin -> plugin.getGroupId().equals(groupId) && + plugin.getArtifactId().equals(artifactId)) + .findAny(); + } private String resolve(String expression) { return getPom().getPom().getValue(expression); diff --git a/components/sbm-core/src/main/java/org/springframework/sbm/build/impl/OpenRewriteMavenPlugin.java b/components/sbm-core/src/main/java/org/springframework/sbm/build/impl/OpenRewriteMavenPlugin.java new file mode 100644 index 000000000..9b93f9fb6 --- /dev/null +++ b/components/sbm-core/src/main/java/org/springframework/sbm/build/impl/OpenRewriteMavenPlugin.java @@ -0,0 +1,193 @@ +/* + * Copyright 2021 - 2022 the original author or authors. + * + * 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 + * + * https://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 org.springframework.sbm.build.impl; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Null; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.Singular; +import org.openrewrite.maven.ChangePluginConfiguration; +import org.openrewrite.maven.internal.MavenXmlMapper; +import org.openrewrite.xml.tree.Xml; +import org.openrewrite.xml.tree.Xml.Document; + +import org.springframework.sbm.build.api.Plugin; +import org.springframework.sbm.project.resource.RewriteSourceFileHolder; + +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor +@JacksonXmlRootElement(localName = "plugin") +@JsonInclude(Include.NON_NULL) +public class OpenRewriteMavenPlugin implements Plugin { + + @NotNull + private String groupId; + + @NotNull + private String artifactId; + + private String version; + + @Singular("execution") + private List executions; + + private OpenRewriteMavenPluginConfiguration configuration; + + @JsonIgnore + private RewriteSourceFileHolder resourceWrapper; + + @JsonIgnore + private MavenBuildFileRefactoring refactoring; + + private String dependencies; + + public OpenRewriteMavenPlugin(org.openrewrite.maven.tree.Plugin openRewritePlugin,RewriteSourceFileHolder resource, MavenBuildFileRefactoring refactoring) { + this.groupId = openRewritePlugin.getGroupId(); + this.artifactId = openRewritePlugin.getArtifactId(); + this.version = openRewritePlugin.getVersion(); + this.configuration = mapConfiguration(openRewritePlugin.getConfiguration()); + this.executions = mapExecutions(openRewritePlugin.getExecutions()); + this.dependencies = null; + this.resourceWrapper = resource; + this.refactoring = refactoring; + } + + private List mapExecutions( + List openRewritePluginExecutions) { + if (openRewritePluginExecutions == null || openRewritePluginExecutions.isEmpty()) { + return new ArrayList<>(); + } + return openRewritePluginExecutions.stream() + .map(orExecution -> new OpenRewriteMavenPluginExecution(orExecution.getId(), orExecution.getGoals(), + orExecution.getPhase(), null)) + .collect(Collectors.toList()); + + } + + private OpenRewriteMavenPluginConfiguration mapConfiguration(JsonNode openRewritePluginConfiguration) { + if (openRewritePluginConfiguration == null || openRewritePluginConfiguration.isEmpty()) { + return new OpenRewriteMavenPluginConfiguration(new LinkedHashMap<>()); + } + return new OpenRewriteMavenPluginConfiguration( + MavenXmlMapper.readMapper().convertValue(openRewritePluginConfiguration, new TypeReference<>() { + })); + } + + @AllArgsConstructor + @NoArgsConstructor + public class OpenRewriteMavenPluginConfiguration implements Configuration { + + @JsonAnyGetter + private Map configuration; + + @Override + public Optional getDeclaredStringValue(String property) { + return Optional.ofNullable((String) configuration.get(property)); + } + + @Override + public String getResolvedStringValue(String property) { + Optional value = getDeclaredStringValue(property); + String propertyValue = value + .orElseThrow((() -> new IllegalStateException("Found no value for property " + property))); + if (propertyValue.startsWith("${")) { + String propertyWithoutBraces = propertyValue.replace("${", "").replace("}", ""); + return MavenBuildFileUtil + .findMavenResolution(OpenRewriteMavenPlugin.this.resourceWrapper.getSourceFile()).get().getPom() + .getProperties().get(propertyWithoutBraces); + } + else { + return propertyValue; + } + } + + @Override + public void setDeclaredStringValue(String property, String value) { + configuration.put(property, value); + changeConfiguration(); + } + + @Override + @JsonIgnore + public Set getPropertyKeys() { + return configuration.keySet(); + } + + private void changeConfiguration() { + try { + String configurationXml = MavenXmlMapper.writeMapper().writerWithDefaultPrettyPrinter() + .writeValueAsString(configuration).replaceFirst("", "") + .replace("", "").replace("", "").trim(); + OpenRewriteMavenPlugin.this.refactoring.execute(new ChangePluginConfiguration( + OpenRewriteMavenPlugin.this.groupId, OpenRewriteMavenPlugin.this.artifactId, configurationXml)); + } + catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + + } + + @Builder + @Getter + @NoArgsConstructor + @AllArgsConstructor + @Setter + @JsonInclude(Include.NON_NULL) + @JacksonXmlRootElement(localName = "execution") + public static class OpenRewriteMavenPluginExecution implements Execution { + + @Null + private String id; + + @Singular("goal") + private List goals; + + @Null + private String phase; + + @Null + private String configuration; + + } + +} diff --git a/components/sbm-core/src/main/java/org/springframework/sbm/build/migration/actions/AddMavenPlugin.java b/components/sbm-core/src/main/java/org/springframework/sbm/build/migration/actions/AddMavenPlugin.java index 293a3ec2b..15d1e7c35 100644 --- a/components/sbm-core/src/main/java/org/springframework/sbm/build/migration/actions/AddMavenPlugin.java +++ b/components/sbm-core/src/main/java/org/springframework/sbm/build/migration/actions/AddMavenPlugin.java @@ -15,10 +15,8 @@ */ package org.springframework.sbm.build.migration.actions; -import lombok.NoArgsConstructor; import lombok.experimental.SuperBuilder; -import org.springframework.sbm.build.api.Plugin; -import org.springframework.sbm.engine.recipe.AbstractAction; +import org.springframework.sbm.build.impl.OpenRewriteMavenPlugin; import org.springframework.sbm.engine.context.ProjectContext; import lombok.Getter; import lombok.Setter; @@ -33,7 +31,7 @@ public class AddMavenPlugin extends MultiModuleAwareAction { @Setter @Valid - private Plugin plugin; + private OpenRewriteMavenPlugin plugin; public AddMavenPlugin() { super(builder()); diff --git a/components/sbm-core/src/main/java/org/springframework/sbm/build/migration/actions/SetProperty.java b/components/sbm-core/src/main/java/org/springframework/sbm/build/migration/actions/SetProperty.java index 351db127c..cf3fa2baf 100644 --- a/components/sbm-core/src/main/java/org/springframework/sbm/build/migration/actions/SetProperty.java +++ b/components/sbm-core/src/main/java/org/springframework/sbm/build/migration/actions/SetProperty.java @@ -15,11 +15,16 @@ */ package org.springframework.sbm.build.migration.actions; +import lombok.NoArgsConstructor; import lombok.Setter; +import lombok.experimental.SuperBuilder; + import org.springframework.sbm.engine.context.ProjectContext; import org.springframework.sbm.engine.recipe.AbstractAction; @Setter +@SuperBuilder +@NoArgsConstructor public class SetProperty extends AbstractAction { private String propertyName; diff --git a/components/sbm-core/src/main/java/org/springframework/sbm/build/migration/conditions/MavenPluginDoesNotExist.java b/components/sbm-core/src/main/java/org/springframework/sbm/build/migration/conditions/MavenPluginDoesNotExist.java index 237924d7c..c45c6a9a5 100644 --- a/components/sbm-core/src/main/java/org/springframework/sbm/build/migration/conditions/MavenPluginDoesNotExist.java +++ b/components/sbm-core/src/main/java/org/springframework/sbm/build/migration/conditions/MavenPluginDoesNotExist.java @@ -15,7 +15,7 @@ */ package org.springframework.sbm.build.migration.conditions; -import org.springframework.sbm.build.api.Plugin; +import org.springframework.sbm.build.impl.OpenRewriteMavenPlugin; import org.springframework.sbm.engine.recipe.Condition; import org.springframework.sbm.engine.context.ProjectContext; import lombok.Setter; @@ -25,7 +25,7 @@ public class MavenPluginDoesNotExist implements Condition { @Setter @Valid - private Plugin plugin; + private OpenRewriteMavenPlugin plugin; @Override public String getDescription() { diff --git a/components/sbm-core/src/main/java/org/springframework/sbm/build/migration/recipe/AddMavenPlugin.java b/components/sbm-core/src/main/java/org/springframework/sbm/build/migration/recipe/AddMavenPlugin.java index ca0a088de..6f6bdadb1 100644 --- a/components/sbm-core/src/main/java/org/springframework/sbm/build/migration/recipe/AddMavenPlugin.java +++ b/components/sbm-core/src/main/java/org/springframework/sbm/build/migration/recipe/AddMavenPlugin.java @@ -15,18 +15,21 @@ */ package org.springframework.sbm.build.migration.recipe; +import com.fasterxml.jackson.core.JsonProcessingException; import lombok.Data; import lombok.EqualsAndHashCode; import org.openrewrite.ExecutionContext; import org.openrewrite.Recipe; import org.openrewrite.TreeVisitor; import org.openrewrite.maven.MavenVisitor; +import org.openrewrite.maven.internal.MavenXmlMapper; import org.openrewrite.xml.AddToTagVisitor; import org.openrewrite.xml.ChangeTagValueVisitor; import org.openrewrite.xml.XPathMatcher; import org.openrewrite.xml.tree.Content; import org.openrewrite.xml.tree.Xml; -import org.springframework.sbm.build.api.Plugin; +import org.springframework.sbm.build.impl.OpenRewriteMavenPlugin; +import org.springframework.sbm.build.impl.OpenRewriteMavenPlugin.OpenRewriteMavenPluginExecution; import java.util.List; import java.util.Optional; @@ -38,7 +41,7 @@ public class AddMavenPlugin extends Recipe { private static final XPathMatcher BUILD_MATCHER = new XPathMatcher("/project/build"); - private final Plugin plugin; + private final OpenRewriteMavenPlugin plugin; @Override protected TreeVisitor getVisitor() { @@ -108,7 +111,7 @@ private String createPluginTagString() { sb.append("\n"); sb.append(renderVersion()); sb.append(renderExecutions()); - sb.append(plugin.getConfiguration() != null ? plugin.getConfiguration().trim() + "\n" : ""); + sb.append(renderConfiguration()); sb.append(plugin.getDependencies() != null ? plugin.getDependencies().trim() + "\n" : ""); sb.append("\n"); return sb.toString(); @@ -122,6 +125,20 @@ private String renderVersion() { return plugin.getVersion() != null ? "" + plugin.getVersion() + "\n" : ""; } + private String renderConfiguration(){ + if (plugin.getConfiguration() != null) { + try { + String configurationXml = MavenXmlMapper.writeMapper().writerWithDefaultPrettyPrinter() + .writeValueAsString(plugin.getConfiguration()); + return configurationXml; + } + catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + return ""; + } + private String renderExecutions() { if (plugin.getExecutions() == null || plugin.getExecutions().isEmpty()) return ""; @@ -130,27 +147,27 @@ private String renderExecutions() { return "\n" + executions + "\n\n"; } - private String renderExecution(Plugin.Execution execution) { + private String renderExecution(OpenRewriteMavenPluginExecution execution) { return "\n" + renderId(execution) + renderGoals(execution) + renderPhase(execution) - + renderConfiguration(execution) + ""; + + renderExecutionConfiguration(execution) + ""; } - private String renderConfiguration(Plugin.Execution execution) { + private String renderExecutionConfiguration(OpenRewriteMavenPluginExecution execution) { return execution.getConfiguration() == null ? "" : execution.getConfiguration().trim(); } - private String renderId(Plugin.Execution execution) { + private String renderId(OpenRewriteMavenPluginExecution execution) { return execution.getId() != null && !execution.getId().isBlank() ? "" + execution.getId() + "\n" : ""; } - private String renderGoals(Plugin.Execution execution) { + private String renderGoals(OpenRewriteMavenPluginExecution execution) { if (execution.getGoals() == null || execution.getGoals().isEmpty()) return ""; String goals = execution.getGoals().stream().map(this::renderGoal).collect(Collectors.joining("\n")); return "\n" + goals + "\n\n"; } - private String renderPhase(Plugin.Execution execution) { + private String renderPhase(OpenRewriteMavenPluginExecution execution) { return execution.getPhase() == null ? "" : "" + execution.getPhase() + ""; } diff --git a/components/sbm-core/src/test/java/org/springframework/sbm/build/api/Module_contains_Test.java b/components/sbm-core/src/test/java/org/springframework/sbm/build/api/Module_contains_Test.java index 1b61b9080..6425770aa 100644 --- a/components/sbm-core/src/test/java/org/springframework/sbm/build/api/Module_contains_Test.java +++ b/components/sbm-core/src/test/java/org/springframework/sbm/build/api/Module_contains_Test.java @@ -31,7 +31,7 @@ class Module_contains_Test { void singleModuleProject() { String rootPom = PomBuilder .buildPom("com.example:parent:1.0") - .type("jar") + .packaging("jar") .withModules("module1", "module2") .build(); @@ -67,7 +67,7 @@ public class SomeClassTest {} void multiModuleProject() { String rootPom = PomBuilder .buildPom("com.example:parent:1.0") - .type("pom") + .packaging("pom") .withModules("module1", "module2") .build(); diff --git a/components/sbm-core/src/test/java/org/springframework/sbm/build/impl/OpenRewriteMavenPluginTest.java b/components/sbm-core/src/test/java/org/springframework/sbm/build/impl/OpenRewriteMavenPluginTest.java new file mode 100644 index 000000000..1895aa996 --- /dev/null +++ b/components/sbm-core/src/test/java/org/springframework/sbm/build/impl/OpenRewriteMavenPluginTest.java @@ -0,0 +1,174 @@ +/* + * Copyright 2021 - 2022 the original author or authors. + * + * 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 + * + * https://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 org.springframework.sbm.build.impl; + +import org.junit.jupiter.api.Test; +import org.openrewrite.maven.internal.MavenXmlMapper; + +import org.springframework.sbm.build.api.BuildFile; +import org.springframework.sbm.build.api.Plugin; +import org.springframework.sbm.project.resource.TestProjectContext; + +import static org.assertj.core.api.Assertions.assertThat; + +class OpenRewriteMavenPluginTest { + + @Test + void serializePlugin() { + String pomXml = + """ + + + 4.0.0 + com.vmwre.sbm.examples + migrate-jsf-2.x-to-spring-boot + 1.0 + jar + + 17 + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.10.1 + + + default-compile + + 9 + + + + base-compile + + compile + + + + module-info.java + + + + + + ${maven.compiler.source} + 17 + + + + + """; + + BuildFile buildFile = TestProjectContext.buildProjectContext() + .withMavenRootBuildFileSource(pomXml) + .build() + .getBuildFile(); + + Plugin plugin = buildFile.getPlugins().get(0); + + assertThat(plugin.getGroupId()).isEqualTo("org.apache.maven.plugins"); + assertThat(plugin.getArtifactId()).isEqualTo("maven-compiler-plugin"); + assertThat(plugin.getVersion()).isEqualTo("3.10.1"); + + //Plugin execution Tests + assertThat(plugin.getExecutions()).hasSize(2); + assertThat(plugin.getExecutions().get(0).getId()).isEqualTo("default-compile"); + assertThat(plugin.getExecutions().get(1).getId()).isEqualTo("base-compile"); + assertThat(plugin.getExecutions().get(1).getGoals()).hasSize(1); + assertThat(plugin.getExecutions().get(1).getGoals().get(0)).isEqualTo("compile"); + + + // Plugin Configuration Tests + assertThat(plugin.getConfiguration()).isNotNull(); +// assertThat(plugin.getConfiguration().getConfigurationPropertyKeys()).hasSize(2); + assertThat(plugin.getConfiguration().getDeclaredStringValue("maven.compiler.source").orElseThrow()) + .isEqualTo("${maven.compiler.source}"); + assertThat(plugin.getConfiguration().getDeclaredStringValue("maven.compiler.target").orElseThrow()) + .isEqualTo("17"); +// assertThat(plugin.getConfiguration().getResolvedStringValue("maven.compiler.source")) +// .isEqualTo("17"); +// assertThat(plugin.getConfiguration().getResolvedStringValue("maven.compiler.target")) +// .isEqualTo("17"); + + } + + + @Test + void deSerializePluginString() { + + String pomXml = + """ + + + 4.0.0 + com.vmwre.sbm.examples + migrate-jsf-2.x-to-spring-boot + 1.0 + jar + + 17 + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.10.1 + + + default-compile + + 9 + + + + base-compile + + compile + + + + module-info.java + + + + + + ${maven.compiler.source} + 17 + + + + + """; + + BuildFile buildFile = TestProjectContext.buildProjectContext() + .withMavenRootBuildFileSource(pomXml) + .build() + .getBuildFile(); + + Plugin plugin = buildFile.getPlugins().get(0); + plugin.getConfiguration().setDeclaredStringValue("maven.compiler.source","17"); + assertThat(plugin.getConfiguration().getDeclaredStringValue("maven.compiler.source").orElseThrow()) + .isEqualTo("17"); + } +} \ No newline at end of file diff --git a/components/sbm-core/src/test/java/org/springframework/sbm/build/migration/actions/AddMavenPluginTest.java b/components/sbm-core/src/test/java/org/springframework/sbm/build/migration/actions/AddMavenPluginTest.java index 179457895..bf8fd10ec 100644 --- a/components/sbm-core/src/test/java/org/springframework/sbm/build/migration/actions/AddMavenPluginTest.java +++ b/components/sbm-core/src/test/java/org/springframework/sbm/build/migration/actions/AddMavenPluginTest.java @@ -18,7 +18,8 @@ import org.junit.jupiter.api.Test; import org.mockito.internal.util.collections.Sets; import org.springframework.sbm.build.api.BuildFile; -import org.springframework.sbm.build.api.Plugin; +import org.springframework.sbm.build.impl.OpenRewriteMavenPlugin; +import org.springframework.sbm.build.impl.OpenRewriteMavenPlugin.OpenRewriteMavenPluginExecution; import org.springframework.sbm.engine.context.ProjectContext; import static org.mockito.Mockito.*; @@ -28,7 +29,7 @@ class AddMavenPluginTest { @Test void testApply() { AddMavenPlugin addMavenPlugin = new AddMavenPlugin(); - Plugin plugin = new Plugin(); + OpenRewriteMavenPlugin plugin = new OpenRewriteMavenPlugin(); addMavenPlugin.setPlugin(plugin); BuildFile buildFile = mock(BuildFile.class); @@ -44,7 +45,7 @@ void testApply() { @Test void addMavenPluginMinimalFields() { AddMavenPlugin sut = new AddMavenPlugin(); - Plugin plugin = Plugin.builder() + OpenRewriteMavenPlugin plugin = OpenRewriteMavenPlugin.builder() .groupId("org.joinfaces") .artifactId("joinfaces-maven-plugin") .build(); @@ -84,19 +85,19 @@ void addMavenPluginMinimalFields() { @Test void addMavenPluginAllFields() { AddMavenPlugin sut = new AddMavenPlugin(); - Plugin plugin = Plugin.builder() + OpenRewriteMavenPlugin plugin = OpenRewriteMavenPlugin.builder() .groupId("org.joinfaces") .artifactId("joinfaces-maven-plugin") .version("2.4.2") .execution( - Plugin.Execution.builder() + OpenRewriteMavenPluginExecution.builder() .id("some-id") .goal("classpath-scan") .goal("another-goal") .build() ) .execution( - Plugin.Execution.builder() + OpenRewriteMavenPluginExecution.builder() .goal("and-another") .build() ) @@ -291,12 +292,12 @@ void addMavenPlugin() { ""; AddMavenPlugin addMavenPlugin = new AddMavenPlugin(); - Plugin plugin = Plugin.builder() + OpenRewriteMavenPlugin plugin = OpenRewriteMavenPlugin.builder() . groupId("org.joinfaces") .artifactId("joinfaces-maven-plugin") .execution( - Plugin.Execution.builder() + OpenRewriteMavenPluginExecution.builder() .goals(Sets.newSet("classpath-scan")) .build() ) diff --git a/components/sbm-core/src/test/java/org/springframework/sbm/build/util/PomBuilder.java b/components/sbm-core/src/test/java/org/springframework/sbm/build/util/PomBuilder.java index 342177926..8cf34bf10 100644 --- a/components/sbm-core/src/test/java/org/springframework/sbm/build/util/PomBuilder.java +++ b/components/sbm-core/src/test/java/org/springframework/sbm/build/util/PomBuilder.java @@ -16,30 +16,42 @@ package org.springframework.sbm.build.util; -import org.openrewrite.maven.tree.Scope; import org.springframework.sbm.project.parser.DependencyHelper; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import com.fasterxml.jackson.core.JsonProcessingException; +import org.openrewrite.maven.internal.MavenXmlMapper; + +import org.springframework.sbm.build.api.Plugin; + +import org.openrewrite.maven.tree.Dependency; +import org.openrewrite.maven.tree.Scope; public class PomBuilder { - private String coordinate; - private List modules; - private String type; - private String parent; - private String artifactId; - private List unscopedDependencies; - private List testScopeDependencies; - private Map properties = new HashMap<>(); - private Map dependencies = new LinkedHashMap(); - - private DependencyHelper dependencyHelper = new DependencyHelper(); - private String parentPom; - - public static PomBuilder buildPom(String coordinate) { - PomBuilder pomBuilder = new PomBuilder(); - pomBuilder.coordinate = coordinate; - return pomBuilder; - } + private String coordinate; + private List modules; + private String packaging; + private String parent; + private String artifactId; + private Map properties = new HashMap<>(); + private Map dependencies = new LinkedHashMap(); + private List plugins = new ArrayList<>(); + + private DependencyHelper dependencyHelper = new DependencyHelper(); + private String parentPom; + + public static PomBuilder buildPom(String coordinate) { + PomBuilder pomBuilder = new PomBuilder(); + pomBuilder.coordinate = coordinate; + return pomBuilder; + } public static PomBuilder buildPom(String parentCoordinate, String artifactId) { PomBuilder pomBuilder = new PomBuilder(); @@ -116,18 +128,13 @@ public String build() { sb.append(" ").append(coord[2]).append("").append("\n"); } - if(!properties.isEmpty()) { - sb.append(" ").append("\n"); - properties.entrySet().forEach(e -> - sb.append(" <").append(e.getKey()).append(">").append(e.getValue()).append("").append("\n") - ); - sb.append(" ").append("\n"); - } - + if(packaging != null ){ + sb.append(" ").append(packaging).append("").append("\n"); + } - if (type != null) { - sb.append(" ").append(type).append("").append("\n"); - } + if(!properties.isEmpty()){ + sb.append(buildProperties(properties)); + } if (modules != null && !modules.isEmpty()) { sb.append(" ").append("\n"); @@ -140,10 +147,24 @@ public String build() { sb.append(dependenciesRendered); } - sb.append(""); + if(!plugins.isEmpty()){ + sb.append(renderPlugins()); + } + + sb.append("\n"); return sb.toString(); } + String buildProperties(Map properties) { + StringBuilder builder = new StringBuilder(); + builder.append(" ").append("").append("\n"); + String props = properties.entrySet().stream().map(entry -> " " + " " + "<" + entry.getKey() + ">" + + entry.getValue() + "").collect(Collectors.joining("\n")); + builder.append(props).append("\n"); + builder.append(" ").append("").append("\n"); + return builder.toString(); + } + String renderDependencies(Map dependencies) { StringBuilder dependenciesSection = new StringBuilder(); dependenciesSection.append(" ").append("").append("\n"); @@ -205,10 +226,28 @@ private void renderDependency(StringBuilder dependenciesSection, Scope scope, or .append("\n"); } - public PomBuilder type(String type) { - this.type = type; - return this; - } + private String renderPlugins(){ + StringBuilder pluginSection = new StringBuilder(); + if (!plugins.isEmpty()) { + pluginSection.append(" ").append("").append("\n"); + pluginSection.append(" ").append(" ").append("").append("\n"); + try { + String plugin = MavenXmlMapper.writeMapper().writerWithDefaultPrettyPrinter().writeValueAsString(plugins.get(0)); + pluginSection.append(plugin.replaceAll(" ", " ").replaceAll("(?m)^", " ".repeat(12))); + } + catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + pluginSection.append(" ").append(" ").append("").append("\n"); + pluginSection.append(" ").append("").append("\n"); + } + return pluginSection.toString(); + } + + public PomBuilder packaging(String type) { + this.packaging = type; + return this; + } public PomBuilder unscopedDependencies(String... coordinates) { dependencyHelper.mapCoordinatesToDependencies(Arrays.asList(coordinates)) @@ -235,4 +274,14 @@ public PomBuilder withProperties(Map properties) { this.properties = properties; return this; } + + public PomBuilder property(String property, String value){ + this.properties.put(property,value); + return this; + } + + public PomBuilder plugins(Plugin... p) { + this.plugins = Arrays.asList(p); + return this; + } } diff --git a/components/sbm-core/src/test/java/org/springframework/sbm/project/buildfile/OpenRewriteMavenBuildFileTest.java b/components/sbm-core/src/test/java/org/springframework/sbm/project/buildfile/OpenRewriteMavenBuildFileTest.java index d5c41a0d9..2a2ec6e56 100644 --- a/components/sbm-core/src/test/java/org/springframework/sbm/project/buildfile/OpenRewriteMavenBuildFileTest.java +++ b/components/sbm-core/src/test/java/org/springframework/sbm/project/buildfile/OpenRewriteMavenBuildFileTest.java @@ -15,9 +15,13 @@ */ package org.springframework.sbm.project.buildfile; -import org.intellij.lang.annotations.Language; import org.jetbrains.annotations.NotNull; -import org.junit.jupiter.api.*; +import org.intellij.lang.annotations.Language; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; import org.mockito.Mockito; import org.springframework.context.ApplicationEventPublisher; @@ -26,6 +30,7 @@ import org.springframework.sbm.build.api.Dependency; import org.springframework.sbm.build.api.Plugin; import org.springframework.sbm.build.util.PomBuilder; +import org.springframework.sbm.build.impl.OpenRewriteMavenPlugin; import org.springframework.sbm.engine.context.ProjectContext; import org.springframework.sbm.engine.context.ProjectContextHolder; import org.springframework.sbm.java.api.Member; @@ -33,7 +38,11 @@ import org.springframework.sbm.project.resource.TestProjectContext; import java.nio.file.Path; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; import java.util.stream.Collectors; import static org.assertj.core.api.Assertions.assertThat; @@ -1453,7 +1462,7 @@ void shouldAddMavenPluginWhenNoPluginSectionExists() { " \n" + ""; - Plugin plugin = new Plugin(); + OpenRewriteMavenPlugin plugin = new OpenRewriteMavenPlugin(); plugin.setGroupId("group.id"); plugin.setArtifactId("some.artifact"); @@ -1496,7 +1505,7 @@ void shouldAddMavenPluginWhenEmptyPluginSectionExists() { " \n" + ""; - Plugin plugin = new Plugin(); + OpenRewriteMavenPlugin plugin = new OpenRewriteMavenPlugin(); plugin.setGroupId("group.id"); plugin.setArtifactId("some.artifact"); @@ -1543,7 +1552,7 @@ void shouldNotAddMavenPluginWhenSamePluginExists() { " \n" + ""; - Plugin plugin = new Plugin(); + OpenRewriteMavenPlugin plugin = new OpenRewriteMavenPlugin(); plugin.setGroupId("group.id"); plugin.setArtifactId("some.artifact"); @@ -1594,7 +1603,7 @@ void shouldAddMavenPluginWhenAnotherPluginExists() { " \n" + ""; - Plugin plugin = new Plugin(); + OpenRewriteMavenPlugin plugin = new OpenRewriteMavenPlugin(); plugin.setGroupId("group.id"); plugin.setArtifactId("some.artifact"); @@ -1943,7 +1952,7 @@ void testHasPlugin() { .build() .getBuildFile(); - Plugin plugin = Plugin.builder() + OpenRewriteMavenPlugin plugin = OpenRewriteMavenPlugin.builder() .groupId("com.example") .artifactId("the-example") .build(); @@ -2060,16 +2069,192 @@ void getPlugins() { assertThat(plugins.get(0).getGroupId()).isEqualTo("org.mule.tools.maven"); assertThat(plugins.get(0).getArtifactId()).isEqualTo("mule-maven-plugin"); assertThat(plugins.get(0).getVersion()).isEqualTo("${mule.maven.plugin.version}"); - assertThat(plugins.get(0).getConfiguration()).isEmpty(); + assertThat(plugins.get(0).getConfiguration().getPropertyKeys()).isNotEmpty(); - assertThat(plugins.get(1).getGroupId()).isEqualTo("com.mulesoft.munit.tools"); + assertThat(plugins.get(1).getGroupId()).isEqualTo("com.mulesoft.munit.tools"); assertThat(plugins.get(1).getArtifactId()).isEqualTo("munit-maven-plugin"); assertThat(plugins.get(1).getVersion()).isEqualTo("${munit.version}"); - assertThat(plugins.get(1).getConfiguration()).isEmpty(); - assertThat(plugins.get(1).getExecutions()).isEmpty(); + assertThat(plugins.get(1).getConfiguration().getPropertyKeys()).isNotEmpty(); + assertThat(plugins.get(1).getExecutions()).isNotEmpty(); + assertThat(plugins.get(1).getExecutions().get(0).getId()).isEqualTo("test"); + assertThat(plugins.get(1).getExecutions().get(0).getPhase()).isEqualTo("test"); + assertThat(plugins.get(1).getExecutions().get(0).getGoals()).hasSize(2); + assertThat(plugins.get(1).getExecutions().get(0).getGoals().get(0)).isEqualTo("test"); + assertThat(plugins.get(1).getExecutions().get(0).getGoals().get(1)).isEqualTo("coverage-report"); } - @Test + @Test + void deserializePluginConfiguration() { + + String pomXml = + "\n" + + "\n" + + "\n" + + " 4.0.0\n" + + " org.springframework.boot\n" + + " spring-boot-starter-parent\n" + + " 2.7.3\n" + + " jar\n" + + " hello-world" + + " \n" + + " 17\n" + + " 17\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " org.apache.maven.plugins\n" + + " maven-compiler-plugin\n" + + " \n" + + " ${source}\n" + + " ${source}\n" + + " 17\n" + + " false\n" + + " true\n" + + " true\n"+ + " \n" + + " -J-Duser.language=en_us\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""; + + BuildFile openRewriteMavenBuildFile = TestProjectContext.buildProjectContext().withMavenRootBuildFileSource(pomXml).build().getBuildFile(); + + Plugin compilerPlugin = openRewriteMavenBuildFile.getPlugins() + .stream() + .filter(plugin -> plugin.getGroupId().equals("org.apache.maven.plugins") && + plugin.getArtifactId().equals("maven-compiler-plugin")) + .findAny().orElseThrow(); + + assertThat(compilerPlugin.getConfiguration().getDeclaredStringValue("source").get()).isEqualTo("${source}"); + assertThat(compilerPlugin.getConfiguration().getDeclaredStringValue("target").get()).isEqualTo("17"); + assertThat(compilerPlugin.getConfiguration().getDeclaredStringValue("fork").get()).isEqualTo("false"); + } + + @Test + void serializePluginConfiguration() { + + String pomXml = + "\n" + + "\n" + + "\n" + + " 4.0.0\n" + + " org.springframework.boot\n" + + " spring-boot-starter-parent\n" + + " 2.7.3\n" + + " jar\n" + + " hello-world" + + " \n" + + " \n" + + " \n" + + " org.apache.maven.plugins\n" + + " maven-compiler-plugin\n" + + " \n" + + " \n" + + " \n" + + ""; + + String expected = + "\n" + + "\n" + + "\n" + + " 4.0.0\n" + + " org.springframework.boot\n" + + " spring-boot-starter-parent\n" + + " 2.7.3\n" + + " jar\n" + + " hello-world" + + " \n" + + " \n" + + " \n" + + " org.apache.maven.plugins\n" + + " maven-compiler-plugin\n" + + " \n" + + " 17\n" + + " 17\n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""; + + BuildFile openRewriteMavenBuildFile = TestProjectContext.buildProjectContext().withMavenRootBuildFileSource(pomXml).build().getBuildFile(); + + Plugin compilerPlugin = openRewriteMavenBuildFile.getPlugins() + .stream() + .filter(plugin -> plugin.getGroupId().equals("org.apache.maven.plugins") && + plugin.getArtifactId().equals("maven-compiler-plugin")) + .findAny().orElseThrow(); + + compilerPlugin.getConfiguration().setDeclaredStringValue("source", "17"); + compilerPlugin.getConfiguration().setDeclaredStringValue("target", "17"); + + assertThat(openRewriteMavenBuildFile.print()).isEqualTo(expected); + + } + + @Test + void deleteProperty() { + + String pomXml = + "\n" + + "\n" + + "\n" + + " 4.0.0\n" + + " org.springframework.boot\n" + + " spring-boot-starter-parent\n" + + " 2.7.3\n" + + " jar\n" + + " hello-world" + + " \n" + + " 17\n" + + " 17\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " org.apache.maven.plugins\n" + + " maven-compiler-plugin\n" + + " \n" + + " \n" + + " \n" + + ""; + + String expected = + "\n" + + "\n" + + "\n" + + " 4.0.0\n" + + " org.springframework.boot\n" + + " spring-boot-starter-parent\n" + + " 2.7.3\n" + + " jar\n" + + " hello-world" + + " \n" + + " 17\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " org.apache.maven.plugins\n" + + " maven-compiler-plugin\n" + + " \n" + + " \n" + + " \n" + + ""; + + BuildFile openRewriteMavenBuildFile = TestProjectContext.buildProjectContext().withMavenRootBuildFileSource(pomXml).build().getBuildFile(); + + openRewriteMavenBuildFile.deleteProperty("java.version"); + + assertThat(openRewriteMavenBuildFile.print()).isEqualTo(expected); + + } + + @Test void removePluginsMatchingRegex() { String pomXml = "\n" + diff --git a/components/sbm-recipes-jee-to-boot/src/main/java/org/springframework/sbm/jee/jaxws/GenerateWebServices.java b/components/sbm-recipes-jee-to-boot/src/main/java/org/springframework/sbm/jee/jaxws/GenerateWebServices.java index db5eed7e1..a2e00cbba 100644 --- a/components/sbm-recipes-jee-to-boot/src/main/java/org/springframework/sbm/jee/jaxws/GenerateWebServices.java +++ b/components/sbm-recipes-jee-to-boot/src/main/java/org/springframework/sbm/jee/jaxws/GenerateWebServices.java @@ -17,7 +17,8 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import org.springframework.sbm.build.api.Module; -import org.springframework.sbm.build.api.Plugin; +import org.springframework.sbm.build.impl.OpenRewriteMavenPlugin; +import org.springframework.sbm.build.impl.OpenRewriteMavenPlugin.OpenRewriteMavenPluginExecution; import org.springframework.sbm.engine.recipe.AbstractAction; import org.springframework.sbm.engine.recipe.UserInteractions; import org.springframework.sbm.java.api.*; @@ -98,7 +99,7 @@ public void apply(ProjectContext context) { private void addMavenPluginForJavaSourceGeneration(Module module, List descriptors) { module.getBuildFile().setProperty(PROPERTY_KEY_JAVA_GEN_FOLDER, PROPERTY_VALUE_JAVA_GEN_FOLDER); - List generateExecs = descriptors.stream().map(d -> Plugin.Execution.builder() + List generateExecs = descriptors.stream().map(d -> OpenRewriteMavenPluginExecution.builder() .goal("generate") .configuration("\n\n" + "${project.basedir}/src/main/resources\n" + @@ -110,7 +111,7 @@ private void addMavenPluginForJavaSourceGeneration(Module module, List\n" + diff --git a/components/sbm-support-boot/src/main/java/org/springframework/sbm/boot/cleanup/actions/RemoveRedundantMavenCompilerPlugin.java b/components/sbm-support-boot/src/main/java/org/springframework/sbm/boot/cleanup/actions/RemoveRedundantMavenCompilerPlugin.java new file mode 100644 index 000000000..4be15f8a5 --- /dev/null +++ b/components/sbm-support-boot/src/main/java/org/springframework/sbm/boot/cleanup/actions/RemoveRedundantMavenCompilerPlugin.java @@ -0,0 +1,46 @@ +/* + * Copyright 2021 - 2022 the original author or authors. + * + * 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 + * + * https://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 org.springframework.sbm.boot.cleanup.actions; + +import java.util.Set; + +import org.springframework.sbm.build.api.Module; +import org.springframework.sbm.engine.context.ProjectContext; +import org.springframework.sbm.engine.recipe.AbstractAction; + +public class RemoveRedundantMavenCompilerPlugin extends AbstractAction { + + private static final String GROUP_ID = "org.apache.maven.plugins"; + + private static final String ARTIFACT_ID = "maven-compiler-plugin"; + + @Override + public void apply(ProjectContext context) { + + context.getApplicationModules().stream().map(Module::getBuildFile) + .forEach(buildFile -> buildFile.findPlugin(GROUP_ID, ARTIFACT_ID).ifPresent(plugin -> { + Set configuration = plugin.getConfiguration().getPropertyKeys(); + + + long otherConfiguration = configuration.stream().filter(config -> !config.equals("source")) + .filter(config -> !config.equals("target")).count(); + if (otherConfiguration == 0) { + buildFile.removePlugins(GROUP_ID + ":" + ARTIFACT_ID); + } + })); + } + +} diff --git a/components/sbm-support-boot/src/main/java/org/springframework/sbm/boot/cleanup/actions/RemoveRedundantMavenCompilerPluginProperties.java b/components/sbm-support-boot/src/main/java/org/springframework/sbm/boot/cleanup/actions/RemoveRedundantMavenCompilerPluginProperties.java new file mode 100644 index 000000000..53059949b --- /dev/null +++ b/components/sbm-support-boot/src/main/java/org/springframework/sbm/boot/cleanup/actions/RemoveRedundantMavenCompilerPluginProperties.java @@ -0,0 +1,80 @@ +/* + * Copyright 2021 - 2022 the original author or authors. + * + * 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 + * + * https://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 org.springframework.sbm.boot.cleanup.actions; + +import java.util.Optional; + +import org.springframework.sbm.build.api.Module; +import org.springframework.sbm.engine.context.ProjectContext; +import org.springframework.sbm.engine.recipe.AbstractAction; + +public class RemoveRedundantMavenCompilerPluginProperties extends AbstractAction { + + private static final String GROUP_ID = "org.apache.maven.plugins"; + + private static final String ARTIFACT_ID = "maven-compiler-plugin"; + + private static final String JAVA_VERSION_PROPERTY = "java.version"; + + private static final String JAVA_VERSION_PLACEHOLDER = "${java.version}"; + + private static final String MAVEN_COMPILER_SOURCE_PROPERTY = "maven.compiler.source"; + + private static final String MAVEN_COMPILER_TARGET_PROPERTY = "maven.compiler.target"; + + @Override + public void apply(ProjectContext context) { + + context.getApplicationModules().stream().map(Module::getBuildFile).forEach(buildFile -> { + buildFile.findPlugin(GROUP_ID, ARTIFACT_ID).ifPresent(plugin -> { + + Optional source = plugin.getConfiguration().getDeclaredStringValue("source"); + Optional target = plugin.getConfiguration().getDeclaredStringValue("target"); + + if (source.isPresent() && target.isPresent()) { + + String sourceLookupValue = plugin.getConfiguration().getResolvedStringValue("source"); + String targetLookupValue = plugin.getConfiguration().getResolvedStringValue("target"); + + if (sourceLookupValue.equals(targetLookupValue)) { + buildFile.setProperty(JAVA_VERSION_PROPERTY, sourceLookupValue); + plugin.getConfiguration().setDeclaredStringValue("source", JAVA_VERSION_PLACEHOLDER); + plugin.getConfiguration().setDeclaredStringValue("target", JAVA_VERSION_PLACEHOLDER); + if(source.get().startsWith("${")){ + buildFile.deleteProperty(source.get().replace("${", "").replace("}", "")); + } + if(target.get().startsWith("${")){ + buildFile.deleteProperty(target.get().replace("${", "").replace("}", "")); + } + } + + } + + }); //Plugin exits + + String sourcePropertyValue = buildFile.getProperty(MAVEN_COMPILER_SOURCE_PROPERTY); + String targetPropertyValue = buildFile.getProperty(MAVEN_COMPILER_TARGET_PROPERTY); + + if (sourcePropertyValue != null && sourcePropertyValue.equals(targetPropertyValue)){ + buildFile.setProperty(JAVA_VERSION_PROPERTY, sourcePropertyValue); + buildFile.deleteProperty(MAVEN_COMPILER_SOURCE_PROPERTY); + buildFile.deleteProperty(MAVEN_COMPILER_TARGET_PROPERTY); + } // If only maven property exists + + }); + } + +} diff --git a/components/sbm-support-boot/src/main/java/org/springframework/sbm/boot/cleanup/conditions/SpringBootMavenCompilerExists.java b/components/sbm-support-boot/src/main/java/org/springframework/sbm/boot/cleanup/conditions/SpringBootMavenCompilerExists.java new file mode 100644 index 000000000..62fbd02d7 --- /dev/null +++ b/components/sbm-support-boot/src/main/java/org/springframework/sbm/boot/cleanup/conditions/SpringBootMavenCompilerExists.java @@ -0,0 +1,50 @@ +/* + * Copyright 2021 - 2022 the original author or authors. + * + * 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 + * + * https://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 org.springframework.sbm.boot.cleanup.conditions; + +import org.springframework.sbm.boot.common.conditions.HasDecalredSpringBootStarterParent; +import org.springframework.sbm.build.impl.OpenRewriteMavenPlugin; +import org.springframework.sbm.build.migration.conditions.MavenPluginDoesNotExist; +import org.springframework.sbm.common.migration.conditions.FileMatchingPatternExist; +import org.springframework.sbm.engine.context.ProjectContext; +import org.springframework.sbm.engine.recipe.Condition; + +public class SpringBootMavenCompilerExists implements Condition { + + @Override + public String getDescription() { + return "Checks if it's a spring boot project pom has a maven compiler plugin exists"; + } + + @Override + public boolean evaluate(ProjectContext context) { + + FileMatchingPatternExist fileMatchingPatternExist = new FileMatchingPatternExist(); + fileMatchingPatternExist.setPattern("/**/pom.xml"); + + HasDecalredSpringBootStarterParent hasDecalredSpringBootStarterParent = new HasDecalredSpringBootStarterParent(); + hasDecalredSpringBootStarterParent.setVersionPattern(".*"); + + MavenPluginDoesNotExist mavenPluginDoesNotExist = new MavenPluginDoesNotExist(); + OpenRewriteMavenPlugin plugin = OpenRewriteMavenPlugin.builder().groupId("org.apache.maven.plugins").artifactId("maven-compiler-plugin") + .build(); + mavenPluginDoesNotExist.setPlugin(plugin); + + return fileMatchingPatternExist.evaluate(context) && !mavenPluginDoesNotExist.evaluate(context) + && hasDecalredSpringBootStarterParent.evaluate(context); + } + +} diff --git a/components/sbm-support-boot/src/main/resources/recipes/remove-redundant-maven-compiler-plugin.yaml b/components/sbm-support-boot/src/main/resources/recipes/remove-redundant-maven-compiler-plugin.yaml new file mode 100644 index 000000000..b0010747b --- /dev/null +++ b/components/sbm-support-boot/src/main/resources/recipes/remove-redundant-maven-compiler-plugin.yaml @@ -0,0 +1,12 @@ +- name: remove-redundant-maven-compiler-plugin + order: 200 + condition: + type: org.springframework.sbm.boot.cleanup.conditions.SpringBootMavenCompilerExists + description: "Remove standard maven-compiler plugin for applications with boot parent." + + actions: + - type: org.springframework.sbm.boot.cleanup.actions.RemoveRedundantMavenCompilerPluginProperties + description: Clean up redundant properties for maven compiler plugin. + + - type: org.springframework.sbm.boot.cleanup.actions.RemoveRedundantMavenCompilerPlugin + description: Clean up redundant maven compiler plugin. \ No newline at end of file diff --git a/components/sbm-support-boot/src/test/java/org/springframework/sbm/boot/cleanup/actions/RemoveRedundantMavenCompilerPluginPropertiesTest.java b/components/sbm-support-boot/src/test/java/org/springframework/sbm/boot/cleanup/actions/RemoveRedundantMavenCompilerPluginPropertiesTest.java new file mode 100644 index 000000000..e40d1cad4 --- /dev/null +++ b/components/sbm-support-boot/src/test/java/org/springframework/sbm/boot/cleanup/actions/RemoveRedundantMavenCompilerPluginPropertiesTest.java @@ -0,0 +1,571 @@ +/* + * Copyright 2021 - 2022 the original author or authors. + * + * 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 + * + * https://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 org.springframework.sbm.boot.cleanup.actions; + +import java.util.LinkedHashMap; +import java.util.Map; + +import com.fasterxml.jackson.core.JsonProcessingException; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +import org.springframework.sbm.build.api.Module; +import org.springframework.sbm.build.impl.OpenRewriteMavenPlugin; +import org.springframework.sbm.build.migration.actions.OpenRewriteMavenBuildFileTestSupport; +import org.springframework.sbm.build.util.PomBuilder; +import org.springframework.sbm.engine.context.ProjectContext; +import org.springframework.sbm.project.resource.TestProjectContext; + +import static org.assertj.core.api.Assertions.assertThat; + +class RemoveRedundantMavenCompilerPluginPropertiesTest { + + @Test + void mavenCompilerPluginNotDefined() { + String pomXml = """ + + + 4.0.0 + org.springframework.boot + spring-boot-starter-parent + 2.7.3 + clean-maven-properties + Remove Redundant configuration + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + """; + + String expected = """ + + + 4.0.0 + org.springframework.boot + spring-boot-starter-parent + 2.7.3 + clean-maven-properties + Remove Redundant configuration + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + """; + + RemoveRedundantMavenCompilerPluginProperties sut = new RemoveRedundantMavenCompilerPluginProperties(); + OpenRewriteMavenBuildFileTestSupport.verifyRefactoring(pomXml, expected, sut); + + } + + @Test + void sourceAndTargetVersionDifferent() { + String pomXml = """ + + + 4.0.0 + org.springframework.boot + spring-boot-starter-parent + 2.7.3 + clean-maven-properties + Remove Redundant configuration + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.8 + 1.6 + + + + + + """; + + String expected = """ + + + 4.0.0 + org.springframework.boot + spring-boot-starter-parent + 2.7.3 + clean-maven-properties + Remove Redundant configuration + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.8 + 1.6 + + + + + + """; + + RemoveRedundantMavenCompilerPluginProperties sut = new RemoveRedundantMavenCompilerPluginProperties(); + OpenRewriteMavenBuildFileTestSupport.verifyRefactoring(pomXml, expected, sut); + + } + + @Test + void mavenCompilerProperties() { + String pomXml = """ + + + 4.0.0 + org.springframework.boot + spring-boot-starter-parent + 2.7.3 + clean-maven-properties + Remove Redundant configuration + + 17 + 17 + + + + + org.apache.maven.plugins + maven-compiler-plugin + + ${maven.compiler.source} + ${maven.compiler.target} + + + + + + """; + + String expected = """ + + + 4.0.0 + org.springframework.boot + spring-boot-starter-parent + 2.7.3 + clean-maven-properties + Remove Redundant configuration + + 17 + + + + + org.apache.maven.plugins + maven-compiler-plugin + + ${java.version} + ${java.version} + + + + + + """; + + RemoveRedundantMavenCompilerPluginProperties sut = new RemoveRedundantMavenCompilerPluginProperties(); + OpenRewriteMavenBuildFileTestSupport.verifyRefactoring(pomXml, expected, sut); + } + + @Test + void customProperty() { + String pomXml = """ + + + 4.0.0 + org.springframework.boot + spring-boot-starter-parent + 2.7.3 + clean-maven-properties + Remove Redundant configuration + + 17 + 17 + + + + + org.apache.maven.plugins + maven-compiler-plugin + + ${source} + ${target} + + + + + + """; + + String expected = """ + + + 4.0.0 + org.springframework.boot + spring-boot-starter-parent + 2.7.3 + clean-maven-properties + Remove Redundant configuration + + 17 + + + + + org.apache.maven.plugins + maven-compiler-plugin + + ${java.version} + ${java.version} + + + + + + """; + + RemoveRedundantMavenCompilerPluginProperties sut = new RemoveRedundantMavenCompilerPluginProperties(); + OpenRewriteMavenBuildFileTestSupport.verifyRefactoring(pomXml, expected, sut); + } + + @Test + void fixedValueAndExistingJavaVersionProperty() { + String pomXml = """ + + + 4.0.0 + org.springframework.boot + spring-boot-starter-parent + 2.7.3 + clean-maven-properties + Remove Redundant configuration + + 15 + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 17 + 17 + + + + + + """; + + String expected = """ + + + 4.0.0 + org.springframework.boot + spring-boot-starter-parent + 2.7.3 + clean-maven-properties + Remove Redundant configuration + + 17 + + + + + org.apache.maven.plugins + maven-compiler-plugin + + ${java.version} + ${java.version} + + + + + + """; + + RemoveRedundantMavenCompilerPluginProperties sut = new RemoveRedundantMavenCompilerPluginProperties(); + OpenRewriteMavenBuildFileTestSupport.verifyRefactoring(pomXml, expected, sut); + } + + @Test + void emptyConfiguration() { + + String pomXml = """ + + + 4.0.0 + org.springframework.boot + spring-boot-starter-parent + 2.7.3 + clean-maven-properties + Remove Redundant configuration + + + + org.apache.maven.plugins + maven-compiler-plugin + + + + + """; + String expected = """ + + + 4.0.0 + org.springframework.boot + spring-boot-starter-parent + 2.7.3 + clean-maven-properties + Remove Redundant configuration + + + + org.apache.maven.plugins + maven-compiler-plugin + + + + + """; + + RemoveRedundantMavenCompilerPluginProperties sut = new RemoveRedundantMavenCompilerPluginProperties(); + OpenRewriteMavenBuildFileTestSupport.verifyRefactoring(pomXml, expected, sut); + } + + @Test + void multiModuleTest() { + + String parentPomStr = """ + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.7.5 + + + + 17 + 17 + + com.example + parent + 1.0 + + module1 + + + + + org.apache.maven.plugins + maven-compiler-plugin + + ${maven.compiler.source} + ${maven.compiler.target} + + + + + + """; + + String childPom1 = """ + + 4.0.0 + + com.example + parent + 1.0 + + module1 + + + """; + + ProjectContext projectContext = TestProjectContext.buildProjectContext() + .withMavenRootBuildFileSource(parentPomStr).withMavenBuildFileSource("module1", childPom1).build(); + + RemoveRedundantMavenCompilerPluginProperties sut = new RemoveRedundantMavenCompilerPluginProperties(); + sut.apply(projectContext); + + } + + @Test + void multiModuleWithPluginAndPropertiesDefinedInParentModule() throws JsonProcessingException { + + OpenRewriteMavenPlugin mavenPlugin = OpenRewriteMavenPlugin.builder() + .groupId("org.apache.maven.plugins") + .artifactId("maven-compiler-plugin") + .build(); + Map configMap = new LinkedHashMap<>(); + configMap.put("source", "${maven.compiler.source}"); + configMap.put("target", "${maven.compiler.target}"); + mavenPlugin.setConfiguration(mavenPlugin.new OpenRewriteMavenPluginConfiguration(configMap)); + + String rootPom = PomBuilder.buildPom("com.example:parent:1.0").packaging("pom").plugins(mavenPlugin) + .property("maven.compiler.source", "17").property("maven.compiler.target", "17").withModules("module1") + .build(); + + String module1Pom = PomBuilder.buildPom("com.example:parent:1.0", "module1").packaging("jar").build(); + + ProjectContext projectContext = TestProjectContext.buildProjectContext() + .withMavenBuildFileSource("pom.xml", rootPom).withMavenBuildFileSource("module1/pom.xml", module1Pom) + .build(); + + RemoveRedundantMavenCompilerPluginProperties sut = new RemoveRedundantMavenCompilerPluginProperties(); + sut.apply(projectContext); + + Module rootModule = projectContext.getApplicationModules().getRootModule(); + assertThat(rootModule.getBuildFile().getProperty("source")).isNull(); + assertThat(rootModule.getBuildFile().getProperty("target")).isNull(); + assertThat(rootModule.getBuildFile().getProperty("java.version")).isEqualTo("17"); + assertThat( + rootModule.getBuildFile().getPlugins().get(0).getConfiguration().getDeclaredStringValue("source").get()) + .isEqualTo("${java.version}"); + assertThat( + rootModule.getBuildFile().getPlugins().get(0).getConfiguration().getDeclaredStringValue("target").get()) + .isEqualTo("${java.version}"); + } + + @Test + @Disabled("To be handled ") + void multiModuleWithPluginDefinedInParentModuleAndPropertiesInChildModule() { + OpenRewriteMavenPlugin mavenPlugin = OpenRewriteMavenPlugin.builder() + .groupId("org.apache.maven.plugins") + .artifactId("maven-compiler-plugin") + .build(); + Map configMap = new LinkedHashMap<>(); + configMap.put("source", "${maven.compiler.source}"); + configMap.put("target", "${maven.compiler.target}"); + mavenPlugin.setConfiguration(mavenPlugin.new OpenRewriteMavenPluginConfiguration(configMap)); + + String rootPom = PomBuilder.buildPom("com.example:parent:1.0").packaging("pom").plugins(mavenPlugin) + .property("maven.compiler.source", "17").property("maven.compiler.target", "17").withModules("module1") + .build(); + + String module1Pom = PomBuilder.buildPom("com.example:parent:1.0", "module1").packaging("jar") + .property("maven.compiler.source", "17").property("maven.compiler.target", "17").build(); + + ProjectContext projectContext = TestProjectContext.buildProjectContext() + .withMavenBuildFileSource("pom.xml", rootPom).withMavenBuildFileSource("module1/pom.xml", module1Pom) + .build(); + + RemoveRedundantMavenCompilerPluginProperties sut = new RemoveRedundantMavenCompilerPluginProperties(); + sut.apply(projectContext); + + Module rootModule = projectContext.getApplicationModules().getRootModule(); + assertThat(rootModule.getBuildFile().getProperty("maven.compiler.source")).isNull(); + assertThat(rootModule.getBuildFile().getProperty("maven.compiler.target")).isNull(); + assertThat(rootModule.getBuildFile().getProperty("java.version")).isEqualTo("17"); + assertThat( + rootModule.getBuildFile().getPlugins().get(0).getConfiguration().getDeclaredStringValue("source").get()) + .isEqualTo("${java.version}"); + assertThat( + rootModule.getBuildFile().getPlugins().get(0).getConfiguration().getDeclaredStringValue("target").get()) + .isEqualTo("${java.version}"); + + Module childModule = projectContext.getApplicationModules().getModule("module1"); + assertThat(childModule.getBuildFile().getProperty("java.version")).isEqualTo("17"); + assertThat(childModule.getBuildFile().getProperty("maven.compiler.source")).isNull(); + assertThat(childModule.getBuildFile().getProperty("maven.compiler.target")).isNull(); + } + + @Test + @Disabled("Need to implement multi module pom updates") + void multiModuleWithPluginAndPropertiesDefinedInChildModule() { + + OpenRewriteMavenPlugin mavenPlugin = OpenRewriteMavenPlugin.builder() + .groupId("org.apache.maven.plugins") + .artifactId("maven-compiler-plugin") + .build(); + Map configMap = new LinkedHashMap<>(); + configMap.put("source", "${maven.compiler.source}"); + configMap.put("target", "${maven.compiler.target}"); + mavenPlugin.setConfiguration(mavenPlugin.new OpenRewriteMavenPluginConfiguration(configMap)); + + String rootPom = PomBuilder.buildPom("com.example:parent:1.0").packaging("pom") + .withModules("module1") + .build(); + + String module1Pom = PomBuilder.buildPom("com.example:parent:1.0", "module1").packaging("jar") + .property("maven.compiler.source", "17").property("maven.compiler.target", "17") + .plugins(mavenPlugin).build(); + + ProjectContext projectContext = TestProjectContext.buildProjectContext() + .withMavenBuildFileSource("pom.xml", rootPom).withMavenBuildFileSource("module1/pom.xml", module1Pom) + .build(); + + RemoveRedundantMavenCompilerPluginProperties sut = new RemoveRedundantMavenCompilerPluginProperties(); + sut.apply(projectContext); + + Module rootModule = projectContext.getApplicationModules().getRootModule(); + assertThat(rootModule.getBuildFile().print()).isEqualTo(rootPom); + + + Module childModule = projectContext.getApplicationModules().getModule("module1"); + assertThat(childModule.getBuildFile().getProperty("source")).isNull(); + assertThat(childModule.getBuildFile().getProperty("target")).isNull(); + assertThat(childModule.getBuildFile().getProperty("java.version")).isEqualTo("17"); + assertThat( + childModule.getBuildFile().getPlugins().get(0).getConfiguration().getDeclaredStringValue("source").get()) + .isEqualTo("${java.version}"); + assertThat( + childModule.getBuildFile().getPlugins().get(0).getConfiguration().getDeclaredStringValue("target").get()) + .isEqualTo("${java.version}"); + + } + + @Test + void multiModuleWithPluginDefinedInChildAndPropertiesInParentModule() { + + } + + @Test + void multiModulePluginDefinedInParentModuleAndDifferentPropertiesInChildModule() { + + } + +} \ No newline at end of file diff --git a/components/sbm-support-boot/src/test/java/org/springframework/sbm/boot/cleanup/actions/RemoveRedundantMavenCompilerPluginTest.java b/components/sbm-support-boot/src/test/java/org/springframework/sbm/boot/cleanup/actions/RemoveRedundantMavenCompilerPluginTest.java new file mode 100644 index 000000000..415396304 --- /dev/null +++ b/components/sbm-support-boot/src/test/java/org/springframework/sbm/boot/cleanup/actions/RemoveRedundantMavenCompilerPluginTest.java @@ -0,0 +1,321 @@ +/* + * Copyright 2021 - 2022 the original author or authors. + * + * 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 + * + * https://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 org.springframework.sbm.boot.cleanup.actions; + +import org.junit.jupiter.api.Test; + +import org.springframework.sbm.build.migration.actions.OpenRewriteMavenBuildFileTestSupport; + +class RemoveRedundantMavenCompilerPluginTest { + + @Test + void standardConfigWithSourceAndTarget() { + + String pomXml = """ + + + 4.0.0 + org.springframework.boot + spring-boot-starter-parent + 2.7.3 + clean-maven-properties + Remove Redundant configuration + + + + org.apache.maven.plugins + maven-compiler-plugin + + ${maven.compiler.source} + ${maven.compiler.target} + + + + + + """; + String expected = """ + + + 4.0.0 + org.springframework.boot + spring-boot-starter-parent + 2.7.3 + clean-maven-properties + Remove Redundant configuration + + """; + + RemoveRedundantMavenCompilerPlugin sut = new RemoveRedundantMavenCompilerPlugin(); + OpenRewriteMavenBuildFileTestSupport.verifyRefactoring(pomXml, expected, sut); + } + + @Test + void additionalConfig() { + String pomXml = """ + + + 4.0.0 + org.springframework.boot + spring-boot-starter-parent + 2.7.3 + clean-maven-properties + Remove Redundant configuration + + + + org.apache.maven.plugins + maven-compiler-plugin + + ${maven.compiler.source} + ${maven.compiler.target} + false + true + true + + + + + + """; + String expected = """ + + + 4.0.0 + org.springframework.boot + spring-boot-starter-parent + 2.7.3 + clean-maven-properties + Remove Redundant configuration + + + + org.apache.maven.plugins + maven-compiler-plugin + + ${maven.compiler.source} + ${maven.compiler.target} + false + true + true + + + + + + """; + + RemoveRedundantMavenCompilerPlugin sut = new RemoveRedundantMavenCompilerPlugin(); + OpenRewriteMavenBuildFileTestSupport.verifyRefactoring(pomXml, expected, sut); + } + + @Test + void emptyConfiguration() { + + String pomXml = """ + + + 4.0.0 + org.springframework.boot + spring-boot-starter-parent + 2.7.3 + clean-maven-properties + Remove Redundant configuration + + + + org.apache.maven.plugins + maven-compiler-plugin + + + + + + """; + String expected = """ + + + 4.0.0 + org.springframework.boot + spring-boot-starter-parent + 2.7.3 + clean-maven-properties + Remove Redundant configuration + + """; + + RemoveRedundantMavenCompilerPlugin sut = new RemoveRedundantMavenCompilerPlugin(); + OpenRewriteMavenBuildFileTestSupport.verifyRefactoring(pomXml, expected, sut); + } + +// @Test +// void multiModuleWithPluginDefinedInParentTest() { +// OpenRewriteMavenPlugin plugin = OpenRewriteMavenPlugin.builder() +// .groupId("org.apache.maven.plugins") +// .artifactId("maven-compiler-plugin") +// .build(); +// plugin.addConfiguration("source","17"); +// plugin.addConfiguration("target","17"); +// +// String rootPom = PomBuilder +// .buildPom("com.example:parent:1.0") +// .packaging("pom") +// .withModules("module1") +// .plugins(plugin) +// .build(); +// +// +// String module1Pom = PomBuilder +// .buildPom("com.example:parent:1.0", "module1") +// .build(); +// +// String expectedParentPom = """ +// +// +// 4.0.0 +// com.example +// parent +// 1.0 +// pom +// +// module1 +// +// """; +// +// ProjectContext projectContext = TestProjectContext.buildProjectContext().withMavenRootBuildFileSource(rootPom) +// .withMavenBuildFileSource("module1", module1Pom).build(); +// +// RemoveRedundantMavenCompilerPlugin sut = new RemoveRedundantMavenCompilerPlugin(); +// sut.apply(projectContext); +// +// Module parentModule = projectContext.getApplicationModules().getRootModule(); +// assertThat(expectedParentPom).isEqualTo(parentModule.getBuildFile().print()); +// System.out.println(parentModule.getBuildFile().getPlugins().size()); +// +// } +// +// @Test +// void multiModuleWithPluginDefinedInChildTest() { +// +// String rootPom = PomBuilder +// .buildPom("com.example:parent:1.0") +// .packaging("pom") +// .withModules("module1") +// .build(); +// +// OpenRewriteMavenPlugin plugin = OpenRewriteMavenPlugin.builder() +// .groupId("org.apache.maven.plugins") +// .artifactId("maven-compiler-plugin") +// .build(); +// plugin.addConfiguration("source","17"); +// plugin.addConfiguration("target","17"); +// +// +// String module1Pom = PomBuilder +// .buildPom("com.example:parent:1.0", "module1") +// .plugins(plugin) +// .build(); +// +// String expectedChildPom = """ +// +// +// 4.0.0 +// +// com.example +// parent +// 1.0 +// +// module1 +// """; +// +// ProjectContext projectContext = TestProjectContext.buildProjectContext().withMavenRootBuildFileSource(rootPom) +// .withMavenBuildFileSource("module1", module1Pom).build(); +// +// RemoveRedundantMavenCompilerPlugin sut = new RemoveRedundantMavenCompilerPlugin(); +// sut.apply(projectContext); +// +// Module childModule = projectContext.getApplicationModules().getModule("module1"); +// assertThat(expectedChildPom).isEqualTo(childModule.getBuildFile().print()); +// } +// +// @Test +// void multiModuleWithPluginDefinedInParentAndChildTest() { +// +// OpenRewriteMavenPlugin plugin = OpenRewriteMavenPlugin.builder() +// .groupId("org.apache.maven.plugins") +// .artifactId("maven-compiler-plugin") +// .build(); +// plugin.addConfiguration("source","${maven.compiler.source}"); +// plugin.addConfiguration("target","${maven.compiler.target}"); +// +// String rootPom = PomBuilder +// .buildPom("com.example:parent:1.0") +// .packaging("pom") +// .withModules("module1") +// .plugins(plugin) +// .build(); +// +// +// String module1Pom = PomBuilder +// .buildPom("com.example:parent:1.0", "module1") +// .plugins(plugin) +// .build(); +// +// String expectedParentPom = """ +// +// +// 4.0.0 +// com.example +// parent +// 1.0 +// pom +// +// module1 +// +// """; +// +// String expectedChildPom = """ +// +// +// 4.0.0 +// +// com.example +// parent +// 1.0 +// +// module1 +// """; +// +// ProjectContext projectContext = TestProjectContext.buildProjectContext().withMavenRootBuildFileSource(rootPom) +// .withMavenBuildFileSource("module1", module1Pom).build(); +// +// RemoveRedundantMavenCompilerPlugin sut = new RemoveRedundantMavenCompilerPlugin(); +// sut.apply(projectContext); +// +// Module rootModule = projectContext.getApplicationModules().getRootModule(); +// Module childModule = projectContext.getApplicationModules().getModule("module1"); +// assertThat(rootModule.getBuildFile().print()).isEqualTo(expectedParentPom); +// assertThat(childModule.getBuildFile().print()).isEqualTo(expectedChildPom); +// +// } + +} \ No newline at end of file diff --git a/components/sbm-support-boot/src/test/java/org/springframework/sbm/boot/cleanup/conditions/SpringBootMavenCompilerExistsTest.java b/components/sbm-support-boot/src/test/java/org/springframework/sbm/boot/cleanup/conditions/SpringBootMavenCompilerExistsTest.java new file mode 100644 index 000000000..70ea1a0d8 --- /dev/null +++ b/components/sbm-support-boot/src/test/java/org/springframework/sbm/boot/cleanup/conditions/SpringBootMavenCompilerExistsTest.java @@ -0,0 +1,137 @@ +/* + * Copyright 2021 - 2022 the original author or authors. + * + * 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 + * + * https://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 org.springframework.sbm.boot.cleanup.conditions; + +import java.util.stream.Stream; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import org.springframework.sbm.engine.context.ProjectContext; +import org.springframework.sbm.project.resource.TestProjectContext; + +import static org.assertj.core.api.Assertions.assertThat; + +public class SpringBootMavenCompilerExistsTest { + + @MethodSource("input") + @ParameterizedTest() + public void springBootDependencyAndMavenCompilerPluginExists(String pomXml, boolean expectedResult) { + + SpringBootMavenCompilerExists target = new SpringBootMavenCompilerExists(); + + ProjectContext context = TestProjectContext.buildProjectContext().withMavenRootBuildFileSource(pomXml).build(); + boolean result = target.evaluate(context); + + assertThat(result).isEqualTo(expectedResult); + } + + private static Stream input() { + return Stream.of( + Arguments.of( + """ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.3.9.RELEASE + + + com.example + demo + 0.0.1-SNAPSHOT + + + + org.springframework.boot + spring-boot-dependencies + 2.7.4 + pom + import + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + ${maven.compiler.source} + ${maven.compiler.target} + + + + + + """, + true), + Arguments.of( + """ + + + 4.0.0 + com.example + demo + 0.0.1-SNAPSHOT + + + + org.apache.maven.plugins + maven-compiler-plugin + + ${maven.compiler.source} + ${maven.compiler.target} + + + + + + + """, + false), + Arguments.of( + """ + + + 4.0.0 + com.example + demo + 0.0.1-SNAPSHOT + + + + org.springframework.boot + spring-boot-dependencies + 2.7.4 + pom + import + + + + + + """, + false)); + } + +} diff --git a/components/sbm-support-boot/src/test/java/org/springframework/sbm/boot/cleanup/recipes/RemoveRedundantMavenCompilerPluginRecipeIntegrationTest.java b/components/sbm-support-boot/src/test/java/org/springframework/sbm/boot/cleanup/recipes/RemoveRedundantMavenCompilerPluginRecipeIntegrationTest.java new file mode 100644 index 000000000..e21cff195 --- /dev/null +++ b/components/sbm-support-boot/src/test/java/org/springframework/sbm/boot/cleanup/recipes/RemoveRedundantMavenCompilerPluginRecipeIntegrationTest.java @@ -0,0 +1,31 @@ +/* + * Copyright 2021 - 2022 the original author or authors. + * + * 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 + * + * https://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 org.springframework.sbm.boot.cleanup.recipes; + +import org.junit.jupiter.api.Test; + +import org.springframework.sbm.test.RecipeIntegrationTestSupport; + +public class RemoveRedundantMavenCompilerPluginRecipeIntegrationTest { + + + @Test + void removeRedundantMavenCompilerPlugin() { + String applicationDir = "simple-boot"; + RecipeIntegrationTestSupport.initializeProject(applicationDir) + .andApplyRecipeComparingWithExpected("remove-redundant-maven-compiler-plugin"); + } +} diff --git a/components/sbm-support-boot/src/test/java/org/springframework/sbm/boot/cleanup/recipes/RemoveRedundantMavenCompilerPluginRecipeTest.java b/components/sbm-support-boot/src/test/java/org/springframework/sbm/boot/cleanup/recipes/RemoveRedundantMavenCompilerPluginRecipeTest.java new file mode 100644 index 000000000..18b33afd2 --- /dev/null +++ b/components/sbm-support-boot/src/test/java/org/springframework/sbm/boot/cleanup/recipes/RemoveRedundantMavenCompilerPluginRecipeTest.java @@ -0,0 +1,43 @@ +/* + * Copyright 2021 - 2022 the original author or authors. + * + * 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 + * + * https://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 org.springframework.sbm.boot.cleanup.recipes; + +import java.nio.file.Path; +import java.util.Optional; + +import org.junit.jupiter.api.Test; + +import org.springframework.sbm.boot.cleanup.actions.RemoveRedundantMavenCompilerPlugin; +import org.springframework.sbm.boot.cleanup.actions.RemoveRedundantMavenCompilerPluginProperties; +import org.springframework.sbm.engine.recipe.Recipe; +import org.springframework.sbm.test.RecipeTestSupport; + +import static org.springframework.sbm.test.RecipeTestSupport.testRecipe; + +public class RemoveRedundantMavenCompilerPluginRecipeTest { + + @Test + void initializeSpringBootMigrationRecipe() { + testRecipe(Path.of("recipes/remove-redundant-maven-compiler-plugin.yaml"), recipes -> { + + Optional recipe = recipes.getRecipeByName("remove-redundant-maven-compiler-plugin"); + + RecipeTestSupport.assertThatRecipeHasActions(recipe, RemoveRedundantMavenCompilerPluginProperties.class, + RemoveRedundantMavenCompilerPlugin.class); + }, freemarker.template.Configuration.class); + } + +} diff --git a/components/sbm-support-boot/testcode/simple-boot/expected/pom.xml b/components/sbm-support-boot/testcode/simple-boot/expected/pom.xml new file mode 100644 index 000000000..ed3b76edf --- /dev/null +++ b/components/sbm-support-boot/testcode/simple-boot/expected/pom.xml @@ -0,0 +1,41 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.7.5 + + + com.example + simple-boot + 0.0.1-SNAPSHOT + simple-boot + Demo project for Spring Boot + + 17 + + + + org.springframework.boot + spring-boot-starter + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/components/sbm-support-boot/testcode/simple-boot/expected/src/main/java/com/example/simple/boot/SimpleBootApplication.java b/components/sbm-support-boot/testcode/simple-boot/expected/src/main/java/com/example/simple/boot/SimpleBootApplication.java new file mode 100644 index 000000000..c996c13b5 --- /dev/null +++ b/components/sbm-support-boot/testcode/simple-boot/expected/src/main/java/com/example/simple/boot/SimpleBootApplication.java @@ -0,0 +1,13 @@ +package com.example.simple.boot; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SimpleBootApplication { + + public static void main(String[] args) { + SpringApplication.run(SimpleBootApplication.class, args); + } + +} diff --git a/components/sbm-support-boot/testcode/simple-boot/expected/src/main/resources/application.properties b/components/sbm-support-boot/testcode/simple-boot/expected/src/main/resources/application.properties new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/components/sbm-support-boot/testcode/simple-boot/expected/src/main/resources/application.properties @@ -0,0 +1 @@ + diff --git a/components/sbm-support-boot/testcode/simple-boot/expected/src/test/java/com/example/simple/boot/SimpleBootApplicationTests.java b/components/sbm-support-boot/testcode/simple-boot/expected/src/test/java/com/example/simple/boot/SimpleBootApplicationTests.java new file mode 100644 index 000000000..7b88777ed --- /dev/null +++ b/components/sbm-support-boot/testcode/simple-boot/expected/src/test/java/com/example/simple/boot/SimpleBootApplicationTests.java @@ -0,0 +1,13 @@ +package com.example.simple.boot; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class SimpleBootApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/components/sbm-support-boot/testcode/simple-boot/given/pom.xml b/components/sbm-support-boot/testcode/simple-boot/given/pom.xml new file mode 100644 index 000000000..a69144502 --- /dev/null +++ b/components/sbm-support-boot/testcode/simple-boot/given/pom.xml @@ -0,0 +1,50 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.7.5 + + + com.example + simple-boot + 0.0.1-SNAPSHOT + simple-boot + Demo project for Spring Boot + + 17 + 17 + + + + org.springframework.boot + spring-boot-starter + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + org.apache.maven.plugins + maven-compiler-plugin + + ${maven.compiler.source} + ${maven.compiler.target} + + + + + + diff --git a/components/sbm-support-boot/testcode/simple-boot/given/src/main/java/com/example/simple/boot/SimpleBootApplication.java b/components/sbm-support-boot/testcode/simple-boot/given/src/main/java/com/example/simple/boot/SimpleBootApplication.java new file mode 100644 index 000000000..c996c13b5 --- /dev/null +++ b/components/sbm-support-boot/testcode/simple-boot/given/src/main/java/com/example/simple/boot/SimpleBootApplication.java @@ -0,0 +1,13 @@ +package com.example.simple.boot; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SimpleBootApplication { + + public static void main(String[] args) { + SpringApplication.run(SimpleBootApplication.class, args); + } + +} diff --git a/components/sbm-support-boot/testcode/simple-boot/given/src/main/resources/application.properties b/components/sbm-support-boot/testcode/simple-boot/given/src/main/resources/application.properties new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/components/sbm-support-boot/testcode/simple-boot/given/src/main/resources/application.properties @@ -0,0 +1 @@ + diff --git a/components/sbm-support-boot/testcode/simple-boot/given/src/test/java/com/example/simple/boot/SimpleBootApplicationTests.java b/components/sbm-support-boot/testcode/simple-boot/given/src/test/java/com/example/simple/boot/SimpleBootApplicationTests.java new file mode 100644 index 000000000..7b88777ed --- /dev/null +++ b/components/sbm-support-boot/testcode/simple-boot/given/src/test/java/com/example/simple/boot/SimpleBootApplicationTests.java @@ -0,0 +1,13 @@ +package com.example.simple.boot; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class SimpleBootApplicationTests { + + @Test + void contextLoads() { + } + +}