diff --git a/.github/workflows/build-sbm-revamp.yml b/.github/workflows/build-sbm-revamp.yml index 4049b2640..30599208f 100644 --- a/.github/workflows/build-sbm-revamp.yml +++ b/.github/workflows/build-sbm-revamp.yml @@ -53,10 +53,10 @@ jobs: run: mvn -DskipTests --batch-mode install --projects :sbm-support-weblogic - name: sbm-recipes-jee-to-boot (build) - run: mvn -DskipTests --batch-mode --projects :sbm-recipes-jee-to-boot + run: mvn -DskipTests --batch-mode install --projects :sbm-recipes-jee-to-boot - name: sbm-recipes-spring-cloud (build) - run: mvn -DskipTests --batch-mode --projects :sbm-recipes-spring-cloud + run: mvn -DskipTests --batch-mode install --projects :sbm-recipes-spring-cloud - name: sbm-recipes-boot-upgrade (build) - run: mvn -DskipTests --batch-mode --projects :sbm-recipes-boot-upgrade \ No newline at end of file + run: mvn -DskipTests --batch-mode install --projects :sbm-recipes-boot-upgrade \ No newline at end of file diff --git a/components/recipe-test-support/pom.xml b/components/recipe-test-support/pom.xml index c425cafca..e3f6d31d7 100644 --- a/components/recipe-test-support/pom.xml +++ b/components/recipe-test-support/pom.xml @@ -66,6 +66,11 @@ test-jar compile + + commons-io + commons-io + 2.13.0 + \ No newline at end of file diff --git a/components/recipe-test-support/src/main/java/org/springframework/sbm/test/ProjectContextFileSystemTestSupport.java b/components/recipe-test-support/src/main/java/org/springframework/sbm/test/ProjectContextFileSystemTestSupport.java index 35512fad3..3094c2a29 100644 --- a/components/recipe-test-support/src/main/java/org/springframework/sbm/test/ProjectContextFileSystemTestSupport.java +++ b/components/recipe-test-support/src/main/java/org/springframework/sbm/test/ProjectContextFileSystemTestSupport.java @@ -21,7 +21,6 @@ import org.springframework.core.io.Resource; import org.springframework.sbm.engine.commands.ScanCommand; import org.springframework.sbm.engine.context.ProjectContext; -import org.springframework.sbm.parsers.RewriteExecutionContext; import org.springframework.sbm.project.parser.ProjectContextInitializer; import java.io.IOException; diff --git a/components/recipe-test-support/src/main/java/org/springframework/sbm/test/RecipeIntegrationTestSupport.java b/components/recipe-test-support/src/main/java/org/springframework/sbm/test/RecipeIntegrationTestSupport.java index 3b868ecba..fa73e5452 100644 --- a/components/recipe-test-support/src/main/java/org/springframework/sbm/test/RecipeIntegrationTestSupport.java +++ b/components/recipe-test-support/src/main/java/org/springframework/sbm/test/RecipeIntegrationTestSupport.java @@ -15,6 +15,7 @@ */ package org.springframework.sbm.test; +import org.apache.commons.io.FileUtils; import org.springframework.sbm.engine.commands.ApplicableRecipeListCommand; import org.springframework.sbm.engine.commands.ApplyCommand; import org.springframework.sbm.engine.commands.ScanCommand; @@ -26,7 +27,6 @@ import freemarker.template.Configuration; import lombok.AccessLevel; import lombok.Setter; -import org.apache.commons.io.FileUtils; import org.springframework.core.io.FileSystemResource; import org.springframework.core.io.Resource; diff --git a/components/sbm-core/pom.xml b/components/sbm-core/pom.xml index 574cb33e0..8127d0e55 100644 --- a/components/sbm-core/pom.xml +++ b/components/sbm-core/pom.xml @@ -173,7 +173,13 @@ tests test - + + commons-io + commons-io + 2.13.0 + test + + com.fasterxml.jackson.dataformat jackson-dataformat-xml 2.14.1 diff --git a/components/sbm-core/src/main/java/org/springframework/sbm/java/impl/DependencyChangeHandler.java b/components/sbm-core/src/main/java/org/springframework/sbm/java/impl/DependencyChangeHandler.java index 5c6dae61a..d676a9891 100644 --- a/components/sbm-core/src/main/java/org/springframework/sbm/java/impl/DependencyChangeHandler.java +++ b/components/sbm-core/src/main/java/org/springframework/sbm/java/impl/DependencyChangeHandler.java @@ -35,7 +35,6 @@ import org.springframework.sbm.engine.context.ProjectContextHolder; import org.springframework.sbm.java.api.JavaSource; import org.springframework.sbm.parsers.JavaParserBuilder; -import org.springframework.sbm.parsers.SortedProjects; import org.springframework.sbm.parsers.SourceFileParser; import org.springframework.sbm.utils.JavaHelper; import org.springframework.stereotype.Component; @@ -43,7 +42,6 @@ import java.io.ByteArrayInputStream; import java.nio.file.Path; import java.util.*; -import java.util.stream.Stream; /** * @author Fabian Krüger diff --git a/components/sbm-core/src/main/java/org/springframework/sbm/project/parser/MavenProjectParser.java b/components/sbm-core/src/main/java/org/springframework/sbm/project/parser/MavenProjectParser.java index 3b3e9378c..48ea62a2c 100644 --- a/components/sbm-core/src/main/java/org/springframework/sbm/project/parser/MavenProjectParser.java +++ b/components/sbm-core/src/main/java/org/springframework/sbm/project/parser/MavenProjectParser.java @@ -18,37 +18,18 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.openrewrite.ExecutionContext; -import org.openrewrite.Parser; import org.openrewrite.SourceFile; -import org.openrewrite.internal.ListUtils; -import org.openrewrite.internal.lang.Nullable; import org.openrewrite.java.JavaParser; -import org.openrewrite.java.marker.JavaSourceSet; -import org.openrewrite.java.tree.J; -import org.openrewrite.marker.GitProvenance; -import org.openrewrite.marker.Marker; -import org.openrewrite.marker.ci.BuildEnvironment; -import org.openrewrite.maven.MavenExecutionContextView; -import org.openrewrite.maven.MavenSettings; -import org.openrewrite.maven.tree.*; import org.openrewrite.maven.utilities.MavenArtifactDownloader; -import org.openrewrite.xml.tree.Xml; import org.springframework.context.ApplicationEventPublisher; import org.springframework.core.io.Resource; -import org.springframework.sbm.build.impl.MavenBuildFileUtil; import org.springframework.sbm.build.impl.RewriteMavenParser; -import org.springframework.sbm.engine.events.*; -import org.springframework.sbm.parsers.RewriteMavenProjectParser; import org.springframework.sbm.parsers.RewriteProjectParser; import org.springframework.sbm.scopes.ProjectMetadata; import org.springframework.stereotype.Component; -import java.io.IOException; -import java.io.InputStream; import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.*; -import java.util.stream.Collectors; +import java.util.List; /** * Parse a Maven project on disk into a list of {@link org.openrewrite.SourceFile} including diff --git a/components/sbm-core/src/test/java/org/springframework/sbm/java/impl/ProjectJavaSourcesImplTest.java b/components/sbm-core/src/test/java/org/springframework/sbm/java/impl/ProjectJavaSourcesImplTest.java index 1b09ba9dc..3b421dc5a 100644 --- a/components/sbm-core/src/test/java/org/springframework/sbm/java/impl/ProjectJavaSourcesImplTest.java +++ b/components/sbm-core/src/test/java/org/springframework/sbm/java/impl/ProjectJavaSourcesImplTest.java @@ -20,7 +20,6 @@ import org.springframework.beans.factory.UnsatisfiedDependencyException; import org.springframework.sbm.engine.context.ProjectContext; import org.springframework.sbm.java.api.JavaSourceAndType; -import org.springframework.sbm.parsers.MavenExecutionResultException; import org.springframework.sbm.project.resource.TestProjectContext; import java.util.List; diff --git a/components/sbm-core/src/test/java/org/springframework/sbm/project/resource/TestProjectContext.java b/components/sbm-core/src/test/java/org/springframework/sbm/project/resource/TestProjectContext.java index 81d0424a9..52b130190 100644 --- a/components/sbm-core/src/test/java/org/springframework/sbm/project/resource/TestProjectContext.java +++ b/components/sbm-core/src/test/java/org/springframework/sbm/project/resource/TestProjectContext.java @@ -16,7 +16,6 @@ package org.springframework.sbm.project.resource; import freemarker.template.Configuration; -import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.RandomStringUtils; import org.jetbrains.annotations.NotNull; import org.openrewrite.ExecutionContext; @@ -31,7 +30,6 @@ import org.springframework.sbm.build.impl.OpenRewriteMavenBuildFile; import org.springframework.sbm.engine.context.ProjectContext; import org.springframework.sbm.engine.context.ProjectContextSerializer; -import org.springframework.sbm.java.impl.RewriteJavaParser; import org.springframework.sbm.java.util.JavaSourceUtil; import org.springframework.sbm.project.TestDummyResource; import org.springframework.sbm.project.parser.DependencyHelper; @@ -190,7 +188,7 @@ private static Path createProjectRoot() { Path sbm = tempDirectory.resolve("sbm"); // FileUtils.cleanDirectory(sbm.toFile()); Path randDir = sbm.resolve(RandomStringUtils.randomAlphanumeric(5)); - FileUtils.forceMkdir(randDir.toFile()); + Files.createDirectories(randDir); return randDir; } catch (IOException e) { throw new RuntimeException(e); @@ -596,9 +594,12 @@ public ProjectContext build() { executionContext); */ - // Writing to filesystem and parsing again changes th eresource order + // Writing to filesystem and parsing again changes the resource order try { - FileUtils.cleanDirectory(projectRoot.toFile()); + Files.walk(projectRoot) + .sorted(Comparator.reverseOrder()) + .map(Path::toFile) + .forEach(File::delete); } catch (IOException e) { throw new RuntimeException(e); } diff --git a/components/sbm-openrewrite/pom.xml b/components/sbm-openrewrite/pom.xml index f99e326eb..f7107386b 100644 --- a/components/sbm-openrewrite/pom.xml +++ b/components/sbm-openrewrite/pom.xml @@ -37,6 +37,21 @@ sbm-support-rewrite 0.1.0-SNAPSHOT + + org.openrewrite + rewrite-java-17 + ${openrewrite.version} + + + org.rocksdb + rocksdbjni + 8.3.2 + + + javax.xml.bind + jaxb-api + 2.3.1 + org.projectlombok lombok diff --git a/components/sbm-recipes-jee-to-boot/pom.xml b/components/sbm-recipes-jee-to-boot/pom.xml index 2ce02fa4b..b892d94e9 100644 --- a/components/sbm-recipes-jee-to-boot/pom.xml +++ b/components/sbm-recipes-jee-to-boot/pom.xml @@ -44,6 +44,11 @@ sbm-support-jee 0.15.2-SNAPSHOT + + commons-io + commons-io + 2.13.0 + diff --git a/components/test-helper/pom.xml b/components/test-helper/pom.xml index a3da7b87b..53089f1d9 100644 --- a/components/test-helper/pom.xml +++ b/components/test-helper/pom.xml @@ -40,12 +40,6 @@ spring-core - - org.apache.maven.resolver - maven-resolver-spi - 1.9.15 - - org.jboss.shrinkwrap.resolver @@ -77,11 +71,17 @@ shrinkwrap-resolver-impl-maven-archive ${shrinkwrap.resolvers.version} + + + + + + + - org.jboss.shrinkwrap.resolver - shrinkwrap-resolver-bom - ${shrinkwrap.resolvers.version} - pom + org.apache.maven.resolver + maven-resolver-spi + 1.9.15 \ No newline at end of file diff --git a/pom.xml b/pom.xml index 72c1e5190..28f1cf545 100644 --- a/pom.xml +++ b/pom.xml @@ -64,26 +64,26 @@ - - org.apache.maven.wagon - wagon-http - 3.5.3 - - - org.apache.maven.resolver - maven-resolver-transport-http - 1.9.14 - - - org.apache.maven.resolver - maven-resolver-api - 1.9.14 - - - org.apache.maven.resolver - maven-resolver-impl - 1.9.14 - + + + + + + + + + + + + + + + + + + + + org.projectlombok @@ -131,11 +131,12 @@ - - org.apache.maven.shared - maven-invoker - ${maven-invoker.version} - + + + + + + org.openrewrite rewrite-core diff --git a/sbm-support-rewrite/pom.xml b/sbm-support-rewrite/pom.xml index c34d8072b..47d1535fb 100644 --- a/sbm-support-rewrite/pom.xml +++ b/sbm-support-rewrite/pom.xml @@ -142,60 +142,71 @@ ${rewrite.version} - org.openrewrite.maven - rewrite-maven-plugin - ${rewrite-maven-plugin.version} + org.openrewrite + rewrite-properties + ${rewrite.version} org.projectlombok lombok provided + + org.apache.maven + maven-model + 3.9.1 + + + + org.openrewrite.maven + rewrite-maven-plugin + ${rewrite-maven-plugin.version} + test + org.apache.maven.wagon wagon-http ${maven-wagon-http.version} + test org.apache.maven.resolver maven-resolver-transport-wagon ${maven-resolver.version} + test org.apache.maven.resolver maven-resolver-connector-basic ${maven-resolver.version} + test org.apache.maven.resolver maven-resolver-impl ${maven-resolver.version} + test org.apache.maven maven-resolver-provider ${maven.version} + test org.apache.maven maven-compat ${maven.version} + test - - org.apache.maven - maven-embedder - ${maven.version} - - - org.sonatype.plexus - plexus-cipher - - - + + + org.codehaus.plexus plexus-cipher ${plexus-cypher.version} + test org.apache.maven.shared @@ -207,6 +218,7 @@ javax.xml.bind jaxb-api ${jaxb-api.version} + test org.springframework.boot @@ -219,6 +231,31 @@ ${junit-pioneer.version} test + + + + + org.codehaus.plexus + plexus-sec-dispatcher + 2.0 + + + + org.apache.maven + maven-embedder + ${maven.version} + + + org.sonatype.plexus + plexus-cipher + + + + + commons-cli + commons-cli + 1.4 + @@ -377,37 +414,6 @@ limitations under the License. - - org.codehaus.mojo - flatten-maven-plugin - 1.4.1 - - - flatten - process-resources - - flatten - - - true - oss - - remove - remove - remove - remove - - - - - flatten-clean - clean - - clean - - - - org.apache.maven.plugins maven-release-plugin @@ -432,37 +438,6 @@ limitations under the License. - - org.codehaus.mojo - flatten-maven-plugin - 1.4.1 - - - flatten - process-resources - - flatten - - - true - oss - - remove - remove - remove - remove - - - - - flatten-clean - clean - - clean - - - - org.apache.maven.plugins maven-release-plugin @@ -474,37 +449,6 @@ limitations under the License. true - - org.codehaus.mojo - flatten-maven-plugin - 1.4.1 - - - flatten - process-resources - - flatten - - - true - oss - - remove - remove - remove - remove - - - - - flatten-clean - clean - - clean - - - - org.apache.maven.plugins maven-release-plugin diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/BuildFileParser.java b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/BuildFileParser.java index 0239cd850..cd11195b4 100644 --- a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/BuildFileParser.java +++ b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/BuildFileParser.java @@ -17,20 +17,14 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.apache.maven.execution.MavenSession; import org.openrewrite.ExecutionContext; import org.openrewrite.Parser; import org.openrewrite.SourceFile; import org.openrewrite.marker.Marker; -import org.openrewrite.maven.MavenExecutionContextView; -import org.openrewrite.maven.MavenMojoProjectParser; import org.openrewrite.maven.MavenParser; -import org.openrewrite.maven.cache.InMemoryMavenPomCache; -import org.openrewrite.maven.cache.MavenPomCache; import org.openrewrite.xml.tree.Xml; import org.springframework.core.io.Resource; import org.springframework.sbm.utils.ResourceUtil; -import org.springframework.stereotype.Component; import org.springframework.util.Assert; import java.nio.file.Path; diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/HelperWithoutAGoodName.java b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/HelperWithoutAGoodName.java new file mode 100644 index 000000000..d6503c22a --- /dev/null +++ b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/HelperWithoutAGoodName.java @@ -0,0 +1,233 @@ +/* + * Copyright 2021 - 2023 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.parsers; + +import lombok.extern.slf4j.Slf4j; +import org.jetbrains.annotations.NotNull; +import org.openrewrite.ExecutionContext; +import org.openrewrite.Parser; +import org.openrewrite.SourceFile; +import org.openrewrite.Tree; +import org.openrewrite.internal.lang.Nullable; +import org.openrewrite.java.JavaParser; +import org.openrewrite.java.internal.JavaTypeCache; +import org.openrewrite.java.marker.JavaSourceSet; +import org.openrewrite.marker.Generated; +import org.openrewrite.marker.Marker; +import org.openrewrite.marker.Markers; +import org.openrewrite.xml.tree.Xml; +import org.springframework.core.io.Resource; +import org.springframework.sbm.utils.ResourceUtil; + +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.*; +import java.util.function.Predicate; +import java.util.function.UnaryOperator; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * @author Fabian Krüger + */ +@Slf4j +public class HelperWithoutAGoodName { + /** + * {@link MavenMojoProjectParser#addProvenance(Path, List, Collection)} + */ + public UnaryOperator addProvenance(Path baseDir, List provenance, @Nullable Collection generatedSources) { +// MavenMojoProjectParser mavenMojoProjectParser = createMavenMojoProjectParser(baseDir); +// Method method = ReflectionUtils.findMethod(MavenMojoProjectParser.class, "addProvenance", Path.class, List.class, Collection.class); +// ReflectionUtils.makeAccessible(method); +// if(method == null) { +// throw new IllegalStateException("Could not find method '%s' on %s while trying to call it.".formatted("addProvenance", MavenMojoProjectParser.class.getName())); +// } +// Object result = ReflectionUtils.invokeMethod(method, mavenMojoProjectParser, baseDir, provenance, generatedSources); +// return (UnaryOperator) result; + return (s) -> { + Markers markers = s.getMarkers(); + + Marker marker; + for (Iterator var5 = provenance.iterator(); var5.hasNext(); markers = markers.addIfAbsent(marker)) { + marker = (Marker) var5.next(); + } + + if (generatedSources != null && generatedSources.contains(baseDir.resolve(s.getSourcePath()))) { + markers = markers.addIfAbsent(new Generated(Tree.randomId())); + } + + return (T) s.withMarkers(markers); + }; + } + + /** + * process sources in src/main/java of current module. + */ + public List processMainSources( + Path baseDir, + List resources, + Xml.Document moduleBuildFile, + JavaParser.Builder javaParserBuilder, + RewriteResourceParser rp, + List provenanceMarkers, + Set alreadyParsed, + ExecutionContext executionContext, + SbmMavenProject currentProject + ) { + log.info("Processing main sources in module '%s'".formatted(currentProject.getProjectId())); + // FIXME: 945 + // Some annotation processors output generated sources to the /target directory. These are added for parsing but + // should be filtered out of the final SourceFile list. + + List mainJavaSources = new ArrayList<>(); + List javaSourcesInTarget = currentProject.getJavaSourcesInTarget(); // listJavaSources(resources, currentProject.getBasedir().resolve(currentProject.getBuildDirectory())); + List javaSourcesInMain = currentProject.getMainJavaSources(); // listJavaSources(resources, currentProject.getBasedir().resolve(currentProject.getSourceDirectory())); + mainJavaSources.addAll(javaSourcesInTarget); + mainJavaSources.addAll(javaSourcesInMain); + + log.info("[%s] Parsing source files".formatted(currentProject)); + + // FIXME 945 classpath + // - Resolve dependencies to non-reactor projects from Maven repository + // - Resolve dependencies to reactor projects by providing the sources + // javaParserBuilder.classpath(byte[]) + + // we're processing a module here. The classpath of the module consists of all declared dependencies and their transitive dependencies too. + // For dependencies to projects that belong to the current rector... + // They'd either need to be built with Maven before to guarantee that the jars are installed to local Maven repo. + // Or, the classpath must be created from the sources of the project. + + + List dependencies = currentProject.getCompileClasspathElements(); + + javaParserBuilder.classpath(dependencies); + + JavaTypeCache typeCache = new JavaTypeCache(); + javaParserBuilder.typeCache(typeCache); + + Iterable inputs = mainJavaSources.stream() + .map(r -> new Parser.Input(ResourceUtil.getPath(r), () -> ResourceUtil.getInputStream(r))) + .toList(); + + Stream cus = Stream.of(javaParserBuilder) + .map(JavaParser.Builder::build) + .flatMap(parser -> parser.parseInputs(inputs, baseDir, executionContext)) + .peek(s -> alreadyParsed.add(baseDir.resolve(s.getSourcePath()))); + + List mainProjectProvenance = new ArrayList<>(provenanceMarkers); + mainProjectProvenance.add(sourceSet("main", dependencies, typeCache)); + + // FIXME: 945 Why target and not all main? + List parsedJavaPaths = mainJavaSources.stream().map(ResourceUtil::getPath).toList(); + Stream parsedJava = cus.map(addProvenance(baseDir, mainProjectProvenance, parsedJavaPaths)); + log.debug("[%s] Scanned %d java source files in main scope.".formatted(currentProject, mainJavaSources.size())); + + //Filter out any generated source files from the returned list, as we do not want to apply the recipe to the + //generated files. + Path buildDirectory = Paths.get(currentProject.getBuildDirectory()); + List sourceFiles = parsedJava + .filter(s -> !s.getSourcePath().startsWith(buildDirectory)) + .collect(Collectors.toCollection(ArrayList::new)); + + int sourcesParsedBefore = alreadyParsed.size(); + alreadyParsed.addAll(parsedJavaPaths); + List parsedResourceFiles = rp.parse(currentProject.getModulePath().resolve("src/main/resources"), resources, alreadyParsed) + .map(addProvenance(baseDir, mainProjectProvenance, null)) + .toList(); + + log.debug("[%s] Scanned %d resource files in main scope.".formatted(currentProject, (alreadyParsed.size() - sourcesParsedBefore))); + // Any resources parsed from "main/resources" should also have the main source set added to them. + sourceFiles.addAll(parsedResourceFiles); + return sourceFiles; + } + + @NotNull + private static JavaSourceSet sourceSet(String name, List dependencies, JavaTypeCache typeCache) { + return JavaSourceSet.build(name, dependencies, typeCache, false); + } + + + /** + * Calls {@link MavenMojoProjectParser#processTestSources(SbmMavenProject, JavaParser.Builder, ResourceParser, List, Set, ExecutionContext)} + */ + public List processTestSources( + Path baseDir, + Xml.Document moduleBuildFile, + JavaParser.Builder javaParserBuilder, + RewriteResourceParser rp, + List provenanceMarkers, + Set alreadyParsed, + ExecutionContext executionContext, + SbmMavenProject currentProject, + List resources + ) { + log.info("Processing test sources in module '%s'".formatted(currentProject.getProjectId())); + + List testDependencies = currentProject.getTestClasspathElements(); + + javaParserBuilder.classpath(testDependencies); + JavaTypeCache typeCache = new JavaTypeCache(); + javaParserBuilder.typeCache(typeCache); + + List testJavaSources = listJavaSources(resources, currentProject.getBasedir().resolve(currentProject.getTestSourceDirectory())); + alreadyParsed.addAll(testJavaSources.stream().map(ResourceUtil::getPath).toList()); + + Iterable inputs = testJavaSources.stream() + .map(r -> new Parser.Input(ResourceUtil.getPath(r), () -> ResourceUtil.getInputStream(r))) + .toList(); + + Stream cus = Stream.of(javaParserBuilder) + .map(JavaParser.Builder::build) + .flatMap(parser -> parser.parseInputs(inputs, baseDir, executionContext)); + + List markers = new ArrayList<>(provenanceMarkers); + markers.add(sourceSet("test", testDependencies, typeCache)); + + Stream parsedJava = cus.map(addProvenance(baseDir, markers, null)); + + log.debug("[%s] Scanned %d java source files in test scope.".formatted(currentProject, testJavaSources.size())); + Stream sourceFiles = parsedJava; + + // Any resources parsed from "test/resources" should also have the test source set added to them. + int sourcesParsedBefore = alreadyParsed.size(); + Stream parsedResourceFiles = rp.parse(currentProject.getBasedir().resolve("src/test/resources"), resources, alreadyParsed) + .map(addProvenance(baseDir, markers, null)); + log.debug("[%s] Scanned %d resource files in test scope.".formatted(currentProject, (alreadyParsed.size() - sourcesParsedBefore))); + sourceFiles = Stream.concat(sourceFiles, parsedResourceFiles); + List result = sourceFiles.toList(); + return result; + } + + + // FIXME: 945 take Java sources from resources + private static List listJavaSources(List resources, Path sourceDirectory) { + return resources.stream() + .filter(whenIn(sourceDirectory)) + .filter(whenFileNameEndsWithJava()) + .toList(); + } + + @NotNull + private static Predicate whenFileNameEndsWithJava() { + return p -> ResourceUtil.getPath(p).getFileName().toString().endsWith(".java"); + } + + @NotNull + private static Predicate whenIn(Path sourceDirectory) { + return r -> ResourceUtil.getPath(r).toString().startsWith(sourceDirectory.toString()); + } +} diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/MavenConfigFileParser.java b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/MavenConfigFileParser.java index 2d2137b73..74f54743c 100644 --- a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/MavenConfigFileParser.java +++ b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/MavenConfigFileParser.java @@ -18,7 +18,6 @@ import org.apache.commons.cli.*; import org.apache.maven.cli.CleanArgument; import org.jetbrains.annotations.NotNull; -import org.springframework.stereotype.Component; import java.io.File; import java.io.IOException; diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/MavenMojoProjectParserPrivateMethods.java b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/MavenMojoProjectParserPrivateMethods.java deleted file mode 100644 index 4fabc7610..000000000 --- a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/MavenMojoProjectParserPrivateMethods.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright 2021 - 2023 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.parsers; - -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.apache.maven.project.MavenProject; -import org.apache.maven.rtinfo.internal.DefaultRuntimeInformation; -import org.apache.maven.settings.crypto.DefaultSettingsDecrypter; -import org.jetbrains.annotations.NotNull; -import org.openrewrite.ExecutionContext; -import org.openrewrite.SourceFile; -import org.openrewrite.internal.lang.Nullable; -import org.openrewrite.java.JavaParser; -import org.openrewrite.marker.Marker; -import org.openrewrite.maven.MavenMojoProjectParser; -import org.openrewrite.maven.ResourceParser; -import org.openrewrite.maven.tree.ResolvedDependency; -import org.openrewrite.maven.utilities.MavenArtifactDownloader; -import org.openrewrite.xml.tree.Xml; -import org.sonatype.plexus.components.cipher.DefaultPlexusCipher; -import org.sonatype.plexus.components.cipher.PlexusCipherException; -import org.sonatype.plexus.components.sec.dispatcher.DefaultSecDispatcher; -import org.springframework.util.ReflectionUtils; - -import java.lang.reflect.Method; -import java.nio.file.Path; -import java.util.Collection; -import java.util.List; -import java.util.Objects; -import java.util.Set; -import java.util.function.UnaryOperator; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -/** - * @author Fabian Krüger - */ -@Slf4j -@RequiredArgsConstructor -class MavenMojoProjectParserPrivateMethods { - - private final MavenMojoProjectParserFactory mavenMojoProjectParserFactory; - private final MavenArtifactDownloader artifactDownloader; - - /** - * Calls {@link MavenMojoProjectParser#processMainSources(MavenProject, JavaParser.Builder, ResourceParser, List, Set, ExecutionContext)} - */ - public List processMainSources(Path baseDir, Xml.Document moduleBuildFile, JavaParser.Builder javaParserBuilder, ResourceParser rp, List provenanceMarkers, Set alreadyParsed, ExecutionContext executionContext, MavenProject mavenProject) { - return invokeProcessMethod(baseDir, mavenProject, moduleBuildFile, javaParserBuilder, rp, provenanceMarkers, alreadyParsed, executionContext, "processMainSources"); - } - - /** - * Calls {@link MavenMojoProjectParser#processTestSources(MavenProject, JavaParser.Builder, ResourceParser, List, Set, ExecutionContext)} - */ - public List processTestSources(Path baseDir, Xml.Document moduleBuildFile, JavaParser.Builder javaParserBuilder, ResourceParser rp, List provenanceMarkers, Set alreadyParsed, ExecutionContext executionContext, MavenProject mavenProject) { - return invokeProcessMethod(baseDir, mavenProject, moduleBuildFile, javaParserBuilder, rp, provenanceMarkers, alreadyParsed, executionContext, "processTestSources"); - } - - /** - * See {@link MavenMojoProjectParser#processMainSources(MavenProject, JavaParser.Builder, ResourceParser, List, Set, ExecutionContext)} - */ - @NotNull - private List invokeProcessMethod( - Path baseDir, - MavenProject mavenProject, Xml.Document moduleBuildFile, - JavaParser.Builder javaParserBuilder, - ResourceParser rp, - List provenanceMarkers, - Set alreadyParsed, - ExecutionContext executionContext, - String methodName - ) { - MavenMojoProjectParser mavenMojoProjectParser = createMavenMojoProjectParser(baseDir); - Method method = ReflectionUtils.findMethod( - MavenMojoProjectParser.class, - methodName, - MavenProject.class, - JavaParser.Builder.class, - ResourceParser.class, - List.class, - Set.class, - ExecutionContext.class); - ReflectionUtils.makeAccessible(method); - if (method == null) { - throw new IllegalStateException("Could not find method '%s' on %s while trying to call it.".formatted(methodName, MavenMojoProjectParser.class.getName())); - } - log.debug("Starting reflective call to %s.%s()".formatted(mavenMojoProjectParser.getClass().getName(), method.getName())); - Object result = ReflectionUtils.invokeMethod(method, mavenMojoProjectParser, - mavenProject, - javaParserBuilder, - rp, - provenanceMarkers, - alreadyParsed, - executionContext - ); - if (result instanceof Stream) { - List sourceFiles = ((Stream) result).toList(); - return sourceFiles; - } else { - throw new RuntimeException("Could not cast result returned from MavenMojoParser#methodName to Stream."); - } - } - - - /** - * {@link MavenMojoProjectParser#addProvenance(Path, List, Collection)} - */ - public UnaryOperator addProvenance(Path baseDir, List provenance, @Nullable Collection generatedSources) { - MavenMojoProjectParser mavenMojoProjectParser = createMavenMojoProjectParser(baseDir); - Method method = ReflectionUtils.findMethod(MavenMojoProjectParser.class, "addProvenance", Path.class, List.class, Collection.class); - ReflectionUtils.makeAccessible(method); - if(method == null) { - throw new IllegalStateException("Could not find method '%s' on %s while trying to call it.".formatted("addProvenance", MavenMojoProjectParser.class.getName())); - } - Object result = ReflectionUtils.invokeMethod(method, mavenMojoProjectParser, baseDir, provenance, generatedSources); - return (UnaryOperator) result; - } - - private MavenMojoProjectParser createMavenMojoProjectParser(Path baseDir) { - try { - return mavenMojoProjectParserFactory.create(baseDir, new DefaultRuntimeInformation(), new DefaultSettingsDecrypter(new DefaultSecDispatcher(new DefaultPlexusCipher()))); - } catch (PlexusCipherException e) { - throw new RuntimeException(e); - } - } - - private List downloadArtifacts(List dependencies) { - -// eventPublisher.publishEvent(new StartDownloadingDependenciesEvent(dependencies.size())); - - - List paths = dependencies - .stream() - .filter(d -> d.getRepository() != null) -// .peek(d -> eventPublisher.publishEvent(new StartDownloadingDependencyEvent(d.getRequested()))) -// .parallel() - .map(artifactDownloader::downloadArtifact) - .filter(Objects::nonNull) - .collect(Collectors.toList()); - -// eventPublisher.publishEvent(new FinishedDownloadingDependencies()); - - return paths; - } -} diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/MavenProjectAnalyzer.java b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/MavenProjectAnalyzer.java new file mode 100644 index 000000000..bf8da395a --- /dev/null +++ b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/MavenProjectAnalyzer.java @@ -0,0 +1,403 @@ +/* + * Copyright 2021 - 2023 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.parsers; + +import org.apache.maven.model.*; +import org.apache.maven.model.io.xpp3.MavenXpp3Reader; +import org.codehaus.plexus.util.xml.pull.XmlPullParserException; +import org.openrewrite.maven.utilities.MavenArtifactDownloader; +import org.springframework.core.io.Resource; +import org.springframework.sbm.utils.ResourceUtil; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.util.*; +import java.util.stream.Collectors; + + +/** + * Implements the ordering of Maven (reactor) build projects. + * See Reactor Sorting + * + * @author Fabian Krüger + */ +public class MavenProjectAnalyzer { + + private static final String POM_XML = "pom.xml"; + private static final MavenXpp3Reader XPP_3_READER = new MavenXpp3Reader(); + private final MavenArtifactDownloader rewriteMavenArtifactDownloader; + + public MavenProjectAnalyzer(MavenArtifactDownloader rewriteMavenArtifactDownloader) { + this.rewriteMavenArtifactDownloader = rewriteMavenArtifactDownloader; + } + + public List getSortedProjects(Path baseDir, List resources) { + + List allPomFiles = resources.stream().filter(r -> ResourceUtil.getPath(r).getFileName().toString().equals(POM_XML)).toList(); + + if (allPomFiles.isEmpty()) { + throw new IllegalArgumentException("The provided resources did not contain any 'pom.xml' file."); + } + + Resource rootPom = allPomFiles.stream().filter(r -> ResourceUtil.getPath(r).toString().equals(baseDir.resolve(POM_XML).normalize().toString())).findFirst().orElseThrow(() -> new IllegalArgumentException("The provided resources do not contain a root 'pom.xml' file.")); + Model rootPomModel = new Model(rootPom); + + if (isSingleModuleProject(rootPomModel)) { + return List.of(new SbmMavenProject(baseDir, rootPom, rootPomModel, rewriteMavenArtifactDownloader, resources)); + } + List reactorModels = new ArrayList<>(); + recursivelyFindReactorModules(baseDir, null, reactorModels, allPomFiles, rootPomModel); + List sortedModels = sortModels(reactorModels); + return map(baseDir, resources, sortedModels); + } + + private List map(Path baseDir, List resources, List sortedModels) { + List sbmMavenProjects = new ArrayList<>(); + sortedModels + .stream() + .filter(Objects::nonNull) + .forEach(m -> { + String projectDir = baseDir.resolve(m.getProjectDirectory().toString()).normalize().toString(); + List filteredResources = resources.stream().filter(r -> ResourceUtil.getPath(r).toString().startsWith(projectDir)).toList(); + sbmMavenProjects.add(new SbmMavenProject(baseDir, m.getResource(), m, rewriteMavenArtifactDownloader, filteredResources)); + }); + // set all non parent poms as collected projects for root parent pom + List collected = new ArrayList<>(sbmMavenProjects); + collected.remove(0); + sbmMavenProjects.get(0).setCollectedProjects(collected); + return sbmMavenProjects; + } + + private List recursivelyFindReactorModules(Path baseDir, String path, List reactorModels, List allPomFiles, Model pomModel) { + // TODO: verify given module is root pom + if(pomModel != null) { + reactorModels.add(pomModel); + } else { + throw new IllegalStateException("PomModel was null."); + } + + List moduleNames = pomModel.getModules(); + + moduleNames.stream() + .forEach(moduleName -> { + + String modulePathSegment = path == null ? moduleName : path + "/" + moduleName; + + allPomFiles.stream() + .filter(resource -> { + String modulePath = baseDir.resolve(modulePathSegment).resolve(POM_XML).toAbsolutePath().normalize().toString(); + String resourcePath = ResourceUtil.getPath(resource).toAbsolutePath().normalize().toString(); + return resourcePath.equals(modulePath); + }) + .map(Model::new) + .forEach(m -> recursivelyFindReactorModules(baseDir, modulePathSegment, reactorModels, allPomFiles, m).stream()); + }); + return reactorModels; + } + + public List sortModels(List reactorModels) { + List sortedModels = new ArrayList<>(); + Map gaToModelMap = reactorModels.stream() + .collect(Collectors.toMap( + m ->{ + return (m.getGroupId() == null ? (m.getParent() == null ? null : m.getParent().getGroupId()) : m.getGroupId()) + ":" + m.getArtifactId(); + } , + m -> m + )); + + Map> dependsOn = new HashMap<>(); + + for (Model m : reactorModels) { + addToDependants(m, dependsOn, null); + if (hasParent(m)) { + String parentGa = m.getParent().getGroupId() + ":" + m.getParent().getArtifactId(); + Model parentModel = gaToModelMap.get(parentGa); + addToDependants(m, dependsOn, parentModel); + } + for (Dependency d : m.getDependencies()) { + String dependencyGa = getGav(d); + if (gaToModelMap.containsKey(dependencyGa)) { + Model dependencyModel = gaToModelMap.get(dependencyGa); + addToDependants(m, dependsOn, dependencyModel); + } + } + if (m.getBuild() != null && m.getBuild().getPluginsAsMap() != null && !m.getBuild().getPluginsAsMap().isEmpty()) { + for (String pluginName : m.getBuild().getPluginsAsMap().keySet()) { + // TODO: find plugin dependencies + } + } + } + + ArrayList>> entries = new ArrayList<>(dependsOn.entrySet()); + + // sort entries by number of values + entries.stream() + .sorted((e1, e2) -> { + int compare = Integer.compare(e1.getValue().size(), e2.getValue().size()); + if(compare != 0) { + return compare; + } else { + // with same number of dependencies order by dependant + if(e1.getValue().contains(e2.getKey())) { + return 1; + } else if(e2.getValue().contains(e1.getKey())) { + return -1; + } else { + // default is order as given by reactorModels + return Integer.compare(reactorModels.indexOf(e1.getKey()), reactorModels.indexOf(e2.getKey())); + } + } + }) + .forEach(e -> sortedModels.add(e.getKey())); + return sortedModels; + } + + private void addToDependants(Model model, Map> dependsOn, Model dependantModel) { + if (!dependsOn.containsKey(model)) { + dependsOn.put(model, new ArrayList<>()); + } + if (dependantModel != null) { + dependsOn.get(model).add(dependantModel); + } + } + + private boolean hasParent(Model m) { + return m.getParent() != null; + } + + private String getGav(Dependency d) { + return d.getGroupId() + ":" + d.getArtifactId(); + } + + private static boolean isSingleModuleProject(Model rootPomModel) { + return !rootPomModel.getPackaging().equals("pom"); + } + + public ParserContext createParserContext(Path baseDir, List resources) { + List sortedProjectsList = getSortedProjects(baseDir, resources); + ParserContext parserContext = new ParserContext(resources, sortedProjectsList); + return parserContext; + } + + static class Model extends org.apache.maven.model.Model { + private final Resource resource; + private final org.apache.maven.model.Model delegate; + + public Model(Resource resource) { + this.resource = resource; + try { + this.delegate = XPP_3_READER.read(ResourceUtil.getInputStream(resource)); + this.delegate.setPomFile(resource.getFile()); + } catch (IOException e) { + throw new RuntimeException(e); + } catch (XmlPullParserException e) { + throw new RuntimeException(e); + } + } + + @Override + public String toString() { + return (delegate.getGroupId() == null ? delegate.getParent().getGroupId() : delegate.getGroupId()) + ":" + delegate.getArtifactId(); + } + + public Resource getResource() { + return resource; + } + + @Override + public String getArtifactId() { + return delegate.getArtifactId(); + } + + @Override + public Build getBuild() { + return delegate.getBuild(); + } + + @Override + public String getChildProjectUrlInheritAppendPath() { + return delegate.getChildProjectUrlInheritAppendPath(); + } + + @Override + public CiManagement getCiManagement() { + return delegate.getCiManagement(); + } + + @Override + public List getContributors() { + return delegate.getContributors(); + } + + @Override + public String getDescription() { + return delegate.getDescription(); + } + + @Override + public List getDevelopers() { + return delegate.getDevelopers(); + } + + @Override + public String getGroupId() { + return delegate.getGroupId(); + } + + @Override + public String getInceptionYear() { + return delegate.getInceptionYear(); + } + + @Override + public IssueManagement getIssueManagement() { + return delegate.getIssueManagement(); + } + + @Override + public List getLicenses() { + return delegate.getLicenses(); + } + + @Override + public List getMailingLists() { + return delegate.getMailingLists(); + } + + @Override + public String getModelEncoding() { + return delegate.getModelEncoding(); + } + + @Override + public String getModelVersion() { + return delegate.getModelVersion(); + } + + @Override + public String getName() { + return delegate.getName(); + } + + @Override + public Organization getOrganization() { + return delegate.getOrganization(); + } + + @Override + public String getPackaging() { + return delegate.getPackaging(); + } + + @Override + public Parent getParent() { + return delegate.getParent(); + } + + @Override + public Prerequisites getPrerequisites() { + return delegate.getPrerequisites(); + } + + @Override + public List getProfiles() { + return delegate.getProfiles(); + } + + @Override + public Scm getScm() { + return delegate.getScm(); + } + + @Override + public String getUrl() { + return delegate.getUrl(); + } + + @Override + public String getVersion() { + return delegate.getVersion(); + } + + @Override + public File getPomFile() { + return delegate.getPomFile(); + } + + @Override + public File getProjectDirectory() { + return delegate.getPomFile().toPath().getParent().toFile(); + } + + @Override + public String getId() { + return delegate.getId(); + } + + @Override + public List getDependencies() { + return delegate.getDependencies(); + } + + @Override + public DependencyManagement getDependencyManagement() { + return delegate.getDependencyManagement(); + } + + @Override + public DistributionManagement getDistributionManagement() { + return delegate.getDistributionManagement(); + } + + @Override + public InputLocation getLocation(Object key) { + return delegate.getLocation(key); + } + + @Override + public List getModules() { + return delegate.getModules(); + } + + @Override + public List getPluginRepositories() { + return delegate.getPluginRepositories(); + } + + @Override + public Properties getProperties() { + return delegate.getProperties(); + } + + @Override + public Reporting getReporting() { + return delegate.getReporting(); + } + + @Override + public Object getReports() { + return delegate.getReports(); + } + + @Override + public List getRepositories() { + return delegate.getRepositories(); + } + + + } +} diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/MavenProvenanceMarkerFactory.java b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/MavenProvenanceMarkerFactory.java new file mode 100644 index 000000000..13b20c9d0 --- /dev/null +++ b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/MavenProvenanceMarkerFactory.java @@ -0,0 +1,110 @@ +/* + * Copyright 2021 - 2023 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.parsers; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.maven.model.Plugin; +import org.codehaus.plexus.util.xml.Xpp3Dom; +import org.openrewrite.Tree; +import org.openrewrite.internal.StringUtils; +import org.openrewrite.internal.lang.Nullable; +import org.openrewrite.java.marker.JavaProject; +import org.openrewrite.java.marker.JavaVersion; +import org.openrewrite.marker.*; +import org.openrewrite.marker.ci.BuildEnvironment; + +import java.nio.file.Path; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; +import java.util.stream.Stream; + + +/** + * @author Fabian Krüger + */ +@Slf4j +@RequiredArgsConstructor +public class MavenProvenanceMarkerFactory { + + public List generateProvenance(Path baseDir, SbmMavenProject mavenProject) { + MavenRuntimeInformation runtime = mavenProject.getMavenRuntimeInformation(); + BuildTool buildTool = new BuildTool(Tree.randomId(), BuildTool.Type.Maven, runtime.getMavenVersion()); + + String javaRuntimeVersion = System.getProperty("java.specification.version"); + String javaVendor = System.getProperty("java.vm.vendor"); + String sourceCompatibility = null; + String targetCompatibility = null; + Plugin compilerPlugin = mavenProject.getPlugin("org.apache.maven.plugins:maven-compiler-plugin"); + if (compilerPlugin != null && compilerPlugin.getConfiguration() instanceof Xpp3Dom) { + Xpp3Dom dom = (Xpp3Dom)compilerPlugin.getConfiguration(); + Xpp3Dom release = dom.getChild("release"); + if (release != null && StringUtils.isNotEmpty(release.getValue()) && !release.getValue().contains("${")) { + sourceCompatibility = release.getValue(); + targetCompatibility = release.getValue(); + } else { + Xpp3Dom source = dom.getChild("source"); + if (source != null && StringUtils.isNotEmpty(source.getValue()) && !source.getValue().contains("${")) { + sourceCompatibility = source.getValue(); + } + + Xpp3Dom target = dom.getChild("target"); + if (target != null && StringUtils.isNotEmpty(target.getValue()) && !target.getValue().contains("${")) { + targetCompatibility = target.getValue(); + } + } + } + + if (sourceCompatibility == null || targetCompatibility == null) { + String propertiesReleaseCompatibility = (String)mavenProject.getProperties().get("maven.compiler.release"); + if (propertiesReleaseCompatibility != null) { + sourceCompatibility = propertiesReleaseCompatibility; + targetCompatibility = propertiesReleaseCompatibility; + } else { + String propertiesSourceCompatibility = (String)mavenProject.getProperties().get("maven.compiler.source"); + if (sourceCompatibility == null && propertiesSourceCompatibility != null) { + sourceCompatibility = propertiesSourceCompatibility; + } + + String propertiesTargetCompatibility = (String)mavenProject.getProperties().get("maven.compiler.target"); + if (targetCompatibility == null && propertiesTargetCompatibility != null) { + targetCompatibility = propertiesTargetCompatibility; + } + } + } + + if (sourceCompatibility == null) { + sourceCompatibility = javaRuntimeVersion; + } + + if (targetCompatibility == null) { + targetCompatibility = sourceCompatibility; + } + + BuildEnvironment buildEnvironment = BuildEnvironment.build(System::getenv); + return (List) Stream.of(buildEnvironment, this.gitProvenance(baseDir, buildEnvironment), OperatingSystemProvenance.current(), buildTool, new JavaVersion(Tree.randomId(), javaRuntimeVersion, javaVendor, sourceCompatibility, targetCompatibility), new JavaProject(Tree.randomId(), mavenProject.getName(), new JavaProject.Publication(mavenProject.getGroupId(), mavenProject.getArtifactId(), mavenProject.getVersion()))).filter(Objects::nonNull).collect(Collectors.toList()); + } + + private @Nullable GitProvenance gitProvenance(Path baseDir, @Nullable BuildEnvironment buildEnvironment) { + try { + return GitProvenance.fromProjectDirectory(baseDir, buildEnvironment); + } catch (Exception var4) { + log.debug("Unable to determine git provenance", var4); + return null; + } + } +} diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/MavenRuntimeInformation.java b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/MavenRuntimeInformation.java new file mode 100644 index 000000000..e53792103 --- /dev/null +++ b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/MavenRuntimeInformation.java @@ -0,0 +1,26 @@ +/* + * Copyright 2021 - 2023 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.parsers; + +/** + * @author Fabian Krüger + */ +public class MavenRuntimeInformation { + public String getMavenVersion() { + // FIXME: 945 implement this + return "3.9.1"; + } +} diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/ParserContext.java b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/ParserContext.java new file mode 100644 index 000000000..6fa977e03 --- /dev/null +++ b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/ParserContext.java @@ -0,0 +1,53 @@ +/* + * Copyright 2021 - 2023 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.parsers; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.springframework.core.io.Resource; +import org.springframework.sbm.utils.ResourceUtil; + +import java.util.List; + +/** + * @author Fabian Krüger + */ +@RequiredArgsConstructor +public class ParserContext { + + @Getter + private final List resources; + @Getter + private final List sortedProjects; + + public List getActiveProfiles() { + // FIXME: Add support for Maven profiles + return List.of("default"); + } + + public Resource getMatchingBuildFileResource(SbmMavenProject pom) { + return resources.stream() + .filter(r -> ResourceUtil.getPath(r).toString().equals(pom.getPomFilePath().toString())) + .findFirst() + .orElseThrow(() -> new IllegalStateException("Could not find a resource in the list of resources that matches the path of SbmMavenProject '%s'".formatted(pom.getPomFile().toString()))); + } + + public List getBuildFileResources() { + return sortedProjects.stream() + .map(p -> p.getPomFile()) + .toList(); + } +} diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/ParserProperties.java b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/ParserProperties.java index fe16054c2..97461a3d9 100644 --- a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/ParserProperties.java +++ b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/ParserProperties.java @@ -81,6 +81,6 @@ public class ParserProperties { /** * Comma-separated list of patterns used to create PathMatcher to exclude paths from being parsed. */ - private Set ignoredPathPatterns = new HashSet<>(); + private Set ignoredPathPatterns = Set.of("**/target/**", "target/**"); } diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/ProjectId.java b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/ProjectId.java new file mode 100644 index 000000000..7ecce0a2b --- /dev/null +++ b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/ProjectId.java @@ -0,0 +1,42 @@ +/* + * Copyright 2021 - 2023 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.parsers; + +import java.util.Objects; + +/** + * @author Fabian Krüger + */ +public record ProjectId(String groupId, String artifactId) { + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ProjectId projectId = (ProjectId) o; + return Objects.equals(groupId, projectId.groupId) && Objects.equals(artifactId, projectId.artifactId); + } + + @Override + public int hashCode() { + return Objects.hash(groupId, artifactId); + } + + @Override + public String toString() { + return groupId + ":" + artifactId; + } +} diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/ProvenanceMarkerFactory.java b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/ProvenanceMarkerFactory.java index 9820fac68..5fbaebaf6 100644 --- a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/ProvenanceMarkerFactory.java +++ b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/ProvenanceMarkerFactory.java @@ -16,15 +16,9 @@ package org.springframework.sbm.parsers; import lombok.RequiredArgsConstructor; -import org.apache.maven.project.MavenProject; -import org.apache.maven.rtinfo.RuntimeInformation; -import org.apache.maven.rtinfo.internal.DefaultRuntimeInformation; -import org.apache.maven.settings.crypto.SettingsDecrypter; import org.openrewrite.marker.Marker; -import org.openrewrite.maven.MavenMojoProjectParser; import org.springframework.core.io.Resource; import org.springframework.sbm.utils.ResourceUtil; -import org.springframework.stereotype.Component; import java.nio.file.Path; import java.util.*; @@ -35,25 +29,22 @@ @RequiredArgsConstructor class ProvenanceMarkerFactory { - private final MavenMojoProjectParserFactory mavenMojoProjectParserFactory; + private final MavenProvenanceMarkerFactory markerFactory; /** * Reuses {@link MavenMojoProjectParser#generateProvenance(MavenProject)} to create {@link Marker}s for pom files in - * provided {@code pomFileResources}. + * provided {@code parserContext}. * * @return the map of pom.xml {@link Resource}s and their {@link Marker}s. */ - public Map> generateProvenanceMarkers(Path baseDir, SortedProjects pomFileResources) { + public Map> generateProvenanceMarkers(Path baseDir, ParserContext parserContext) { - RuntimeInformation runtimeInformation = new DefaultRuntimeInformation(); - SettingsDecrypter settingsDecrypter = null; - - MavenMojoProjectParser helper = mavenMojoProjectParserFactory.create(baseDir, runtimeInformation, settingsDecrypter); Map> result = new HashMap<>(); - pomFileResources.getSortedProjects().forEach(mavenProject -> { - List markers = helper.generateProvenance(mavenProject); - Resource resource = pomFileResources.getMatchingBuildFileResource(mavenProject); + parserContext.getSortedProjects().forEach(mavenProject -> { + + List markers = markerFactory.generateProvenance(baseDir, mavenProject); + Resource resource = parserContext.getMatchingBuildFileResource(mavenProject); Path path = ResourceUtil.getPath(resource); result.put(path, markers); }); diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/RewriteParserConfiguration.java b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/RewriteParserConfiguration.java index b173406ed..82f8bf20f 100644 --- a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/RewriteParserConfiguration.java +++ b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/RewriteParserConfiguration.java @@ -29,7 +29,6 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Import; import org.springframework.sbm.boot.autoconfigure.ParserPropertiesPostProcessor; -import org.springframework.sbm.boot.autoconfigure.ScannerConfiguration; import org.springframework.sbm.parsers.events.RewriteParsingEventListenerAdapter; import org.springframework.sbm.scopes.ProjectMetadata; import org.springframework.sbm.scopes.ScanScope; @@ -56,34 +55,19 @@ public class RewriteParserConfiguration { @Autowired private ParserProperties parserProperties; - @Bean - MavenPlexusContainer plexusContainer() { - return new MavenPlexusContainer(); - } - - @Bean - MavenConfigFileParser configFileParser() { - return new MavenConfigFileParser(); - } - - @Bean - MavenExecutionRequestFactory requestFactory(MavenConfigFileParser configFileParser) { - return new MavenExecutionRequestFactory(configFileParser); - } +// @Bean +// ProvenanceMarkerFactory provenanceMarkerFactory(MavenMojoProjectParserFactory projectParserFactory) { +// return new ProvenanceMarkerFactory(projectParserFactory); +// } @Bean - MavenExecutor mavenExecutor(MavenExecutionRequestFactory requestFactory, MavenPlexusContainer plexusContainer) { - return new MavenExecutor(requestFactory, plexusContainer); + MavenProvenanceMarkerFactory mavenProvenanceMarkerFactory() { + return new MavenProvenanceMarkerFactory(); } @Bean - MavenMojoProjectParserFactory projectParserFactory() { - return new MavenMojoProjectParserFactory(parserProperties); - } - - @Bean - ProvenanceMarkerFactory provenanceMarkerFactory(MavenMojoProjectParserFactory projectParserFactory) { - return new ProvenanceMarkerFactory(projectParserFactory); + ProvenanceMarkerFactory provenanceMarkerFactory(MavenProvenanceMarkerFactory mavenPovenanceMarkerFactory) { + return new ProvenanceMarkerFactory(mavenPovenanceMarkerFactory); } @Bean @@ -97,10 +81,6 @@ BuildFileParser buildFileParser() { return new BuildFileParser(); } - @Bean - MavenModelReader modelReader() { - return new MavenModelReader(); - } @Bean @ConditionalOnMissingBean(MavenArtifactCache.class) @@ -121,13 +101,13 @@ RewriteMavenArtifactDownloader artifactDownloader(MavenArtifactCache mavenArtifa } @Bean - MavenMojoProjectParserPrivateMethods mavenMojoProjectParserPrivateMethods(MavenMojoProjectParserFactory parserFactory, MavenArtifactDownloader artifactDownloader) { - return new MavenMojoProjectParserPrivateMethods(parserFactory, artifactDownloader); + HelperWithoutAGoodName helperWithoutAGoodName() { + return new HelperWithoutAGoodName(); } @Bean - SourceFileParser sourceFileParser(MavenModelReader modelReader, MavenMojoProjectParserPrivateMethods mavenMojoProjectParserPrivateMethods, JavaParserBuilder javaParserBuilder) { - return new SourceFileParser(parserProperties, mavenMojoProjectParserPrivateMethods, javaParserBuilder); + SourceFileParser sourceFileParser(JavaParserBuilder javaParserBuilder, HelperWithoutAGoodName helperWithoutAGoodName) { + return new SourceFileParser(parserProperties, helperWithoutAGoodName); } @Bean @@ -141,21 +121,26 @@ ParsingEventListener parsingEventListener(ApplicationEventPublisher eventPublish return new RewriteParsingEventListenerAdapter(eventPublisher); } + // FIXME: 945 +// @Bean +// RewriteMavenProjectParser rewriteMavenProjectParser(MavenPlexusContainer plexusContainer, ParsingEventListener parsingListener, MavenExecutor mavenExecutor, MavenMojoProjectParserFactory projectParserFactory, ScanScope scanScope, ConfigurableListableBeanFactory beanFactory, ExecutionContext executionContext) { +// return new RewriteMavenProjectParser( +// plexusContainer, +// parsingListener, +// mavenExecutor, +// projectParserFactory, +// scanScope, +// beanFactory, +// executionContext); +// } + @Bean - RewriteMavenProjectParser rewriteMavenProjectParser(MavenPlexusContainer plexusContainer, ParsingEventListener parsingListener, MavenExecutor mavenExecutor, MavenMojoProjectParserFactory projectParserFactory, ScanScope scanScope, ConfigurableListableBeanFactory beanFactory, ExecutionContext executionContext) { - return new RewriteMavenProjectParser( - plexusContainer, - parsingListener, - mavenExecutor, - projectParserFactory, - scanScope, - beanFactory, - executionContext); + MavenProjectAnalyzer mavenProjectAnalyzer(MavenArtifactDownloader artifactDownloader) { + return new MavenProjectAnalyzer(artifactDownloader); } @Bean RewriteProjectParser rewriteProjectParser( - MavenExecutor mavenExecutor, ProvenanceMarkerFactory provenanceMarkerFactory, BuildFileParser buildFileParser, SourceFileParser sourceFileParser, @@ -166,9 +151,9 @@ RewriteProjectParser rewriteProjectParser( ScanScope scanScope, ConfigurableListableBeanFactory beanFactory, ProjectScanner projectScanner, - ExecutionContext executionContext) { + ExecutionContext executionContext, + MavenProjectAnalyzer mavenProjectAnalyzer) { return new RewriteProjectParser( - mavenExecutor, provenanceMarkerFactory, buildFileParser, sourceFileParser, @@ -179,7 +164,8 @@ RewriteProjectParser rewriteProjectParser( scanScope, beanFactory, projectScanner, - executionContext); + executionContext, + mavenProjectAnalyzer); } @Bean diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/RewriteProjectParser.java b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/RewriteProjectParser.java index 684e99d0c..1a4881906 100644 --- a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/RewriteProjectParser.java +++ b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/RewriteProjectParser.java @@ -17,18 +17,12 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.apache.maven.execution.MavenSession; -import org.apache.maven.plugin.MojoExecutionException; -import org.apache.maven.plugin.MojoFailureException; -import org.apache.maven.project.MavenProject; +import org.jetbrains.annotations.NotNull; import org.openrewrite.ExecutionContext; -import org.openrewrite.InMemoryExecutionContext; import org.openrewrite.SourceFile; import org.openrewrite.marker.Marker; -import org.openrewrite.maven.AbstractRewriteMojo; import org.openrewrite.maven.MavenExecutionContextView; -import org.openrewrite.maven.MavenMojoProjectParser; -import org.openrewrite.maven.tree.MavenRepository; +import org.openrewrite.maven.tree.*; import org.openrewrite.style.NamedStyles; import org.openrewrite.tree.ParsingEventListener; import org.openrewrite.tree.ParsingExecutionContextView; @@ -40,14 +34,13 @@ import org.springframework.sbm.parsers.events.StartedParsingProjectEvent; import org.springframework.sbm.scopes.ScanScope; import org.springframework.sbm.utils.ResourceUtil; -import org.springframework.stereotype.Component; import org.springframework.util.ReflectionUtils; import java.lang.reflect.Method; import java.nio.file.Path; import java.util.*; -import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; +import java.util.stream.Collectors; import java.util.stream.Stream; /** @@ -70,16 +63,13 @@ * } * * - * @see RewriteMavenProjectParser - * @see org.springframework.sbm.recipes.RewriteRecipeDiscovery - * * @author Fabian Krüger + * @see org.springframework.sbm.recipes.RewriteRecipeDiscovery */ @Slf4j @RequiredArgsConstructor public class RewriteProjectParser { - private final MavenExecutor mavenExecutor; private final ProvenanceMarkerFactory provenanceMarkerFactory; private final BuildFileParser buildFileParser; private final SourceFileParser sourceFileParser; @@ -91,10 +81,10 @@ public class RewriteProjectParser { private final ConfigurableListableBeanFactory beanFactory; private final ProjectScanner scanner; private final ExecutionContext executionContext; + private final MavenProjectAnalyzer mavenProjectAnalyzer; public RewriteProjectParsingResult parse(Path baseDir) { - Set ignorePatterns = parserProperties.getIgnoredPathPatterns(); List resources = scanner.scan(baseDir); return this.parse(baseDir, resources, executionContext); } @@ -116,16 +106,12 @@ public RewriteProjectParsingResult parse(Path baseDir) { * Parse resources * processMainSources() * processTestSources() - * - * @see MavenMojoProjectParser#listSourceFiles(MavenProject, List, ExecutionContext) */ public RewriteProjectParsingResult parse(Path givenBaseDir, List resources, ExecutionContext executionContext) { scanScope.clear(beanFactory); - if (!givenBaseDir.isAbsolute()) { - givenBaseDir = givenBaseDir.toAbsolutePath().normalize(); - } - final Path baseDir = givenBaseDir; + final Path baseDir = normalizePath(givenBaseDir); + // FIXME: ... WARN 30694 --- [ main] .m.p.i.DeprecatedCoreExpressionValidator : Parameter 'local' is deprecated core expression; Avoid use of ArtifactRepository type. If you need access to local repository, switch to '${repositorySystemSession}' expression and get LRM from it instead. MavenExecutionContextView.view(executionContext).setLocalRepository(new MavenRepository("local", "file://" + Path.of(System.getProperty("user.home")).resolve(".m2/repository"), null, null, false, null, null, null)); eventPublisher.publishEvent(new StartedParsingProjectEvent(resources)); @@ -137,82 +123,54 @@ public RewriteProjectParsingResult parse(Path givenBaseDir, List resou // TODO: where to retrieve styles from? --> see AbstractRewriteMojo#getActiveStyles() & AbstractRewriteMojo#loadStyles() List styles = List.of(); - AtomicReference atomicReference = new AtomicReference<>(); - - withMavenSession(baseDir, mavenSession -> { - // Get the ordered list of projects - List sortedProjectsList = mavenSession.getProjectDependencyGraph().getSortedProjects(); - // SortedProjects makes downstream components independent of Maven classes - SortedProjects mavenInfos = new SortedProjects(resources, sortedProjectsList, List.of("default")); + // Get the ordered list of projects + ParserContext parserContext = mavenProjectAnalyzer.createParserContext(baseDir, resources); + // SortedProjects makes downstream components independent of Maven classes + // TODO: 945 Is SortedProjects still required? // List sortedBuildFileResources = buildFileParser.filterAndSortBuildFiles(resources); - // generate provenance - Map> provenanceMarkers = provenanceMarkerFactory.generateProvenanceMarkers(baseDir, mavenInfos); + // generate provenance + Map> provenanceMarkers = provenanceMarkerFactory.generateProvenanceMarkers(baseDir, parserContext); - // 127: parse build files - Map resourceToDocumentMap = buildFileParser.parseBuildFiles(baseDir, mavenInfos.getResources(), mavenInfos.getActiveProfiles(), executionContext, parserProperties.isSkipMavenParsing(), provenanceMarkers); + // 127: parse build files + Map resourceToDocumentMap = buildFileParser.parseBuildFiles(baseDir, parserContext.getBuildFileResources(), parserContext.getActiveProfiles(), executionContext, parserProperties.isSkipMavenParsing(), provenanceMarkers); - List parsedAndSortedBuildFileDocuments = mavenInfos.getResources().stream() - .map(r -> resourceToDocumentMap.get(ResourceUtil.getPath(r))) - .map(SourceFile.class::cast) - .toList(); + List parsedAndSortedBuildFileDocuments = parserContext.getBuildFileResources().stream() + .map(r -> resourceToDocumentMap.get(ResourceUtil.getPath(r))) + .map(SourceFile.class::cast) + // FIXME: 945 ugly hack + .peek(sourceFile -> addSourceFileToModel(baseDir, parserContext.getSortedProjects(), sourceFile)) + .toList(); - // 128 : 131 - log.trace("Start to parse %d source files in %d modules".formatted(resources.size() + resourceToDocumentMap.size(), resourceToDocumentMap.size())); - List list = sourceFileParser.parseOtherSourceFiles(baseDir, mavenInfos, resourceToDocumentMap, mavenInfos.getResources(), provenanceMarkers, styles, executionContext); + log.trace("Start to parse %d source files in %d modules".formatted(resources.size() + resourceToDocumentMap.size(), resourceToDocumentMap.size())); + List list = sourceFileParser.parseOtherSourceFiles(baseDir, parserContext, resourceToDocumentMap, resources, provenanceMarkers, styles, executionContext); // List sourceFilesWithoutPoms = sourceFilesStream.filter(sf -> resourceToDocumentMap.keySet().contains(baseDir.resolve(sf.getSourcePath()).toAbsolutePath().normalize())).toList(); - List resultingList = new ArrayList<>(); // sourceFilesStream2.toList(); - resultingList.addAll(parsedAndSortedBuildFileDocuments); - resultingList.addAll(list); - List sourceFiles = styleDetector.sourcesWithAutoDetectedStyles(resultingList.stream()); - - eventPublisher.publishEvent(new SuccessfullyParsedProjectEvent(sourceFiles)); - - atomicReference.set(new RewriteProjectParsingResult(sourceFiles, executionContext)); - }); - - return atomicReference.get(); - } - - private void withMavenSession(Path baseDir, Consumer consumer) { - List goals = List.of("clean", "package"); - log.debug("Successfully finished goals %s".formatted(goals)); - mavenExecutor.onProjectSucceededEvent(baseDir, goals, event -> consumer.accept(event.getSession())); - } + List resultingList = new ArrayList<>(); // sourceFilesStream2.toList(); + resultingList.addAll(parsedAndSortedBuildFileDocuments); + resultingList.addAll(list); + List sourceFiles = styleDetector.sourcesWithAutoDetectedStyles(resultingList.stream()); - @org.jetbrains.annotations.Nullable - private static List autoDetectStyles(Stream sourceFilesStream) { - RewriteMojo dummyRewriteMojo = new RewriteMojo(); - Method sourcesWithAutoDetectedStylesMethod = ReflectionUtils.findMethod(RewriteMojo.class, "sourcesWithAutoDetectedStyles"); - ReflectionUtils.makeAccessible(sourcesWithAutoDetectedStylesMethod); - Object o = ReflectionUtils.invokeMethod(sourcesWithAutoDetectedStylesMethod, dummyRewriteMojo, sourceFilesStream); - List sourceFiles = (List) o; - return sourceFiles; - } + eventPublisher.publishEvent(new SuccessfullyParsedProjectEvent(sourceFiles)); -// private Stream parseToAst(Path baseDir, List resources, List styles, ExecutionContext executionContext) throws DependencyResolutionRequiredException, MojoExecutionException { -// MavenProject mavenProject = createFakeMavenProjectForProvenance(baseDir, resources, executionContext); -// return super.listSourceFiles(mavenProject, styles, executionContext); -// } + return new RewriteProjectParsingResult(sourceFiles, executionContext); +// }); - private MavenProject createFakeMavenProjectForProvenance(Path baseDir, List resources, ExecutionContext executionContext) { - MavenProject mavenProject = new MavenProject(); - // Plugin compilerPlugin = mavenProject.getPlugin("org.apache.maven.plugins:maven-compiler-plugin"); - mavenProject.setPluginArtifacts(Set.of()); - return mavenProject; } - /** - * Extending {@code AbstractRewriteMojo} to open up protected method for reuse - */ - static class RewriteMojo extends AbstractRewriteMojo { - - @Override - public void execute() throws MojoExecutionException, MojoFailureException { - + @NotNull + private static Path normalizePath(Path givenBaseDir) { + if (!givenBaseDir.isAbsolute()) { + givenBaseDir = givenBaseDir.toAbsolutePath().normalize(); } + final Path baseDir = givenBaseDir; + return baseDir; } + private static void addSourceFileToModel(Path baseDir, List sortedProjectsList, SourceFile s) { + sortedProjectsList.stream() + .filter(p -> ResourceUtil.getPath(p.getPomFile()).toString().equals(baseDir.resolve(s.getSourcePath()).toString())) + .forEach(p -> p.setSourceFile(s)); + } } diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/RewriteResourceParser.java b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/RewriteResourceParser.java new file mode 100644 index 000000000..20fbebfd0 --- /dev/null +++ b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/RewriteResourceParser.java @@ -0,0 +1,316 @@ +/* + * Copyright 2021 - 2023 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.parsers; + +import lombok.extern.slf4j.Slf4j; +import org.jetbrains.annotations.NotNull; +import org.openrewrite.ExecutionContext; +import org.openrewrite.Parser; +import org.openrewrite.SourceFile; +import org.openrewrite.hcl.HclParser; +import org.openrewrite.java.JavaParser; +import org.openrewrite.json.JsonParser; +import org.openrewrite.properties.PropertiesParser; +import org.openrewrite.protobuf.ProtoParser; +import org.openrewrite.quark.QuarkParser; +import org.openrewrite.text.PlainTextParser; +import org.openrewrite.xml.XmlParser; +import org.openrewrite.yaml.YamlParser; +import org.springframework.core.io.FileSystemResource; +import org.springframework.core.io.Resource; +import org.springframework.sbm.utils.ResourceUtil; + +import java.nio.file.*; +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * Code from https://github.com/fabapp2/rewrite-maven-plugin/blob/83d184ea9ffe3046429f16c91aa56a9610bae832/src/main/java/org/openrewrite/maven/ResourceParser.java + * The motivation was to decouple the parser from file access. + */ +@Slf4j +public class RewriteResourceParser { + private static final Set DEFAULT_IGNORED_DIRECTORIES = new HashSet<>(Arrays.asList("build", "target", "out", ".sonar", ".gradle", ".idea", ".project", "node_modules", ".git", ".metadata", ".DS_Store")); + + private final Path baseDir; + private final Collection exclusions; + private final int sizeThresholdMb; + private final Collection excludedDirectories; + private final Collection plainTextMasks; + + /** + * Sometimes java files will exist in the src/main/resources directory. For example, Drools: + */ + private final JavaParser.Builder javaParserBuilder; + private final ExecutionContext executionContext; + + public RewriteResourceParser( + Path baseDir, + Collection exclusions, + Collection plainTextMasks, + int sizeThresholdMb, + Collection excludedDirectories, + JavaParser.Builder javaParserBuilder, + ExecutionContext executionContext + ) { + this.baseDir = baseDir; + this.javaParserBuilder = javaParserBuilder; + this.executionContext = executionContext; + this.exclusions = pathMatchers(baseDir, exclusions); + this.sizeThresholdMb = sizeThresholdMb; + this.excludedDirectories = excludedDirectories; + this.plainTextMasks = pathMatchers(baseDir, plainTextMasks); + } + + private Collection pathMatchers(Path basePath, Collection pathExpressions) { + return pathExpressions.stream() + .map(o -> basePath.getFileSystem().getPathMatcher("glob:" + o)) + .collect(Collectors.toList()); + } + + public Stream parse(Path searchDir, List resources, Set alreadyParsed) { + // TODO: 945 remove/clean this up + List resourcesLeft = resources.stream() + .filter(r -> alreadyParsed.stream().noneMatch(path -> ResourceUtil.getPath(r).toString().startsWith(path.toString()))) + .toList(); + return this.parseSourceFiles(searchDir, resourcesLeft, alreadyParsed, executionContext); + + +// +// Stream sourceFiles = Stream.empty(); +// if (!searchDir.toFile().exists()) { +// return sourceFiles; +// } else { +// Consumer errorConsumer = (t) -> { +// this.logger.debug("Error parsing", t); +// }; +// InMemoryExecutionContext ctx = new InMemoryExecutionContext(errorConsumer); +// +// try { +// sourceFiles = Stream.concat(sourceFiles, this.parseSourceFiles(searchDir, alreadyParsed, ctx)); +// return sourceFiles; +// } catch (IOException var7) { +// this.logger.error(var7.getMessage(), var7); +// throw new UncheckedIOException(var7); +// } +// } + } + + @SuppressWarnings({"DuplicatedCode", "unchecked"}) + public Stream parseSourceFiles( + Path searchDir, + List resources, + Set alreadyParsed, + ExecutionContext ctx) { + + List resourcesLeft = new ArrayList<>(); + List quarkPaths = new ArrayList<>(); + List plainTextPaths = new ArrayList<>(); + + List filteredResources = resources + .stream() + .filter(r -> ResourceUtil.getPath(r).toString().startsWith(searchDir.toString())) + .toList(); + + filteredResources.forEach(resource -> { + Path file = ResourceUtil.getPath(resource); + Path dir = file.getParent(); + if (isExcluded(dir) || isIgnoredDirectory(searchDir, dir) || excludedDirectories.contains(dir) || alreadyParsed.contains(new FileSystemResource(dir)) || alreadyParsed.contains(resource)) { + return; + } else { + // FIXME: 945 only check threshold if value > 0 is given + long fileSize = ResourceUtil.contentLength(resource); + if (isOverSizeThreshold(fileSize)) { + log.info("Parsing as quark " + file + " as its size " + fileSize / (1024L * 1024L) + + "Mb exceeds size threshold " + sizeThresholdMb + "Mb"); + quarkPaths.add(file); + } else if (isParsedAsPlainText(file)) { + plainTextPaths.add(file); + } else { + resourcesLeft.add(file); + } + } + }); + + Stream sourceFiles = Stream.empty(); + + JavaParser javaParser = javaParserBuilder.build(); + List javaPaths = new ArrayList<>(); + + JsonParser jsonParser = new JsonParser(); + List jsonPaths = new ArrayList<>(); + + XmlParser xmlParser = new XmlParser(); + List xmlPaths = new ArrayList<>(); + + YamlParser yamlParser = new YamlParser(); + List yamlPaths = new ArrayList<>(); + + PropertiesParser propertiesParser = new PropertiesParser(); + List propertiesPaths = new ArrayList<>(); + + ProtoParser protoParser = new ProtoParser(); + List protoPaths = new ArrayList<>(); + + // Python currently not supported +// PythonParser pythonParser = PythonParser.builder().build(); +// List pythonPaths = new ArrayList<>(); + + HclParser hclParser = HclParser.builder().build(); + List hclPaths = new ArrayList<>(); + + PlainTextParser plainTextParser = new PlainTextParser(); + + QuarkParser quarkParser = new QuarkParser(); + + filteredResources + .forEach(resource -> { + // See https://github.com/quarkusio/quarkus/blob/main/devtools/project-core-extension-codestarts/src/main/resources/codestarts/quarkus/extension-codestarts/resteasy-reactive-codestart/java/src/main/java/org/acme/%7Bresource.class-name%7D.tpl.qute.java + // for an example of why we don't want qute files be parsed as java + Path path = ResourceUtil.getPath(resource); +// if (javaParser.accept(path) && !path.toString().endsWith(".qute.java")) { +// javaPaths.add(path); +// } + if (jsonParser.accept(path)) { + jsonPaths.add(path); + } else if (xmlParser.accept(path)) { + xmlPaths.add(path); + } else if (yamlParser.accept(path)) { + yamlPaths.add(path); + } else if (propertiesParser.accept(path)) { + propertiesPaths.add(path); + } else if (protoParser.accept(path)) { + protoPaths.add(path); + } /*else if(pythonParser.accept(path)) { + pythonPaths.add(path); + }*/ else if (hclParser.accept(path)) { + hclPaths.add(path); + } else if (quarkParser.accept(path)) { + quarkPaths.add(path); + } + }); + + Map pathToResource = filteredResources.stream().collect(Collectors.toMap(r -> ResourceUtil.getPath(r), r -> r)); + + if (!javaPaths.isEmpty()) { + List inputs = getInputs(pathToResource, javaPaths); + sourceFiles = Stream.concat(sourceFiles, (Stream) javaParser.parseInputs(inputs, baseDir, ctx)); + alreadyParsed.addAll(javaPaths); + } + + if (!jsonPaths.isEmpty()) { + List inputs = getInputs(pathToResource, jsonPaths); + sourceFiles = Stream.concat(sourceFiles, (Stream) jsonParser.parseInputs(inputs, baseDir, ctx)); + alreadyParsed.addAll(jsonPaths); + } + + if (!xmlPaths.isEmpty()) { + List inputs = getInputs(pathToResource, xmlPaths); + sourceFiles = Stream.concat(sourceFiles, (Stream) xmlParser.parseInputs(inputs, baseDir, ctx)); + alreadyParsed.addAll(xmlPaths); + } + + if (!yamlPaths.isEmpty()) { + List inputs = getInputs(pathToResource, yamlPaths); + sourceFiles = Stream.concat(sourceFiles, (Stream) yamlParser.parseInputs(inputs, baseDir, ctx)); + alreadyParsed.addAll(yamlPaths); + } + + if (!propertiesPaths.isEmpty()) { + List inputs = getInputs(pathToResource, propertiesPaths); + sourceFiles = Stream.concat(sourceFiles, (Stream) propertiesParser.parseInputs(inputs, baseDir, ctx)); + alreadyParsed.addAll(propertiesPaths); + } + + if (!protoPaths.isEmpty()) { + List inputs = getInputs(pathToResource, protoPaths); + sourceFiles = Stream.concat(sourceFiles, (Stream) protoParser.parseInputs(inputs, baseDir, ctx)); + alreadyParsed.addAll(protoPaths); + } + +// if (!pythonPaths.isEmpty()) { +// List inputs = getInputs(pathToResource, pythonPaths); +// sourceFiles = Stream.concat(sourceFiles, (Stream) pythonParser.parseInputs(inputs, baseDir, ctx)); +// alreadyParsed.addAll(pythonPaths); +// } + + if (!hclPaths.isEmpty()) { + List inputs = getInputs(pathToResource, hclPaths); + sourceFiles = Stream.concat(sourceFiles, (Stream) hclParser.parseInputs(inputs, baseDir, ctx)); + alreadyParsed.addAll(hclPaths); + } + + if (!plainTextPaths.isEmpty()) { + List inputs = getInputs(pathToResource, plainTextPaths); + sourceFiles = Stream.concat(sourceFiles, (Stream) plainTextParser.parseInputs(inputs, baseDir, ctx)); + alreadyParsed.addAll(plainTextPaths); + } + + if (!quarkPaths.isEmpty()) { + List inputs = getInputs(pathToResource, quarkPaths); + sourceFiles = Stream.concat(sourceFiles, (Stream) quarkParser.parseInputs(inputs, baseDir, ctx)); + alreadyParsed.addAll(quarkPaths); + } + + return sourceFiles; + } + + @NotNull + private static List getInputs(Map pathResourceMap, List paths) { + return paths.stream() + .map(path -> new Parser.Input(path, () -> ResourceUtil.getInputStream(pathResourceMap.get(path)))).toList(); + } + + private boolean isOverSizeThreshold(long fileSize) { + return sizeThresholdMb > 0 && fileSize > sizeThresholdMb * 1024L * 1024L; + } + + private boolean isExcluded(Path path) { + if (!exclusions.isEmpty()) { + for (PathMatcher excluded : exclusions) { + if (excluded.matches(baseDir.relativize(path))) { + return true; + } + } + } + return false; + } + + private boolean isParsedAsPlainText(Path path) { + if (!plainTextMasks.isEmpty()) { + Path computed = baseDir.relativize(path); + if (!computed.startsWith("/")) { + computed = Paths.get("/").resolve(computed); + } + for (PathMatcher matcher : plainTextMasks) { + if (matcher.matches(computed)) { + return true; + } + } + } + return false; + } + + private boolean isIgnoredDirectory(Path searchDir, Path path) { + for (Path pathSegment : searchDir.relativize(path)) { + if (DEFAULT_IGNORED_DIRECTORIES.contains(pathSegment.toString())) { + return true; + } + } + return false; + } +} diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/SbmMavenProject.java b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/SbmMavenProject.java new file mode 100644 index 000000000..0debaebb9 --- /dev/null +++ b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/SbmMavenProject.java @@ -0,0 +1,220 @@ +/* + * Copyright 2021 - 2023 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.parsers; + +import lombok.Getter; +import lombok.Setter; +import org.apache.maven.model.Model; +import org.apache.maven.model.Plugin; +import org.jetbrains.annotations.NotNull; +import org.openrewrite.SourceFile; +import org.openrewrite.maven.tree.*; +import org.openrewrite.maven.utilities.MavenArtifactDownloader; +import org.springframework.core.io.Resource; +import org.springframework.sbm.utils.ResourceUtil; + +import java.io.File; +import java.nio.file.Path; +import java.util.*; +import java.util.function.Predicate; + + +@Getter +@Setter +/** + * @author Fabian Krüger + */ +public class SbmMavenProject { + + private final Path projectRoot; + private final Resource pomFile; + // FIXME: 945 temporary method, model should nopt come from Maven + private final Model pomModel; + private List collectedProjects = new ArrayList<>(); + private SourceFile sourceFile; + private final MavenArtifactDownloader rewriteMavenArtifactDownloader; + private final List resources; + private ProjectId projectId; + + public SbmMavenProject(Path projectRoot, Resource pomFile, Model pomModel, MavenArtifactDownloader rewriteMavenArtifactDownloader, List resources) { + this.projectRoot = projectRoot; + this.pomFile = pomFile; + this.pomModel = pomModel; + this.rewriteMavenArtifactDownloader = rewriteMavenArtifactDownloader; + this.resources = resources; + projectId = new ProjectId(getGroupId(), getArtifactId()); + } + + public File getFile() { + return ResourceUtil.getPath(pomFile).toFile(); + } + + public Path getBasedir() { + // TODO: 945 Check if this is correct + return pomFile == null ? null : ResourceUtil.getPath(pomFile).getParent(); + } + + public void setCollectedProjects(List collected) { + this.collectedProjects = collected; + } + + public List getCollectedProjects() { + return collectedProjects; + } + + public Resource getResource() { + return pomFile; + } + + public Path getModuleDir() { + if(getBasedir() == null) { + return null; + } else if(projectRoot.relativize(ResourceUtil.getPath(pomFile)).toString().equals("pom.xml")){ + return Path.of(""); + } else { + return projectRoot.relativize(ResourceUtil.getPath(pomFile)).getParent(); + } + } + + + public String getGroupIdAndArtifactId() { + return this.pomModel.getGroupId() + ":" + pomModel.getArtifactId(); + } + + public Path getPomFilePath() { + return ResourceUtil.getPath(pomFile); + } + + public Plugin getPlugin(String s) { + return pomModel.getBuild() == null ? null : pomModel.getBuild().getPluginsAsMap().get(s); + } + + public Properties getProperties() { + return pomModel.getProperties(); + } + + public MavenRuntimeInformation getMavenRuntimeInformation() { + // FIXME: 945 implement this + return new MavenRuntimeInformation(); + } + + public String getName() { + return pomModel.getName(); + } + + public String getGroupId() { + return pomModel.getGroupId() == null ? pomModel.getParent().getGroupId() : pomModel.getGroupId(); + } + + public String getArtifactId() { + return pomModel.getArtifactId(); + } + + public String getVersion() { + return pomModel.getVersion(); + } + + @Override + public String toString() { + String groupId = pomModel.getGroupId() == null ? pomModel.getParent().getGroupId() : pomModel.getGroupId(); + return groupId + ":" + pomModel.getArtifactId(); + } + + public String getBuildDirectory() { + String s = pomModel.getBuild() != null ? pomModel.getBuild().getDirectory() : null; + return s == null ? ResourceUtil.getPath(pomFile).getParent().resolve("target").toAbsolutePath().normalize().toString() : s; + } + + public String getSourceDirectory() { + String s = pomModel.getBuild() != null ? pomModel.getBuild().getSourceDirectory() : null; + return s == null ? ResourceUtil.getPath(pomFile).getParent().resolve("src/main/java").toAbsolutePath().normalize().toString() : s; + } + + public List getCompileClasspathElements() { + Scope scope = Scope.Compile; + return getClasspathElements(scope); + } + + public List getTestClasspathElements() { + return getClasspathElements(Scope.Test); + } + + @NotNull + private List getClasspathElements(Scope scope) { + MavenResolutionResult pom = getSourceFile().getMarkers().findFirst(MavenResolutionResult.class).get(); + List resolvedDependencies = pom.getDependencies().get(scope); + if(resolvedDependencies != null) { + return resolvedDependencies + // FIXME: 945 - deal with dependencies to projects in reactor + // + .stream() + .filter(rd -> rd.getRepository() != null) + .map(rd -> rewriteMavenArtifactDownloader.downloadArtifact(rd)) + .filter(Objects::nonNull) + .distinct() + .toList(); + } else { + return new ArrayList<>(); + } + } + + public String getTestSourceDirectory() { + String s = pomModel.getBuild() != null ? pomModel.getBuild().getSourceDirectory() : null; + return s == null ? ResourceUtil.getPath(pomFile).getParent().resolve("src/test/java").toAbsolutePath().normalize().toString() : s; + } + + public void setSourceFile(SourceFile sourceFile) { + this.sourceFile = sourceFile; + } + + private static List listJavaSources(List resources, Path sourceDirectory) { + return resources.stream() + .filter(whenIn(sourceDirectory)) + .filter(whenFileNameEndsWithJava()) + .toList(); + } + + @NotNull + private static Predicate whenFileNameEndsWithJava() { + return p -> ResourceUtil.getPath(p).getFileName().toString().endsWith(".java"); + } + + @NotNull + private static Predicate whenIn(Path sourceDirectory) { + return r -> ResourceUtil.getPath(r).toString().startsWith(sourceDirectory.toString()); + } + + + public List getJavaSourcesInTarget() { + return listJavaSources(getResources(), getBasedir().resolve(getBuildDirectory())); + } + + private List getResources() { + return this.resources; + } + + public List getMainJavaSources() { + return listJavaSources(resources, getProjectRoot().resolve(getModuleDir()).resolve("src/main/java")); + } + + public Path getModulePath() { + return projectRoot.resolve(getModuleDir()); + } + + public ProjectId getProjectId() { + return projectId; + } +} diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/SortedProjects.java b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/SortedProjects.java deleted file mode 100644 index 1174809f0..000000000 --- a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/SortedProjects.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2021 - 2023 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.parsers; - -import lombok.Getter; -import org.apache.maven.model.Model; -import org.apache.maven.project.MavenProject; -import org.springframework.core.io.Resource; -import org.springframework.sbm.utils.ResourceUtil; - -import java.io.File; -import java.nio.file.Path; -import java.util.List; - -/** - * Helper class - * - * TODO: Make class independant to Maven and find better name. - * TODO: Can this class be used to transport build information from Maven and Gradle to reuse functionality? - * - * @author Fabian Krüger - */ -public class SortedProjects { - private final List resources; - @Getter - private final List sortedProjects; - @Getter - private final List activeProfiles; - - - - // FIXME: The relation between resource and project is brittle, if it's really needed we should validate in constructor - public SortedProjects(List given, List allProjects, List activeProfiles) { - this.resources = given; - this.sortedProjects = allProjects; - this.activeProfiles = activeProfiles; - } - - public List getResources() { - return sortedProjects - .stream() - .map(MavenProject::getFile) - .map(File::toPath) - .map(m -> this.findResourceWithPath(m, resources)) - .toList(); - } - - private Resource findResourceWithPath(Path m, List resources) { - return resources.stream() - .filter(r -> ResourceUtil.getPath(r).equals(m)) - .findFirst() - .orElseThrow(() -> new IllegalStateException("Could not find a resource in the list of resources that matches the path of pom '%s'".formatted(m.toString()))); - } - - public Resource getMatchingBuildFileResource(MavenProject pom) { - return resources.stream() - .filter(r -> ResourceUtil.getPath(r).equals(pom.getFile().toPath())) - .findFirst() - .orElseThrow(() -> new IllegalStateException("Could not find a resource in the list of resources that matches the path of MavenProject '%s'".formatted(pom.getFile().getPath().toString()))); - } - - private List readActiveProfiles(Model topLevelModel) { - return activeProfiles; - } - - public MavenProject getMavenProject(Resource r) { - Path path = ResourceUtil.getPath(r); - return sortedProjects.stream() - .filter(p -> p.getFile().getPath().toString().equals(path.toString())) - .findFirst() - .orElseThrow(() -> new IllegalArgumentException("Could not find MavenProject for given resource '%s'".formatted(path))); - } -} diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/SourceFileParser.java b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/SourceFileParser.java index 757b64688..eccdcbd7b 100644 --- a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/SourceFileParser.java +++ b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/SourceFileParser.java @@ -17,13 +17,10 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.apache.maven.project.MavenProject; import org.openrewrite.ExecutionContext; import org.openrewrite.SourceFile; import org.openrewrite.java.JavaParser; import org.openrewrite.marker.Marker; -import org.openrewrite.maven.MavenMojoProjectParser; -import org.openrewrite.maven.ResourceParser; import org.openrewrite.style.NamedStyles; import org.openrewrite.xml.tree.Xml; import org.springframework.core.io.Resource; @@ -44,12 +41,11 @@ public class SourceFileParser { private final ParserProperties parserProperties; - private final MavenMojoProjectParserPrivateMethods mavenMojoProjectParserPrivateMethods; - private final JavaParserBuilder javaParserBuilder; + private final HelperWithoutAGoodName mavenMojoProjectParserPrivateMethods; public List parseOtherSourceFiles( Path baseDir, - SortedProjects mavenProject, + ParserContext parserContext, Map pathToDocumentMap, List resources, Map> provenanceMarkers, @@ -58,12 +54,12 @@ public List parseOtherSourceFiles( Set parsedSourceFiles = new LinkedHashSet<>(); - mavenProject.getSortedProjects().forEach(currentMavenProject -> { - Resource moduleBuildFileResource = mavenProject.getMatchingBuildFileResource(currentMavenProject); + parserContext.getSortedProjects().forEach(currentMavenProject -> { + Resource moduleBuildFileResource = parserContext.getMatchingBuildFileResource(currentMavenProject); Xml.Document moduleBuildFile = pathToDocumentMap.get(ResourceUtil.getPath(moduleBuildFileResource)); List markers = provenanceMarkers.get(ResourceUtil.getPath(moduleBuildFileResource)); if(markers == null || markers.isEmpty()) { - log.warn("Could not find provenance markers for resource '%s'".formatted(mavenProject.getMatchingBuildFileResource(currentMavenProject))); + log.warn("Could not find provenance markers for resource '%s'".formatted(parserContext.getMatchingBuildFileResource(currentMavenProject))); } List sourceFiles = parseModuleSourceFiles(resources, currentMavenProject, moduleBuildFile, markers, styles, executionContext, baseDir); parsedSourceFiles.addAll(sourceFiles); @@ -72,18 +68,16 @@ public List parseOtherSourceFiles( return new ArrayList<>(parsedSourceFiles); } - /** - * {@link org.openrewrite.maven.MavenMojoProjectParser#listSourceFiles(MavenProject, Xml.Document, List, List, ExecutionContext)} - */ private List parseModuleSourceFiles( List resources, - MavenProject mavenProject, + SbmMavenProject currentProject, Xml.Document moduleBuildFile, List provenanceMarkers, List styles, ExecutionContext executionContext, Path baseDir) { + List sourceFiles = new ArrayList<>(); // 146:149: get source encoding from maven // TDOD: @@ -97,36 +91,38 @@ private List parseModuleSourceFiles( .styles(styles) .logCompilationWarningsAndErrors(false); - Path buildFilePath = mavenProject.getBasedir().toPath().resolve(moduleBuildFile.getSourcePath()); + Path buildFilePath = currentProject.getBasedir().resolve(moduleBuildFile.getSourcePath()); + log.info("Parsing module " + buildFilePath); // these paths will be ignored by ResourceParser - Set skipResourceScanDirs = pathsToOtherMavenProjects(mavenProject, buildFilePath); - ResourceParser rp = new ResourceParser( + Set skipResourceScanDirs = pathsToOtherMavenProjects(currentProject, buildFilePath); + // FIXME: Why is skipResourceScanDirs required at all? Shouldn't the module know it's resources + RewriteResourceParser rp = new RewriteResourceParser( baseDir, - new Slf4jToMavenLoggerAdapter(log), parserProperties.getIgnoredPathPatterns(), parserProperties.getPlainTextMasks(), parserProperties.getSizeThresholdMb(), skipResourceScanDirs, - javaParserBuilder.clone() - ); + javaParserBuilder.clone(), + executionContext); // 155:156: parse main and test sources Set alreadyParsed = new HashSet<>(); - alreadyParsed.add(baseDir.resolve(moduleBuildFile.getSourcePath())); - List mainSources = parseMainSources(baseDir, mavenProject, moduleBuildFile, javaParserBuilder.clone(), rp, provenanceMarkers, alreadyParsed, executionContext); - List testSources = parseTestSources(baseDir, mavenProject, moduleBuildFile, javaParserBuilder.clone(), rp, provenanceMarkers, alreadyParsed, executionContext); - + Path moduleBuildFilePath = baseDir.resolve(moduleBuildFile.getSourcePath()); + alreadyParsed.add(moduleBuildFilePath); alreadyParsed.addAll(skipResourceScanDirs); - // 171:175 - Stream parsedResourceFiles = rp.parse(baseDir.resolve(moduleBuildFile.getSourcePath()).getParent(), alreadyParsed ) + List mainSources = parseMainSources(baseDir, currentProject, moduleBuildFile, resources, javaParserBuilder.clone(), rp, provenanceMarkers, alreadyParsed, executionContext); + List testSources = parseTestSources(baseDir, currentProject, moduleBuildFile, javaParserBuilder.clone(), rp, provenanceMarkers, alreadyParsed, executionContext, resources); + // Collect the dirs of modules parsed in previous steps + + // parse other project resources + Stream parsedResourceFiles = rp.parse(moduleBuildFilePath.getParent(), resources, alreadyParsed) // FIXME: handle generated sources .map(mavenMojoProjectParserPrivateMethods.addProvenance(baseDir, provenanceMarkers, null)); - // 157:169 - List resourceSourceFiles = mergeAndFilterExcluded(baseDir, parserProperties.getIgnoredPathPatterns(), mainSources, testSources); + List mainAndTestSources = mergeAndFilterExcluded(baseDir, parserProperties.getIgnoredPathPatterns(), mainSources, testSources); List resourceFilesList = parsedResourceFiles.toList(); + sourceFiles.addAll(mainAndTestSources); sourceFiles.addAll(resourceFilesList); - sourceFiles.addAll(resourceSourceFiles); return sourceFiles; } @@ -149,21 +145,20 @@ private static boolean isNotExcluded(Path baseDir, List exclusions, .noneMatch(pm -> pm.matches(baseDir.resolve(s.getSourcePath()).toAbsolutePath().normalize())); } - private List parseTestSources(Path baseDir, MavenProject mavenProject, Xml.Document moduleBuildFile, JavaParser.Builder javaParserBuilder, ResourceParser rp, List provenanceMarkers, Set alreadyParsed, ExecutionContext executionContext) { - return mavenMojoProjectParserPrivateMethods.processTestSources(baseDir, moduleBuildFile, javaParserBuilder, rp, provenanceMarkers, alreadyParsed, executionContext, mavenProject); + private List parseTestSources(Path baseDir, SbmMavenProject sbmMavenProject, Xml.Document moduleBuildFile, JavaParser.Builder javaParserBuilder, RewriteResourceParser rp, List provenanceMarkers, Set alreadyParsed, ExecutionContext executionContext, List resources) { + return mavenMojoProjectParserPrivateMethods.processTestSources(baseDir, moduleBuildFile, javaParserBuilder, rp, provenanceMarkers, alreadyParsed, executionContext, sbmMavenProject, resources); } /** - * {@link MavenMojoProjectParser#processMainSources(MavenProject, JavaParser.Builder, ResourceParser, List, Set, ExecutionContext)} */ - private List parseMainSources(Path baseDir, MavenProject mavenProject, Xml.Document moduleBuildFile, JavaParser.Builder javaParserBuilder, ResourceParser rp, List provenanceMarkers, Set alreadyParsed, ExecutionContext executionContext) { - // MavenMojoProjectParser#processMainSources(..) takes MavenProject + private List parseMainSources(Path baseDir, SbmMavenProject sbmMavenProject, Xml.Document moduleBuildFile, List resources, JavaParser.Builder javaParserBuilder, RewriteResourceParser rp, List provenanceMarkers, Set alreadyParsed, ExecutionContext executionContext) { + // MavenMojoProjectParser#processMainSources(..) takes SbmMavenProject // it reads from it: - // - mavenProject.getBuild().getDirectory() - // - mavenProject.getBuild().getSourceDirectory() - // - mavenProject.getCompileClasspathElements() --> The classpath of the given project/module - // - mavenProject.getBasedir().toPath() - return mavenMojoProjectParserPrivateMethods.processMainSources(baseDir, moduleBuildFile, javaParserBuilder, rp, provenanceMarkers, alreadyParsed, executionContext, mavenProject); + // - sbmMavenProject.getBuild().getDirectory() + // - sbmMavenProject.getBuild().getSourceDirectory() + // - sbmMavenProject.getCompileClasspathElements() --> The classpath of the given project/module + // - sbmMavenProject.getBasedir().toPath() + return mavenMojoProjectParserPrivateMethods.processMainSources(baseDir, resources, moduleBuildFile, javaParserBuilder, rp, provenanceMarkers, alreadyParsed, executionContext, sbmMavenProject); // return invokeProcessMethod(baseDir, moduleBuildFile, javaParserBuilder, rp, provenanceMarkers, alreadyParsed, executionContext, "processMainSources"); } @@ -173,16 +168,16 @@ private List parseMainSources(Path baseDir, MavenProject mavenProjec /** - * private Set pathsToOtherMavenProjects(MavenProject mavenProject) { + * private Set pathsToOtherMavenProjects(SbmMavenProject sbmMavenProject) { * return mavenSession.getProjects().stream() - * .filter(o -> o != mavenProject) + * .filter(o -> o != sbmMavenProject) * .map(o -> o.getBasedir().toPath()) * .collect(Collectors.toSet()); * } */ - private Set pathsToOtherMavenProjects(MavenProject mavenProject, Path moduleBuildFile) { - return mavenProject.getCollectedProjects().stream() - .filter(p -> !p.getFile().toPath().equals(moduleBuildFile)) + private Set pathsToOtherMavenProjects(SbmMavenProject sbmMavenProject, Path moduleBuildFile) { + return sbmMavenProject.getCollectedProjects().stream() + .filter(p -> !p.getFile().toPath().toString().equals(moduleBuildFile.toString())) .map(p -> p.getFile().toPath().getParent()) .collect(Collectors.toSet()); } diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/StyleDetector.java b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/StyleDetector.java index a6c7e0031..fd38c5383 100644 --- a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/StyleDetector.java +++ b/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/StyleDetector.java @@ -15,15 +15,20 @@ */ package org.springframework.sbm.parsers; -import org.apache.maven.plugin.MojoExecutionException; -import org.apache.maven.plugin.MojoFailureException; import org.openrewrite.SourceFile; -import org.openrewrite.maven.AbstractRewriteMojo; -import org.springframework.stereotype.Component; +import org.openrewrite.Tree; +import org.openrewrite.internal.ListUtils; +import org.openrewrite.java.style.Autodetect; +import org.openrewrite.java.tree.JavaSourceFile; +import org.openrewrite.marker.Marker; +import org.openrewrite.style.NamedStyles; +import org.openrewrite.xml.tree.Xml; import org.springframework.util.ReflectionUtils; import java.lang.reflect.Method; -import java.util.List; +import java.util.*; +import java.util.function.UnaryOperator; +import java.util.stream.Collectors; import java.util.stream.Stream; /** @@ -31,18 +36,49 @@ */ class StyleDetector { - public List sourcesWithAutoDetectedStyles(Stream sourceFilesStream) { - OpenedRewriteMojo m = new OpenedRewriteMojo(); - Method method = ReflectionUtils.findMethod(OpenedRewriteMojo.class, "sourcesWithAutoDetectedStyles", Stream.class); - ReflectionUtils.makeAccessible(method); - return (List) ReflectionUtils.invokeMethod(method, m, sourceFilesStream); + + List sourcesWithAutoDetectedStyles(Stream sourceFiles) { + org.openrewrite.java.style.Autodetect.Detector javaDetector = org.openrewrite.java.style.Autodetect.detector(); + org.openrewrite.xml.style.Autodetect.Detector xmlDetector = org.openrewrite.xml.style.Autodetect.detector(); + List sourceFileList = sourceFiles + .peek(javaDetector::sample) + .peek(xmlDetector::sample) + .toList(); + + Map, NamedStyles> stylesByType = new HashMap<>(); + stylesByType.put(JavaSourceFile.class, javaDetector.build()); + stylesByType.put(Xml.Document.class, xmlDetector.build()); + + return ListUtils.map(sourceFileList, applyAutodetectedStyle(stylesByType)); } - static class OpenedRewriteMojo extends AbstractRewriteMojo { + private UnaryOperator applyAutodetectedStyle(Map, NamedStyles> stylesByType) { + return (before) -> { + Iterator var2 = stylesByType.entrySet().iterator(); - @Override - public void execute() throws MojoExecutionException, MojoFailureException { - throw new UnsupportedOperationException(); - } + while(var2.hasNext()) { + Map.Entry, NamedStyles> styleTypeEntry = (Map.Entry)var2.next(); + if (((Class)styleTypeEntry.getKey()).isAssignableFrom(before.getClass())) { + before = (SourceFile)before.withMarkers(before.getMarkers().add((Marker)styleTypeEntry.getValue())); + } + } + + return before; + }; } + +// public List sourcesWithAutoDetectedStyles(Stream sourceFilesStream) { +// OpenedRewriteMojo m = new OpenedRewriteMojo(); +// Method method = ReflectionUtils.findMethod(OpenedRewriteMojo.class, "sourcesWithAutoDetectedStyles", Stream.class); +// ReflectionUtils.makeAccessible(method); +// return (List) ReflectionUtils.invokeMethod(method, m, sourceFilesStream); +// } +// +// static class OpenedRewriteMojo extends AbstractRewriteMojo { +// +// @Override +// public void execute() throws MojoExecutionException, MojoFailureException { +// throw new UnsupportedOperationException(); +// } +// } } diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/recipes/RewriteRecipeDiscovery.java b/sbm-support-rewrite/src/main/java/org/springframework/sbm/recipes/RewriteRecipeDiscovery.java index ffd0cabf2..008b53e5f 100644 --- a/sbm-support-rewrite/src/main/java/org/springframework/sbm/recipes/RewriteRecipeDiscovery.java +++ b/sbm-support-rewrite/src/main/java/org/springframework/sbm/recipes/RewriteRecipeDiscovery.java @@ -17,9 +17,6 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.apache.maven.plugin.MojoExecutionException; -import org.apache.maven.plugin.MojoFailureException; -import org.apache.maven.project.MavenProject; import org.openrewrite.Recipe; import org.openrewrite.Validated; import org.openrewrite.config.ClasspathScanningLoader; @@ -27,10 +24,8 @@ import org.openrewrite.config.RecipeDescriptor; import org.openrewrite.config.ResourceLoader; import org.openrewrite.internal.lang.Nullable; -import org.openrewrite.maven.AbstractRewriteMojo; import org.springframework.sbm.parsers.RecipeValidationErrorException; import org.springframework.sbm.parsers.ParserProperties; -import org.springframework.stereotype.Component; import java.nio.file.Path; import java.util.ArrayList; @@ -101,41 +96,41 @@ public List discoverFilteredRecipes(List activeRecipes, Properti return recipes; } - public List discoverFilteredRecipes(List activeRecipes, MavenProject mavenProject) { - if (activeRecipes.isEmpty()) { - log.warn("No active recipes were provided."); - return emptyList(); - } - - List recipes = new ArrayList<>(); - - AbstractRewriteMojoHelper helper = new AbstractRewriteMojoHelper(mavenProject); - - Environment env =helper.environment(getClass().getClassLoader()); - Recipe recipe = env.activateAll(); -// Recipe recipe = env.activateRecipes(activeRecipes); - - if (recipe.getRecipeList().isEmpty()) { - log.warn("No recipes were activated. None of the provided 'activeRecipes' matched any of the applicable recipes."); - return emptyList(); - } - - Collection> validated = recipe.validateAll(); - List> failedValidations = validated.stream().map(Validated::failures) - .flatMap(Collection::stream).collect(toList()); - if (!failedValidations.isEmpty()) { - failedValidations.forEach(failedValidation -> log.error( - "Recipe validation error in " + failedValidation.getProperty() + ": " + - failedValidation.getMessage(), failedValidation.getException())); - if (parserProperties.isFailOnInvalidActiveRecipes()) { - throw new RecipeValidationErrorException("Recipe validation errors detected as part of one or more activeRecipe(s). Please check error logs."); - } else { - log.error("Recipe validation errors detected as part of one or more activeRecipe(s). Execution will continue regardless."); - } - } - - return recipes; - } +// public List discoverFilteredRecipes(List activeRecipes, MavenProject mavenProject) { +// if (activeRecipes.isEmpty()) { +// log.warn("No active recipes were provided."); +// return emptyList(); +// } +// +// List recipes = new ArrayList<>(); +// +// AbstractRewriteMojoHelper helper = new AbstractRewriteMojoHelper(mavenProject); +// +// Environment env = helper.environment(getClass().getClassLoader()); +// Recipe recipe = env.activateAll(); +//// Recipe recipe = env.activateRecipes(activeRecipes); +// +// if (recipe.getRecipeList().isEmpty()) { +// log.warn("No recipes were activated. None of the provided 'activeRecipes' matched any of the applicable recipes."); +// return emptyList(); +// } +// +// Collection> validated = recipe.validateAll(); +// List> failedValidations = validated.stream().map(Validated::failures) +// .flatMap(Collection::stream).collect(toList()); +// if (!failedValidations.isEmpty()) { +// failedValidations.forEach(failedValidation -> log.error( +// "Recipe validation error in " + failedValidation.getProperty() + ": " + +// failedValidation.getMessage(), failedValidation.getException())); +// if (parserProperties.isFailOnInvalidActiveRecipes()) { +// throw new RecipeValidationErrorException("Recipe validation errors detected as part of one or more activeRecipe(s). Please check error logs."); +// } else { +// log.error("Recipe validation errors detected as part of one or more activeRecipe(s). Execution will continue regardless."); +// } +// } +// +// return recipes; +// } public RecipeDescriptor findRecipeDescriptor(String anotherDummyRecipe) { ResourceLoader resourceLoader = new ClasspathScanningLoader(new Properties(), new String[]{"io.example"}); @@ -166,69 +161,73 @@ public List findRecipesByTags(String tag) { } - class AbstractRewriteMojoHelper extends AbstractRewriteMojo { - - public AbstractRewriteMojoHelper(MavenProject mavenProject) { - super.project = mavenProject; - } - - @Override - public void execute() throws MojoExecutionException, MojoFailureException { - throw new UnsupportedOperationException(); - } - - @Override - public Environment environment(@Nullable ClassLoader recipeClassLoader) { - Environment.Builder env = Environment.builder(this.project.getProperties()); - if (recipeClassLoader == null) { - env.scanRuntimeClasspath(new String[0]).scanUserHome(); - } else { - env.load(new ClasspathScanningLoader(this.project.getProperties(), recipeClassLoader)); - } - - - /*env.load(new ResourceLoader() { - @Override - public Collection listRecipes() { - return List.of(); - } - - @Override - public Collection listRecipeDescriptors() { - return List.of(); - } - - @Override - public Collection listStyles() { - return List.of(); - } - - @Override - public Collection listCategoryDescriptors() { - return List.of(); - } - - @Override - public Map> listContributors() { - return Map.of(); - } - - @Override - public Map> listRecipeExamples() { - return Map.of(); - } - });*/ - return env.build(); - } - - @Override - protected Environment environment() throws MojoExecutionException { - return super.environment(); - } - - @Override - public Path repositoryRoot() { - return super.repositoryRoot(); - } - } +// class AbstractRewriteMojoHelper extends AbstractRewriteMojo { +// +// public AbstractRewriteMojoHelper(MavenProject mavenProject) { +// super.project = mavenProject; +// } +// +// @Override +// public void execute() throws MojoExecutionException, MojoFailureException { +// throw new UnsupportedOperationException(); +// } +// +// @Override +// public Environment environment(@Nullable ClassLoader recipeClassLoader) { +// Environment.Builder env = Environment.builder(this.project.getProperties()); +// if (recipeClassLoader == null) { +// env.scanRuntimeClasspath(new String[0]).scanUserHome(); +// } else { +// env.load(new ClasspathScanningLoader(this.project.getProperties(), recipeClassLoader)); +// } +// +// +// /*env.load(new ResourceLoader() { +// @Override +// public Collection listRecipes() { +// return List.of(); +// } +// +// @Override +// public Collection listRecipeDescriptors() { +// return List.of(); +// } +// +// @Override +// public Collection listStyles() { +// return List.of(); +// } +// +// @Override +// public Collection listCategoryDescriptors() { +// return List.of(); +// } +// +// @Override +// public Map> listContributors() { +// return Map.of(); +// } +// +// @Override +// public Map> listRecipeExamples() { +// return Map.of(); +// } +// });*/ +// return env.build(); +// } +// +//// @Override +//// protected Environment environment() { +//// try { +//// return super.environment(); +//// } catch (MojoExecutionException e) { +//// throw new RuntimeException(e); +//// } +//// } +// +// @Override +// public Path repositoryRoot() { +// return super.repositoryRoot(); +// } +// } } diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/utils/ResourceUtil.java b/sbm-support-rewrite/src/main/java/org/springframework/sbm/utils/ResourceUtil.java index 562f40677..0cb16a1c2 100644 --- a/sbm-support-rewrite/src/main/java/org/springframework/sbm/utils/ResourceUtil.java +++ b/sbm-support-rewrite/src/main/java/org/springframework/sbm/utils/ResourceUtil.java @@ -80,4 +80,12 @@ public static String getContent(Resource r) { throw new RuntimeException(e); } } + + public static long contentLength(Resource resource) { + try { + return resource.contentLength(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } } diff --git a/sbm-support-rewrite/src/test/java/org/openrewrite/maven/CalculateClasspathTest.java b/sbm-support-rewrite/src/test/java/org/openrewrite/maven/CalculateClasspathTest.java new file mode 100644 index 000000000..da183ff5f --- /dev/null +++ b/sbm-support-rewrite/src/test/java/org/openrewrite/maven/CalculateClasspathTest.java @@ -0,0 +1,149 @@ +/* + * Copyright 2021 - 2023 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.openrewrite.maven; + +import org.intellij.lang.annotations.Language; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import org.openrewrite.SourceFile; +import org.openrewrite.java.marker.JavaSourceSet; +import org.openrewrite.java.tree.J; +import org.openrewrite.java.tree.JavaType; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.core.io.Resource; +import org.springframework.sbm.boot.autoconfigure.ScannerConfiguration; +import org.springframework.sbm.parsers.RewriteExecutionContext; +import org.springframework.sbm.parsers.RewriteProjectParser; +import org.springframework.sbm.parsers.RewriteProjectParsingResult; +import org.springframework.sbm.test.util.DummyResource; +import org.springframework.sbm.test.util.TestProjectHelper; + +import java.nio.file.Path; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author Fabian Krüger + */ +@SpringBootTest(classes = {ScannerConfiguration.class}) +public class CalculateClasspathTest { + + @Autowired + RewriteProjectParser parser; + + @Test + @DisplayName("classpath for single-module project") + void classpathForSingleModuleProject(@TempDir Path tmpDir) { + @Language("xml") + String pom = """ + + + 4.0.0 + com.example + example-1 + 0.1.0-SNAPSHOT + + 17 + 17 + + + + javax.validation + validation-api + 2.0.1.Final + + + org.junit.jupiter + junit-jupiter-api + 5.9.3 + test + + + + """; + + @Language("java") + String mainClass = """ + package com.example; + import javax.validation.constraints.Min; + + public class MainClass { + @Min("10") + private int value; + } + """; + + @Language("java") + String testClass = """ + package com.example; + import org.junit.jupiter.api.Test; + + public class TestClass { + @Test + void someTest() {} + } + """; + + Path baseDir = tmpDir.resolve("/example-1").toAbsolutePath().normalize(); + List resources = List.of( + new DummyResource(baseDir.resolve("pom.xml"), pom), + new DummyResource(baseDir.resolve("src/main/java/com/example/MainClass.java"), mainClass), + new DummyResource(baseDir.resolve("src/test/java/com/example/TestClass.java"), testClass) + ); + + RewriteProjectParsingResult parsingResult = parser.parse(baseDir, resources, new RewriteExecutionContext()); + + // verify types in use + SourceFile mainSourceFile = parsingResult.sourceFiles().get(1); + J.CompilationUnit mainCu = (J.CompilationUnit) mainSourceFile; + // Having Min annotation resolved proves type resolution is working for main resources + assertThat(mainCu.getTypesInUse().getTypesInUse().stream().map(t -> t.toString())).containsExactlyInAnyOrder("int", "String", "javax.validation.constraints.Min"); + + SourceFile testSourceFile = parsingResult.sourceFiles().get(2); + J.CompilationUnit testCu = (J.CompilationUnit) testSourceFile; + // Having Test annotation resolved proves type resolution is working for test resources + assertThat(testCu.getTypesInUse().getTypesInUse().stream().map(t -> t.toString())).containsExactlyInAnyOrder("void", "org.junit.jupiter.api.Test"); + + // verify classpath + List mainClasspath = mainCu.getMarkers().findFirst(JavaSourceSet.class).get().getClasspath().stream().map(JavaType.FullyQualified::getFullyQualifiedName).toList(); + // Min is on main classpath + assertThat(mainClasspath).contains("javax.validation.constraints.Min"); + // Test is not + assertThat(mainClasspath).doesNotContain("org.junit.jupiter.api.Test"); + + List testClasspath = testCu.getMarkers().findFirst(JavaSourceSet.class).get().getClasspath().stream().map(JavaType.FullyQualified::getFullyQualifiedName).toList(); + // all main classes on test classpath + assertThat(testClasspath).containsAll(mainClasspath); + // plus the classes from test dependencies + assertThat(testClasspath).contains("org.junit.jupiter.api.Test"); + } + + /** + * Given a multi-module Maven reactor project. + * - Where module A depends on B and both inherit from same parent. + * - Module A has a + */ + @Test + @DisplayName("classpath for reactor build") + void classpathForReactorBuild() { + Path mavenProject = TestProjectHelper.getMavenProject("classpath-test/example-1"); + RewriteProjectParsingResult parsingResult = parser.parse(mavenProject); + } +} diff --git a/sbm-support-rewrite/src/test/java/org/springframework/sbm/ParserTest.java b/sbm-support-rewrite/src/test/java/org/springframework/sbm/ParserTest.java index 40c81b3b3..b3088f58a 100644 --- a/sbm-support-rewrite/src/test/java/org/springframework/sbm/ParserTest.java +++ b/sbm-support-rewrite/src/test/java/org/springframework/sbm/ParserTest.java @@ -20,6 +20,8 @@ import org.openrewrite.SourceFile; import org.openrewrite.maven.MavenParser; +import static org.assertj.core.api.Assertions.assertThat; + /** * @author Fabian Krüger */ @@ -75,7 +77,6 @@ void mavenParserShouldParsePom() { """).toList().get(0); - System.out.println(sourceFile.printAll()); - + assertThat(sourceFile).isNotNull(); } } diff --git a/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/BuildFileParserTest.java b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/BuildFileParserTest.java index 4fe9254f4..197436dd8 100644 --- a/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/BuildFileParserTest.java +++ b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/BuildFileParserTest.java @@ -15,7 +15,8 @@ */ package org.springframework.sbm.parsers; -import org.apache.maven.project.MavenProject; +import org.apache.commons.cli.*; +import org.apache.maven.cli.CleanArgument; import org.intellij.lang.annotations.Language; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/MavenExecutionRequestFactory.java b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/MavenExecutionRequestFactory.java similarity index 98% rename from sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/MavenExecutionRequestFactory.java rename to sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/MavenExecutionRequestFactory.java index 7d25a82df..988591c60 100644 --- a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/MavenExecutionRequestFactory.java +++ b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/MavenExecutionRequestFactory.java @@ -15,6 +15,7 @@ */ package org.springframework.sbm.parsers; +import org.sonatype.plexus.components.sec.dispatcher.SecDispatcher; import lombok.RequiredArgsConstructor; import org.apache.maven.artifact.repository.ArtifactRepository; import org.apache.maven.artifact.repository.ArtifactRepositoryFactory; diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/MavenExecutionResultException.java b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/MavenExecutionResultException.java similarity index 100% rename from sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/MavenExecutionResultException.java rename to sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/MavenExecutionResultException.java diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/MavenExecutor.java b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/MavenExecutor.java similarity index 98% rename from sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/MavenExecutor.java rename to sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/MavenExecutor.java index f39ea56f8..f5cdaee33 100644 --- a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/MavenExecutor.java +++ b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/MavenExecutor.java @@ -22,7 +22,7 @@ import org.apache.maven.project.MavenProject; import org.codehaus.plexus.PlexusContainer; import org.codehaus.plexus.component.repository.exception.ComponentLookupException; -import org.springframework.stereotype.Component; +import org.springframework.sbm.parsers.MavenExecutionRequestFactory; import java.nio.file.Path; import java.util.List; diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/MavenMojoProjectParserFactory.java b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/MavenMojoProjectParserFactory.java similarity index 98% rename from sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/MavenMojoProjectParserFactory.java rename to sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/MavenMojoProjectParserFactory.java index 0dc4dd5bb..fec162d79 100644 --- a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/MavenMojoProjectParserFactory.java +++ b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/MavenMojoProjectParserFactory.java @@ -25,7 +25,6 @@ import org.codehaus.plexus.PlexusContainer; import org.jetbrains.annotations.NotNull; import org.openrewrite.maven.MavenMojoProjectParser; -import org.springframework.stereotype.Component; import java.nio.file.Path; import java.util.Collection; diff --git a/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/MavenMojoProjectParserPrivateMethods.java b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/MavenMojoProjectParserPrivateMethods.java new file mode 100644 index 000000000..7eadc5a1a --- /dev/null +++ b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/MavenMojoProjectParserPrivateMethods.java @@ -0,0 +1,64 @@ +/* + * Copyright 2021 - 2023 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.parsers; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.maven.rtinfo.internal.DefaultRuntimeInformation; +import org.apache.maven.settings.crypto.DefaultSettingsDecrypter; +import org.jetbrains.annotations.NotNull; +import org.openrewrite.ExecutionContext; +import org.openrewrite.Parser; +import org.openrewrite.SourceFile; +import org.openrewrite.Tree; +import org.openrewrite.internal.lang.Nullable; +import org.openrewrite.java.JavaParser; +import org.openrewrite.java.internal.JavaTypeCache; +import org.openrewrite.java.marker.JavaSourceSet; +import org.openrewrite.marker.Generated; +import org.openrewrite.marker.Marker; +import org.openrewrite.marker.Markers; +import org.openrewrite.maven.MavenMojoProjectParser; +import org.openrewrite.maven.ResourceParser; +import org.openrewrite.maven.tree.ResolvedDependency; +import org.openrewrite.maven.utilities.MavenArtifactDownloader; +import org.openrewrite.xml.tree.Xml; +import org.sonatype.plexus.components.cipher.DefaultPlexusCipher; +import org.sonatype.plexus.components.cipher.PlexusCipherException; +import org.sonatype.plexus.components.sec.dispatcher.DefaultSecDispatcher; +import org.springframework.core.io.Resource; +import org.springframework.sbm.utils.ResourceUtil; + +import java.nio.file.*; +import java.util.*; +import java.util.function.Predicate; +import java.util.function.UnaryOperator; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * @author Fabian Krüger + */ +@Slf4j +@RequiredArgsConstructor +class MavenMojoProjectParserPrivateMethods { + + private final MavenMojoProjectParserFactory mavenMojoProjectParserFactory; + private final MavenArtifactDownloader artifactDownloader; + + + +} diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/MavenPlexusContainer.java b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/MavenPlexusContainer.java similarity index 95% rename from sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/MavenPlexusContainer.java rename to sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/MavenPlexusContainer.java index a77e511f7..962cf3c81 100644 --- a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/MavenPlexusContainer.java +++ b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/MavenPlexusContainer.java @@ -15,20 +15,18 @@ */ package org.springframework.sbm.parsers; -import org.apache.maven.graph.GraphBuilder; import org.codehaus.plexus.*; import org.codehaus.plexus.classworlds.ClassWorld; import org.codehaus.plexus.classworlds.realm.ClassRealm; import org.codehaus.plexus.component.repository.exception.ComponentLookupException; import org.springframework.context.annotation.Lazy; -import org.springframework.stereotype.Component; import java.net.URL; @Lazy class MavenPlexusContainer { - public GraphBuilder lookup(Class aClass) { + public T lookup(Class aClass) { try { return ContainerHolder.INSTANCE.lookup(aClass); } catch (ComponentLookupException e) { diff --git a/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/MavenProjectAnalyzerTest.java b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/MavenProjectAnalyzerTest.java new file mode 100644 index 000000000..638de9420 --- /dev/null +++ b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/MavenProjectAnalyzerTest.java @@ -0,0 +1,748 @@ +/* + * Copyright 2021 - 2023 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.parsers; + +import org.apache.maven.execution.MavenSession; +import org.apache.maven.project.MavenProject; +import org.intellij.lang.annotations.Language; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import org.openrewrite.maven.utilities.MavenArtifactDownloader; +import org.springframework.core.io.Resource; +import org.springframework.sbm.test.util.DummyResource; +import org.springframework.sbm.utils.ResourceUtil; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.concurrent.atomic.AtomicReference; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +/** + * @author Fabian Krüger + */ +class MavenProjectAnalyzerTest { + + private MavenProjectAnalyzer sut; + + @BeforeEach + void beforeEach() { + MavenArtifactDownloader rewriteMavenArtifactDownloader = mock(RewriteMavenArtifactDownloader.class); + sut = new MavenProjectAnalyzer(rewriteMavenArtifactDownloader); + } + + @Nested + class CompareWithMaven { + @Test + @DisplayName("compare MavenProject.getCollectedProjects()") + void compareMavenProjectGetCollectedProjects(@TempDir Path tmpDir) { + @Language("xml") + String parentPom = + """ + + + 4.0.0 + com.acme + parent + 0.1.0-SNAPSHOT + pom + + module-a + module-b + parent-b + + + """; + + @Language("xml") + String moduleAPom = + """ + + + 4.0.0 + + com.acme + parent + 0.1.0-SNAPSHOT + + module-a + + """; + + @Language("xml") + String moduleBPom = + """ + + + 4.0.0 + + com.acme + parent + 0.1.0-SNAPSHOT + + module-b + + + com.acme + module-a + ${project.version} + + + + """; + + @Language("xml") + String parentPomB = + """ + + + 4.0.0 + + com.acme + parent + 0.1.0-SNAPSHOT + + parent-b + pom + + module-1 + + + """; + + @Language("xml") + String module1Pom = + """ + + + 4.0.0 + + com.acme + parent-b + 0.1.0-SNAPSHOT + + module-1 + + """; + + Path baseDir = tmpDir; + + List resources = List.of( + new DummyResource(baseDir.resolve("pom.xml"), parentPom), + new DummyResource(baseDir.resolve("module-a/pom.xml"), moduleAPom), + new DummyResource(baseDir.resolve("module-b/pom.xml"), moduleBPom), + new DummyResource(baseDir.resolve("parent-b/pom.xml"), parentPomB), + new DummyResource(baseDir.resolve("parent-b/module-1/pom.xml"), module1Pom) + ); + + writeToDisk(baseDir, resources); + MavenSession mavenSession = startMavenSession(baseDir); + + List mavenSorted = mavenSession.getProjectDependencyGraph().getSortedProjects(); + List sbmSorted = sut.getSortedProjects(baseDir, resources); + + assertThat(mavenSorted).hasSize(5); + assertThat(mavenSorted.size()).isEqualTo(sbmSorted.size()); + + assertThat(mavenSorted.get(0).getGroupId()).isEqualTo("com.acme"); + assertThat(mavenSorted.get(0).getGroupId()).isEqualTo(sbmSorted.get(0).getGroupId()); + + assertThat(mavenSorted.get(0).getArtifactId()).isEqualTo("parent"); + assertThat(mavenSorted.get(0).getArtifactId()).isEqualTo(sbmSorted.get(0).getArtifactId()); + + assertThat(mavenSorted.get(0).getCollectedProjects()).hasSize(4); + assertThat(mavenSorted.get(0).getCollectedProjects().size()).isEqualTo(sbmSorted.get(0).getCollectedProjects().size()); + + List projectsCollectedByMaven = mavenSorted.get(0).getCollectedProjects().stream().map(p -> p.getArtifactId()).toList(); + assertThat(projectsCollectedByMaven).containsExactlyInAnyOrder( + "module-a", "module-b", "module-1", "parent-b" + ); + + assertThat(sbmSorted.get(0).getCollectedProjects().stream().map(p -> p.getArtifactId()).toList()).hasSameElementsAs(projectsCollectedByMaven); + } + + private void writeToDisk(Path baseDir, List resources) { + resources.stream() + .forEach(r -> { + try { + Path resolve = ResourceUtil.getPath(r); + Files.createDirectories(resolve.getParent()); + Files.writeString(resolve, ResourceUtil.getContent(r)); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + ); + } + + private MavenSession startMavenSession(Path baseDir) { + List goals = List.of("clean", "package"); + MavenExecutor mavenExecutor = new MavenExecutor(new MavenExecutionRequestFactory(new MavenConfigFileParser()), new MavenPlexusContainer()); + AtomicReference mavenSession = new AtomicReference<>(); + mavenExecutor.onProjectSucceededEvent(baseDir, goals, event -> mavenSession.set(event.getSession())); + return mavenSession.get(); + } + + } + + + /** + * The simplest possible Maven project. + */ + @Test + @DisplayName("projectWithSinglePom") + void projectWithSinglePom() { + @Language("xml") + String singlePom = + """ + + + 4.0.0 + com.acme + 0.1.0-SNAPSHOT + example + + """; + + List resources = List.of(new DummyResource(Path.of("pom.xml"), singlePom)); + + Path baseDir = Path.of(".").toAbsolutePath().normalize(); + List sortedProjects = sut.getSortedProjects(baseDir, resources); + assertThat(sortedProjects).hasSize(1); + } + + /** + * A simple reactor build with one parent and one module pom. + */ + @Test + @DisplayName("reactorBuild") + void reactorBuild() { + @Language("xml") + String parentPom = + """ + + + 4.0.0 + com.acme + parent + 0.1.0-SNAPSHOT + pom + + example + + + """; + + @Language("xml") + String modulePom = + """ + + + 4.0.0 + + com.acme + parent + 0.1.0-SNAPSHOT + + example + + """; + + List resources = List.of( + new DummyResource(Path.of("pom.xml"), parentPom), + new DummyResource(Path.of("example/pom.xml"), modulePom) + ); + + + List sortedProjects = sut.getSortedProjects(Path.of(".").toAbsolutePath(), resources); + + assertThat(sortedProjects).hasSize(2); + + String parentPomPath = Path.of(".").toAbsolutePath().normalize().toString(); + assertThat(sortedProjects.get(0).getBasedir().toString()).isEqualTo(parentPomPath); + + String modulePomPath = Path.of(".").resolve("example").toAbsolutePath().normalize().toString(); + assertThat(sortedProjects.get(1).getBasedir().toString()).isEqualTo(modulePomPath); + } + + /** + * Two pom files building a rector build should be returned. + * The dangling pom not belonging to the reactor build defined through parent pom will be ignored. + */ + @Test + @DisplayName("reactorBuildWithDanglingPom") + void reactorBuildWithDanglingPom() { + @Language("xml") + String parentPom = + """ + + + 4.0.0 + com.acme + parent + 0.1.0-SNAPSHOT + pom + + example + + + """; + + @Language("xml") + String modulePom = + """ + + + 4.0.0 + + com.acme + parent + 0.1.0-SNAPSHOT + + example + + """; + + @Language("xml") + String danglingPom = + """ + + + 4.0.0 + com.acme + dangling + 0.1.0-SNAPSHOT + + """; + + List resources = List.of( + new DummyResource(Path.of("pom.xml"), parentPom), + new DummyResource(Path.of("example/pom.xml"), modulePom), + new DummyResource(Path.of("dangling/pom.xml"), danglingPom) + ); + + + List sortedProjects = sut.getSortedProjects(Path.of(".").toAbsolutePath(), resources); + + assertThat(sortedProjects).hasSize(2); + + String parentPomPath = Path.of(".").toAbsolutePath().normalize().toString(); + assertThat(sortedProjects.get(0).getBasedir().toString()).isEqualTo(parentPomPath); + + String modulePomPath = Path.of(".").resolve("example").toAbsolutePath().normalize().toString(); + assertThat(sortedProjects.get(1).getBasedir().toString()).isEqualTo(modulePomPath); + } + + /** + * A project with three Maven pom files. + * Two of them build a reactor. + * The third is not part of the reactor but a dependency of the child module in the reactor build. + */ + @Test + @DisplayName("reactorBuildWithDanglingPomWhichAReactorModuleDependsOn") + void reactorBuildWithDanglingPomWhichAReactorModuleDependsOn() { + @Language("xml") + String parentPom = + """ + + + 4.0.0 + com.acme + parent + 0.1.0-SNAPSHOT + pom + + example + + + """; + + @Language("xml") + String modulePom = + """ + + + 4.0.0 + + com.acme + parent + 0.1.0-SNAPSHOT + + example + + + com.acme + dangling + 0.1.0-SNAPSHOT + + + + """; + + @Language("xml") + String danglingPom = + """ + + + 4.0.0 + com.acme + dangling + 0.1.0-SNAPSHOT + + """; + + List resources = List.of( + new DummyResource(Path.of("pom.xml"), parentPom), + new DummyResource(Path.of("example/pom.xml"), modulePom), + new DummyResource(Path.of("dangling/pom.xml"), danglingPom) + ); + + + List sortedProjects = sut.getSortedProjects(Path.of(".").toAbsolutePath(), resources); + + assertThat(sortedProjects).hasSize(2); + + String parentPomPath = Path.of(".").toAbsolutePath().normalize().toString(); + assertThat(sortedProjects.get(0).getBasedir().toString()).isEqualTo(parentPomPath); + + String modulePomPath = Path.of(".").resolve("example").toAbsolutePath().normalize().toString(); + assertThat(sortedProjects.get(1).getBasedir().toString()).isEqualTo(modulePomPath); + } + + /** + * A reactor project with four modules provided in "wrong" order. + * The returned order differs and reflects the order of the modules in reactor build. + */ + @Test + @DisplayName("theReactorBuildOrderIsReturned") + void theReactorBuildOrderIsReturned() { + @Language("xml") + String parentPom = """ + + + 4.0.0 + com.acme + parent + pom + 0.1.0-SNAPSHOT + + module-a + module-b + module-c + + + """; + + @Language("xml") + String moduleAPom = """ + + + 4.0.0 + + com.acme + parent + 0.1.0-SNAPSHOT + + module-a + + """; + + @Language("xml") + String moduleBPom = """ + + + 4.0.0 + + com.acme + parent + 0.1.0-SNAPSHOT + + module-b + + """; + + @Language("xml") + String moduleCPom = """ + + + 4.0.0 + + com.acme + parent + 0.1.0-SNAPSHOT + + module-c + + """; + + // Provided unordered + List resources = List.of( + new DummyResource(Path.of("module-b/pom.xml"), moduleBPom), + new DummyResource(Path.of("module-a/pom.xml"), moduleAPom), + new DummyResource(Path.of("module-c/pom.xml"), moduleCPom), + new DummyResource(Path.of("pom.xml"), parentPom) + ); + + + List sortedProjects = sut.getSortedProjects(Path.of(".").toAbsolutePath(), resources); + + // Returned ordered + assertThat(sortedProjects).hasSize(4); + assertThat(sortedProjects.get(0).getModuleDir().toString()).isEqualTo(""); + assertThat(sortedProjects.get(1).getModuleDir().toString()).isEqualTo("module-a"); + assertThat(sortedProjects.get(2).getModuleDir().toString()).isEqualTo("module-b"); + assertThat(sortedProjects.get(3).getModuleDir().toString()).isEqualTo("module-c"); + } + + /** + * Provided unordered list of resources + * Order in modules is not correct + * Order is defined by dependencies + */ + @Test + @DisplayName("moreComplex") + void moreComplex() { + + // Modules declared in order a,b,c + @Language("xml") + String parentPom = """ + + + 4.0.0 + com.acme + parent + 0.1.0-SNAPSHOT + pom + + module-a + module-b + module-c + + + """; + + // Module A depends on C, so C must be built first effectively changing the order in + @Language("xml") + String moduleAPom = """ + + + 4.0.0 + + com.acme + parent + 0.1.0-SNAPSHOT + + module-a + + + com.acme + module-c + 0.1.0-SNAPSHOT + + + + """; + + @Language("xml") + String moduleBPom = """ + + + 4.0.0 + + com.acme + parent + 0.1.0-SNAPSHOT + + module-b + + """; + + // C depends on B + @Language("xml") + String moduleCPom = """ + + + 4.0.0 + + com.acme + parent + 0.1.0-SNAPSHOT + + module-c + + + com.acme + module-b + 0.1.0-SNAPSHOT + + + + """; + + + + List resources = List.of( + new DummyResource(Path.of("module-b/pom.xml"), moduleBPom), + new DummyResource(Path.of("module-a/pom.xml"), moduleAPom), + new DummyResource(Path.of("module-c/pom.xml"), moduleCPom), + new DummyResource(Path.of("pom.xml"), parentPom) + ); + + + // Provided unordered + List sortedProjects = sut.getSortedProjects(Path.of(".").toAbsolutePath(), resources); + + // Expected order is parent, module-b, module-c, module-a + assertThat(sortedProjects).hasSize(4); + + assertThat(sortedProjects.get(0).getModuleDir().toString()).isEqualTo(""); + assertThat(sortedProjects.get(1).getModuleDir().toString()).isEqualTo("module-b"); + assertThat(sortedProjects.get(2).getModuleDir().toString()).isEqualTo("module-c"); + assertThat(sortedProjects.get(3).getModuleDir().toString()).isEqualTo("module-a"); + } + + @Test + @DisplayName("sortModels") + void sortModels() { + + + // Modules declared in order a,b,c + @Language("xml") + String parentPom = """ + + + 4.0.0 + com.acme + parent + 0.1.0-SNAPSHOT + pom + + module-a + module-b + module-c + + + """; + + // Module A depends on C, so C must be built first effectively changing the order in + @Language("xml") + String moduleAPom = """ + + + 4.0.0 + + com.acme + parent + 0.1.0-SNAPSHOT + + module-a + + + com.acme + module-c + 0.1.0-SNAPSHOT + + + + """; + + @Language("xml") + String moduleBPom = """ + + + 4.0.0 + + com.acme + parent + 0.1.0-SNAPSHOT + + module-b + + """; + + // C depends on B + @Language("xml") + String moduleCPom = """ + + + 4.0.0 + + com.acme + parent + 0.1.0-SNAPSHOT + + module-c + + + com.acme + module-b + 0.1.0-SNAPSHOT + + + + """; + + // Provided unordered + List models = List.of( + new MavenProjectAnalyzer.Model(new DummyResource(Path.of("module-b/pom.xml"), moduleBPom)), + new MavenProjectAnalyzer.Model(new DummyResource(Path.of("module-a/pom.xml"), moduleAPom)), + new MavenProjectAnalyzer.Model(new DummyResource(Path.of("module-c/pom.xml"), moduleCPom)), + new MavenProjectAnalyzer.Model(new DummyResource(Path.of("pom.xml"), parentPom)) + ); + + // Expected order is parent, module-b, module-c, module-a + List sorted = sut.sortModels(models); + assertThat(sorted.get(0).getArtifactId()).isEqualTo("parent"); + assertThat(sorted.get(1).getArtifactId()).isEqualTo("module-b"); + assertThat(sorted.get(2).getArtifactId()).isEqualTo("module-c"); + assertThat(sorted.get(3).getArtifactId()).isEqualTo("module-a"); + } + + // TODO: Test with parent pom that has boot-starter as parent +} \ No newline at end of file diff --git a/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/ParserEventPublicationIntegrationTest.java b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/ParserEventPublicationIntegrationTest.java index f63e4337b..3e605cbdf 100644 --- a/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/ParserEventPublicationIntegrationTest.java +++ b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/ParserEventPublicationIntegrationTest.java @@ -51,6 +51,9 @@ public class ParserEventPublicationIntegrationTest { @Autowired ParserProperties parserProperties; + @Autowired + ExecutionContext executionContext; + private static List capturedEvents = new ArrayList<>(); private static StartedParsingProjectEvent startedParsingEvent; private static SuccessfullyParsedProjectEvent finishedParsingEvent; @@ -59,13 +62,22 @@ public class ParserEventPublicationIntegrationTest { @DisplayName("Should publish parsing events") void shouldPublishParsingEvents() { Path baseDir = Path.of("./testcode/maven-projects/multi-module-events"); - parserProperties.setIgnoredPathPatterns(Set.of("{**/target,target}", "**.adoc")); + parserProperties.setIgnoredPathPatterns(Set.of("{**/target/**,target/**}", "**.adoc")); List resources = projectScanner.scan(baseDir); - ExecutionContext ctx = new InMemoryExecutionContext(t -> {throw new RuntimeException(t);}); - RewriteProjectParsingResult parsingResult = sut.parse(baseDir, resources, ctx); + RewriteProjectParsingResult parsingResult = sut.parse(baseDir, resources, executionContext); + + assertThat(parsingResult.sourceFiles()).hasSize(5); + assertThat(parsingResult.sourceFiles().stream().map(s -> s.getSourcePath().toString()).toList()) + .containsExactly( + "pom.xml", + "module-b/pom.xml", + "module-a/pom.xml", + "module-b/src/test/resources/application.yaml", + "module-a/src/main/java/com/acme/SomeClass.java" + ); - assertThat(capturedEvents).hasSize(4); + assertThat(capturedEvents).hasSize(5); assertThat(capturedEvents.get(0).sourceFile().getSourcePath().toString()) .isEqualTo("pom.xml"); @@ -74,6 +86,8 @@ void shouldPublishParsingEvents() { assertThat(capturedEvents.get(2).sourceFile().getSourcePath().toString()) .isEqualTo("module-a/pom.xml"); assertThat(capturedEvents.get(3).sourceFile().getSourcePath().toString()) + .isEqualTo("module-b/src/test/resources/application.yaml"); + assertThat(capturedEvents.get(4).sourceFile().getSourcePath().toString()) .isEqualTo("module-a/src/main/java/com/acme/SomeClass.java"); // ResourceParser not firing events // TODO: reactivate after https://github.com/openrewrite/rewrite-maven-plugin/issues/622 diff --git a/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/ProvenanceMarkerFactoryTest.java b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/ProvenanceMarkerFactoryTest.java index 9cb30a29c..56a2e74d0 100644 --- a/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/ProvenanceMarkerFactoryTest.java +++ b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/ProvenanceMarkerFactoryTest.java @@ -74,13 +74,13 @@ void testMavenMojoProjectParserGenerateProvenance() { MavenMojoProjectParserFactory mavenMojoProjectParserFactory = new MavenMojoProjectParserFactory(new ParserProperties()); MavenMojoProjectParser sut = mavenMojoProjectParserFactory.create(baseDir, runtimeInformation, settingsDecrypter); - // the sut requires a MavenProject, let's retrieve it from Maven + // the sut requires a SbmMavenProject, let's retrieve it from Maven MavenExecutor mavenExecutor = new MavenExecutor(new MavenExecutionRequestFactory(new MavenConfigFileParser()), new MavenPlexusContainer()); // doing a 'mvn clean install' mavenExecutor.onProjectSucceededEvent(baseDir, List.of("clean", "package"), event -> { - // and then use the MavenProject from the MavenSession + // and then use the SbmMavenProject from the MavenSession MavenProject mavenModel = event.getSession().getCurrentProject(); // to call the sut @@ -169,36 +169,36 @@ void shouldCreateProvenanceMarkers(@TempDir Path tempDir) { MavenMojoProjectParser mojoProjectParser = mock(MavenMojoProjectParser.class); when(parserFactory.create(isA(Path.class), isA(DefaultRuntimeInformation.class), isNull())).thenReturn(mojoProjectParser); - ProvenanceMarkerFactory sut = new ProvenanceMarkerFactory(parserFactory); - - SortedProjects sortedProjects = mock(SortedProjects.class); - MavenProject mavenProject1 = mock(MavenProject.class); - MavenProject mavenProject2 = mock(MavenProject.class); - List mavenProjects = List.of( - mavenProject1, - mavenProject2 + ParserContext sortedProjects = mock(ParserContext.class); + SbmMavenProject sbmMavenProject1 = mock(SbmMavenProject.class); + SbmMavenProject sbmMavenProject2 = mock(SbmMavenProject.class); + List sbmMavenProjects = List.of( + sbmMavenProject1, + sbmMavenProject2 ); // The provided TopologicallySortedProjects instance will // provide the sorted MavenProjects - when(sortedProjects.getSortedProjects()).thenReturn(mavenProjects); + when(sortedProjects.getSortedProjects()).thenReturn(sbmMavenProjects); // internally the Maven projects will be matched with the provided resources Path path1 = Path.of("some/path").toAbsolutePath().normalize(); - // path1 matches with mavenProject1 - when(sortedProjects.getMatchingBuildFileResource(mavenProject1)).thenReturn(new DummyResource(path1, "")); + // path1 matches with sbmMavenProject1 + when(sortedProjects.getMatchingBuildFileResource(sbmMavenProject1)).thenReturn(new DummyResource(path1, "")); Path path2 = Path.of("some/other").toAbsolutePath().normalize(); - // path2 matches with mavenProject2 - when(sortedProjects.getMatchingBuildFileResource(mavenProject2)).thenReturn(new DummyResource(path2, "")); + // path2 matches with sbmMavenProject2 + when(sortedProjects.getMatchingBuildFileResource(sbmMavenProject2)).thenReturn(new DummyResource(path2, "")); List markers1 = List.of(); List markers2 = List.of(); - when(mojoProjectParser.generateProvenance(mavenProject1)).thenReturn(markers1); - when(mojoProjectParser.generateProvenance(mavenProject2)).thenReturn(markers2); - - Map> resourceListMap = sut.generateProvenanceMarkers(baseDir, sortedProjects); - - assertThat(resourceListMap.get(path1)).isEqualTo(markers1); - assertThat(resourceListMap.get(path2)).isEqualTo(markers2); + // FIXME: 945 +// when(mojoProjectParser.generateProvenance(sbmMavenProject1)).thenReturn(markers1); + // FIXME: 945 +// when(mojoProjectParser.generateProvenance(sbmMavenProject2)).thenReturn(markers2); + // FIXME: 945 +// Map> resourceListMap = sut.generateProvenanceMarkers(baseDir, sortedProjects); + // FIXME: 945 +// assertThat(resourceListMap.get(path1)).isEqualTo(markers1); +// assertThat(resourceListMap.get(path2)).isEqualTo(markers2); } /** diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/RewriteMavenProjectParser.java b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/RewriteMavenProjectParser.java similarity index 100% rename from sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/RewriteMavenProjectParser.java rename to sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/RewriteMavenProjectParser.java diff --git a/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/RewriteMavenProjectParserIntegrationTest.java b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/RewriteMavenProjectParserIntegrationTest.java index de0ca36f3..b9531e261 100644 --- a/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/RewriteMavenProjectParserIntegrationTest.java +++ b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/RewriteMavenProjectParserIntegrationTest.java @@ -22,6 +22,7 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.TestConfiguration; import org.springframework.context.event.EventListener; +import org.springframework.sbm.boot.autoconfigure.SbmSupportRewriteConfiguration; import org.springframework.sbm.boot.autoconfigure.ScannerConfiguration; import org.springframework.sbm.parsers.events.FinishedParsingResourceEvent; @@ -34,7 +35,7 @@ /** * @author Fabian Krüger */ -@SpringBootTest(classes = {ScannerConfiguration.class, RewriteMavenProjectParserIntegrationTest.TestEventListener.class}) +@SpringBootTest(classes = {SbmSupportRewriteConfiguration.class, SbmTestConfiguration.class}) public class RewriteMavenProjectParserIntegrationTest { @Autowired diff --git a/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/RewriteMavenProjectParserTest.java b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/RewriteMavenProjectParserTest.java index 4d2fbd02f..097668d07 100644 --- a/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/RewriteMavenProjectParserTest.java +++ b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/RewriteMavenProjectParserTest.java @@ -40,7 +40,6 @@ import org.openrewrite.maven.MavenExecutionContextView; import org.openrewrite.maven.MavenSettings; import org.openrewrite.maven.cache.*; -import org.openrewrite.maven.cache.InMemoryMavenPomCache; import org.openrewrite.maven.cache.LocalMavenArtifactCache; import org.openrewrite.maven.cache.MavenArtifactCache; import org.openrewrite.maven.tree.MavenResolutionResult; @@ -277,14 +276,13 @@ void parseMultiModule1_WithCustomParser() { MavenArtifactCache mavenArtifactCache = new LocalMavenArtifactCache(Paths.get(System.getProperty("user.home"), ".m2", "repository")); @Nullable MavenSettings mavenSettings = null; Consumer onError = (t) -> {throw new RuntimeException(t);}; - MavenMojoProjectParserPrivateMethods mavenMojoParserPrivateMethods = new MavenMojoProjectParserPrivateMethods(mavenMojoProjectParserFactory, new RewriteMavenArtifactDownloader(mavenArtifactCache, mavenSettings, onError)); + HelperWithoutAGoodName helperWithoutAGoodName = new HelperWithoutAGoodName(); JavaParserBuilder javaParserBuilder = new JavaParserBuilder(); RewriteProjectParser rpp = new RewriteProjectParser( - new MavenExecutor(new MavenExecutionRequestFactory(new MavenConfigFileParser()), new MavenPlexusContainer()), - new ProvenanceMarkerFactory(mavenMojoProjectParserFactory), + new ProvenanceMarkerFactory(new MavenProvenanceMarkerFactory()), new BuildFileParser(), - new SourceFileParser(parserProperties, mavenMojoParserPrivateMethods, javaParserBuilder), + new SourceFileParser(parserProperties, helperWithoutAGoodName), new StyleDetector(), parserProperties, mock(ParsingEventListener.class), @@ -292,7 +290,8 @@ void parseMultiModule1_WithCustomParser() { scanScope, beanFactory, new ProjectScanner(new DefaultResourceLoader(), parserProperties), - ctx + ctx, + new MavenProjectAnalyzer(mock(RewriteMavenArtifactDownloader.class)) ); Set ignoredPatters = Set.of(); diff --git a/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/RewriteProjectParserIntegrationTest.java b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/RewriteProjectParserIntegrationTest.java index a68e06b54..b2aa8f7d6 100644 --- a/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/RewriteProjectParserIntegrationTest.java +++ b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/RewriteProjectParserIntegrationTest.java @@ -22,12 +22,15 @@ import org.openrewrite.java.tree.J; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.TestConfiguration; import org.springframework.core.io.Resource; +import org.springframework.sbm.boot.autoconfigure.SbmSupportRewriteConfiguration; import org.springframework.sbm.boot.autoconfigure.ScannerConfiguration; import org.springframework.sbm.parsers.events.FinishedParsingResourceEvent; import org.springframework.sbm.parsers.events.StartedParsingProjectEvent; import org.springframework.sbm.parsers.events.SuccessfullyParsedProjectEvent; import org.springframework.sbm.boot.autoconfigure.ScannerConfiguration; +import org.springframework.sbm.test.util.TestProjectHelper; import java.nio.file.Path; import java.util.ArrayList; @@ -38,7 +41,7 @@ /** * @author Fabian Krüger */ -@SpringBootTest(classes = {ScannerConfiguration.class}) +@SpringBootTest(classes = {SbmSupportRewriteConfiguration.class, SbmTestConfiguration.class}) public class RewriteProjectParserIntegrationTest { @Autowired @@ -53,7 +56,7 @@ public class RewriteProjectParserIntegrationTest { @Test @DisplayName("parseCheckstyle") void parseCheckstyle() { - Path baseDir = getMavenProject("checkstyle"); + Path baseDir = TestProjectHelper.getMavenProject("checkstyle"); List resources = projectScanner.scan(baseDir); RewriteProjectParsingResult parsingResult = sut.parse(baseDir, resources, new InMemoryExecutionContext(t -> {throw new RuntimeException(t);})); assertThat(parsingResult.sourceFiles().stream().map(sf -> sf.getSourcePath().toString()).toList()).contains("checkstyle/rules.xml"); @@ -74,11 +77,11 @@ void testFailingProject() { @Test @DisplayName("parseResources") void parseResources() { - Path baseDir = getMavenProject("resources"); + Path baseDir = TestProjectHelper.getMavenProject("resources"); List resources = projectScanner.scan(baseDir); - RewriteProjectParsingResult parsingResult1 = mavenProjectParser.parse(baseDir); - assertThat(parsingResult1.sourceFiles()).hasSize(5); +// RewriteProjectParsingResult parsingResult1 = mavenProjectParser.parse(baseDir); +// assertThat(parsingResult1.sourceFiles()).hasSize(5); RewriteProjectParsingResult parsingResult = sut.parse(baseDir, resources, new InMemoryExecutionContext(t -> { throw new RuntimeException(t); @@ -89,7 +92,7 @@ void parseResources() { @Test @DisplayName("parse4Modules") void parse4Modules() { - Path baseDir = getMavenProject("4-modules"); + Path baseDir = TestProjectHelper.getMavenProject("4-modules"); List resources = projectScanner.scan(baseDir); assertThat(resources).hasSize(4); @@ -98,8 +101,4 @@ void parse4Modules() { assertThat(parsingResult.sourceFiles()).hasSize(4); } - private Path getMavenProject(String s) { - return Path.of("./testcode/maven-projects/").resolve(s).toAbsolutePath().normalize(); - } - } diff --git a/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/RewriteProjectParserTest.java b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/RewriteProjectParserTest.java index 9a8a09aef..32792270b 100644 --- a/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/RewriteProjectParserTest.java +++ b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/RewriteProjectParserTest.java @@ -101,13 +101,12 @@ void parseSimpleMavenProject(@TempDir Path tempDir) { Consumer onError = (t) -> { throw new RuntimeException(t); }; - MavenMojoProjectParserPrivateMethods mavenMojoParserPrivateMethods = new MavenMojoProjectParserPrivateMethods(mavenMojoProjectParserFactory, new RewriteMavenArtifactDownloader(mavenArtifactCache, mavenSettings, onError)); + HelperWithoutAGoodName mavenMojoParserPrivateMethods = new HelperWithoutAGoodName(); ExecutionContext executionContext = new InMemoryExecutionContext(t -> {throw new RuntimeException(t);}); RewriteProjectParser projectParser = new RewriteProjectParser( - new MavenExecutor(new MavenExecutionRequestFactory(new MavenConfigFileParser()), new MavenPlexusContainer()), - new ProvenanceMarkerFactory(mavenMojoProjectParserFactory), + new ProvenanceMarkerFactory(new MavenProvenanceMarkerFactory()), new BuildFileParser(), - new SourceFileParser(parserProperties, mavenMojoParserPrivateMethods, new JavaParserBuilder()), + new SourceFileParser(parserProperties, mavenMojoParserPrivateMethods), new StyleDetector(), parserProperties, mock(ParsingEventListener.class), @@ -115,7 +114,8 @@ void parseSimpleMavenProject(@TempDir Path tempDir) { new ScanScope(), mock(ConfigurableListableBeanFactory.class), new ProjectScanner(new DefaultResourceLoader(), parserProperties), - executionContext + executionContext, + new MavenProjectAnalyzer(mock(RewriteMavenArtifactDownloader.class)) ); List parsedFiles = new ArrayList<>(); diff --git a/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/MavenProjectResolutionTest.java b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/SbmMavenProjectResolutionTest.java similarity index 98% rename from sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/MavenProjectResolutionTest.java rename to sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/SbmMavenProjectResolutionTest.java index d67bfc0ce..3e160e037 100644 --- a/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/MavenProjectResolutionTest.java +++ b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/SbmMavenProjectResolutionTest.java @@ -32,10 +32,10 @@ /** * @author Fabian Krüger */ -class MavenProjectResolutionTest { +class SbmMavenProjectResolutionTest { @Test - @DisplayName("Factory should create fully initialized MavenProject") + @DisplayName("Factory should create fully initialized SbmMavenProject") void verifyMavenProjectRetrievedFromSession(@TempDir Path tempDir) throws Exception { @Language("xml") String pomXml = """ diff --git a/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/SbmTestConfiguration.java b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/SbmTestConfiguration.java new file mode 100644 index 000000000..c1b2ad37d --- /dev/null +++ b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/SbmTestConfiguration.java @@ -0,0 +1,90 @@ +/* + * Copyright 2021 - 2023 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.parsers; + +import lombok.extern.slf4j.Slf4j; +import org.openrewrite.ExecutionContext; +import org.openrewrite.maven.utilities.MavenArtifactDownloader; +import org.openrewrite.tree.ParsingEventListener; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Import; +import org.springframework.sbm.scopes.ScanScope; + +import static org.mockito.Mockito.mock; + +/** + * @author Fabian Krüger + */ +@TestConfiguration +@Slf4j +@Import(RewriteParserConfiguration.class) +public class SbmTestConfiguration { + + @Autowired + private ParserProperties parserProperties; + + @Bean + MavenMojoProjectParserPrivateMethods mavenMojoProjectParserPrivateMethods(MavenMojoProjectParserFactory parserFactory, MavenArtifactDownloader artifactDownloader) { + return new MavenMojoProjectParserPrivateMethods(parserFactory, artifactDownloader); + } + + + @Bean + MavenConfigFileParser configFileParser() { + return new MavenConfigFileParser(); + } + + @Bean + MavenExecutionRequestFactory requestFactory(MavenConfigFileParser configFileParser) { + return new MavenExecutionRequestFactory(configFileParser); + } + + @Bean + MavenExecutor mavenExecutor(MavenExecutionRequestFactory requestFactory, MavenPlexusContainer plexusContainer) { + return new MavenExecutor(requestFactory, plexusContainer); + } + + @Bean + MavenMojoProjectParserFactory projectParserFactory() { + return new MavenMojoProjectParserFactory(parserProperties); + } + + @Bean + MavenPlexusContainer plexusContainer() { + return new MavenPlexusContainer(); + } + + @Bean + MavenModelReader modelReader() { + return new MavenModelReader(); + } + + @Bean + RewriteMavenProjectParser rewriteMavenProjectParser(MavenPlexusContainer plexusContainer, ParsingEventListener parsingEventListenerAdapter, MavenExecutor mavenExecutor, MavenMojoProjectParserFactory mavenMojoProjectParserFactory, ScanScope scanScope, ConfigurableListableBeanFactory beanFactory, ExecutionContext executionContext) { + return new RewriteMavenProjectParser( + plexusContainer, + parsingEventListenerAdapter, + mavenExecutor, + mavenMojoProjectParserFactory, + scanScope, + beanFactory, + executionContext + ); + } +} diff --git a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/Slf4jToMavenLoggerAdapter.java b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/Slf4jToMavenLoggerAdapter.java similarity index 97% rename from sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/Slf4jToMavenLoggerAdapter.java rename to sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/Slf4jToMavenLoggerAdapter.java index 046b580db..5b0545f2e 100644 --- a/sbm-support-rewrite/src/main/java/org/springframework/sbm/parsers/Slf4jToMavenLoggerAdapter.java +++ b/sbm-support-rewrite/src/test/java/org/springframework/sbm/parsers/Slf4jToMavenLoggerAdapter.java @@ -21,7 +21,7 @@ /** * @author Fabian Krüger */ -class Slf4jToMavenLoggerAdapter implements Log { +public class Slf4jToMavenLoggerAdapter implements Log { private final Logger log; public Slf4jToMavenLoggerAdapter(Logger log) { diff --git a/sbm-support-rewrite/src/test/java/org/springframework/sbm/test/util/TestProjectHelper.java b/sbm-support-rewrite/src/test/java/org/springframework/sbm/test/util/TestProjectHelper.java new file mode 100644 index 000000000..fa323de37 --- /dev/null +++ b/sbm-support-rewrite/src/test/java/org/springframework/sbm/test/util/TestProjectHelper.java @@ -0,0 +1,27 @@ +/* + * Copyright 2021 - 2023 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.test.util; + +import java.nio.file.Path; + +/** + * @author Fabian Krüger + */ +public class TestProjectHelper { + public static Path getMavenProject(String s) { + return Path.of("./testcode/maven-projects/").resolve(s).toAbsolutePath().normalize(); + } +} diff --git a/sbm-support-rewrite/testcode/maven-projects/classpath-test/example-1/module-a/pom.xml b/sbm-support-rewrite/testcode/maven-projects/classpath-test/example-1/module-a/pom.xml new file mode 100644 index 000000000..d78510fc7 --- /dev/null +++ b/sbm-support-rewrite/testcode/maven-projects/classpath-test/example-1/module-a/pom.xml @@ -0,0 +1,28 @@ + + + 4.0.0 + + com.example + example-1-parent + 0.1.0-SNAPSHOT + + module-a + + 17 + 17 + + + + com.example + module-b + ${project.version} + + + javax.validation + validation-api + 2.0.1.Final + + + + diff --git a/sbm-support-rewrite/testcode/maven-projects/classpath-test/example-1/module-a/src/main/java/com/example/ModuleA.java b/sbm-support-rewrite/testcode/maven-projects/classpath-test/example-1/module-a/src/main/java/com/example/ModuleA.java new file mode 100644 index 000000000..2f0222c8f --- /dev/null +++ b/sbm-support-rewrite/testcode/maven-projects/classpath-test/example-1/module-a/src/main/java/com/example/ModuleA.java @@ -0,0 +1,4 @@ +package com.example; +public class ModuleA extends ModuleB { + +} \ No newline at end of file diff --git a/sbm-support-rewrite/testcode/maven-projects/classpath-test/example-1/module-b/pom.xml b/sbm-support-rewrite/testcode/maven-projects/classpath-test/example-1/module-b/pom.xml new file mode 100644 index 000000000..c02acadc7 --- /dev/null +++ b/sbm-support-rewrite/testcode/maven-projects/classpath-test/example-1/module-b/pom.xml @@ -0,0 +1,15 @@ + + + 4.0.0 + + com.example + example-1-parent + 0.1.0-SNAPSHOT + + module-b + + 17 + 17 + + diff --git a/sbm-support-rewrite/testcode/maven-projects/classpath-test/example-1/module-b/src/main/java/com/example/ModuleB.java b/sbm-support-rewrite/testcode/maven-projects/classpath-test/example-1/module-b/src/main/java/com/example/ModuleB.java new file mode 100644 index 000000000..eb093f173 --- /dev/null +++ b/sbm-support-rewrite/testcode/maven-projects/classpath-test/example-1/module-b/src/main/java/com/example/ModuleB.java @@ -0,0 +1,5 @@ +package com.example; + +public class ModuleB { + +} \ No newline at end of file diff --git a/sbm-support-rewrite/testcode/maven-projects/classpath-test/example-1/pom.xml b/sbm-support-rewrite/testcode/maven-projects/classpath-test/example-1/pom.xml new file mode 100644 index 000000000..403606457 --- /dev/null +++ b/sbm-support-rewrite/testcode/maven-projects/classpath-test/example-1/pom.xml @@ -0,0 +1,18 @@ + + + 4.0.0 + + com.example + example-1-parent + 0.1.0-SNAPSHOT + pom + + 17 + 17 + + + module-a + module-b + + +