I'm trying to reuse common logic among multiple Gradle tasks, similar to what was suggested in this answer, but I'm having trouble with extra project properties not being visible.
Boiled down, here's the problem. Say I have a root Gradle build script, build.gradle
that sets an extra project property,
project.ext.myProp = 'myValue'
I have a subproject defined in settings.gradle
,
include 'subproject'
and the subproject defines and uses a custom task that references that extra project property,
class CustomTask extends DefaultTask {
CustomTask() {
doFirst {
println project.ext.myProp
}
}
}
task custom(type: CustomTask) {
println 'custom task'
}
Executing this gives me this:
FAILURE: Build failed with an exception.
...
* Exception is:
org.gradle.api.GradleScriptException: A problem occurred evaluating project ':subproject'.
...
Caused by: org.gradle.api.tasks.TaskInstantiationException: Could not create task of type 'CustomTask'.
...
Caused by: groovy.lang.MissingPropertyException: cannot get property 'myProp' on extra properties extension as it does not exist
...
BUILD FAILED
Note that this seems to work if:
The recommended syntax for reading an extra property named foo
in a build script is foo
or project.foo
(rather than ext.foo
), which will also search the parent projects' (extra) properties. EDIT: In a task class, you can use project.foo
.
It's important to note that extra properties are only meant for ad-hoc scripting in build scripts; task classes and plugins should not use them. A task class shouldn't reach out into the Gradle object model at all; instead, it should declare properties (and, if necessary, methods) which allow build scripts and/or plugins to supply it with all information that it needs. This makes it easier to understand, reuse, and document the task class, and makes it possible to declare inputs and outputs via @Input...
and @Output...
annotations.
PS: Instead of calling doFirst
in a constructor, a task class usually has a method annotated with @TaskAction
.