diff --git a/devtools/maven/src/main/java/io/quarkus/maven/DevMojo.java b/devtools/maven/src/main/java/io/quarkus/maven/DevMojo.java index 99da1770f7cf1..01cb5c4af3d25 100644 --- a/devtools/maven/src/main/java/io/quarkus/maven/DevMojo.java +++ b/devtools/maven/src/main/java/io/quarkus/maven/DevMojo.java @@ -59,6 +59,7 @@ import org.apache.maven.plugin.MojoExecution; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.plugin.PluginParameterExpressionEvaluator; import org.apache.maven.plugin.descriptor.MojoDescriptor; import org.apache.maven.plugin.descriptor.PluginDescriptor; import org.apache.maven.plugin.logging.Log; @@ -71,6 +72,8 @@ import org.apache.maven.shared.utils.cli.CommandLineUtils; import org.apache.maven.toolchain.Toolchain; import org.apache.maven.toolchain.ToolchainManager; +import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException; +import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator; import org.codehaus.plexus.util.xml.Xpp3Dom; import org.eclipse.aether.RepositorySystem; import org.eclipse.aether.RepositorySystemSession; @@ -97,6 +100,7 @@ import io.quarkus.bootstrap.resolver.BootstrapAppModelResolver; import io.quarkus.bootstrap.resolver.maven.BootstrapMavenContext; import io.quarkus.bootstrap.resolver.maven.BootstrapMavenContextConfig; +import io.quarkus.bootstrap.resolver.maven.BootstrapMavenException; import io.quarkus.bootstrap.resolver.maven.MavenArtifactResolver; import io.quarkus.bootstrap.util.BootstrapUtils; import io.quarkus.bootstrap.workspace.ArtifactSources; @@ -1405,6 +1409,18 @@ private DevModeCommandLine newLauncher(String actualDebugPort, String bootstrapI if (appModel != null) { bootstrapProvider.close(); } else { + Path rootProjectDir = null; + String topLevelBaseDirStr = systemProperties.get(BootstrapMavenContext.MAVEN_TOP_LEVEL_PROJECT_BASEDIR); + if (topLevelBaseDirStr != null) { + final Path tmp = Path.of(topLevelBaseDirStr); + if (!Files.exists(tmp)) { + throw new BootstrapMavenException("Top-level project base directory " + topLevelBaseDirStr + + " specified with system property " + BootstrapMavenContext.MAVEN_TOP_LEVEL_PROJECT_BASEDIR + + " does not exist"); + } + rootProjectDir = tmp; + } + final BootstrapMavenContextConfig mvnConfig = BootstrapMavenContext.config() .setUserSettings(session.getRequest().getUserSettingsFile()) .setRemoteRepositories(repos) @@ -1413,7 +1429,8 @@ private DevModeCommandLine newLauncher(String actualDebugPort, String bootstrapI // it's important to set the base directory instead of the POM // which maybe manipulated by a plugin and stored outside the base directory .setCurrentProject(project.getBasedir().toString()) - .setEffectiveModelBuilder(BootstrapMavenContextConfig.getEffectiveModelBuilderProperty(projectProperties)); + .setEffectiveModelBuilder(BootstrapMavenContextConfig.getEffectiveModelBuilderProperty(projectProperties)) + .setRootProjectDir(rootProjectDir); // There are a couple of reasons we don't want to use the original Maven session: // 1) a reload could be triggered by a change in a pom.xml, in which case the Maven session might not be in sync any more with the effective POM; @@ -1521,22 +1538,30 @@ private void copySurefireVariables() { return; } + ExpressionEvaluator evaluator = new PluginParameterExpressionEvaluator(session, mojoExecution); Xpp3Dom config = (Xpp3Dom) surefireMavenPlugin.getConfiguration(); if (config != null) { // we copy the maps because they can be unmodifiable environmentVariables = new HashMap<>(environmentVariables); - copyConfiguration(config.getChild("environmentVariables"), environmentVariables); + copyConfiguration(config.getChild("environmentVariables"), environmentVariables, evaluator); systemProperties = new HashMap<>(systemProperties); - copyConfiguration(config.getChild("systemPropertyVariables"), systemProperties); + copyConfiguration(config.getChild("systemPropertyVariables"), systemProperties, evaluator); } } - private void copyConfiguration(Xpp3Dom config, Map targetMap) { + private void copyConfiguration(Xpp3Dom config, Map targetMap, ExpressionEvaluator evaluator) { if (config == null) { return; } for (Xpp3Dom child : config.getChildren()) { - targetMap.putIfAbsent(child.getName(), child.getValue()); + targetMap.computeIfAbsent(child.getName(), ignored -> { + try { + Object value = evaluator.evaluate(child.getValue()); + return value == null ? null : value.toString(); + } catch (ExpressionEvaluationException e) { + throw new RuntimeException(e); + } + }); } } diff --git a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/BootstrapMavenContext.java b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/BootstrapMavenContext.java index 711a029b2bb25..d94821329717d 100644 --- a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/BootstrapMavenContext.java +++ b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/BootstrapMavenContext.java @@ -92,7 +92,7 @@ public class BootstrapMavenContext { private static final String MAVEN_DOT_HOME = "maven.home"; private static final String MAVEN_HOME = "MAVEN_HOME"; private static final String MAVEN_SETTINGS = "maven.settings"; - private static final String MAVEN_TOP_LEVEL_PROJECT_BASEDIR = "maven.top-level-basedir"; + public static final String MAVEN_TOP_LEVEL_PROJECT_BASEDIR = "maven.top-level-basedir"; private static final String SETTINGS_XML = "settings.xml"; private static final String SETTINGS_SECURITY = "settings.security"; diff --git a/integration-tests/maven/src/test/java/io/quarkus/maven/it/DevMojoIT.java b/integration-tests/maven/src/test/java/io/quarkus/maven/it/DevMojoIT.java index cebc0029d3e09..e4effebd3ffd0 100644 --- a/integration-tests/maven/src/test/java/io/quarkus/maven/it/DevMojoIT.java +++ b/integration-tests/maven/src/test/java/io/quarkus/maven/it/DevMojoIT.java @@ -1666,4 +1666,12 @@ void testMultimoduleFilteredClassifier() run(true); assertThat(devModeClient.getHttpResponse("/")).isEqualTo("Big"); } + + @Test + public void testNonParentAggregator() throws MavenInvocationException, IOException { + testDir = initProject("projects/non-parent-aggregator"); + run(true, "-f", "aggregator"); + assertThat(devModeClient.getHttpResponse("/model")).isEqualTo("Hello model"); + assertThat(devModeClient.getHttpResponse("/service")).isEqualTo("Hello service"); + } } diff --git a/integration-tests/maven/src/test/resources-filtered/projects/non-parent-aggregator/aggregator/pom.xml b/integration-tests/maven/src/test/resources-filtered/projects/non-parent-aggregator/aggregator/pom.xml new file mode 100644 index 0000000000000..4ffb2c65f4580 --- /dev/null +++ b/integration-tests/maven/src/test/resources-filtered/projects/non-parent-aggregator/aggregator/pom.xml @@ -0,0 +1,15 @@ + + + 4.0.0 + + com.example + aggregator + 1.0.0-SNAPSHOT + pom + + + ../model + ../service + + diff --git a/integration-tests/maven/src/test/resources-filtered/projects/non-parent-aggregator/model/pom.xml b/integration-tests/maven/src/test/resources-filtered/projects/non-parent-aggregator/model/pom.xml new file mode 100644 index 0000000000000..0c45a5ea79d23 --- /dev/null +++ b/integration-tests/maven/src/test/resources-filtered/projects/non-parent-aggregator/model/pom.xml @@ -0,0 +1,52 @@ + + + 4.0.0 + + com.example + model + 1.0.0-SNAPSHOT + + + UTF-8 + UTF-8 + + 17 + 17 + 17 + true + + + + + + io.quarkus + quarkus-bom + @project.version@ + pom + import + + + + + + + io.quarkus + quarkus-rest + + + + + + + + io.quarkus + quarkus-maven-plugin + @project.version@ + + false + + + + + diff --git a/integration-tests/maven/src/test/resources-filtered/projects/non-parent-aggregator/model/src/main/java/com/example/model/ModelResource.java b/integration-tests/maven/src/test/resources-filtered/projects/non-parent-aggregator/model/src/main/java/com/example/model/ModelResource.java new file mode 100644 index 0000000000000..1d867fc71a833 --- /dev/null +++ b/integration-tests/maven/src/test/resources-filtered/projects/non-parent-aggregator/model/src/main/java/com/example/model/ModelResource.java @@ -0,0 +1,14 @@ +package com.example.model; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; + +@Path("/model") +@ApplicationScoped +public class ModelResource { + @GET + public String hello() { + return "Hello model"; + } +} diff --git a/integration-tests/maven/src/test/resources-filtered/projects/non-parent-aggregator/model/src/main/resources/META-INF/beans.xml b/integration-tests/maven/src/test/resources-filtered/projects/non-parent-aggregator/model/src/main/resources/META-INF/beans.xml new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/integration-tests/maven/src/test/resources-filtered/projects/non-parent-aggregator/service/pom.xml b/integration-tests/maven/src/test/resources-filtered/projects/non-parent-aggregator/service/pom.xml new file mode 100644 index 0000000000000..7325a847394b4 --- /dev/null +++ b/integration-tests/maven/src/test/resources-filtered/projects/non-parent-aggregator/service/pom.xml @@ -0,0 +1,65 @@ + + + 4.0.0 + + com.example + service + 1.0.0-SNAPSHOT + + + UTF-8 + UTF-8 + + 17 + 17 + 17 + 17 + + + + + + io.quarkus + quarkus-bom + @project.version@ + pom + import + + + + + + + io.quarkus + quarkus-rest + + + com.example + model + \${project.version} + + + + + + + io.quarkus + quarkus-maven-plugin + @project.version@ + + + \${session.topLevelProject.basedir.absolutePath} + + + + + + build + + + + + + + diff --git a/integration-tests/maven/src/test/resources-filtered/projects/non-parent-aggregator/service/src/main/java/com/example/service/ServiceResource.java b/integration-tests/maven/src/test/resources-filtered/projects/non-parent-aggregator/service/src/main/java/com/example/service/ServiceResource.java new file mode 100644 index 0000000000000..cec17a58963f5 --- /dev/null +++ b/integration-tests/maven/src/test/resources-filtered/projects/non-parent-aggregator/service/src/main/java/com/example/service/ServiceResource.java @@ -0,0 +1,14 @@ +package com.example.service; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; + +@Path("/service") +@ApplicationScoped +public class ServiceResource { + @GET + public String hello() { + return "Hello service"; + } +} diff --git a/integration-tests/maven/src/test/resources-filtered/projects/non-parent-aggregator/service/src/main/resources/META-INF/beans.xml b/integration-tests/maven/src/test/resources-filtered/projects/non-parent-aggregator/service/src/main/resources/META-INF/beans.xml new file mode 100644 index 0000000000000..e69de29bb2d1d