Create empty default tasks across projects

I’ve noticed that gradle doesn’t have the same notion of build ‘stages’ as maven. It seems to me like it’d be useful to have some default ‘dummy’ packages, like prepare, compile, test, package, install, that tasks could just register dependencies for. This would make it a bit easier to manage multi-module build with different languages and build tasks.

This would also reduce the likelihood of certain name collisions since plugins wouldn’t have to use such easy to remember/type (read: short) task names. Instead they could just add tasks as dependencies of default build tasks.

There are already a bunch of so-called lifecycle tasks serving this purpose: ‘clean’, ‘assemble’, ‘check’, ‘build’, to name a few. Anything that you are missing particularly?

Gradle’s camel case abbreviation for task names should help to have longer task names that are nevertheless convenient to use.

Awesome, apparently I missed this. Are these documented anywhere? Are these always present? I noticed gradle usually complains when you create a task with a name that already exists, but it hasn’t complained when I created eg clean and check tasks.

Is the suggested best practice then to append e.g. plugin information to the task name? For example, one of my plugins is building packages for R code, so I’d just have checkR, buildR, etc. And then would “gradle build” also run buildR and any other build tasks?

Thanks for the tip on camel case, too. I think I’d seen that in the manual but had forgotten.

The lifecycle tasks aren’t “global” but are brought in by some plugins like ‘base’ and ‘java-base’ (which really is ‘jvm-base’). They are documented in the Gradle User Guide. Maybe some of the stuff in ‘java-base’ should go somewhere else, e.g. into a new ‘language-base’. These things are still being sorted out as we move into non-JVM land.

Typically, your plugin won’t have tasks as general as ‘classes’ and ‘check’. It will just make those tasks depend on its own, more specific tasks like ‘compileR’ and ‘testR’. Typically you won’t have to add task dependencies to ‘build’ directly, because ‘build’ depends on ‘classes’ and ‘check’ anyway. Have a look at the Groovy or Scala plugin to get some inspiration.

Sorry, am I missing something? The only reference I see to the lifecycle tasks in the base plugin are brief mentions that they exist: googled. I guess I should just look more closely at the gradle source.

From the user guide:

The Java plugin also adds a number of tasks which form a lifecycle for the project: […]

Gradle doesn’t have baked-in phases like Maven does. Instead, conventions like these lifecycle tasks are provided by plugins, and that’s also where they are documented. If you can think of a better way to document this, feel free to send a pull request.

I noticed that at least the java plugins explicitly apply other plugins (e.g. base) to their project. Is that the preferred strategy (instead of e.g. potentially awkward inheritance) ?

Yes, delegation is strongly preferred over inheritance.

Does anything bad happen if two plugins both attempt to apply BasePlugin.class?

No.

So from the command line, “gradle check” will also run “checkR” task if it exists, but that doesn’t mean “checkR” will run when “check” is run as a dependency for “build” correct?

So I still need to add explicit dependencies to the lifecycle tasks, right?

You just need a dependency from ‘check’ on ‘checkR’. Just give it a try and see what happens.

Thanks again, I’ll stop pestering you with questions I can answer myself.

One last comment. I see build, clean, assemble and upload lifecycle tasks. I think it would be useful to have one additional lifecycle tasks e.g. “prepare” or “generate”. There are cases where it may be necessary to do either some additional configuration or downloading, etc before the rest of the build can begin.

I also think that the “check” lifecycle task in the java plugin is general enough to be pulled up into the base plugin. Documentation generation also could have a lifecycle task, e.g. javadoc, scaladoc, etc.

Also I thought “install” was available as a task with the java plugin, but I can’t seem to find it. Maybe it’s loaded when I specified the maven repo. Anyway, it seems like “install” would also make sense as a lifecycle task.

A task like ‘prepare’ that everything else depends on is a smell. Instead you should be specific about who depends on what. In cases where you absolutely need a global ‘prepare’, you should use a hook like gradle.buildStarted()’ rather than a task.

‘docs’ would certainly be a useful addition.

‘install’ is added by the Maven plugin. Not sure it would make sense as a lifecycle task, because it could mean many different things.

I think you have a good point. I think the concept of installation is pretty clear, but you’re right, even with a java project I want to know whether installation means put a jar in the maven repo, or install the jar and a sh script in /usr/local/

I think it’d be convenient to group those kinds of tasks, but it could certainly add a lot of ambiguity about what exactly is happening with the lifecycle.

I guess I meant something more like “generate”. In one case I’m extracting meta-data from source code annotations into a file(that’s required for the build to be up-to-date and check and install to succeed), in another I’m processing (java) annotations to generate ® source code, and in another I’m downloading source code from a repository (to package it locally for a remote installation).

Or should these simply be “build” tasks that all other “build” tasks depend on?