The build lifecycle implemented for the first alpha has been extremely helpful, but there are some remaining tasks to allow it to be a complete replacement for the goal graph of Maven 1.x.
Defining the lifecycle according to packaging
I think it is worthwhile defining the lifecycle by the packaging, so the phases are fixed, but their mapping to
goals are defined as configuration inside the artifact type handler. This allows a plugin to add a plugin:descriptor
goal. It also allows a packaging of pom to not register any of the goals other than install/deploy.
The alternative is to always register them, disregarding the type, and use the type as a mojo execution guard - but
I think this might be less clean in this particular case.
Lifecycle alterations
Use cases:
- plexus application use case
- idea:idea running generate-sources (defined by the mojo)
- assembly:assembly running package (defined by the project)
- clover running tests
- jcoverage, modifying class files
- reports running tests, etc
Plexus application
want to be able to run "plexus:app plexus:bundle-application plexus:test-runtime"
plexus:app and plexus:bundle-application are analogous to war:exploded and war:war, so it would be better there for:
- app and bundle to share the same logic, so app is run for a quick deployment, but bundle is all that is actually needed
- plexus:bundle-application be the goal used for "package" when type = plexus-application
plexus:test-runtime is like making an assembly. It would be wired in as the "executePhase" for assembly:assembly (see
below), and in turn "package" would be the executePhase for this goal.
idea:idea running generate-sources
This is covered by the current addition of @executePhase to the mojo declaration, so that generate-sources is
always run before the execution of idea:idea as a new lifecycle instance, with the results that affect the project
(ie the addition of a new compile source root) still applies afterwards.
The project used needs to be a clone that lasts the life of the executed lifecycle and the idea:idea goal, but
goes back to normal afterwards so the effects don't hit other goals.
assembly:assembly running package (defined by the project)
This can be covered by the addition of <executePhase/> to the goal configuration, ie:
<plugin> <artifactId>maven-assembly-plugin</artifactId> <executePhase>package</executePhase> <configuration> ... </configuration> </plugin>
Here, this would override anything specified on the mojo using @executePhase, if applicable, but otherwise would
behave identically.
Clover use case
M1 plugin:
- clover:init -> sets up classpath, no real work
- clover -> clover:test, clover:report
- clover:on -> sets up clover compiler, turns of test failure, turns on test forking, changes class dest
- clover:off -> undoes clover:on
- clover:test -> on, test, off (builds database)
Desired use: m2 clover:clover
- register clover compiler goal into generate-sources
- modify output directory
- run test (based on executePhase)
- report database later reused
register clover compiler goal into generate-sources
- the binding is a parameter of the executed goal, not any existing lifecycle, so is different. Don't want to use
@phase - declaring this as part of the qdox block could be a bit tricky - we'll use XML.
- this is an overlay, just like the type handlers, so reuse that
modify output directory
- in this specific case, we actually want to keep it all separate, so we are adding a new output directory to a
source root, so we need to pair those up, and also add a new runtime classpath element
run test
- as for other executePhase above
- can't do any dependendant stuff in clover:clover itself, as executePhase is done before that is executed
How to bind the clover compiler goal:
@goal clover
@executePhase test
META-INF/maven/lifecycle.xml (one per plugin - could it be in plugin.xml?)
<lifecycle> <phase> <id>generate-sources</id> <goals> <goal> <id>clover:compile</id> </goal> </goals> </phase> </lifecycle>
@goal compile @parameter name="outputDirectory" expression="$\{project.build.directory\}/generated-sources/clover"
Jcoverage use case
Different to clover in that it modifies classes rather than adding compiled classes. Still not looking at the reporting
case just yet.
Desired use: m2 jcoverage:jcoverage
- register jcoverage:instrument goal for process-classes
- modify classpath for test running
- run test
- report database later reused
register jcoverage:instrument goal for process-classes
- done with an overlay just like clover
modify classpath for test running
- we use some configuration in the lifecycle overlay which specifies new defaults
- the ognl symmetry could play some part in this instead, so depends on how John works that.
eg, instrument could do @export outputDirectory project.build.outputDirectory
run test
- as for other executePhase above
How to bind:
@goal jcoverage @executePhase test
META-INF/maven/lifecycle.xml (one per plugin - could it be in plugin.xml?)
<lifecycle> <phase> <id>process-classes</id> <goals> <goal> <id>jcoverage:instrument</id> </goal> </goals> </phase> <!-- ... --> <phase> <id>test</id> <goals> <goal> <id>surefire:test</id> <configuration> <!-- This assumes this is used instead of adding a runtime classpath element, which might be a good idea --> <classesDirectory>${project.build.directory}/generated-classes/jcoverage</classesDirectory> <ignoreFailures>true</ignoreFailures> </configuration> </goal> </goals> </phase> </lifecycle>
@goal instrument @parameter name="outputDirectory" expression="$\{project.build.directory\}/generated-classes/jcoverage"
Other reporting
Do other reports require anything additional?
junit-report:
- this executes the test goal, no change in parameters
pmd:
- standard report
- will use generated sources so needs to ensure this has been run
- might also fail based on certain threshold
- all fits
overall site:
- is this a new lifecycle, or does it run each goal on its own based on the registered reports? I believe it is the
latter.
Random notes
- does executePhase need something that indicates "pre" in the name?
- did we decide on something like an around notation AOP style for the lifecycle?
- do we really execute a lifecycle, or just require to avoid re-executing?
- this would avoid running test:test again
- theoretically, test:test should be smart enough not to run again anyway
- this could get back to the @prereq situation to some extent
- how is it actullay run if it hasn't been already? forked lifecycle? Is this a little inconsistent?
- common use is generated-sources which might not be fast to run over and over
- here I would like to flatten down the lifecycle
- still means getting back to a @requires style notation, and auto-ordering seems dangerous
- perhaps it isn't doing any ordering? All the reports are in a bucket that are in the right place, and only
required phases get activated? - or does it start from a blank lifecycle and each additional goal overlays additional stuff?
- does this cause a risk of things not working because there are now three test executions, each with different
parameters? - can we instead do the forked execution, but make use of the execution strategies so things still only execute once
with identical parameters? - but what if another goal modifies some of its parameters?
- general behaviour is that if something is specified twice now, it is run twice, because of the removal of prereqs
- inclined to say we do the forking here for now at least.
- @phase vs. lifecycle declaration is a bit arbitrary. eg, should resources:resources always be part of
process-resources? Why not use the @phase and somehow trigger it's inclusion? - encapsulate all transfer in mojo fields, use OGNL to translate back to project
- how would this be specified? does each field that exports provide an @export tag, or does it have an
in, out, inout specifier? (urgh, CORBA flashback!)
- how would this be specified? does each field that exports provide an @export tag, or does it have an