How to manage development life cycle of IntelliJ plugins with Maven

Introduction

Even though Jetbrains provides sources for IntelliJ CE[1], as well as some documentation on how to set up a development environment, they do not provide any automatic tool to perform the following tasks :

  • Compiling source code against a specific IntelliJ version
  • Packaging compiled code in versioned artifact
  • Syncing “plugin.xml” file with the version and other meta-information of the package
  • Deploying versioned artifact to a repository
  • Tagging the source code on SCM

These tasks are perfectly handled by Maven and that’s why we would like to integrate it in our development process, but there are several problems to resolve :

  • Compiling classes we need to have a dependency towards IntelliJ’s artifacts
  • We need something to compile forms

To best solution for the first problem would be to have a repository containing all IntelliJ CE’s artifacts. Unfortunately as far as we know there exists no such repository[2]. Of course we could deploy all the artifacts in our own repository and add missing dependency information, but this would require a lot of work, and a lot of maintenance at every IntelliJ CE release.

The most appropriate solution for the second point would be to have a Maven plugin that performs the forms compilation. There exists such a plugin[3], unfortunately it is not maintained anymore, and, once again, using this plugin would require a dependency towards the appropriate version of forms_rt.jar, javac2.jar and all their transitive dependencies.

The solution to keep the plugin.xml file synced with the pom.xml is straightforward. We simply put the plugin.xml file in src/main/resources/META-INF and enables filtering on it. The rest is simply adapting configuration in IntelliJ so it uses the filtered file, and always keep it up-to-date.

In the first section of this article, we’ll show how we workaround the dependency problem to compile classes. In the second section we’ll see how to compile forms, reusing the dependency workaround from first section. Finally, in the third section, we’ll show how to configure pom.xml so that plugin.xml can benefit from Maven filtering, and how to configure IntelliJ to use the filtered file and keep it up-to-date.

Classes compilation

Main problem with compilation is to provide IntelliJ CE’s jar to the compiler, without having them as a direct dependency.

To have IntelliJ CE available in Maven build, the simplest solution is to upload a vanilla IntelliJ CE installation as a zip file on our repository. We can then depend on this zip. We can’t use this dependency in a standard Maven way, so the scope does not really matter, but the dependency will be used only for compilation and is provided by the runtime environment which semantically correspond to “provided” scope.

Now that IntelliJ CE is available in our Maven build, we need to unzip it somewhere in our build directory to use it concretely. To do this, we use “unpack-dependencies” goal from Maven dependency plugin. As we’re only interested in jar files, we filter the rest with an “includes” tag.

Now we have all IntelliJ CE  jars available, we need to provide them to the compiler. Unfortunately, Maven compiler plugin determines the compilation classpath based on dependencies and their scope, and that’s not possible to customize or override this behavior. A possible workaround for this is to use the “extdirs”[4] option of the compiler. This option allows to give a list of directories in which the compiler will look for jar files and add them to its compilation classpath.

Forms compilation

IntelliJ forms compiler, Javac2, provides an Ant task that we can use with Maven Antrun plugin to compile forms. First we need to define the Task, and for that, we need to define a classpath containing IntelliJ CE’s libraries. We’ll reuse the jars from the distribution we unzipped for compilation. This is done in line 15 through 20 of  the next pom.xml snippet.

On line 21, we define the task in itself, using the classpath we just defined before.

The next step is to define the path that contains all source files. We use standard Maven file structure, so we define a path containing src/main/java and src/main/resources. This is done in line 22 through 27.

Finally, in line 28 through 31, we call the task that will actually perform forms compilation. This task is an extension of Javac Ant task and takes the same parameters. We provide source path, compilation path, and we also add IntelliJ CE’s jar as “extdirs”, just like we did for traditional compilation. The instrumented classes are output in standard Maven output location : target/classes.

It’s also worth to note that this task requires tools.jar to work fine.

Customizing plugin.xml and configuring IntelliJ

Now that our Maven build is able to compile both classes and forms, the final step is to use meta-information from pom.xml file, like artifact ID and version to fulfill our plugin.xml. We must also configure IntelliJ so that it uses the filtered file, and keep it up-to-date.

First step is to move the file in src/main/resources/META-INF directory. Then we replace interesting values with Maven properties.

We must of course enable resources filtering in our pom.xml, and define all properties we use in plugin.xml.

Then we tell IntelliJ to use the filtered version of the plugin.xml file by setting  the path to META-INF\plugin.xml to target classes of our module. To ensure the file is filtered by Maven before running, we need to launch Maven process-resources phase before “make” in the run configuration of the plugin. Unfortunately, doing this will also unzip IntelliJ distribution each time we launch the run configuration because it’s bound to process-sources phase. To avoid this situation, we can create a profile that will skip Maven dependency plugin when activated.

IntelliJ plugin - run configuration

Conclusion

In this article, we showed how to use Maven to develop IntelliJ plugins. We showed how to circumvent the dependency problem, by just uploading a zipped vanilla IntelliJ CE distribution in our own Maven repository, and how to compile classes and forms using this dependency. Finally, we also showed ho to use meta-information from pom.xml in plugin.xml file.

Finally, as example, we provide a small test plugin available on GitHub with a single action and and a single form to concretely demonstrate all this.


  1. CE stands for Community Edition.
  2. Actually there exists a Maven JetBrains repository (http://repository.jetbrains.com/all/), but it does not contains all artifacts of every release, and artifacts that are present do not necessarily contain dependency information. In practice, this repository is not really useful four our case.
  3. See here for more information on this plugin : http://mojo.codehaus.org/ideauidesigner-maven-plugin/dependencies.html
  4. See here for more information on Java compiler options : http://docs.oracle.com/javase/7/docs/technotes/tools/windows/javac.html#options

2 comments to How to manage development life cycle of IntelliJ plugins with Maven

Leave a Reply

  

  

  


− 4 = one

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">