rorschach
rorschach

Reputation: 2947

Conditionally skip subproject in multi-module Gradle build

Consider the following Gradle project structure:

- root
|- build.gradle
|- barProject
 |- build.gradle
|- fooProject
 |- build.gradle

where the root build.gradle configures its subprojects like so:

subprojects {
    apply plugin: 'java'

    //bunch of other stuff
}

Now when I call gradlew build on the root project it automatically configures both subprojects and then builds them - all well and good.

I also know that I can skip a specific task with various means (onlyIf(), [taskName].enabled = false, etc.) but when I utilize any of those on build Gradle still runs all the dependent tasks (compileJava, processResources, classes, etc.) until finally hitting build which it then skips.

My question is, is there any way to have Gradle stop and go to the next subproject right after the configuration phase?

EDIT:

To clarify; each subproject has a property called skip that is evaluated in the configuration phase.

Now when I call gradlew build on the root project I want Gradle to, ideally, check that property and if it's true then to completely skip the corresponding project.

Executing external task 'build'...

//check project.skip -> IF true -> skip project, go to :foo ELSE continue
:bar:compileJava
:bar:processResources UP-TO-DATE
:bar:classes
:bar:jar
:bar:startScripts
:bar:distTar
:bar:distZip
:bar:assemble
:bar:compileTestJava UP-TO-DATE
:bar:processTestResources UP-TO-DATE
:bar:testClasses UP-TO-DATE
:bar:test UP-TO-DATE
:bar:check UP-TO-DATE
:bar:build

//check project.skip -> IF true -> skip project, go to end ELSE continue
:foo:compileJava
:foo:processResources UP-TO-DATE
:foo:classes
:foo:jar
:foo:startScripts
:foo:distTar
:foo:distZip
:foo:assemble
:foo:compileTestJava UP-TO-DATE
:foo:processTestResources UP-TO-DATE
:foo:testClasses UP-TO-DATE
:foo:test UP-TO-DATE
:foo:check UP-TO-DATE
:foo:build

BUILD SUCCESSFUL

I hope this makes more sense

Upvotes: 2

Views: 8558

Answers (1)

Lukas Körfer
Lukas Körfer

Reputation: 14493

Well, first of all: An easy solution would be calling exactly the task(s) you need. In simple Gradle builds, task names are unique. However, in multi-project builds, each project can have a task with a specific name. This is the reason why Gradle introduced task paths. Task paths combine the unique project paths with the intra-project unique task names: :projectX:taskY.

Using project paths, you can easily specify the project-specific task you want to execute: :build for the build task in the root project and :<subproject>:build for the build task in a subproject. If a task name, e.g. build, is provided for a multi-project build, Gradle will search through any project (root and subs) for a task with the specified name and execute them all. This explains the current behaviour.

The task names for execution are managed by a StartParameter object of the Gradle Settings. These Settings can be modified in your settings.gradle file, where you also include subprojects:

include ':foo', ':bar'

startParameter.excludedTaskNames += ':foo:build'

This line excludes the build task of the foo subproject from the execution. You could add the subproject task path (even independent from the task name) to the excluded task names, if a specific condition is met. But, I did not find a way to access the Settings in your build file, so this solution can not be used during configuration phase. However, if your condition is solely based on project / system properties, they can be accessed from settings.gradle.

Another solution for the configuration phase came to my mind, but it's basically what you already mentioned, because it simply skips the tasks:

if (project.skip) {
    project.tasks.all { task -> task.enabled = false }
}

This way, all tasks from the project (not only the build task) will be skipped.

Please consider, that tasks can also be executed, because they create a dependency for another project. Even gradle :bar:build will execute the task :foo:jar and its task dependencies, if foo is a project dependency of bar. You can disable this behaviour with the Gradle command line options -a or --no-rebuild or the following entry in your settings.gradle:

startParameter.buildProjectDependencies = false

Upvotes: 4

Related Questions