Wednesday, July 8, 2009

One of my favorite enhancements to Grails 1.1 is the automatic transitive plugin resolution. This feature is great for team development. When a new plug-in is introduced to a project only one developer needs to install it. When they do, the application.properties is updated with the plugin name and version numbers like Listing 1 which shows an application.properties containing the hibernate, image-tools and jsecurity plugins.

When other members of the team get the updated application.properties file they just run grails run-app and the plugins will automatically be downloaded and installed on their machine. Life couldn’t be easier. Well, maybe it could be. See for this to work, the plugin must be installed in the central grails plugin repository found at http://plugins.grails.org/ or you can use another one of my favorite new features of Grails 1.1, multiple repositories. To configure multiple repositories just create a BuildConfig.groovy in your application’s grails-app/conf directory and add a new entry for your additional repository like Listing 2.

The only problem with this is it assumes the repository is hosted in Subversion (SVN). This is not always the case. With the popularity of git many of the plug-in developers have gone to using github for hosting their plugins. One example is the popular image-tools plugin.

Another important use case takes advantage of my second favorite feature of Grails 1.1, the Apache Ant and Apache Ivy integration which enables you to do a continuous integration builds in something like Hudson by executing the Ant build.xml without even having to have Grails installed on the build machine. Everything required is installed as a bootstrap. Now that is awesome. Of course this assumes the plugins are in a configured repository that is backed by SVN.

To simplify developer setup and continuous integration, I looked for documentation to setup a custom Grails plugin repository for plugins I did not maintain but I still want to access using the new Grails 1.1 features. All I found were instructions on how to do it if you are the plugin provider or using the Grails central repository. If that is your goal it can not be easier. For deploying to the central repository you first need to request permission to the Grails plugin SVN repository. Then to deploy the plugin just type grails release-plugin. For a custom plugin repository, you will need an additional configuration in your BuildConfig.groovy file to point to your SVN repository like the one found in Listing 3 and type grails release-plugin -repository=myRepository where the repository parameter is the last part of the property name. That’s it.

Listing 3 - BuildConfig.groovy with an entry to a repository for distribution.

I could not find any documentation about creating a custom read-only repository for third party plugins you don’t want to maintain or if you just don’t want to have to maintain a SVN repository just for those third-party plugins. So after a little bit of exploring the central repository and some trial and error, this is how I created my own read-only repository saving time and simplifying my team setup.

Note: for a read-only repository you don’t need SVN all you need is an HTTP based server that can serve files.

1. Create a BuildConfig.groovy file in your application’s grails-app/config directory containing grails.plugin.repos.discovery.myRepository="http://company.com/grails/" entry where the URL is addressable via HTTP and is the root of the plugin repository.

2. Create a plugins-list.xml file in a .plugin-meta data directory under the repository root. This file needs to contain your plugin(s) meta data like the following for image-tools:

3. Create a grails-/trunk directory under the repository root and copy the zipped plugin package there with the name grails--.zip.

Implementing these 3 steps made my third-party plugins available to the list-plugin and install-plugin commands but more importantly to the automatic transitive plugin resolutions for developer and continuous integration servers.