Maven to Gradle

Hi, I am trying to write a Gradle 2.2.1 plugin to replace our Maven 3 parent pom. We have a number of JAR libraries we develop that are in turn used by our WAR applications.

The functionality I need to provide is:

  1. Set common dependencies for all JAR/WAR projects. 2) Add equivalent Maven install/deploy functions (externalizing repository credentials). 3) Add sensible defaults for Integration test code Source Sets. 4) Set Source/Target compatibility. 5) Add provided Maven scope equivalent for JAR/WAR (I know War Plugin provides this but Java Plugin doesn’t).

I have created a custom plugin that applies pre-existing plugins e.g. Java, Maven. It also sets the Source Compatibility, adds Source sets for integration tests and configures the Maven plugin to to uploadArchives to our corporate Maven repository.

I had to create a second plugin to apply the War Plugin, as if I only use it, all JAR files are created as WAR files. I am having trouble getting the second custom plugin to re-used the uploadArchives task created in the first. This just feels wrong to me and I’m sure there is a better solution, I just haven’t figured it out.

Question 1) Is my approach correct, or is there a way to have one custom plugin to satisfy both JAR and WAR needs? Question 2) I have elected to create a custom plugin rather than just create a build.gradle and locate it somewhere accessible and use apply from, is this a good solution?

Can anyone enlighten me as to a pre-existing example of these requirements, I can’t be the first, most examples I’ve found so far are quite simplistic, not real-world problems. Any help would be gratefully received.

MARK

For your first question you can conditionally do configuration based on the existence of a plugin.

plugins.withId(‘java’) {

// configure all java projects

}

plugins.withId(‘war’) {

// additional configuration for war projects

}

For you second question, basically, it depends. There are benefits to both approaches, script plugins (using ‘apply from: …’ are a bit easier to create and require less infrastructure to maintain, however binary plugins allow you to do things like versioning, testing, etc.

Thanks for the reply, I’ve looked at the JavaDocs for the PluginContainer but it doesn’t give much insight into how to use the withId method. I’m not looking to configure based on the existence of the plugin. I’m looking to apply a plugin based on some config. For instance:

JAR Projects

ext {
      type = 'jar'
    }

For WAR projects:

ext {
      type = 'war'
    }

My custom plugin would read this configuration and apply the appropriate plugin:

if (project.properties['type'] == 'jar') {
      project.apply(JavaPlugin)
    } else if (project.properties['type'] == 'jar') {
      project.apply(WarPlugin)
    }

Is this possible? If not, what is the correct solution to this type of issue? This is how Maven works and maybe I’m not doing things the gradle way, I’m happy to change.

Sorry typo in my previous post, should be:

if (project.properties['type'] == 'jar') {
  project.apply(JavaPlugin)
} else if (project.properties['type'] == 'war') {
  project.apply(WarPlugin)
}

This is possible, but I’m not sure I’d recommend it. If you want to do different types of things based on the project packaging type, then you should key off the existence of the plugin. Basically, Gradle users are used to declaring their project creates a jar by applying the ‘java’ plugin, or a war by applying the ‘war’ plugin. Ideally, you’d want to conform to this convention rather than introduce your own.

Basically, let the user tell you what type of project they have by having them apply the requisite plugin, rather than have them configure an extension property, and apply the plugin for them.

The configuration for the Java and War plugins are pretty much identical, it looks like the big wins of applying the War Plugin are it provides provideCompile scope and the war task, I’m sure there is more, but these are the big wins.

So, say I want to set the source compatibility for all libraries/applications. If I defer applying the Java/War Plugin to each libary/application, then I cannot configure the plugin in one location, each library/application would need to do the exact same configuration, breaking DRY principals. This also

makes updating problematic as you have to make the same change in multiple locations e.g. each library/application. This to me doesn’t feel right, but may be the Gradle way, or I’m missing something?

Let’s take a concrete example, say I need to standardize the sourceCompatibility to Java 1.7 across all projects, whether they be a JAR library or a WAR application. If we defer applying the appropriate plugin to each project, then the configuration will also need to be deferred, am I correct with this assumption? If we need to defer configuration as well, then there is a lot of needless duplication, this makes the likely-hood of human error higher e.g. typos, copy-paste errors etc.

You are right in the assumption that configuration that depends on a particular plugin will need to be deferred. However, I’m not sure why that would result in duplication. That deferred configuration can still go inside your plugin. In fact, that’s exactly what ‘PluginContainer.withId()’ does. It defers the evaluation of closure argument until the plugin is applied.

Ah, the penny drops.

The documentation for PluginContainer.withId is pretty basic and I didn’t grasp that. Cheers, I’ll investigate that method.