Monday, August 17, 2015

Getting execution coverage in eclipse with maven m2e

Falling from cloud nine

One thing I like about eclipse and maven is that I can get the fast coding cycle in eclipse and there is a jenkins (or another CI) server running exactly the same build whenever I push my code.

So, I'm currently playing at bit around with the grpc framework implementation in Java. Creating a new maven project in eclipse and start adding the example getting started maven using the protobuf-based codegen, and it doesn't work as intended. *sigh*

Part of the offending pom below:

...
<build>
  <extensions>
    <extension>
      <groupId>kr.motd.maven</groupId>
      <artifactId>os-maven-plugin</artifactId>
      <version>1.2.3.Final</version>
    </extension>
  </extensions>
  <plugins>
    <plugin>
      <groupId>com.google.protobuf.tools</groupId>
      <artifactId>maven-protoc-plugin</artifactId>
      <version>0.4.2</version>
      <configuration>
        <!--
          The version of protoc must match protobuf-java. If you don't depend on
          protobuf-java directly, you will be transitively depending on the
          protobuf-java version that grpc depends on.
        -->
        <protocArtifact>com.google.protobuf:protoc:3.0.0-alpha-2:exe:${os.detected.classifier}</protocArtifact>
        <pluginId>grpc-java</pluginId>
        <pluginArtifact>io.grpc:protoc-gen-grpc-java:0.7.1:exe:${os.detected.classifier}</pluginArtifact>
      </configuration>
...

The problem is that the grpc code generator is build as an extension/plugin to the google proto buffer code generator, and both generators are binary native executables. To provide the correct os and platform combination it relies on the os-maven-plugin to pick the correct combo and replacing ${os.detected.classifier} in my instance with "osx-x86_64". If I run the maven build manually or insert the constant it works as intended.

m2e simply doesn't pick it up.

plugin not running in eclipse

As noted on the os-maven-plugin website itself, m2e will not use extensions defined in the file.
That is unless we tell it specifically or someone else already did as an eclipse plugin.
In the code for the plugin, there is a goal defines to run in the validation phase:

@Mojo(name = "detect", defaultPhase = LifecyclePhase.VALIDATE)

Making it explicit in the pom.xml file it will look like this:

...
<build>
 <extensions>
  <extension>
   <groupId>kr.motd.maven</groupId>
   <artifactId>os-maven-plugin</artifactId>
   <version>1.2.3.Final</version>
  </extension>
 </extensions>
 <plugins>
  <plugin>
   <groupId>kr.motd.maven</groupId>
   <artifactId>os-maven-plugin</artifactId>
   <version>1.2.3.Final</version>
   <executions>
    <execution>
     <id>detect-os</id>
     <phase>validate</phase>
     <goals>
      <goal>detect</goal>
     </goals>
    </execution>
   </executions>
  </plugin>
...

Now that m2e picks it up, we just need to tell m2e what to do with it.

m2e lifecycle-mapping

In eclipse, m2e doesn't simply run any plugin it doesn't know about. Someone need to tell eclipse that it should either run or ignore a plugin. There are several places you can do that - one of them is in the maven pom file. The problem is documented pretty well on the eclipse website under the easy to google title of Execution Not Covered, which more or less the error message eclipse will give if it doesn't know what to do with a maven plugin.

Adding an entry in pluginManagement of the build section will take care of it:

...
<pluginManagement>
 <plugins>
  <plugin>
   <groupId>org.eclipse.m2e</groupId>
   <artifactId>lifecycle-mapping</artifactId>
   <version>1.0.0</version>
   <configuration>
    <lifecycleMappingMetadata>
     <pluginExecutions>
      <pluginExecution>
       <pluginExecutionFilter>
        <groupId>kr.motd.maven</groupId>
        <artifactId>os-maven-plugin</artifactId>
        <versionRange>[1.2.3.Final,)</versionRange>
        <goals>
         <goal>detect</goal>
        </goals>
       </pluginExecutionFilter>
       <action> 
        <execute>
         <runOnConfiguration>true</runOnConfiguration>
         <runOnIncremental>true</runOnIncremental>
        </execute>
       </action>
      </pluginExecution>
     </pluginExecutions>
    </lifecycleMappingMetadata>
   </configuration>
  </plugin>
 </plugins>
</pluginManagement>

...

In the grpc case, the protoc plugin itself also needs to be added.

And that should be it! Hope it was usefull.