Gradle extra properties not visible in a custom ta

2019-04-18 16:00发布

问题:

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 custom task is defined in the root project alongside the extra property
  • if you use dynamic properties instead of extra properties, but those are deprecated

回答1:

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.