Gradle IDEA plugin, configuration and usage

We are using Gradle as a build and release tool in our project. It’s flexible and does exactly what you expect from it, with no xml configuration magic.
Gradle IDEA plugin gave us a way of generating IntelliJ project and modules files out of the freshly checkout source with a single instruction.

Gradle IDEA plugin

All we needed to do is to include the plugin in out multi project setup and run the gradle idea tasks from the command line.

allprojects {
…
  apply plugin: ‘idea’
…
}

First time when we generated the files they were valid, however the module configurations needed few simple fixes. The IDEA plugins provide hooks into project and module generation that we used to amend the generated IntelliJ files.

Setting the Java version on the project


allprojects {
…
  ideaProject {
    javaVersion = '1.6'
  }
…
}

This code snipped sets version of JDK on the whole project, which in turns makes it ready for compilation in IntelliJ.

Moving module dependencies to the top of the list

Gradle IDEA plugin creates dependencies for all the modules, however it moves the dependencies between modules to the bottom of the list. For example, if module B has dependencies on module A plus some of it’s own JAR dependencies, the JAR will appear before the module A dependency.  It was problematic for our project.  The snippet below is using module configuration hook to reorder module dependencies to the top of the list.

allprojects {
…
  ideaModule {
    whenConfigured { module ->
      def moduleDependencies = []
        module.dependencies.each {
          if (it.class.simpleName == 'ModuleDependency') {
            if (it.scope.equalsIgnoreCase("COMPILE")) {
              moduleDependencies += it
            }
          }
        }
      module.dependencies.removeAll(moduleDependencies)
      def jarDependencies = new LinkedHashSet(module.dependencies)
      module.dependencies.clear()
      module.dependencies.addAll(moduleDependencies)
      module.dependencies.addAll(jarDependencies)
    }
  }
…
}

Adding defaults to Run configurations

We have also discovered that it was useful to add some extra defaults to Run configurations and to TestNG running configurations.

We did this with Idea Workspace hook and a bit of XML injection. Code bellow is the sample snipped we used.


allprojects{
...
  ideaWorkspace {
    withXml { provider ->
      def applicationDefaults = provider.node.component.find { it.@name == 'RunManager'}.configuration.find { it.@type == 'Application'}
      if (applicationDefaults != null) {
        applicationDefaults.option.find { it.@name == 'VM_PARAMETERS'}.@value = '-Xmx1024m -XX:MaxPermSize=256m -Xss64k'
        applicationDefaults.option.find { it.@name == 'WORKING_DIRECTORY'}.@value = 'file://$MODULE_DIR$'
      }
      def testNGDefaults = provider.node.component.find { it.@name == 'RunManager'}.configuration.find { it.@type == 'TestNG'}
      if (testNGDefaults != null) {
        testNGDefaults.option.find { it.@name == 'VM_PARAMETERS'}.@value = '-XX:MaxPermSize=128M -Xmx1024M'
        testNGDefaults.option.find { it.@name == 'WORKING_DIRECTORY'}.@value = 'file://$MODULE_DIR$'
      } else {
        def clonedNode = new XmlParser().parseText( XmlUtil.serialize(applicationDefaults))
        clonedNode.@type = 'TestNG'
        clonedNode.@factoryName = 'TestNG'
        provider.node.component.find { it.@name == 'RunManager'}.append(clonedNode)
      }
    }
  }
...

}

This snippet sets some default JVM parameters and working directory for running configurations.

The snippets made it possible for anyone to quickly get up and running on any clean machine with checked out project sources.

Cheers, Greg