Which task types (and their respective methods/variables) need to be set/used during configuration vs execution?

Example: After much trial and error I discovered that I needed to configure my Exec tasks AFTER configuration, but BEFORE the actual Exec task by using doFirst. If I set things up during configuration, my plugin’s variables would be evaluated during configuration, before they were set in the actual build.gradle file. But, the configuration had to be set with doFirst or else Exec would try exec without a command.

Example: In contrast, it seems that Tar tasks MUST be setup during the configuration stage or else Tar doesn’t think it contains anything and won’t create the archive.

Do we just need to know this stuff? I wasn’t able to find information about this in the documentation.

It doesn’t depend on the task type. In general, everything must be configured in the configuration phase. However, if your plugin accesses a mutable property of the Gradle object model, it must defer that access (and the related configuration operation) so that it picks up any change made to the property during the configuration phase (e.g. by a build script). There are several techniques for doing so, which are a frequent topic of discussion on the forum.

This is by far the hardest part of writing plugins, and it isn’t well documented. Hopefully we’ll be able to offer a better solution in the future. Meanwhile, I recommend to study similar questions in the forum (e.g. http://forums.gradle.org/gradle/topics/how_to_create_a_plugin_that_can_be_configured_through_the_build_gradle) and/or on Stack Overflow, and to study the plugins in the Gradle source code (e.g. the code quality plugins).

Thanks. I was going to point out a seemingly contradictory experience I’ve had with the Tar task, but now I see that despite the documentation implying that archiveName is a property, in the java implementation, it’s just getters and setters, which is why it appears as if archiveName updates as I change things like the version in build.gradle.

So that thread mentioned gradle.projectsEvaluated() but it’s not clear exactly the order of operations, particularly for the “up-to-date” determinations, which so far seem like one of few things that must be set during project configuration. Will closures passed to projectsEvaluated or beforeProject be evaluated before the up-to-date determinations are made?

I assume you mean ‘afterProject’ (‘beforeProject’ is too early). The up-to-date check is done immediately before the task gets executed, so the answer is yes. The one thing that can get you into troubles with regard to up-to-date checking is performing configuration work in ‘task.doFirst {}’.

So is there any reason a plugin shouldn’t do all of it’s configuration (other than setting defaults) in projectsEvaluated or afterProject?

The main problem is that build scripts and other plugins (depending on how they are written) won’t be able to override that configuration. It’s up to you to decide if that’s tolerable in your case.

To be clear I mean it seems like general rules should be

project.task('name',..) {
//set default values for variables you create
project.gradle.projectsEvaluated {
  //use your variables to set any other variables, e.g. inherited ones (hint: input, output)
}
doLast {
  //do actual actions
}
}

It seems like tasks where you’re pretty much assigning inherited variables should always do their assignments in a projectsEvaluated or similar. Only new variables should be assigned/created in the configuration section.

Not sure what you mean by new variables and inherited variables. Regarding default values, the problem is that quite often, you do need to access Gradle object model properties to compute them, hence you must defer computing them while still allowing people to override them.

I mean that at least for me, most of my tasks use a preexisting type, just reparameterizing it. Maybe my use cases are just abnormal. You’re saying that much of the time your parameters look like Tar.archiveName, with a default based on project properties but that can be explicitly overridden, requiring the kind of sneaky business they do with getters and setters.

Forgive my groovy inocence but are all getters and setters exposed like Tar.archiveName as pseudo-properties or do you have to do anything special?

It’s automatic.

Thanks so much for your help. Gradle is awesome, but this stuff is complicated and having knowledgeable people around to answer questions is fantastic.