Chapter 15
Organizing Build Logic

Gradle offers a variety of ways to organize your build logic. First of all you can put your build logic directly in the action closure of a task. If a couple of tasks share the same logic you can extract this logic into a method. If multiple projects of a multi-project build share some logic you can define this method in the parent project. If the build logic gets too complex for being properly modeled by methods you want have an OO Model.1 Gradle makes this very easy. Just drop your classes in a certain folder and Gradle automatically compiles them and puts them in the classpath of your build script.

15.1 Build Sources

If you run Gradle, it checks for the existence of a folder called buildSrc. Just put your build source code in this folder and stick to the layout convention for a Java/Groovy project (see Table 9.1). Gradle then automatically compiles and tests this code and puts it in the classpath of your build script. You don’t need to provide any further instruction. For multi-project builds there can be only one buildSrc directory which has to be in the root project.

This is probably good enough for most of the cases. If you need more flexibility, you can provide a build.gradle and a settings.gradle file in the buildSrc folder. If you like, you can even have a multi-project build in there.

15.2 External dependencies

If your build script needs external libraries you can declare them in the settings.gradle file.

  dependencies("commons-math:commons-math:1.1:jar")

You can pass any of the dependencies described in section ?? (except project dependencies). There is no need to provide a dependency configuration(e.g. compile). For multi-project builds dependencies declared in the settings.gradle file of the root project, are available to all build scripts of the sub-projects.

15.3 Ant Optional Dependencies

For reasons we don’t fully understand yet, external dependencies are not picked up by Ant’s optional tasks. But you can easily do it in another way.2

  dependencies {
      addConfiguration('ftpAntTask')
      clientModule(['ftpAntTask'], ":ant-commons-net:1.7.0") {
          clientModule(":commons-net:1.4.1") {
              dependencies(":oro:2.0.8:jar")
          }
      }
  }
  createTask('ftp') {
      ant {
          taskdef(name: 'ftp',
                  classname: 'org.apache.tools.ant.taskdefs.optional.net.FTP',
                  classpath: dependencies.antpath('ftpAntTask'))
          ftp(server: "ftp.apache.org", userid: "anonymous", password: "me@myorg.com") {
              fileset(dir: "htdocs/manual")
          }
      }
  }

15.4 Summary

Gradle offers you a variety of ways of organizing your build logic. You can choose what is right for your domain and find the right balance between unnecessary indirections, and avoiding redundancy and a hard to maintain code base. It is our experience that even very complex custom build logic is rarely shared between different builds. Other build tools enforce a separation of this build logic into a separate project. Gradle spares you this unnecessary overhead and indirection.