Provide a way to control the execution of MOJOs within a phase and guarantee that specific MOJOs will be executed around lifecycle phases
The standard Maven lifecycles have a number of phases with names that start with
post- as siblings to a main phase, for example:
post-integration-testare siblings of
post-siteare siblings of
post-cleanare siblings of
Most new users assume that as the
pre- phases will be executed before the main phase (which is correct, but only be the accident of the lifecycle ordering) the
post- phases will be executed after the main phase much like the finally block in a Java try expression (which is incorrect).
- Most Maven users will invoke the
cleanlifecycle with a command like
mvn clean, yet to ensure that the lifecycle has run correctly you should really run
sitelifecycle is slightly better as at least invoking
mvn site-deploywill afford the
post-sitephase to execute, but this is only for the happy path where the
sitephase completed successfully.
defaultlifecycle has the least worst situation because
integration-testis so long to type that most people will run
mvn verifywhich again affords execution only for the happy path where
integration-testcompletes successfully. To enable the successful use of the
integration-testphase therefore requires that MOJOs used in this phase are written in such a way that they never fail and instead provide a second MOJO that can be bound to the verify phase in order to fail the build after the
post-integration-testphase has completed. This prevents the use of general purpose MOJOs with integration testing and complicates plugin design.
If we look more critically at the lifecycle phases we can also identify a number of phases that are purely present to enable the correct sequencing of MOJO executions:
process-sources: it's hard to see why you would ever want to generate the sources and not have them processed, given that any executions bound to
process-sourcesis a necessary pre-requisite for compilation
process-classes: it's hard to see why you would want the classes that have not been processed
package: the prepare-package phase was added specifically to enable two phase packaging
The resulting multiude of phases just furthers the complexity for users: they become parallelized by choice.
pom.xml only naming scheme for ad-hoc dynamic phases that will enable the
pom.xml to control execution while restricting this syntax to the
pom.xml only. The command line would only be able to invoke the explicit lifecycle phases directly.
To clarify, these dynamic phases would only be valid in the
/executions/execution/phase element of a
<plugin> in the
There will be two classes of dynamic phases:
- Guaranteed execution
- In phase ordering
Note: please append any alternative syntax proposals to this section
This syntax uses two prefixes before: and after: to identify phases that will be guaranteed to run before and after the named phase
$phase. As a result we would be able to deprecate the
post-integration-test phases in favour of
after:integration-test which would not be defined in any lifecycle, but instead be dynamically created by virtue of specifying an execution bound to that phase.
<plugin> ... <executions> <execution> <id>start-server</id> <phase>before:integration-test</phase> <goals> <goal>start</goal> </goals> ... </execution> <execution> <id>stop-server</id> <phase>after:integration-test</phase> <goals> <goal>stop</goal> </goals> ... </execution> ... </executions> ... </plugin>
Every phase in any lifecycle would have its own implicit
after: phases in the lifecycle.
The logic of using
: in these prefix names is that it would expressly be impossible to invoke these dynamic pseudo phases from the CLI as Maven will interpret any attempt to invoke them as
$plugin:$goal and look for a
The within phase ordering will be achieved by the addition of a
[$priority] suffix. The priority will be an integer (positive and negative allowed) and execution of the lifecycle phase will invoke all bound MOJOs in order starting with the highest priority and ending with the lowest priority. Where two executions have the same priority, they will be executed in
The logic of using
 in these suffix priorities is that these characters are in the typical reserved set for POSIX shells and used to specify a range of characters, again making it difficult to envision invoking a phase with priority from the command line without careful escaping. In any case the CLI would not permit the execution of a phase with priority. The CLI will only be able to execute a phase as a whole.
<packaging>war</packaging> ... <plugin> <artifactId>maven-jar-plugin</artifactId> <executions> <!-- create the jar file to use inside the war --> <execution> <phase>package[-1000]</phase> <goals> <goal>jar</goal> </goals> ... </execution> ... </executions> ... </plugin> <plugin> <artifactId>maven-assembly-plugin</artifactId> <executions> <!-- create the distribution that includes the war and docs --> <execution> <phase>package</phase> <goals> <goal>assemble</goal> </goals> ... </execution> ... </executions> ... </plugin>
In order to allow lifecycle bindings per project type to include information about the pseudo phases and phase priorities, we would need to modify the syntax of the bindings reference, e.g. https://maven.apache.org/ref/3.6.2/maven-core/default-bindings.html
This proposal would modify the bindings XML schema to include optional attributes of
priority if not specified then the execution point would be considered to be the phase itself and not
after and the priority would be assumed to be
<phases> ... <integration-test execution-point="before"> ...:...:...:start </integration-test> <integration-test execution-point="after" priority="1000"> ...:...:...:stop </integration-test> ... </phases>
The rationale is that this schema change is backwards compatible with the existing bindings schema and thus existing extensions defining bindings will still remain valid (just not able to bind to these dynamic phases)
We would also need to modify the
@Mojo annotation adding new properties
executionPoint = ExecutionPoint.BEFORE|ExecutionPoint.AFTER and
priority = <int>
This proposal would lay the groundwork for the simplification of the Maven lifecycles. This proposal would only bring us to the transitional state, with the migration to the future state likely part of the Maven 5.0.0 effort.
To be determined:
- Do we really need a differentiation between sources and resources. If we have priority could we not just assign a different priority to the resource element of the sources leaving the default lifecyle in the future state as:
validate, initialize, sources, compile, test-sources, test-compile, test, package, integration-test verify, install, deploy?
- Do we need a differentiation between
- Should we add a special phase to represent all lifecycles, e.g.
before:*that will always execute before any lifecycle starts and
after:*that will always execute after any lifecycle completes?