diff --git a/doc/design.md b/doc/design.md index 4162b053..09fbbe2b 100644 --- a/doc/design.md +++ b/doc/design.md @@ -166,6 +166,20 @@ Covers: Needs: impl, itest +#### Excluding Implicit Plugins from Dependencies.md + +`dsn~dependency.md-file-validator-excludes-implicit-plugins~1` + +PK excludes implicit plugins from `dependencies.md`. + +Background: + +Maven implicitly adds plugins like `org.apache.maven.plugins:maven-clean-plugin` due to the Maven lifecycle. The version of these plugins depends on the Maven version. Each plugin version defines its own name and license which is included in `dependencies.md`. That means the content of `dependencies.md` depends on the Maven version, causing build failures when using a different Maven version, see [issue #436](https://github.com/exasol/project-keeper/issues/436). + +One workaround is pinning the Maven version using `maven-enforcer-plugin` but this causes problems on developer's machines. That's why we decided to remove these implicit plugins from `dependencies.md`. + +Needs: impl, utest, itest + ### Readme.md File Validator `dsn~readme-validator~1` diff --git a/maven-project-crawler/pom.xml b/maven-project-crawler/pom.xml index 1c6a6562..1aaa3581 100644 --- a/maven-project-crawler/pom.xml +++ b/maven-project-crawler/pom.xml @@ -80,6 +80,11 @@ mockito-core test + + org.mockito + mockito-junit-jupiter + test + com.exasol maven-plugin-integration-testing diff --git a/maven-project-crawler/src/main/java/com/exasol/projectkeeper/validators/dependencies/ProjectDependencyReader.java b/maven-project-crawler/src/main/java/com/exasol/projectkeeper/validators/dependencies/ProjectDependencyReader.java index 7ed09dc5..2a6c76d0 100644 --- a/maven-project-crawler/src/main/java/com/exasol/projectkeeper/validators/dependencies/ProjectDependencyReader.java +++ b/maven-project-crawler/src/main/java/com/exasol/projectkeeper/validators/dependencies/ProjectDependencyReader.java @@ -42,7 +42,8 @@ public ProjectDependencyReader(final MavenModelFromRepositoryReader artifactMode */ public ProjectDependencies readDependencies() { final List dependencies = getDependenciesIncludingPlugins() - .map(dependency -> getLicense(dependency, project)).collect(Collectors.toList()); + .map(dependency -> getLicense(dependency, project)) // + .collect(Collectors.toList()); return new ProjectDependencies(dependencies); } @@ -86,6 +87,7 @@ private Stream getPluginDependencies() { * @param plugin the plugin to check * @return {@code true} if the plugin is explicitly added to the build */ + // [impl -> dsn~dependency.md-file-validator-excludes-implicit-plugins~1] private boolean isExplicitPlugin(final Plugin plugin) { final String location = plugin.getLocation("").getSource().getLocation(); return location != null; diff --git a/maven-project-crawler/src/test/java/com/exasol/projectkeeper/dependencies/ProjectDependencyReaderTest.java b/maven-project-crawler/src/test/java/com/exasol/projectkeeper/dependencies/ProjectDependencyReaderTest.java new file mode 100644 index 00000000..a17224ed --- /dev/null +++ b/maven-project-crawler/src/test/java/com/exasol/projectkeeper/dependencies/ProjectDependencyReaderTest.java @@ -0,0 +1,90 @@ +package com.exasol.projectkeeper.dependencies; + +import static java.util.Collections.emptyList; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.empty; +import static org.mockito.ArgumentMatchers.anyList; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +import java.util.List; + +import org.apache.maven.model.*; +import org.apache.maven.project.MavenProject; +import org.apache.maven.project.ProjectBuildingException; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import com.exasol.projectkeeper.pom.MavenModelFromRepositoryReader; +import com.exasol.projectkeeper.shared.dependencies.BaseDependency.Type; +import com.exasol.projectkeeper.shared.dependencies.License; +import com.exasol.projectkeeper.shared.dependencies.ProjectDependency; +import com.exasol.projectkeeper.validators.dependencies.ProjectDependencyReader; + +@ExtendWith(MockitoExtension.class) +class ProjectDependencyReaderTest { + + @Mock + MavenModelFromRepositoryReader artifactModelReaderMock; + + private List readDependencies(final List plugins) { + final MavenProject project = new MavenProject(new Model()); + project.getModel().setBuild(new Build()); + project.getModel().getBuild().setPlugins(plugins); + return new ProjectDependencyReader(artifactModelReaderMock, project).readDependencies().getDependencies(); + } + + @Test + void noDependencies() { + assertThat(readDependencies(emptyList()), empty()); + } + + @Test + void explicitPlugin() throws ProjectBuildingException { + simulateDependencies("group", "art", "ver", "website", List.of(mavenLicense("license", "licenseUrl"))); + + assertThat(readDependencies(List.of(plugin("group", "art", "ver", "no-null"))), + contains(ProjectDependency.builder().type(Type.PLUGIN).name("name:group:art").websiteUrl("website") + .licenses(List.of(new License("license", "licenseUrl"))).build())); + } + + // [utest -> dsn~dependency.md-file-validator-excludes-implicit-plugins~1] + @Test + void implicitPlugin() throws ProjectBuildingException { + assertThat(readDependencies(List.of(plugin("group", "art", "ver", null))), empty()); + } + + private void simulateDependencies(final String groupId, final String artifactId, final String version, + final String url, final List licenses) throws ProjectBuildingException { + final Model model = new Model(); + model.setArtifactId(artifactId); + model.setGroupId(groupId); + model.setVersion(version); + model.setName("name:" + groupId + ":" + artifactId); + model.setUrl(url); + model.setLicenses(licenses); + when(artifactModelReaderMock.readModel(eq(artifactId), eq(groupId), eq(version), anyList())).thenReturn(model); + } + + private org.apache.maven.model.License mavenLicense(final String name, final String url) { + final org.apache.maven.model.License license = new org.apache.maven.model.License(); + license.setName(name); + license.setUrl(url); + return license; + } + + private Plugin plugin(final String groupId, final String artifactId, final String version, + final String sourceLocation) { + final Plugin plugin = new Plugin(); + plugin.setGroupId(groupId); + plugin.setArtifactId(artifactId); + plugin.setVersion(version); + final InputSource source = new InputSource(); + source.setLocation(sourceLocation); + plugin.setLocation("", new InputLocation(0, 0, source)); + return plugin; + } +} diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/dependencies/DependenciesValidatorIT.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/dependencies/DependenciesValidatorIT.java index 5d4d2880..ef6b9d51 100644 --- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/dependencies/DependenciesValidatorIT.java +++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/dependencies/DependenciesValidatorIT.java @@ -67,6 +67,7 @@ void testWrongContentWithNonDefaultRepository() throws IOException { assertThat(output, containsString("E-PK-CORE-53: The dependencies.md file has outdated content.")); } + // [itest -> dsn~dependency.md-file-validator-excludes-implicit-plugins~1] @Test void testFix() throws IOException { createExamplePomFile();