slawekjaranowski commented on code in PR #13330: URL: https://github.com/apache/maven/pull/13330#discussion_r4178310251
########## src/site/markdown/aggregator-goals.md: ########## @@ -0,0 +1,124 @@ +<!-- +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. +--> +# Aggregator Mojos and Reactor Lifecycle Specification + +## Overview + +Aggregation was introduced early in Maven 2 ([MNG-250](https://issues.apache.org/jira/browse/MNG-250)) to enable plugins to operate across an entire multi-module build reactor rather than on a single isolated module. It is exposed to plugin developers via the `@Mojo(aggregator = true)` annotation (or `@aggregator` in JavaDoc tag format). + +This document analyzes the current behavior, outlines historical shortcomings, and establishes a target design specification for refactoring aggregator goals in Maven ([MNG-7991](https://issues.apache.org/jira/browse/MNG-7991)). + +--- + +## 1. Current Aggregator Behavior + +Maven treats aggregator Mojos differently depending on whether they are invoked directly via the Command Line Interface (CLI) or bound to a build lifecycle phase in a POM. + +### 1.1 CLI Invocation (`mvn plugin:goal`) +When an aggregating goal is invoked from the command line: +1. **Task Segment Classification**: `DefaultLifecycleTaskSegmentCalculator` inspects the Mojo descriptor: + ```java + boolean aggregating = mojoDescriptor.isAggregator() || !mojoDescriptor.isProjectRequired(); + ``` +2. **Aggregating Task Segment**: A distinct aggregating `TaskSegment` is created. +3. **Execution on Root Project Only**: `BuildListCalculator` (and `BuildPlanExecutor` in the concurrent path) restricts aggregating task segments to the top-level project (`session.getTopLevelProject()`). Submodules in the reactor are skipped for this goal. +4. **Ordering**: If the CLI invocation specifies both a lifecycle phase and an aggregator goal (e.g. `mvn clean install site:stage`), the normal lifecycle runs across all modules first, and the aggregator goal executes once at the end on the root module. + +### 1.2 Lifecycle-Bound Execution (`<phase>...</phase>`) +When an aggregator Mojo is bound to a phase in a `pom.xml`: +1. **Lifecycle Segment Classification**: Lifecycle phases (e.g. `package`, `verify`) produce standard non-aggregating `TaskSegment`s. +2. **Per-Module Execution**: The goal is injected into the execution plan of **every module** in the reactor that inherits the plugin configuration. +3. **Redundant Executions**: Unless the project author explicitly configures `<inherited>false</inherited>` on the plugin execution in the parent POM, the aggregator Mojo executes once for each module in the reactor. +4. **Thread Locking**: In parallel builds (`-T`), `MojoExecutor` acquires an exclusive reactor-wide write lock (`aggregatorLock.writeLock()`) whenever an aggregator executes: + ```java + acquiredAggregatorLock = aggregator ? aggregatorLock.writeLock() : aggregatorLock.readLock(); + ``` + Executing an aggregator Mojo across multiple submodules repeatedly halts parallel build concurrency across all threads. + +### 1.3 Dependency Resolution +When executing an aggregator Mojo: +- `MojoExecutor.ensureDependenciesAreResolved` checks `mojoDescriptor.isAggregator()`. +- If `true`, Maven resolves dependencies not only for the current project, but also across all projects in `session.getProjects()` matching the scopes requested by the Mojo. + +### 1.4 Forked Lifecycles +When an aggregator Mojo declares `@Execute(phase = ...)` or `@Execute(goal = ...)`: +- `BuildPlanExecutor` creates a forked plan encompassing the current project and all collected sub-projects (`step.project.getCollectedProjects()`). +- This forks execution across the entire reactor tree, leading to duplicated builds, redundant tests, and nested reactor re-executions. + +--- + +## 2. Identified Shortcomings & Problem Space + +Over successive Maven releases, multiple discrepancies and pain points have been identified: + +1. **CLI vs. Lifecycle Discrepancy ([MNG-6336](https://issues.apache.org/jira/browse/MNG-6336))**: Review Comment: As we migrated issues to GH, I would like to point to current at GH. In JIRA all issues are read only. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
