diff options
author | HÃ¥kon Hallingstad <hakon.hallingstad@gmail.com> | 2022-11-15 10:36:05 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-11-15 10:36:05 +0100 |
commit | 5698a43566d6f7ab93fbb8b5a1d1fd64e89c372b (patch) | |
tree | 5e62f0511155653de159dca9d0f1e6570cca60c7 | |
parent | 4a531ae198d2616c03fb5df237a95e29b5352af5 (diff) | |
parent | 1d090a4db78d683a31df3cd7a2998b49fb2000ef (diff) |
Merge pull request #24862 from vespa-engine/hakonhall/support-super-pom-with-dependency-enforcer
Support super-pom with dependency enforcer
4 files changed, 60 insertions, 15 deletions
diff --git a/maven-plugins/pom.xml b/maven-plugins/pom.xml index d71e1a0f068..f12731ba9da 100644 --- a/maven-plugins/pom.xml +++ b/maven-plugins/pom.xml @@ -48,6 +48,7 @@ <configuration> <rules> <enforceDependencies implementation="com.yahoo.vespa.maven.plugin.enforcer.EnforceDependenciesAllProjects"> + <rootProjectId>com.yahoo.vespa:maven-plugins</rootProjectId> <specFile>allowed-maven-dependencies.txt</specFile> <ignored> <i>com.yahoo.vespa:*:*</i> diff --git a/vespa-dependencies-enforcer/pom.xml b/vespa-dependencies-enforcer/pom.xml index a0e6dc19ccb..768e5708ee5 100644 --- a/vespa-dependencies-enforcer/pom.xml +++ b/vespa-dependencies-enforcer/pom.xml @@ -39,6 +39,7 @@ <configuration> <rules> <enforceDependencies implementation="com.yahoo.vespa.maven.plugin.enforcer.EnforceDependenciesAllProjects"> + <rootProjectId>com.yahoo.vespa:vespa</rootProjectId> <specFile>allowed-maven-dependencies.txt</specFile> <ignored> <i>ai.vespa:*:*</i> diff --git a/vespa-enforcer-extensions/src/main/java/com/yahoo/vespa/maven/plugin/enforcer/EnforceDependenciesAllProjects.java b/vespa-enforcer-extensions/src/main/java/com/yahoo/vespa/maven/plugin/enforcer/EnforceDependenciesAllProjects.java index 82c705c4611..f569ce6550f 100644 --- a/vespa-enforcer-extensions/src/main/java/com/yahoo/vespa/maven/plugin/enforcer/EnforceDependenciesAllProjects.java +++ b/vespa-enforcer-extensions/src/main/java/com/yahoo/vespa/maven/plugin/enforcer/EnforceDependenciesAllProjects.java @@ -21,8 +21,11 @@ import java.io.UncheckedIOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.ArrayDeque; +import java.util.ArrayList; import java.util.Comparator; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.SortedSet; @@ -40,6 +43,7 @@ public class EnforceDependenciesAllProjects implements EnforcerRule { private static final String NON_TEST_HEADER = "#[non-test]"; private static final String TEST_ONLY_HEADER = "#[test-only]"; + private String rootProjectId; private String specFile; private List<String> ignored = List.of(); private List<String> testUtilProjects = List.of(); @@ -47,7 +51,7 @@ public class EnforceDependenciesAllProjects implements EnforcerRule { @Override public void execute(EnforcerRuleHelper helper) throws EnforcerRuleException { Log log = helper.getLog(); - Dependencies deps = getDependenciesOfAllProjects(helper, ignored, testUtilProjects); + Dependencies deps = getDependenciesOfAllProjects(helper, ignored, testUtilProjects, rootProjectId); log.info("Found %d unique dependencies (%d non-test, %d test only)".formatted( deps.nonTest().size() + deps.testOnly().size(), deps.nonTest().size(), deps.testOnly().size())); Path specFile = resolveSpecFile(helper, this.specFile); @@ -61,6 +65,8 @@ public class EnforceDependenciesAllProjects implements EnforcerRule { } // Config injection for rule configuration. Method names must match config XML elements. + @SuppressWarnings("unused") public void setRootProjectId(String l) { this.rootProjectId = l; } + @SuppressWarnings("unused") public String getRootProjectId() { return rootProjectId; } @SuppressWarnings("unused") public void setSpecFile(String f) { this.specFile = f; } @SuppressWarnings("unused") public String getSpecFile() { return specFile; } @SuppressWarnings("unused") public void setIgnored(List<String> l) { this.ignored = l; } @@ -107,7 +113,7 @@ public class EnforceDependenciesAllProjects implements EnforcerRule { throw new EnforcerRuleException( errorMsg.append("Maven dependency validation failed. ") .append("If this change was intentional, update the dependency spec by running:\n") - .append("$ mvn validate -D").append(WRITE_SPEC_PROP).append(" -pl ").append(moduleName) + .append("$ mvn validate -D").append(WRITE_SPEC_PROP).append(" -pl :").append(moduleName) .append(" -f ").append(aggregatorPomRoot).append("\n").toString()); } } @@ -129,7 +135,7 @@ public class EnforceDependenciesAllProjects implements EnforcerRule { } private static Dependencies getDependenciesOfAllProjects(EnforcerRuleHelper helper, List<String> ignored, - List<String> testUtilProjects) + List<String> testUtilProjects, String rootProjectId) throws EnforcerRuleException { try { Pattern depIgnorePattern = Pattern.compile( @@ -144,16 +150,12 @@ public class EnforceDependenciesAllProjects implements EnforcerRule { SortedSet<Dependency> testDeps = new TreeSet<>(); MavenSession session = mavenSession(helper); var graphBuilder = helper.getComponent(DependencyGraphBuilder.class); - List<MavenProject> projects = session.getAllProjects(); - if (projects.size() == 1) { - throw new EnforcerRuleException( - "Only a single Maven module detected. Enforcer must be executed from root of aggregator pom."); - } + List<MavenProject> projects = getAllProjects(session, rootProjectId); for (MavenProject project : projects) { var req = new DefaultProjectBuildingRequest(session.getProjectBuildingRequest()); req.setProject(project); DependencyNode root = graphBuilder.buildDependencyGraph(req, null); - String projectId = "%s:%s".formatted(project.getGroupId(), project.getArtifactId()); + String projectId = projectIdOf(project); boolean overrideToTest = projectIgnorePattern.matcher(projectId).matches(); if (overrideToTest) helper.getLog().info("Treating dependencies of '%s' as 'test'".formatted(projectId)); addDependenciesRecursive(root, nonTestDeps, testDeps, depIgnorePattern, overrideToTest); @@ -165,6 +167,50 @@ public class EnforceDependenciesAllProjects implements EnforcerRule { } } + private static String projectIdOf(MavenProject project) { return "%s:%s".formatted(project.getGroupId(), project.getArtifactId()); } + + /** Only return the projects we'd like to enforce dependencies for: the root project, its modules, their modules, etc. */ + private static List<MavenProject> getAllProjects(MavenSession session, String rootProjectId) throws EnforcerRuleException { + if (rootProjectId == null) throw new EnforcerRuleException("Missing required <rootProjectId> in <enforceDependencies> in pom.xml"); + + List<MavenProject> allProjects = session.getAllProjects(); + if (allProjects.size() == 1) { + throw new EnforcerRuleException( + "Only a single Maven module detected. Enforcer must be executed from root of aggregator pom."); + } + MavenProject rootProject = allProjects + .stream() + .filter(project -> rootProjectId.equals(projectIdOf(project))) + .findAny() + .orElseThrow(() -> new EnforcerRuleException("Root project not found: " + rootProjectId)); + + Map<Path, MavenProject> projectsByBaseDir = allProjects + .stream() + .collect(Collectors.toMap(project -> project.getBasedir().toPath().normalize(), project -> project)); + + var projects = new ArrayList<MavenProject>(); + + var pendingProjects = new ArrayDeque<MavenProject>(); + pendingProjects.add(rootProject); + + while (!pendingProjects.isEmpty()) { + MavenProject project = pendingProjects.pop(); + projects.add(project); + + for (var module : project.getModules()) { + // Assumption: The module is a relative path to a project base directory. + Path moduleBaseDir = project.getBasedir().toPath().resolve(module).normalize(); + MavenProject moduleProject = projectsByBaseDir.get(moduleBaseDir); + if (moduleProject == null) + throw new EnforcerRuleException("Failed to find module '" + module + "' in project " + project.getBasedir()); + pendingProjects.add(moduleProject); + } + } + + projects.sort(Comparator.comparing(EnforceDependenciesAllProjects::projectIdOf)); + return projects; + } + private static void addDependenciesRecursive( DependencyNode node, Set<Dependency> nonTestDeps, Set<Dependency> testDeps, Pattern ignored, boolean overrideToTest) { @@ -188,10 +234,7 @@ public class EnforceDependenciesAllProjects implements EnforcerRule { return Paths.get(mavenProject(helper).getBasedir() + File.separator + specFile).normalize(); } - private static String projectName(EnforcerRuleHelper helper) { - MavenProject p = mavenProject(helper); - return p.getModules().isEmpty() ? p.getName() : "."; - } + private static String projectName(EnforcerRuleHelper helper) { return mavenProject(helper).getArtifactId(); } private static Path aggregatorPomRoot(EnforcerRuleHelper helper) { return mavenSession(helper).getRequest().getPom().toPath(); diff --git a/vespa-enforcer-extensions/src/test/java/com/yahoo/vespa/maven/plugin/enforcer/EnforceDependenciesAllProjectsTest.java b/vespa-enforcer-extensions/src/test/java/com/yahoo/vespa/maven/plugin/enforcer/EnforceDependenciesAllProjectsTest.java index 6e47aad0d06..59062cbd61c 100644 --- a/vespa-enforcer-extensions/src/test/java/com/yahoo/vespa/maven/plugin/enforcer/EnforceDependenciesAllProjectsTest.java +++ b/vespa-enforcer-extensions/src/test/java/com/yahoo/vespa/maven/plugin/enforcer/EnforceDependenciesAllProjectsTest.java @@ -60,7 +60,7 @@ class EnforceDependenciesAllProjectsTest { Forbidden non-test dependencies: - com.example:foobar:3.4.5 Maven dependency validation failed. If this change was intentional, update the dependency spec by running: - $ mvn validate -DdependencyEnforcer.writeSpec -pl my-dep-enforcer -f /vespa-src/pom.xml + $ mvn validate -DdependencyEnforcer.writeSpec -pl :my-dep-enforcer -f /vespa-src/pom.xml """; assertEquals(expectedErrorMessage, exception.getMessage()); } @@ -83,7 +83,7 @@ class EnforceDependenciesAllProjectsTest { Removed test-only dependencies: - com.example:testbar:2.3.4 Maven dependency validation failed. If this change was intentional, update the dependency spec by running: - $ mvn validate -DdependencyEnforcer.writeSpec -pl my-dep-enforcer -f /vespa-src/pom.xml + $ mvn validate -DdependencyEnforcer.writeSpec -pl :my-dep-enforcer -f /vespa-src/pom.xml """; assertEquals(expectedErrorMessage, exception.getMessage()); } |