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();