21

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
Community
  • 1
  • 1
Alan Krueger
  • 4,701
  • 4
  • 35
  • 48

1 Answers1

35

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.

Peter Niederwieser
  • 121,412
  • 21
  • 324
  • 259
  • 1
    When I use `project.foo` instead of `project.ext.foo`, I get deprecation warnings about using dynamic project properties. – Alan Krueger Jan 27 '13 at 05:21
  • 2
    You'll only get deprecation warnings if you *set* `project.foo` (which you shouldn't do). – Peter Niederwieser Jan 27 '13 at 12:56
  • 1
    Your comments helped me get past this issue. I discovered that using Task.configure was a simpler and cleaner way to share common configuration among multiple tasks. I'm using that instead. – Alan Krueger Jan 28 '13 at 16:37
  • 2
    Driving myself nuts with trying to set project.ext this and that in my plugin. This got me off the dime: **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.** Thanks for saving my sanity. In my situation, I'm trying to drive into plugins what I have earlier handled in scripts. However, I would ask why the User's Guide does not make these points, instead showing samples of "plugins" written in gradle build files! – Steve Cohen Feb 15 '16 at 21:51