Lifecycle Plugin (quokka.plugin.lifecycle:0.3, namespace=lifecycle)

The lifecycle plugin defines abstract targets defining the build lifecycle of a module, including compile, test, package and install. Other plugins implement such targets, providing the actual functionality.

The lifecycle plugin is central to building projects with quokka. The plugin itself is entirely abstract. i.e. including the plugin on it's own doesn't actually do anything that effects your project files. Instead, it defines an abstract framework that other plugins implement. For example, the lifecycle plugin defines the abstract compile target that Javac plugin implements.

The Lifecycle

The lifecycle targets are organised as a chain of dependencies. The following lists the targets in order. If you execute any target in the list, all targets that proceed it get executed.

  • initialise
  • generate-sources
  • process-sources
  • generate-resources
  • process-resources
  • compile
  • process-compiled
  • instrument-compiled
  • generate-test-sources
  • process-test-sources
  • generate-test-resources
  • process-test-resources
  • test-compile
  • test
  • package
  • initialise-integration-test
  • integration-test-impl
  • finalise-integration-test
  • integration-test
  • verify
  • install

For example, if you execute process-sources, the project build sequence will be initialise, then generate-sources, followed by process-sources

Continuing the example of Javac plugin, let's consider what happens when the Javac plugin implements compile. If you consult the Javac plugin documentation you will see that it declares a target javac:compile that implements lifecycle:compile. When quokka encounters an implements declaration during initialisation, it rewires the target dependencies as follows:

  • The implementing target is added as a dependency of the abstract target.
  • Any dependencies of the abstract target are moved to become dependencies of the implementing target.

So in the case adding the Javac plugin, the modified build sequence becomes:

    ...
  • process-resources
  • javac:compile
  • compile
  • ...

This mechanism is quite flexible as it allows the user to continue using the abstract target name of compile regardless of what implementations are available. However, it also exposes the javac:compile to the user for direct access if desired.

There is one detail missing for the above description, namely pre-targets. If you look at the real sequence below you will notice that every lifecycle target is proceed by a target of the same name prefixed by pre-.

So the real build sequence is actually:

    ...
  • pre-process-resources
  • process-resources
  • pre-compile
  • javac:compile
  • compile
  • ...

Why the extra targets? They are there so the users can reliably insert additional ad hoc targets into the build sequence. For example, let's assume the user wants insert a target between compile and process-resources

Without the pre-targets, they would have to refer to the javac target as follows:

<target name="mytarget" depends="process-resources" dependency-of="javac:compile">

This is problematic because there may be no implementations, or multiple implementations (whose order is undefined), or may break if an additional implementation is added. Using pre-targets, these problems are avoided completely with the delcaration becoming:

<target name="mytarget" depends="process-resources" dependency-of="pre-compile">

Project Paths

The other important aspect to the lifecycle plugin is that it defines some important project paths and controls how they are merged. The following paths are defined:

id Description Descends Default
compile Compilation class path false
test-compile Tests compilation class path false
test Tests runtime class path true
itest Integration tests runtime class path true
runtime Runtime class path true

The descends default value controls whether transitive dependendencies (dependencies of dependencies) are added when you add a dependency to a path. See here for more information.

Targets merge the above paths as follows:

Target Merged Paths
compile compile
test-compile test-compile, compile
test test, test-compile, compile, ${q.lifecycle.testPaths}*
integration-test-impl itest, test, test-compile, compile, ${q.lifecycle.itestPaths}*

* The q.lifecycle.testPaths/itestPaths entries are an elaborate means of adding the runtime paths to the merged testing paths. By default, q.lifecycle.testPaths/itestPaths are defined to be the value of q.project.exportedPaths. q.project.exportedPaths contains any project paths that you are exporting to the repository, which is usually runtime.

