Is it possible to build from a sub-project without needing to maintain all sub-projects in a master settings.gradle?

I am working on a project that is currently using Ant. Our project does not have a ‘root’ project, in that there are several different client and server processes that could be created depending on where you built from, and building from the root directory just builds ‘everything’.

Our setup enables us to ‘cd’ to a directory and just call ‘ant build’ and it determines the proper project dependencies and builds them as necessary. I was curious if Gradle would fit in to our project, just out of curiosity. After reading the documentation, I am having a hard time wrapping my head around the multi-project setup and whether or not I could use it similar to how we are now with Ant.

If we had a directory/project setup like the following, would gradle allow me to ‘cd’ to something like ‘serverProject2’ and do a ‘gradle build’ and have it build javaSharedLibraryProject1, javaLibraryProject1, and serverProject2 if it depended on them? It almost seemed possible with some manipulation of a settings.gradle in the root directory, but I’d like to avoid needing to keep track of projects in a file if at all possible.

root
    - projects
        -
shared
            - javaSharedLibraryProject1
            - javaSharedLibraryProject2
        -
application
            - server
                - serverProject1
                - serverProject2
            - client
                - clientProject1
                - clientProject2
            - lib
                - javaLibraryProject1
                - javaLibraryProject2

You do need a settings.gradle, but you don’t need to manually maintain it. You should be able to automatically include projects by recursing through your directory tree.

This might need some tweaking, but here’s something to start with:

rootDir.eachDirRecurse { dir ->
  if (new File(dir, 'build.gradle').exists()) {
    include((dir.absolutePath - rootDir.absolutePath).replaceAll('/', ':'))
  }
}

That would result in project names like :application:server:serverProject1, which might make calling tasks on other projects cumbersome. If you wanted to just have names like :serverProject1 (assuming those directories are uniquely named) you could change to this:

rootDir.eachDirRecurse { dir ->
  if (new File(dir, 'build.gradle').exists()) {
    include dir.name
    project(":${dir.name}").projectDir = dir
  }
}

Perfect, that’s exactly what I was looking for. In the examples I had looked at, there was only including done in the settings.gradle, so it did not dawn on me that I could actually put ‘real code’ in there. I have not tried this yet, but it should work. Thanks!

Only drawback is that you’ll pay a startup cost for every build. We’ve seen this become a problem for large builds. Might pay off to limit the recursion to only a couple of directories deep, and/or to exclude certain (patterns of) directories which definitely don’t contain build scripts (e.g. ‘src’, ‘build’, hidden directories, etc.). Or maybe you have a way of recognizing leaf projects (e.g. contains a ‘src’ directory) and can stop recursing there.