diff --git a/pom.xml b/pom.xml
index 0de3e5b3..3688f4ab 100644
--- a/pom.xml
+++ b/pom.xml
@@ -264,6 +264,11 @@ under the License.
junit-jupiter-api
test
+
+ org.junit.jupiter
+ junit-jupiter-params
+ test
+
org.mockito
mockito-core
@@ -377,6 +382,10 @@ under the License.
+
+ org.eclipse.sisu
+ sisu-maven-plugin
+
diff --git a/src/main/java/org/apache/maven/plugins/invoker/AbstractInvokerMojo.java b/src/main/java/org/apache/maven/plugins/invoker/AbstractInvokerMojo.java
index 09987f4b..92f4583a 100644
--- a/src/main/java/org/apache/maven/plugins/invoker/AbstractInvokerMojo.java
+++ b/src/main/java/org/apache/maven/plugins/invoker/AbstractInvokerMojo.java
@@ -410,6 +410,10 @@ public abstract class AbstractInvokerMojo extends AbstractMojo {
/**
* The MAVEN_OPTS
environment variable to use when invoking Maven. This value can be overridden for
* individual integration tests by using {@link #invokerPropertiesFile}.
+ *
+ * Since the version 3.7.0 using an alternate syntax for mavenOpts, @{...}
+ * allows late replacement of properties when the plugin is executed,
+ * so properties that have been modified by other plugins will be picked up correctly.
*
* @since 1.2
*/
@@ -739,6 +743,9 @@ public abstract class AbstractInvokerMojo extends AbstractMojo {
@Component
private ToolchainManagerPrivate toolchainManagerPrivate;
+ @Component
+ private InterpolatorUtils interpolatorUtils;
+
/**
* Invokes Maven on the configured test projects.
*
@@ -2363,7 +2370,7 @@ private InvokerProperties getInvokerProperties(final File projectDirectory, Prop
invokerProperties.setDefaultGoals(goals);
invokerProperties.setDefaultProfiles(profiles);
invokerProperties.setDefaultMavenExecutable(mavenExecutable);
- invokerProperties.setDefaultMavenOpts(mavenOpts);
+ invokerProperties.setDefaultMavenOpts(interpolatorUtils.interpolateAtPattern(mavenOpts));
invokerProperties.setDefaultTimeoutInSeconds(timeoutInSeconds);
invokerProperties.setDefaultEnvironmentVariables(environmentVariables);
invokerProperties.setDefaultUpdateSnapshots(updateSnapshots);
diff --git a/src/main/java/org/apache/maven/plugins/invoker/InterpolatorUtils.java b/src/main/java/org/apache/maven/plugins/invoker/InterpolatorUtils.java
new file mode 100644
index 00000000..a4804b9b
--- /dev/null
+++ b/src/main/java/org/apache/maven/plugins/invoker/InterpolatorUtils.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.plugins.invoker;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.interpolation.InterpolationException;
+import org.codehaus.plexus.interpolation.Interpolator;
+import org.codehaus.plexus.interpolation.MapBasedValueSource;
+import org.codehaus.plexus.interpolation.RegexBasedInterpolator;
+
+/**
+ * Helper component for interpolating values.
+ */
+@Named
+class InterpolatorUtils {
+
+ private final Interpolator atInterpolator;
+
+ /**
+ * A default constructor.
+ *
+ * @param mavenProject a MavenProject
+ */
+ @Inject
+ InterpolatorUtils(MavenProject mavenProject) {
+ atInterpolator = new RegexBasedInterpolator("[@\\$]\\{(.+?)", "}");
+ atInterpolator.addValueSource(new MapBasedValueSource(mavenProject.getProperties()));
+ }
+
+ public String interpolateAtPattern(String value) throws MojoExecutionException {
+
+ if (value == null || !(value.contains("@{") || value.contains("${"))) {
+ return value;
+ }
+
+ try {
+ return atInterpolator.interpolate(value);
+ } catch (InterpolationException e) {
+ throw new MojoExecutionException(e.getMessage(), e);
+ }
+ }
+}
diff --git a/src/test/java/org/apache/maven/plugins/invoker/InterpolatorUtilsTest.java b/src/test/java/org/apache/maven/plugins/invoker/InterpolatorUtilsTest.java
new file mode 100644
index 00000000..ceab70aa
--- /dev/null
+++ b/src/test/java/org/apache/maven/plugins/invoker/InterpolatorUtilsTest.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.plugins.invoker;
+
+import java.util.Properties;
+import java.util.stream.Stream;
+
+import org.apache.maven.project.MavenProject;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(MockitoExtension.class)
+class InterpolatorUtilsTest {
+
+ @Mock
+ private MavenProject mavenProject;
+
+ static Stream testAtInterpolate() {
+ return Stream.of(
+ Arguments.of(null, null),
+ Arguments.of("test", "test"),
+ Arguments.of("test@test", "test@test"),
+ Arguments.of("test$test", "test$test"),
+ Arguments.of("@{test}", "testInProps"),
+ Arguments.of("${test}", "testInProps"),
+ Arguments.of("test @{test} test", "test testInProps test"),
+ Arguments.of("test ${test} test", "test testInProps test"),
+ Arguments.of("@{test} @{test}", "testInProps testInProps"),
+ Arguments.of("${test} ${test}", "testInProps testInProps"),
+ Arguments.of("@{test} ${test}", "testInProps testInProps"));
+ }
+
+ @ParameterizedTest
+ @MethodSource
+ void testAtInterpolate(String input, String expected) throws Exception {
+ // given
+ Properties properties = new Properties();
+ properties.put("test", "testInProps");
+ when(mavenProject.getProperties()).thenReturn(properties);
+ InterpolatorUtils interpolatorUtils = new InterpolatorUtils(mavenProject);
+
+ // when
+ String output = interpolatorUtils.interpolateAtPattern(input);
+
+ // then
+ assertThat(output).isEqualTo(expected);
+ }
+}
diff --git a/src/test/java/org/apache/maven/plugins/invoker/InvokerMojoTest.java b/src/test/java/org/apache/maven/plugins/invoker/InvokerMojoTest.java
index d57a5876..fd603222 100644
--- a/src/test/java/org/apache/maven/plugins/invoker/InvokerMojoTest.java
+++ b/src/test/java/org/apache/maven/plugins/invoker/InvokerMojoTest.java
@@ -49,11 +49,13 @@ private MavenProject getMavenProject() {
@Test
void testSingleInvokerTest() throws Exception {
// given
+ MavenProject mavenProject = getMavenProject();
InvokerMojo invokerMojo = new InvokerMojo();
String dirPath = getBasedir() + "/src/test/resources/unit";
setVariableValueToObject(invokerMojo, "projectsDirectory", new File(dirPath));
setVariableValueToObject(invokerMojo, "invokerPropertiesFile", "invoker.properties");
- setVariableValueToObject(invokerMojo, "project", getMavenProject());
+ setVariableValueToObject(invokerMojo, "project", mavenProject);
+ setVariableValueToObject(invokerMojo, "interpolatorUtils", new InterpolatorUtils(mavenProject));
setVariableValueToObject(invokerMojo, "invokerTest", "*dummy*");
setVariableValueToObject(invokerMojo, "settings", new Settings());
@@ -67,11 +69,13 @@ void testSingleInvokerTest() throws Exception {
@Test
void testMultiInvokerTest() throws Exception {
// given
+ MavenProject mavenProject = getMavenProject();
InvokerMojo invokerMojo = new InvokerMojo();
String dirPath = getBasedir() + "/src/test/resources/unit";
setVariableValueToObject(invokerMojo, "projectsDirectory", new File(dirPath));
setVariableValueToObject(invokerMojo, "invokerPropertiesFile", "invoker.properties");
- setVariableValueToObject(invokerMojo, "project", getMavenProject());
+ setVariableValueToObject(invokerMojo, "project", mavenProject);
+ setVariableValueToObject(invokerMojo, "interpolatorUtils", new InterpolatorUtils(mavenProject));
setVariableValueToObject(invokerMojo, "invokerTest", "*dummy*,*terpolatio*");
setVariableValueToObject(invokerMojo, "settings", new Settings());
@@ -85,11 +89,13 @@ void testMultiInvokerTest() throws Exception {
@Test
void testFullPatternInvokerTest() throws Exception {
// given
+ MavenProject mavenProject = getMavenProject();
InvokerMojo invokerMojo = new InvokerMojo();
String dirPath = getBasedir() + "/src/test/resources/unit";
setVariableValueToObject(invokerMojo, "projectsDirectory", new File(dirPath));
setVariableValueToObject(invokerMojo, "invokerPropertiesFile", "invoker.properties");
- setVariableValueToObject(invokerMojo, "project", getMavenProject());
+ setVariableValueToObject(invokerMojo, "project", mavenProject);
+ setVariableValueToObject(invokerMojo, "interpolatorUtils", new InterpolatorUtils(mavenProject));
setVariableValueToObject(invokerMojo, "invokerTest", "*");
setVariableValueToObject(invokerMojo, "settings", new Settings());
@@ -106,11 +112,13 @@ void testFullPatternInvokerTest() throws Exception {
@Test
void testSetupInProjectList() throws Exception {
// given
+ MavenProject mavenProject = getMavenProject();
InvokerMojo invokerMojo = new InvokerMojo();
String dirPath = getBasedir() + "/src/test/resources/unit";
setVariableValueToObject(invokerMojo, "projectsDirectory", new File(dirPath));
setVariableValueToObject(invokerMojo, "invokerPropertiesFile", "invoker.properties");
- setVariableValueToObject(invokerMojo, "project", getMavenProject());
+ setVariableValueToObject(invokerMojo, "project", mavenProject);
+ setVariableValueToObject(invokerMojo, "interpolatorUtils", new InterpolatorUtils(mavenProject));
setVariableValueToObject(invokerMojo, "settings", new Settings());
setVariableValueToObject(invokerMojo, "setupIncludes", Collections.singletonList("dum*/pom.xml"));
@@ -134,11 +142,13 @@ void testSetupInProjectList() throws Exception {
@Test
void testSetupProjectIsFiltered() throws Exception {
// given
+ MavenProject mavenProject = getMavenProject();
InvokerMojo invokerMojo = new InvokerMojo();
String dirPath = getBasedir() + "/src/test/resources/unit";
setVariableValueToObject(invokerMojo, "projectsDirectory", new File(dirPath));
setVariableValueToObject(invokerMojo, "invokerPropertiesFile", "invoker.properties");
- setVariableValueToObject(invokerMojo, "project", getMavenProject());
+ setVariableValueToObject(invokerMojo, "project", mavenProject);
+ setVariableValueToObject(invokerMojo, "interpolatorUtils", new InterpolatorUtils(mavenProject));
setVariableValueToObject(invokerMojo, "settings", new Settings());
setVariableValueToObject(invokerMojo, "setupIncludes", Collections.singletonList("dum*/pom.xml"));
setVariableValueToObject(invokerMojo, "invokerTest", "*project-dir*");