You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by sl...@apache.org on 2026/09/15 23:43:06 UTC
(maven-invoker-plugin) branch agent/parallel-log-prefix created (now 0050f2a)
This is an automated email from the ASF dual-hosted git repository.
slachiewicz pushed a change to branch agent/parallel-log-prefix
in repository https://gitbox.apache.org/repos/asf/maven-invoker-plugin.git
at 0050f2a Prefix per-job console output with project path under parallelThreads
This branch includes the following new commits:
new 0050f2a Prefix per-job console output with project path under parallelThreads
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
(maven-invoker-plugin) 01/01: Prefix per-job console output with project path under parallelThreads
Posted by sl...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
slachiewicz pushed a commit to branch agent/parallel-log-prefix
in repository https://gitbox.apache.org/repos/asf/maven-invoker-plugin.git
commit 0050f2a05855384c459c79c8af152274b710c615
Author: Sylwester Lachiewicz <sl...@apache.org>
AuthorDate: Wed Sep 16 01:42:56 2026 +0200
Prefix per-job console output with project path under parallelThreads
Interleaved output from concurrent jobs could not be attributed to a
project; every mojo-log line for a job (Building, script-run, streamed
build output) now carries a "[<project>] " prefix when parallelThreads
> 1, while single-threaded output and build.log file content stay
unchanged.
Fixes #684
---
src/it/parallel-log-prefix-single-threaded/pom.xml | 68 +++++++++++++++++++++
.../src/it/alpha/pom.xml | 32 ++++++++++
.../src/it/alpha/setup.groovy | 26 ++++++++
.../src/it/beta/pom.xml | 32 ++++++++++
.../src/it/beta/setup.groovy | 26 ++++++++
.../verify.groovy | 39 ++++++++++++
src/it/parallel-log-prefix/pom.xml | 70 ++++++++++++++++++++++
src/it/parallel-log-prefix/src/it/alpha/pom.xml | 32 ++++++++++
.../parallel-log-prefix/src/it/alpha/setup.groovy | 26 ++++++++
src/it/parallel-log-prefix/src/it/beta/pom.xml | 32 ++++++++++
.../parallel-log-prefix/src/it/beta/setup.groovy | 26 ++++++++
src/it/parallel-log-prefix/verify.groovy | 64 ++++++++++++++++++++
.../maven/plugins/invoker/AbstractInvokerMojo.java | 30 +++++++---
.../apache/maven/plugins/invoker/FileLogger.java | 29 ++++++++-
14 files changed, 523 insertions(+), 9 deletions(-)
diff --git a/src/it/parallel-log-prefix-single-threaded/pom.xml b/src/it/parallel-log-prefix-single-threaded/pom.xml
new file mode 100644
index 0000000..faa255e
--- /dev/null
+++ b/src/it/parallel-log-prefix-single-threaded/pom.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+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.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>org.apache.maven.plugins.invoker</groupId>
+ <artifactId>parallel-log-prefix-single-threaded</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ <packaging>pom</packaging>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+
+ <!--
+ MINVOKER-684 control case: with the default parallelThreads=1, console output must stay byte-identical
+ to before the fix, i.e. no "[<project>] " prefix is added to any line.
+ -->
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-invoker-plugin</artifactId>
+ <version>@project.version@</version>
+ <configuration>
+ <cloneProjectsTo>${project.build.directory}/its</cloneProjectsTo>
+ <pomIncludes>
+ <pomInclude>*/pom.xml</pomInclude>
+ </pomIncludes>
+ <preBuildHookScript>setup</preBuildHookScript>
+ <goals>
+ <goal>validate</goal>
+ </goals>
+ <streamLogs>true</streamLogs>
+ </configuration>
+ <executions>
+ <execution>
+ <id>integration-test</id>
+ <phase>initialize</phase>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/src/it/parallel-log-prefix-single-threaded/src/it/alpha/pom.xml b/src/it/parallel-log-prefix-single-threaded/src/it/alpha/pom.xml
new file mode 100644
index 0000000..b45c6da
--- /dev/null
+++ b/src/it/parallel-log-prefix-single-threaded/src/it/alpha/pom.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+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.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>test</groupId>
+ <artifactId>alpha</artifactId>
+ <version>0.1-SNAPSHOT</version>
+ <packaging>pom</packaging>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+</project>
diff --git a/src/it/parallel-log-prefix-single-threaded/src/it/alpha/setup.groovy b/src/it/parallel-log-prefix-single-threaded/src/it/alpha/setup.groovy
new file mode 100644
index 0000000..25c5a1f
--- /dev/null
+++ b/src/it/parallel-log-prefix-single-threaded/src/it/alpha/setup.groovy
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+import java.io.*;
+
+// marker for parent build that this sub build was indeed run
+File touchFile = new File( basedir, "touch.txt" )
+touchFile.createNewFile()
+
+println("Output from setup script for alpha")
diff --git a/src/it/parallel-log-prefix-single-threaded/src/it/beta/pom.xml b/src/it/parallel-log-prefix-single-threaded/src/it/beta/pom.xml
new file mode 100644
index 0000000..836512c
--- /dev/null
+++ b/src/it/parallel-log-prefix-single-threaded/src/it/beta/pom.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+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.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>test</groupId>
+ <artifactId>beta</artifactId>
+ <version>0.1-SNAPSHOT</version>
+ <packaging>pom</packaging>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+</project>
diff --git a/src/it/parallel-log-prefix-single-threaded/src/it/beta/setup.groovy b/src/it/parallel-log-prefix-single-threaded/src/it/beta/setup.groovy
new file mode 100644
index 0000000..c38a165
--- /dev/null
+++ b/src/it/parallel-log-prefix-single-threaded/src/it/beta/setup.groovy
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+import java.io.*;
+
+// marker for parent build that this sub build was indeed run
+File touchFile = new File( basedir, "touch.txt" )
+touchFile.createNewFile()
+
+println("Output from setup script for beta")
diff --git a/src/it/parallel-log-prefix-single-threaded/verify.groovy b/src/it/parallel-log-prefix-single-threaded/verify.groovy
new file mode 100644
index 0000000..b58aa1d
--- /dev/null
+++ b/src/it/parallel-log-prefix-single-threaded/verify.groovy
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+def FS = File.separator
+def alphaProject = 'alpha' + FS + 'pom.xml'
+def betaProject = 'beta' + FS + 'pom.xml'
+
+// make sure both sub builds were indeed run
+assert new File(basedir, 'target/its/alpha/touch.txt').exists()
+assert new File(basedir, 'target/its/beta/touch.txt').exists()
+
+def buildLog = new File(basedir, 'build.log').text
+
+// MINVOKER-684 control case: with the default parallelThreads=1, output must stay byte-identical to
+// before the fix, so none of the per-job lines get a "[<project>] " prefix.
+assert buildLog.contains('Building: ' + alphaProject)
+assert buildLog.contains('Building: ' + betaProject)
+assert buildLog.contains('Running pre-build script')
+assert buildLog.contains('Output from setup script for alpha')
+assert buildLog.contains('Output from setup script for beta')
+
+assert !buildLog.contains('[' + alphaProject + ']')
+assert !buildLog.contains('[' + betaProject + ']')
diff --git a/src/it/parallel-log-prefix/pom.xml b/src/it/parallel-log-prefix/pom.xml
new file mode 100644
index 0000000..97cad1d
--- /dev/null
+++ b/src/it/parallel-log-prefix/pom.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+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.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>org.apache.maven.plugins.invoker</groupId>
+ <artifactId>parallel-log-prefix</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ <packaging>pom</packaging>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+
+ <!--
+ MINVOKER-684: when several jobs run in parallel their console lines interleave. Every mojo-log line
+ emitted on behalf of one job (Building, script-run, streamed build output, ...) must be prefixed with
+ the job's project path so it stays attributable.
+ -->
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-invoker-plugin</artifactId>
+ <version>@project.version@</version>
+ <configuration>
+ <cloneProjectsTo>${project.build.directory}/its</cloneProjectsTo>
+ <pomIncludes>
+ <pomInclude>*/pom.xml</pomInclude>
+ </pomIncludes>
+ <preBuildHookScript>setup</preBuildHookScript>
+ <goals>
+ <goal>validate</goal>
+ </goals>
+ <streamLogs>true</streamLogs>
+ <parallelThreads>2</parallelThreads>
+ </configuration>
+ <executions>
+ <execution>
+ <id>integration-test</id>
+ <phase>initialize</phase>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/src/it/parallel-log-prefix/src/it/alpha/pom.xml b/src/it/parallel-log-prefix/src/it/alpha/pom.xml
new file mode 100644
index 0000000..b45c6da
--- /dev/null
+++ b/src/it/parallel-log-prefix/src/it/alpha/pom.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+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.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>test</groupId>
+ <artifactId>alpha</artifactId>
+ <version>0.1-SNAPSHOT</version>
+ <packaging>pom</packaging>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+</project>
diff --git a/src/it/parallel-log-prefix/src/it/alpha/setup.groovy b/src/it/parallel-log-prefix/src/it/alpha/setup.groovy
new file mode 100644
index 0000000..25c5a1f
--- /dev/null
+++ b/src/it/parallel-log-prefix/src/it/alpha/setup.groovy
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+import java.io.*;
+
+// marker for parent build that this sub build was indeed run
+File touchFile = new File( basedir, "touch.txt" )
+touchFile.createNewFile()
+
+println("Output from setup script for alpha")
diff --git a/src/it/parallel-log-prefix/src/it/beta/pom.xml b/src/it/parallel-log-prefix/src/it/beta/pom.xml
new file mode 100644
index 0000000..836512c
--- /dev/null
+++ b/src/it/parallel-log-prefix/src/it/beta/pom.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+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.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>test</groupId>
+ <artifactId>beta</artifactId>
+ <version>0.1-SNAPSHOT</version>
+ <packaging>pom</packaging>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+</project>
diff --git a/src/it/parallel-log-prefix/src/it/beta/setup.groovy b/src/it/parallel-log-prefix/src/it/beta/setup.groovy
new file mode 100644
index 0000000..c38a165
--- /dev/null
+++ b/src/it/parallel-log-prefix/src/it/beta/setup.groovy
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+import java.io.*;
+
+// marker for parent build that this sub build was indeed run
+File touchFile = new File( basedir, "touch.txt" )
+touchFile.createNewFile()
+
+println("Output from setup script for beta")
diff --git a/src/it/parallel-log-prefix/verify.groovy b/src/it/parallel-log-prefix/verify.groovy
new file mode 100644
index 0000000..006c3bc
--- /dev/null
+++ b/src/it/parallel-log-prefix/verify.groovy
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+def FS = File.separator
+def alphaProject = 'alpha' + FS + 'pom.xml'
+def betaProject = 'beta' + FS + 'pom.xml'
+
+// make sure both sub builds were indeed run
+assert new File(basedir, 'target/its/alpha/touch.txt').exists()
+assert new File(basedir, 'target/its/beta/touch.txt').exists()
+
+def buildLog = new File(basedir, 'build.log').text
+def lines = buildLog.readLines()
+
+// MINVOKER-684: with parallelThreads > 1, every console line emitted on behalf of a job is prefixed with
+// the job's project path, so interleaved output from several jobs stays attributable.
+
+// the "Building: <project>" line is prefixed
+assert lines.any { it.contains('[' + alphaProject + '] Building: ' + alphaProject) }
+assert lines.any { it.contains('[' + betaProject + '] Building: ' + betaProject) }
+
+// script-run lines reaching the console via streamLogs are prefixed
+assert lines.any { it.contains('[' + alphaProject + '] Running pre-build script') }
+assert lines.any { it.contains('[' + betaProject + '] Running pre-build script') }
+
+// streamed script output lines are prefixed
+assert lines.any { it.contains('[' + alphaProject + '] Output from setup script for alpha') }
+assert lines.any { it.contains('[' + betaProject + '] Output from setup script for beta') }
+
+// the result summary line already carries the project name via the padded column, so it must not get a
+// second, bracketed copy of it; "SUCCESS (" is unique to that summary line (as opposed to the streamed
+// "BUILD SUCCESS" output of the nested Maven invocation, which has no trailing elapsed time)
+def alphaResultLine = lines.find { it.contains(alphaProject) && it.contains('SUCCESS (') }
+assert alphaResultLine != null
+assert !alphaResultLine.contains('[' + alphaProject + ']')
+
+def betaResultLine = lines.find { it.contains(betaProject) && it.contains('SUCCESS (') }
+assert betaResultLine != null
+assert !betaResultLine.contains('[' + betaProject + ']')
+
+// the prefix is a console-only concern: the per-job build.log file content must stay untouched
+def alphaLog = new File(basedir, 'target/its/alpha/build.log').text
+def betaLog = new File(basedir, 'target/its/beta/build.log').text
+
+assert !alphaLog.contains('[' + alphaProject + ']')
+assert !betaLog.contains('[' + betaProject + ']')
+assert alphaLog.contains('Running pre-build script')
+assert betaLog.contains('Running pre-build script')
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 c687ad9..0a066f7 100644
--- a/src/main/java/org/apache/maven/plugins/invoker/AbstractInvokerMojo.java
+++ b/src/main/java/org/apache/maven/plugins/invoker/AbstractInvokerMojo.java
@@ -1300,7 +1300,8 @@ public abstract class AbstractInvokerMojo extends AbstractMojo {
}
try {
- if (runWithParallelThreads > 1) {
+ boolean parallelRun = runWithParallelThreads > 1;
+ if (parallelRun) {
getLog().info("use parallelThreads " + runWithParallelThreads);
}
@@ -1314,7 +1315,8 @@ public abstract class AbstractInvokerMojo extends AbstractMojo {
mergedSettingsFile,
javaHome,
actualJreVersion,
- globalInvokerProperties.get(ancestorFolder));
+ globalInvokerProperties.get(ancestorFolder),
+ parallelRun);
});
} finally {
if (interpolatedSettingsFile != null && cloneProjectsTo == null) {
@@ -1506,7 +1508,8 @@ public abstract class AbstractInvokerMojo extends AbstractMojo {
File settingsFile,
File actualJavaHome,
CharSequence actualJreVersion,
- Properties globalInvokerProperties)
+ Properties globalInvokerProperties,
+ boolean parallelRun)
throws MojoExecutionException {
// FIXME: Think about the following code part -- START
File pomFile = new File(projectsDir, buildJob.getProject());
@@ -1526,7 +1529,15 @@ public abstract class AbstractInvokerMojo extends AbstractMojo {
File interpolatedPomFile = interpolatePomFile(pomFile, basedir);
// FIXME: Think about the following code part -- ^^^^^^^ END
- getLog().info(buffer().a("Building: ").strong(buildJob.getProject()).build());
+ // when several jobs run in parallel, their console output interleaves; prefix every line emitted on
+ // behalf of this job with its project path so it stays attributable (MINVOKER-684). Lines that already
+ // carry the project name via pad(buildJob) are left alone to avoid a duplicate copy.
+ String logPrefix = parallelRun ? "[" + buildJob.getProject() + "] " : "";
+
+ getLog().info(buffer().a(logPrefix)
+ .a("Building: ")
+ .strong(buildJob.getProject())
+ .build());
InvokerProperties invokerProperties = getInvokerProperties(basedir, globalInvokerProperties);
@@ -1540,7 +1551,7 @@ public abstract class AbstractInvokerMojo extends AbstractMojo {
long startTime = System.currentTimeMillis();
boolean executed;
- FileLogger buildLogger = setupBuildLogFile(basedir, buildJob.getExecutionCount());
+ FileLogger buildLogger = setupBuildLogFile(basedir, buildJob.getExecutionCount(), logPrefix);
if (buildLogger != null) {
buildJob.setBuildlog(buildLogger.getOutputFile().getAbsolutePath());
}
@@ -1609,7 +1620,7 @@ public abstract class AbstractInvokerMojo extends AbstractMojo {
buildJob.setFailureMessage(e.getMessage());
if (!suppressSummaries) {
- getLog().info(" " + e.getMessage());
+ getLog().info(logPrefix + " " + e.getMessage());
getLog().info(pad(buildJob).failure("FAILED").a(' ') + "(" + formatElapsedTime(buildJob.getTime())
+ ")");
}
@@ -1955,10 +1966,13 @@ public abstract class AbstractInvokerMojo extends AbstractMojo {
*
* @param basedir The base directory of the project, must not be <code>null</code>.
* @param executionCount current execution count of the build job, used to determine whether to append to or create a new log file
+ * @param logPrefix prefix prepended to every line mirrored to the mojo logger (empty when not running in
+ * parallel), never affects the content written to {@code build.log}.
* @return The build logger or <code>null</code> if logging has been disabled.
* @throws org.apache.maven.plugin.MojoExecutionException If the log file could not be created.
*/
- private FileLogger setupBuildLogFile(File basedir, int executionCount) throws MojoExecutionException {
+ private FileLogger setupBuildLogFile(File basedir, int executionCount, String logPrefix)
+ throws MojoExecutionException {
FileLogger logger = null;
if (!noLog) {
@@ -1988,7 +2002,7 @@ public abstract class AbstractInvokerMojo extends AbstractMojo {
getLog().debug("Renaming existing log file " + logPath + " to " + logFileBackup);
Files.move(logPath, logFileBackup, StandardCopyOption.REPLACE_EXISTING);
}
- logger = new FileLogger(logPath.toFile(), streamLogger);
+ logger = new FileLogger(logPath.toFile(), streamLogger, logPrefix);
getLog().debug("New build log initialized: " + logPath);
} catch (IOException e) {
throw new MojoExecutionException("Error initializing build logfile in: " + projectLogDirectory, e);
diff --git a/src/main/java/org/apache/maven/plugins/invoker/FileLogger.java b/src/main/java/org/apache/maven/plugins/invoker/FileLogger.java
index 1a0d535..6f6011c 100644
--- a/src/main/java/org/apache/maven/plugins/invoker/FileLogger.java
+++ b/src/main/java/org/apache/maven/plugins/invoker/FileLogger.java
@@ -23,6 +23,7 @@ import java.io.IOException;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.shared.invoker.InvocationOutputHandler;
+import org.apache.maven.shared.scriptinterpreter.FileLoggerMirrorHandler;
/**
*
@@ -37,6 +38,32 @@ class FileLogger extends org.apache.maven.shared.scriptinterpreter.FileLogger im
* @throws IOException If the output file could not be created.
*/
FileLogger(File outputFile, final Log log) throws IOException {
- super(outputFile, log != null ? log::info : null);
+ this(outputFile, log, null);
+ }
+
+ /**
+ * Creates a new logger that writes to the specified file and optionally mirrors messages to the given mojo
+ * logger, prefixing every mirrored line with {@code logPrefix}. The file content is never prefixed, only the
+ * lines mirrored to the mojo logger, which is how per-job output stays attributable when several jobs run in
+ * parallel and interleave on the console.
+ *
+ * @param outputFile The path to the output file, must not be <code>null</code>.
+ * @param log The mojo logger to additionally output messages to, may be <code>null</code> if not used.
+ * @param logPrefix The prefix to prepend to every line mirrored to the mojo logger, may be <code>null</code> or
+ * empty if no prefix is needed.
+ * @throws IOException If the output file could not be created.
+ */
+ FileLogger(File outputFile, final Log log, final String logPrefix) throws IOException {
+ super(outputFile, toMirrorHandler(log, logPrefix));
+ }
+
+ private static FileLoggerMirrorHandler toMirrorHandler(final Log log, final String logPrefix) {
+ if (log == null) {
+ return null;
+ }
+ if (logPrefix == null || logPrefix.isEmpty()) {
+ return log::info;
+ }
+ return line -> log.info(logPrefix + line);
}
}