Why all this indirection? The reason is that quokka (and it's repositories) supports multiple runtime paths. By default Quokka defines a path with an id of runtime. However, this is just a convenience and users are free to ignore it.

Notes for Maven users:

There are some important differences between how Quokka and Maven handle project paths:

  • In Maven you do not actually assign dependencies to paths. Instead you set scopes and Maven attempts to derive the paths based on the scopes.
  • Maven's compile scope includes transitive dependencies, where adding a dependency to Quokka's compile path does not. Quokka's approach is the correct approach as it forces you to declare all source code dependencies explicitly. Maven states that it doesn't do this due to cases where extending an abstract class requires classes not referenced in the source. This is true, however Quokka allows you to add such dependencies as options when required. e.g. in this example, bootstrap-util is for compilation, but not actually referenced in the source
    <dependency group="quokka.core.plugin-spi" version="?" paths="compile(bootstrap-util), runtime"/>
  • Quokka splits the Maven test scope into test-compile, test and itest. Again, this forces explicit declaration of all source dependencies. If you don't like this, see the next section for overriding the defaults.

Overriding the defaults

The defaults in Quokka are designed to be strict to enforce all dependencies to be declared. However, you can override the defaults simply if you don't like them using path specifications. Here's some examples:

  • Excluding transitive dependencies for runtime paths: To do this, just append a + character after the path name. e.g.
    <dependency group="apache.ant" version="1.7.1" paths="runtime+"/>
  • Including transitive dependencies for test paths: To do this, just append a < after the path name. e.g.
    <dependency group="apache.ant" version="1.7.1" paths="test-compile<"/>

Abstract Targets

clean Cleans the project, deleting all generated files
pre-initialise
initialise Initialisation hook for plugins
pre-generate-sources
generate-sources Generate any source code for inclusion in compilation
pre-process-sources
process-sources Process the source code, for example to filter any values
pre-generate-resources
generate-resources Generate resources for inclusion in the package
pre-process-resources
process-resources Copy and process the resources into the destination directory, ready for packaging
pre-compile
compile Compile the source code of the project
pre-process-compiled
process-compiled Post-process the generated files from compilation, for example to do bytecode enhancement on Java classes
pre-instrument-compiled
instrument-compiled Instruments compiled classes for code coverage
pre-generate-test-sources
generate-test-sources Generate any test source code for inclusion in compilation
pre-process-test-sources
process-test-sources Process the test source code, for example to filter any values
pre-generate-test-resources
generate-test-resources Create resources for testing
pre-process-test-resources
process-test-resources Copy and process the resources into the test destination directory
pre-test-compile
test-compile Compile the test source code into the test destination directory
pre-test
test Run tests using a suitable unit testing framework. These tests should not require the code be packaged or deployed
pre-package
package Take the compiled code and package it in its distributable format, such as a JAR
pre-initialise-integration-test
initialise-integration-test
pre-integration-test-impl
integration-test-impl Abstract target that plugins that implement integration tests should implement
pre-finalise-integration-test
finalise-integration-test
integration-test Process and deploy the package if necessary into an environment where integration tests can be run
pre-verify
verify Run any checks to verify the package is valid and meets quality criteria
pre-install
install Install the package into the local repository, for use as a dependency in other projects locally

Shared Default Properties

q.lifecycle.compileOutput ${q.project.targetDir}/compile
q.lifecycle.resourcesOutput ${q.lifecycle.compileOutput}
q.lifecycle.packageOutput ${q.project.targetDir}/package
q.lifecycle.testCompileOutput ${q.project.targetDir}/test-compile
q.lifecycle.instrumentCompiledOutput ${q.project.targetDir}/instrumented-compile
q.lifecycle.testResourcesOutput ${q.lifecycle.testCompileOutput}

clean

Cleans the project, deleting all generated files

  • alias: clean

pre-initialise


initialise

Initialisation hook for plugins

  • depends: pre-initialise

pre-generate-sources

  • depends: initialise

generate-sources

Generate any source code for inclusion in compilation

  • alias: generate-sources
  • depends: pre-generate-sources

pre-process-sources

  • depends: generate-sources

process-sources

Process the source code, for example to filter any values

  • alias: process-sources
  • depends: pre-process-sources

pre-generate-resources

  • depends: process-sources

generate-resources

Generate resources for inclusion in the package

  • alias: generate-resources
  • depends: pre-generate-resources

pre-process-resources

  • depends: generate-resources

process-resources

Copy and process the resources into the destination directory, ready for packaging

  • alias: process-resources
  • depends: pre-process-resources

pre-compile

  • depends: process-resources

compile

Compile the source code of the project

  • alias: compile
  • depends: pre-compile

pre-process-compiled

  • depends: compile

process-compiled

Post-process the generated files from compilation, for example to do bytecode enhancement on Java classes

  • alias: process-compiled
  • depends: pre-process-compiled

pre-instrument-compiled

  • depends: process-compiled

instrument-compiled

Instruments compiled classes for code coverage

  • alias: instrument-compiled
  • depends: pre-instrument-compiled

pre-generate-test-sources

  • depends: instrument-compiled

generate-test-sources

Generate any test source code for inclusion in compilation

  • alias: generate-test-sources
  • depends: pre-generate-test-sources

pre-process-test-sources

  • depends: generate-test-sources

process-test-sources

Process the test source code, for example to filter any values

  • alias: process-test-sources
  • depends: pre-process-test-sources

pre-generate-test-resources

  • depends: process-test-sources

generate-test-resources

Create resources for testing

  • alias: generate-test-resources
  • depends: pre-generate-test-resources

pre-process-test-resources

  • depends: generate-test-resources

process-test-resources

Copy and process the resources into the test destination directory

  • alias: process-test-resources
  • depends: pre-process-test-resources

pre-test-compile

  • depends: process-test-resources

test-compile

Compile the test source code into the test destination directory

  • alias: test-compile
  • depends: pre-test-compile

pre-test

  • depends: test-compile

test

Run tests using a suitable unit testing framework. These tests should not require the code be packaged or deployed

  • alias: test
  • depends: pre-test

Default Properties

q.lifecycle.testPaths ${q.project.exportedPaths}

pre-package

  • depends: test

package

Take the compiled code and package it in its distributable format, such as a JAR

  • alias: package
  • depends: pre-package

pre-initialise-integration-test

  • depends: package

initialise-integration-test

  • depends: pre-initialise-integration-test

pre-integration-test-impl

  • depends: initialise-integration-test

integration-test-impl

Abstract target that plugins that implement integration tests should implement

  • depends: pre-integration-test-impl

Default Properties

q.lifecycle.itestPaths ${q.project.exportedPaths}

pre-finalise-integration-test

  • depends: integration-test-impl

finalise-integration-test

  • depends: pre-finalise-integration-test

integration-test

Process and deploy the package if necessary into an environment where integration tests can be run

  • alias: itest
  • depends: finalise-integration-test

pre-verify

  • depends: integration-test

verify

Run any checks to verify the package is valid and meets quality criteria

  • alias: verify
  • depends: pre-verify

pre-install

  • depends: verify

install

Install the package into the local repository, for use as a dependency in other projects locally

  • alias: install
  • depends: pre-verify

Plugin Paths

runtime : Runtime class path

quokka.core.plugin-spi plugin-spi 0.3

quokka.core.bootstrap-util bootstrap-util 0.3

apache.ant ant 1.7.1