Grails 2.2 – Publishing your Plugins as Maven Artifacts To Resolve Dependency Resolution Issues

Grails developers may have noticed that since version 2.1, there have been a lot of features added for Maven support. It probably won’t be long before Ivy is phased out, if this article is any indication of what is to come.

If you have already upgraded to Grails 2.2, you may have run into some issues with plugins and dependency resolution. Thankfully, the workaround for this problem is published on the Grails website here: http://grails.org/doc/latest/guide/upgradingFromPreviousVersionsOfGrails.html

The documentation states that,

“Grails 2.2 no longer uses the BuildConfig of the plugin for dependency resolution and only uses data provided by POMs, this may impact some plugins that had previously incorrectly specified dependency information.”

And the quick fix is to set legacyResolve to true in BuildConfig.groovy.

grails.project.dependency.resolution = {    
    …
    legacyResolve true
    …
}

However, this is apparently ill-advised, as a plugin might specify a scope that is not valid in a Maven POM file, for example, “build” is not a valid scope. The documentation then goes on to say,

“Plugins like this will need to be re-publish with a corrected scope of “compile”. If you then specify the plugin as “build” scope in your application, transitive compile and runtime scoped dependencies will be converted to “build” scope as well.”

Alright, so let’s say that you are the plugin author and you have done it “correctly”, and all of your dependencies are declared with valid Maven scopes. For example, in your plugin’s BuildConfig.groovy, you have something like this:

dependencies {
		compile (group: 'something-external', name: 'some-external-dependency', version: '2.1.0') {
				excludes([ group: 'org.springframework', name: 'spring'])
        	}        
}

You should be good to go, right? Not necessarily. If you built your plugin as a zip file with grails package-plugin, and people are using it in Grails 2.2 via the grails install-plugin command, which by the way, is deprecated, your dependencies will still fail to resolve unless the app that is using your plugin has legacyResolve set to true. What you need to do is publish your plugin as a Maven artifact. And in fact, you may already be doing just that. But if the dependencies are not defined in your plugin’s POM file, your users will run into issues. What follows is one way to do it “correctly”, and you do need to have Maven installed for this to work.

Fortunately, publishing your plugin as a Maven artifact is pretty easy to do. The Grails release plugin provides this functionality and now ships with Grails.

If you are using an older version of Grails, you can easily add it to your plugin’s BuildConfig and start using it.

plugins {
	build ":release:2.2.0"
}

But, if you are using Grails 2.2 to author your plugin, you will run into problems. As of this writing, the release plugin (2.2.0) has its own issues with dependency resolution.
You can try it out yourself in Grails 2.2 by doing the following:

grails create-plugin test-maven
cd test-maven
grails compile
grails maven-install

And you will likely see the following:
| Error Error executing script MavenInstall: : Problem: failed to create task or type antlib:org.apache.maven.artifact.ant:install

To get around this, you need to use the same workaround that you’re trying to get your users to avoid. You will have to set legacyResolve to true in your plugin’s BuildConfig. You will then be able to use the release plugin.

As mentioned before, if you are still using an earlier version of Grails for your plugin, then you shouldn’t have this issue. The issue arises when authoring your plugin in Grails 2.2. Anyway, once you have the release plugin functioning as expected, you will want to add a groupId to your plugin’s main groovy file, (i.e., MyPlugin.groovy):

// specify the groupId for publishing artifacts to maven and/or grails repositories
def groupId="myPlugins"

Then go ahead and compile your plugin and use the release plugin to build and install the plugin into your local Maven repo.

grails clean
grails compile
grails maven-install

You should see the plugin’s POM, zip file, sha1, etc. in your local Maven repo now. You should also see that all of your plugin’s dependencies are explicitly defined in the POM file. This is the key to ensuring that your users won’t have to set legacyResolve to true. Well, at least not for your plugin.

You can also use the release plugin to publish to a private or public repo or perhaps an enterprise repo. To publish to a private repo, open the plugin’s BuildConfig.groovy file again and add the necessary configuration properties to the top, before the grails.project.dependency.resolution closure.

grails.project.repos.myRepository.url = "http://myRepo1:8081/myrepo/releases"
grails.project.repos.default = "myRepository"
grails.project.repos.myRepository.username = "your_repo_username"
grails.project.repos.myRepository.password = "your_repo_password"

And then from the command line, it’s just:

grails maven-deploy --repository=myRepository

Grails 2.2 apps will now be able to use your plugin without using the legacyResolve workaround. You can verify this by creating an app in Grails 2.2 and adding your plugin to the BuildConfig, for example:

plugins {
...
   compile "myPlugins:my-plugin:1.0.0"
...
} 

There are other ways to do it “correctly”, but the above method works, and I’m sure that the release plugin issue will be resolved (no pun intended) soon, as it ships with Grails now.

Happy plugin coding!

One thought on “Grails 2.2 – Publishing your Plugins as Maven Artifacts To Resolve Dependency Resolution Issues

Leave a Reply

Your email address will not be published. Required fields are marked *

*

*