From adae635e4ea2f45720efca8d6a9b71a28e76e9e2 Mon Sep 17 00:00:00 2001 From: Adam Wisniewski Date: Thu, 29 Feb 2024 11:31:20 -0500 Subject: [PATCH] Enhance mulit-module conflict check for dev mode Signed-off-by: Adam Wisniewski --- .../tools/maven/ServerFeatureSupport.java | 4 +- .../tools/maven/server/DevMojo.java | 93 ++++++++++++++++++- 2 files changed, 94 insertions(+), 3 deletions(-) diff --git a/liberty-maven-plugin/src/main/java/io/openliberty/tools/maven/ServerFeatureSupport.java b/liberty-maven-plugin/src/main/java/io/openliberty/tools/maven/ServerFeatureSupport.java index 2e9c84d98..958411ee5 100644 --- a/liberty-maven-plugin/src/main/java/io/openliberty/tools/maven/ServerFeatureSupport.java +++ b/liberty-maven-plugin/src/main/java/io/openliberty/tools/maven/ServerFeatureSupport.java @@ -168,12 +168,12 @@ protected void checkMultiModuleConflicts(ProjectDependencyGraph graph) throws Mo + ". Specify the module containing the Liberty configuration that you want to use for the server by including the following parameters in the Maven command: -pl -am"); } } - + /** * Returns whether potentialTopModule is a multi module project that has * potentialSubModule as one of its sub-modules. */ - private static boolean isSubModule(MavenProject potentialTopModule, MavenProject potentialSubModule) { + protected static boolean isSubModule(MavenProject potentialTopModule, MavenProject potentialSubModule) { List multiModules = potentialTopModule.getModules(); if (multiModules != null) { for (String module : multiModules) { diff --git a/liberty-maven-plugin/src/main/java/io/openliberty/tools/maven/server/DevMojo.java b/liberty-maven-plugin/src/main/java/io/openliberty/tools/maven/server/DevMojo.java index 3e958ce8e..8aa0ca547 100644 --- a/liberty-maven-plugin/src/main/java/io/openliberty/tools/maven/server/DevMojo.java +++ b/liberty-maven-plugin/src/main/java/io/openliberty/tools/maven/server/DevMojo.java @@ -32,6 +32,7 @@ import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Objects; @@ -1277,7 +1278,14 @@ private void doDevMode() throws MojoExecutionException { List upstreamMavenProjects = new ArrayList(); ProjectDependencyGraph graph = session.getProjectDependencyGraph(); if (graph != null) { - checkMultiModuleConflicts(graph); + + // In a multi-module build, dev mode will only be run on one project (the farthest downstream) and compile will + // be run on any relative upstream projects. If this current project in the Maven Reactor is not one of those projects, skip it. + List devModeProjects = getMultiModuleDevModeProjects(graph); + if (!devModeProjects.contains(project)) { + getLog().info("\nSkipping dev goal.\n"); + return; + } List downstreamProjects = graph.getDownstreamProjects(project, true); @@ -1563,6 +1571,89 @@ public void execute() throws MojoExecutionException { doDevMode(); } + + protected List getMultiModuleDevModeProjects(ProjectDependencyGraph graph) throws MojoExecutionException { + getLog().debug("Resolve dev mode projects"); + + List sortedReactorProjects = graph.getSortedProjects(); + Set conflicts = new LinkedHashSet(); // keeps the order of items added in + + // A leaf here is a module without any downstream modules depending on it + List leaves = new ArrayList(); + for (MavenProject reactorProject : sortedReactorProjects) { + if (graph.getDownstreamProjects(reactorProject, true).isEmpty()) { + leaves.add(reactorProject); + getLog().debug("Found final downstream project: " + reactorProject.getArtifactId()); + } + } + + // Remove jar projects since these are not relavent to dev mode + List jarLeaves = new ArrayList(); + for (MavenProject leaf : leaves) { + if (leaf.getPackaging().equals("jar")) { + jarLeaves.add(leaf); + getLog().debug("Removing jar project: " + leaf.getArtifactId()); + } + } + leaves.removeAll(jarLeaves); + + // Remove any projects that are configured to be skipped + List skipLeaves = new ArrayList(); + for (MavenProject leaf : leaves) { + + // Properties that are set in the pom file + Properties props = leaf.getProperties(); + + // Properties that are set by user via CLI parameters + Properties userProps = session.getUserProperties(); + Plugin libertyPlugin = getLibertyPluginForProject(leaf); + Xpp3Dom config = ExecuteMojoUtil.getPluginGoalConfig(libertyPlugin, "dev", getLog()); + + boolean skipGoal = DevHelper.getBooleanFlag(config, userProps, props, "skip"); + + if (skipGoal) { + getLog().debug("Skip configured on project: " + leaf.getArtifactId()); + skipLeaves.add(leaf); + } + } + leaves.removeAll(skipLeaves); + + // Find any remaining conflicts + for (MavenProject leaf1 : leaves) { + for (MavenProject leaf2 : leaves) { + if (leaf1 != leaf2 && !(isSubModule(leaf2, leaf1) || isSubModule(leaf1, leaf2)) ) { + conflicts.add(leaf1); + conflicts.add(leaf2); + } + } + } + + if (conflicts.isEmpty() ) { + List devModeProjects = new ArrayList(); + for (MavenProject leaf : leaves) { + devModeProjects.addAll(graph.getUpstreamProjects(leaf, true)); + devModeProjects.add(leaf); + } + + for (MavenProject project : devModeProjects) { + getLog().debug("Dev mode projects list: "); + getLog().debug(project.getArtifactId()); + } + return devModeProjects; + } else { + + List conflictModuleRelativeDirs = new ArrayList(); + for (MavenProject conflict : conflicts) { + // Make the module path relative to the multi-module project directory + conflictModuleRelativeDirs.add(getModuleRelativePath(conflict)); + } + + throw new MojoExecutionException("Found multiple independent modules in the Reactor build order: " + + conflictModuleRelativeDirs + + ". Skip a conflicting module in the Liberty configuration or specify the module containing the Liberty configuration that you want to use for the server by including the following parameters in the Maven command: -pl -am"); + } + } + /** * Update map with list of parent poms and their subsequent child poms