Eclipse Common Build Infrastructure (CBI)

Writing code is more effective if it can be built. The goal of the Eclipse CBI initiative is to focus on a set of tools and technologies that make the build easy to perform, easy to test, and easy to repeat.

The Eclipse CBI stack features Git (the SCM), Hudson (the CI server), Nexus (Maven repository), Tycho and p2. While CBI at Eclipse is not a new initiative (early work dates back to 2006), recent technologies such as Tycho have greatly facilitated the effort.

In this article, we'll explore the tools in the CBI stack as we outline the steps required to migrate a typical project from PDE build to CBI.

Before you Begin

You will need the following tools to begin exploring the CBI:

  • Git (http://git-scm.com/downloads)
  • Maven (http://maven.apache.org/download.cgi)
  • Tycho (Maven will install Tycho automatically)

The Slideshow Examples Project

We'll start with a simple project, Slideshow. It is a project in the Examples repository, which can be found here:

http://github.com/zxiiro/org.eclipse.examples.slideshow

Clone the repository:

git clone https://github.com/zxiiro/org.eclipse.examples.slideshow.git

Tycho and Maven

Tycho is a Maven extension for building Eclipse artifacts. Maven uses pom.xml files as metadata providing Maven with the information it needs in order to build a project. Every bundle / feature / product / etc... in your project will require its own separate pom.xml file.

Tycho has a build goal (generate-poms) which will automatically generate initial pom.xml files for us:

mvn org.eclipse.tycho:tycho-pomgenerator-plugin:generate-poms
-DgroupId=org.eclipse.examples.slideshow

The only parameter is the -DgroupId which tells Tycho what to fill for the “GroupID” field in Maven. This is one of the 3 parameters needed by Maven to determine the coordinates for your artifacts via the Maven GAV which we will discuss in more detail later. Typically you will want to enter your project or subproject's Eclipse Group here, in this case org.eclipse.examples.slideshow.

Note: Tycho automatic pom generation only searches 1 level deep. So you might have to run this multiple times if your project's structured with multiple sub-directories. Please see: https://bugs.eclipse.org/bugs/show_bug.cgi?id=409871

Once mvn completes you should now have pom.xml files generated for each of your bundles as well as a pom.xml in your root directory that lists all your sub-directories it created pom.xml files for as “<modules>”.

You can try to build your project now using the command: mvn clean verify

This should fail and if you scroll through your logs you should see something similar to this:

[ERROR] Cannot resolve project dependencies:
[ERROR] Software being installed:
  org.eclipse.examples.slideshow.feature.feature.group 0.2.0.qualifier
[ERROR] Missing requirement:
  org.eclipse.examples.slideshow.feature.feature.group 0.2.0.qualifier requires
  'org.eclipse.platform.feature.group [4.2.1,4.2.2)'
  but it could not be found

This is expected since we have not yet told Tycho where to get dependencies for your project.

Maven Parent Pom

Before we do anything let's take a look at what was generated for us. Tycho should have generated a pom.xml in your root directory which will be the parent pom for all of your modules. A parent pom.xml usually provides all the build details in your project which is then inherited by the modules that declare it as parent. This is where you will set all the parameters and build details which are globally used to build your project.

Maven also allows chaining parent poms as well, so a parent pom can itself have its own parent pom from which it inherits some configuration. Having multiple parents can be useful in large projects where multiple repositories each require their own specific settings. By defining their own parent they could inherit configuration from the global parent and fine tune any settings specific to their sub-project.

In the root directory your root pom.xml should look something like this:

<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
   http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <modelVersion>4.0.0</modelVersion>

  <groupId>org.eclipse.examples.slideshow</groupId>
  <artifactId>org.eclipse.examples.slideshow</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>pom</packaging>

  <modules>
    <module>org.eclipse.examples.slideshow.core</module>
    <module>org.eclipse.examples.slideshow.feature</module>
    <module>org.eclipse.examples.slideshow.jdt</module>
    <module>org.eclipse.examples.slideshow.jdt.tests</module>
    <module>org.eclipse.examples.slideshow.runner</module>
    <module>org.eclipse.examples.slideshow.runner.tests</module>
    <module>org.eclipse.examples.slideshow.site</module>
    <module>org.eclipse.examples.slideshow.text</module>
    <module>org.eclipse.examples.slideshow.text.tests</module>
    <module>org.eclipse.examples.slideshow.ui</module>
  </modules>

  <build>
    <plugins>
      <plugin>
        <groupId>org.eclipse.tycho</groupId>
        <artifactId>tycho-maven-plugin</artifactId>
        <version>0.18.1</version>
        <extensions>true</extensions>
      </plugin>
    </plugins>
  </build>
</project>

There are three important details here that Tycho was able to generate automatically for us. The first section is the Maven “Group, Artifact and Version”, or GAV. This is how Maven determines an artifact's coordinates:

<groupId>org.eclipse.examples.slideshow</groupId>
<artifactId>org.eclipse.examples.slideshow</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>

There is an additional declaration, <packaging>, which is metadata to let Maven know what to do with the current pom.xml. In this case the root pom is just Maven metadata and is not actually building anything so the packaging type is just “pom”.

The next section, <modules>, tells Maven which directories have pom.xml files which need to be built. This is where you will list all of the artifacts to be built. In some larger projects some modules defined here might list even more modules that need to be built.

Finally the last section, <build>, defines allows you to define any plugins for which you need the artifacts in your project.

  <build>
    <plugins>
      <plugin>
        <groupId>org.eclipse.tycho</groupId>
        <artifactId>tycho-maven-plugin</artifactId>
        <version>0.18.1</version>
        <extensions>true</extensions>
      </plugin>
    </plugins>
  </build>

You will want to list Maven plugins that are globally used here as they will be inherited to the specific modules when Maven determines what plugins should be used to build your bundles. If only a single bundle needs a specific Maven plugin you should define it in the specific bundle's pom.xml file. So far we only have the tycho-maven-plugin defined which is necessary to build Eclipse projects. This plugin is what enables Maven to understand package types such as eclipse-plugin, eclipse-feature, eclipse-repository, etc...

Packaging type eclipse-plugin

Next let's take a look at an eclipse-plugin pom.xml that Tycho generated for us. Open up org.eclipse.examples.slideshow.core/pom.xml. You should see something similar to this:

<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>org.eclipse.examples.slideshow</groupId>
    <artifactId>org.eclipse.examples.slideshow</artifactId>
    <version>0.0.1-SNAPSHOT</version>
  </parent>

  <groupId>org.eclipse.examples.slideshow</groupId>
  <artifactId>org.eclipse.examples.slideshow.core</artifactId>
  <version>0.2.0-SNAPSHOT</version>
  <packaging>eclipse-plugin</packaging>
</project>

This time we are seeing 2 GAVs. Once between <parent> and again after the parent tags. The GAV defined between the <parent> tags tell Maven where to find the parent of this pom.xml in which it will inherit any configuration from. In this case we are inheriting the tycho-maven-plugin settings from the parent pom.xml if you recall from the earlier example.

In this example the Artifact ID and Version is derived from the MANIFEST.MF file for this Eclipse bundle and the Group ID was what we filled in by the parameter we passed to the pom-generator. Tycho requires the Artifact ID and Version to match exactly what's in the MANIFEST.MF otherwise building will fail.

Finally there is the new packaging type “eclipse-plugin” which is a type that Tycho provides allowing us to build Eclipse plugins.

Packaging type eclipse-test-plugin

Next let's take a look at a eclipse test plugin. The file org.eclipse.examples.slideshow.jdt.tests/pom.xml should look similar to this:

<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation=
  "http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
  xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>org.eclipse.examples.slideshow</groupId>
    <artifactId>org.eclipse.examples.slideshow</artifactId>
    <version>0.0.1-SNAPSHOT</version>
  </parent>

  <groupId>org.eclipse.examples.slideshow</groupId>
  <artifactId>org.eclipse.examples.slideshow.jdt.tests</artifactId>
  <version>0.2.0-SNAPSHOT</version>
  <packaging>eclipse-test-plugin</packaging>
</project>

The only difference between this and the previous plugin is the packaging type is now “eclipse-test-plugin”. This is another packaging type Tycho provides for building test bundles. By default it will try to detect your unit tests and run them during the build by launching the tycho-surefire-plugin. This happens automatically and you do not need to configure the tycho-surefire-plugin unless you have additional configuration you require.

This packaging type also uses your bundle's MANIFEST.MF file to fill out the Artifact ID and Version. Again these values must be identical to what's found in the MANIFEST.MF or Tycho will throw an error when you run a build.

Packaging type eclipse-feature

Next let's take a look at an eclipse-feature. If you open org.eclipse.examples.slideshow.feature/pom.xml you should see a feature similar to this:

<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>org.eclipse.examples.slideshow</groupId>
    <artifactId>org.eclipse.examples.slideshow</artifactId>
    <version>0.0.1-SNAPSHOT</version>
  </parent>

  <groupId>org.eclipse.examples.slideshow</groupId>
  <artifactId>org.eclipse.examples.slideshow.feature</artifactId>
  <version>0.2.0-SNAPSHOT</version>
  <packaging>eclipse-feature</packaging>
</project>

Once again the only difference we see here the packaging type is eclipse-feature which is another type provided by Tycho. Unlike eclipse-plugin and eclipse-test-plugin however, the eclipse-feature uses the file “feature.xml” to get any required metadata for the build. Like the other types the Artifact ID and Version must match what is defined in the feature.xml in this case.

Packaging type eclipse-repository

Finally there is one more packaging type that Tycho defined for us. The file org.eclipse.examples.slideshow.site/pom.xml should look like this:

<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
    http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>org.eclipse.examples.slideshow</groupId>
    <artifactId>org.eclipse.examples.slideshow</artifactId>
    <version>0.0.1-SNAPSHOT</version>
  </parent>

  <groupId>org.eclipse.examples.slideshow</groupId>
  <artifactId>org.eclipse.examples.slideshow.site</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>eclipse-update-site</packaging>
</project>

Again, the packaging type is the only thing that's different. In this case Tycho generated an eclipse-update-site for us. This packaging type is actually deprecated in favour of a new type: eclipse-repository. So before we move on let's change it:

  <packaging>eclipse-repository</packaging>

This packaging type uses the category.xml file to build an eclipse repository for you which is usually a p2 repository. With additional configuration you can also have Tycho produce an eclipse product for you too via a product file instead of a category.xml. More details on this can be found on the wiki page here: http://wiki.eclipse.org/Tycho/Packaging_Types#eclipse-repository

Defining dependency repositories

That was a quick overview of what the Tycho pom generator created for us. Before we can actually perform a build there is additional configuration we need to do. Our earlier error was due to missing dependencies that Maven/Tycho was not able to calculate. By default Maven looks for dependencies in Maven Central, which is a central repository containing (in theory) all the Java artifacts you will need to build anything. In practice though not all projects push their artifacts there, so you will most likely need to define additional repositories of where Maven should look.

In the Eclipse world most software repositories come in the form of p2 repositories hosted on eclipse.org. Maven by itself does not work with p2 repositories but Tycho adds this additional functionality to Maven. Add the following section below to your root pom.xml. I added it just before the “<modules>” section in my root pom.xml.

  <repositories>
    <repository>
      <id>eclipse-juno</id>
      <url>http://download.eclipse.org/releases/juno/</url>
      <layout>p2</layout>
    </repository>
  </repositories>

For the purpose of this example we are using the Eclipse release train p2 repository to retrieve all the dependencies required by our project (the Slideshow project requires bundles from Eclipse Juno). In a real project you will probably want to narrow down the specific repositories that your project needs to build rather than including the entire release train.

With our repository now configured let's try to build a plugin. With Maven/Tycho you do not need to build your entire project all at once. If your plugin does not have any dependencies on other plugins in your project you can actually build your plugin by itself. For a quick test let's try doing that now by navigating to the org.eclipse.examples.slideshow.core directory and running the build command:

    mvn clean verify

You should successfully build this eclipse-plugin and its output will be available in the new “target/” sub-directory. You should now see a file with the name org.eclipse.examples.slideshow.core-0.2.0-SNAPSHOT.jar. This is the build output for our plugin. Don't mind the -SNAPSHOT in the name for now. When an eclipse-repository is built later it will replace this name with the build time stamp as you normally see in eclipse bundles.

Now that we've proven the new repository is working for finding dependencies, let's try to build the whole project. Navigate back to the root of the project and run the build command:

    mvn clean verify

This time a new error appears:

[ERROR] Internal error: java.lang.RuntimeException: org.osgi.framework.BundleException:
  Bundle org.eclipse.examples.slideshow.jdt cannot be resolved
[ERROR] Resolution errors:
[ERROR] Bundle org.eclipse.examples.slideshow.jdt - Missing Constraint:
  Import-Package: org.eclipse.jface.text; version="0.0.0"

Tycho is unable to resolve dependency org.eclipse.jface.text from the bundle org.eclipse.examples.slideshow.jdt because this bundle is a split package provided by two bundles (org.eclipse.jface.text and org.eclipse.text). An explaination of this issue can be found on the tycho-user mailing list here: http://dev.eclipse.org/mhonarc/lists/cbi-dev/msg00335.html

We can help Tycho resolve this bundle by adding some additional configuration. If you recall earlier, bundle-specific configuration should go into the specific pom.xml for the bundle so that other bundles do not inherit it. In this case the bundle that needs additional configuration is the org.eclipse.examples.slideshow.jdt, so open up the pom.xml for that bundle.

We can use the tycho-platform-configuration plugin to define a build-time dependency for org.eclipse.jface.text. This will help Tycho resolve this bundle during the build. Modify your pom.xml to look similar to this (see highlighted area):

<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
   http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>org.eclipse.examples.slideshow</groupId>
    <artifactId>org.eclipse.examples.slideshow</artifactId>
    <version>0.0.1-SNAPSHOT</version>
  </parent>
  <groupId>org.eclipse.examples.slideshow</groupId>
  <artifactId>org.eclipse.examples.slideshow.jdt</artifactId>
  <version>0.2.0-SNAPSHOT</version>
  <packaging>eclipse-plugin</packaging>

  <build>
    <plugins>
      <plugin>
        <groupId>org.eclipse.tycho</groupId>
        <artifactId>target-platform-configuration</artifactId>
        <configuration>
          <dependency-resolution>
            <extraRequirements>
              <requirement>
                <type>eclipse-plugin</type>
                <id>org.eclipse.jface.text</id>
                <versionRange>0.0.0</versionRange>
              </requirement>
            </extraRequirements>
          </dependency-resolution>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

This adds a new <build> section to the pom.xml containing plugin configuration for the tycho-platform-configuration plugin. With this setting we are telling Tycho that we need it to resolve an eclipse-plugin with the id org.eclipse.jface.text and accept any version (0.0.0). Typically, defining 0.0.0 for the version will retrieve the latest version available from whatever repository I can find it in.

It is possible to restrict the version with a range as well. For example:

    <versionRange>[2.9,3.0)</versionRange>

This will restrict the version to be any 2.9 version or greater but less than 3.0. The the square braces [] is an inclusive denotation and the parenthesis () denote an exclusive number.

Once you're ready, run the build from the root of the project again. You should once again see a similar error:

[ERROR] Internal error: java.lang.RuntimeException: org.osgi.framework.BundleException:
  Bundle org.eclipse.examples.slideshow.runner cannot be resolved
[ERROR] Resolution errors:
[ERROR] Bundle org.eclipse.examples.slideshow.runner -
  Missing Constraint: Import-Package: org.eclipse.core.runtime; version="0.0.0"

This time the dependency org.eclipse.core.runtime is missing when trying to build org.eclipse.examples.slideshow.runner. You will need to modify the pom.xml for org.eclipse.examples.slideshow.runner similar to what was done above. Fix this and run the build again.

    mvn clean verify

This time a new error appears:

[ERROR] Failed to execute goal
  org.eclipse.tycho:tycho-packaging-plugin:0.18.1:package-plugin
  (default-package-plugin) on project org.eclipse.examples.slideshow.jdt:
  Error assembling JAR:
  /buildroot/org.eclipse.examples.slideshow/org.
    eclipse.examples.slideshow.jdt/build.properties:
  bin.includes value(s) [plugin.xml] do not match any files. -> [Help 1]

In some cases Tycho helps us find issues with our build. In this case the build.properties for org.eclipse.examples.slideshow.jdt wants to include a file “plugin.xml” that does not exist. Either we need to create this file or remove it from the build.properties. In this example we'll just remove it. Open org.eclipse.examples.slideshow.jdt/build.properties and remove the “plugin.xml” from bin.includes.

Once that's done run the build once more:

    mvn clean verify

We will now get a new error:

[ERROR] Failed to execute goal
  org.eclipse.tycho:tycho-packaging-plugin:0.18.1:package-feature
  (default-package-feature) on project org.eclipse.examples.slideshow.feature:
  Error creating feature package: license feature must include build.properties
  file -> [Help 1]

This is due to the Juno version of org.eclipse.license missinging a build.properties. Tycho requires this file in order to determine which license files need to be included in your feature.

Since we have no control over this, lets remove the license requirement for now. Modify org.eclipse.examples.slideshow.feature/feature.xml and remove the license feature as follows:

 <feature
       id="org.eclipse.examples.slideshow.feature"
       label="Eclipse Slideshow Feature"
-      version="0.2.0.qualifier"
-      license-feature="org.eclipse.platform"
-      license-feature-version="4.2.1.qualifier">
+      version="0.2.0.qualifier">

Once the license issue is resolved we'll want to run the build again. Using the usual build command:

    mvn clean verify

Hopefully you've become quite familiar with this command by now...

Building Tests

This time we make it a little further and run into a new error against org.eclipse.examples.slideshow.jdt.tests:

[ERROR] Failed to execute goal org.eclipse.tycho:tycho-surefire-plugin:0.18.1:test
  (default-test) on project org.eclipse.examples.slideshow.jdt.tests:
  An unexpected error occured (return code 13). See log for details. -> [Help 1]

This error is extremely vague, so we'll run the build command with full debugging enabled by passing the parameter “-X” to Maven. This will output quite a bit of text so I would recommend piping it to a file or a pager so you can browse it more easily.

    mvn clean verify -X > log

Usually I jump to the bottom of the log and read backwards looking for anything that looks interesting. In this case I found a couple of lines below that mention some unresolvable constraints.

!ENTRY org.eclipse.osgi 2 0 2013-08-12 14:45:52.118
!MESSAGE One or more bundles are not resolved because
  the following root constraints are not resolved:
!SUBENTRY 1 org.eclipse.osgi 2 0 2013-08-12 14:45:52.118
!MESSAGE Bundle initial@reference:file:../../../org.eclipse.examples.slideshow.
   jdt/target/org.eclipse.examples.slideshow.jdt-0.2.0-SNAPSHOT.jar was not resolved.
!SUBENTRY 2 org.eclipse.examples.slideshow.jdt 2 0 2013-08-12 14:45:52.119
!MESSAGE Missing imported package org.eclipse.jface.text_0.0.0.

It's an issue with the bundle org.eclipse.jface.text again. You will want to help Tycho find this bundle by copying what we did with org.eclipse.examples.slideshow.jdt previously into the pom.xml for org.eclipse.examples.slideshow.jdt.tests. For convenience, here is the section:

  <build>
    <plugins>
      <plugin>
        <groupId>org.eclipse.tycho</groupId>
        <artifactId>target-platform-configuration</artifactId>
        <configuration>
          <dependency-resolution>
            <extraRequirements>
              <requirement>
                <type>eclipse-plugin</type>
                <id>org.eclipse.jface.text</id>
                <versionRange>0.0.0</versionRange>
              </requirement>
            </extraRequirements>
          </dependency-resolution>
        </configuration>
      </plugin>
    </plugins>
  </build>

Once done run the build again:

    mvn clean verify

This time a different error occurs:

[ERROR] Failed to execute goal org.eclipse.tycho:tycho-surefire-plugin:0.18.1:test
(default-test) on project org.eclipse.examples.slideshow.jdt.tests: No tests found.
  -> [Help 1]

No tests found. This is because the test for this bundle is in a name format that Tycho does not detect by default. The test in this bundle, found in src/org/eclipse/examples/slideshow/jdt, is named URLHandlingTests.java.

According to the tycho-surefire-plugin documentation (http://www.eclipse.org/tycho/sitedocs/tycho-surefire/tycho-surefire-plugin/test-mojo.html) the default search patterns are: **/Test*.java **/*Test.java **/*TestCase.java

Since our test file doesn't match any of the patterns, we will need to modify our pom to tell tycho-surefire-plugin to match our file. Open up org.eclipse.examples.slideshow.jdt.tests/pom.xml and add the following section:

      <plugin>
        <groupId>org.eclipse.tycho</groupId>
        <artifactId>tycho-surefire-plugin</artifactId>
        <configuration>
          <includes>
            <include>**/*Tests.java</include>
          </includes>
        </configuration>
      </plugin>

I added this immediately after the plugin section we added previously for the tycho-platform-configuration.

Once added try running the build again: mvn clean verify

It will fail again saying that some tests failed to execute. If you scroll the output up a little bit, just before the reactor summary you will see the following message:

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running org.eclipse.examples.slideshow.jdt.URLHandlingTests
Tests run: 2, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.394 sec<<< FAILURE!

Results :

Tests in error:
  testParseJavaURLWithMethod(org.eclipse.examples.slideshow.jdt.URLHandlingTests):
    Type "org.eclipse.tests.Junk" not found!

Tests run: 2, Failures: 0, Errors: 1, Skipped: 0

The good news is Tycho's successfully finding and executing our tests. The problem is the tests are failing. Looking through the source code for this specific test it looks like there's a TODO item stating that the tests are not working so I guess this is expected. In order to move forward we will need to tell Tycho to ignore these failing tests instead of failing the build. According to the tycho-surefire-plugin documentation there is a configuration for skipping the tests which we can use in this case.

      <plugin>
        <groupId>org.eclipse.tycho</groupId>
        <artifactId>tycho-surefire-plugin</artifactId>
        <configuration>
          <skipTests>true</skipTests>
          <includes>
            <include>**/*Tests.java</include>
          </includes>
        </configuration>
      </plugin>

The <skipTests> section when set to true will skip the tests during the build. It will still build the bundle -- it just won't run the tests.

If you run the build again you will see a familiar error:

[ERROR] Failed to execute goal org.eclipse.tycho:tycho-surefire-plugin:0.18.1:test
  (default-test) on project org.eclipse.examples.slideshow.runner.tests:
  No tests found. -> [Help 1]

Again no tests were found, this time for org.eclipse.examples.slideshow.runner.tests. In this case however when I look in the src directory I did not see anything that resembled a test. So instead here we will want to ignore this bundle. The tycho-surefire-plugin has a configuration to not fail when no tests are found by setting <failIfNoTests> to false. Add this section to the runner tests pom.xml file:

  <build>
    <plugins>
      <plugin>
        <groupId>org.eclipse.tycho</groupId>
        <artifactId>tycho-surefire-plugin</artifactId>
        <configuration>
          <failIfNoTests>false</failIfNoTests>
        </configuration>
      </plugin>
    </plugins>
  </build>

Once added try running the build again to see how much further we get. This time you will fail on the last and final bundle, org.eclipse.examples.slideshow.text.tests with a familiar error message:

[ERROR] Failed to execute goal org.eclipse.tycho:tycho-surefire-plugin:0.18.1:test
  (default-test) on project org.eclipse.examples.slideshow.text.tests:
  No tests found. -> [Help 1]

This is exactly the same issue we saw previously, where the tests had a name that was not in Tycho's default search parameters. We simply need to add a config section to the pom.xml to help Tycho find the test.

  <build>
    <plugins>
      <plugin>
        <groupId>org.eclipse.tycho</groupId>
        <artifactId>tycho-surefire-plugin</artifactId>
        <configuration>
          <includes>
            <include>**/*Tests.java</include>
          </includes>
        </configuration>
      </plugin>
    </plugins>
  </build>

Unfortunately, after fixing this there will be tests errors again:

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running org.eclipse.examples.slideshow.text.WikiTextParserTests
Tests run: 8, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.083 sec <<< FAILURE!

Results :

Failed tests:
  testParseImageTagParts(org.eclipse.examples.slideshow.text.WikiTextParserTests):
  expected:<30> but was:<-1>

Tests run: 8, Failures: 1, Errors: 0, Skipped: 0

I just went ahead and used the <skipTests> setting to work around this issue like we did previously.

Final build results

If you've made it this far, your example slideshow should now successfully build using Maven/Tycho. You can retrieve your final build results from the site bundle by looking in org.eclipse.examples.slideshow.site/target/repository.

This produced a p2 repository containing all the build artifacts that were defined in the category.xml for the site bundle.

(Bonus) Signing your jars using the eclipse-jarsigner-plugin

The CBI project provides a convenient plugin for signing jar files using Eclipse Infrastructure via the eclipse-jarsigner-plugin. Jar signing is only available while on the Eclipse internal network such as on build.eclipse.org or using the Hudson CI. Since you must be on the Eclipse Network in order to sign jars you will want to enable signing in such a way that it's only activated on request, that way people can continue to build your project even if they are not in the Eclipse Network. This can be achieved in Maven using Profiles. For example adding the code block below to your root pom.xml (parent pom) will add a profile “eclipse-sign” (I added this at the bottom of my pom.xml just before the final </project> tag).

  <profiles>
    <profile>
      <id>eclipse-sign</id>
      <build>
        <plugins>
          <plugin>
            <groupId>org.eclipse.cbi.maven.plugins</groupId>
            <artifactId>eclipse-jarsigner-plugin</artifactId>
            <version>1.0.4</version>
            <executions>
              <execution>
                <id>sign</id>
                <goals>
                  <goal>sign</goal>
                </goals>
                <phase>verify</phase>
              </execution>
            </executions>
          </plugin>
        </plugins>
      </build>
    </profile>
  </profiles>

When activated, this profile will make your project sign all its artifacts using the Eclipse signing infrastructure, and the produced jars will be signed. Note that this will only work on the Eclipse network such as on build.eclipse.org. To activate this profile you will need to run the build using this command:

    mvn clean verify -P eclipse-sign

Unfortunately this is not all that needs to be done in order to use the plugin. We still need to inform Maven of where to get the eclipse-jarsigner-plugin. Since eclipse-jarsigner-plugin is a Maven plugin we will need to add the following section to your parent pom (I added this immediately after the </repositories> section):

  <pluginRepositories>
    <pluginRepository>
      <id>cbi</id>
      <url>https://repo.eclipse.org/content/repositories/cbi-releases/</url>
      <releases>
        <enabled>true</enabled>
      </releases>
      <snapshots>
        <enabled>false</enabled>
      </snapshots>
    </pluginRepository>
  </pluginRepositories>

The eclipse-jarsigner-plugin is a CBI plugin available in the CBI releases repo on repo.eclipse.org, a Maven repository where Eclipse projects can publish Maven artifacts.

You should now be able to run a build and have it signed on build.eclipse.org. If successful you will see messages such as this go by:

[INFO] --- eclipse-jarsigner-plugin:1.0.4:sign (sign) @
  org.eclipse.examples.slideshow.feature ---
[INFO] Signed org.eclipse.examples.slideshow:org.eclipse.examples.slideshow.feature:
  eclipse-feature:0.2.0-SNAPSHOT in 1 seconds.

Your jars will also contain the files ECLIPSE_.SF and ECLIPSE_.RSA when they are signed.

One thing that should be noted: if your project uses pack200, the pack200 tool will break signing unless you use some additional Tycho configuration. In this case you will need to wrap the eclipse-jarsigner-plugin between the Tycho pack200 plugins as follows:

  <profiles>
    <profile>
      <id>eclipse-sign</id>
      <build>
        <plugins>
          <plugin>
            <groupId>org.eclipse.tycho</groupId>
            <artifactId>target-platform-configuration</artifactId>
            <version>0.18.1</version>
            <configuration>
              <includePackedArtifacts>false</includePackedArtifacts>
            </configuration>
          </plugin>
          <plugin>
            <groupId>org.eclipse.tycho.extras</groupId>
            <artifactId>tycho-pack200a-plugin</artifactId>
            <version>0.18.1</version>
            <executions>
              <execution>
                <id>pack200-normalize</id>
                <goals>
                  <goal>normalize</goal>
                </goals>
                <phase>verify</phase>
              </execution>
            </executions>
          </plugin>
          <plugin>
            <groupId>org.eclipse.cbi.maven.plugins</groupId>
            <artifactId>eclipse-jarsigner-plugin</artifactId>
            <version>1.0.4</version>
            <executions>
              <execution>
                <id>sign</id>
                <goals>
                  <goal>sign</goal>
                </goals>
                <phase>verify</phase>
              </execution>
            </executions>
          </plugin>
          <plugin>
            <groupId>org.eclipse.tycho.extras</groupId>
            <artifactId>tycho-pack200b-plugin</artifactId>
            <version>0.18.1</version>
            <executions>
              <execution>
                <id>pack200-pack</id>
                <goals>
                  <goal>pack</goal>
                </goals>
                <phase>verify</phase>
              </execution>
            </executions>
          </plugin>
          <plugin>
            <groupId>org.eclipse.tycho</groupId>
            <artifactId>tycho-p2-plugin</artifactId>
            <version>0.18.1</version>
            <executions>
              <execution>
                <id>p2-metadata</id>
                <goals>
                  <goal>p2-metadata</goal>
                </goals>
                <phase>verify</phase>
              </execution>
            </executions>
            <configuration>
              <defaultP2Metadata>false</defaultP2Metadata>
            </configuration>
          </plugin>
        </plugins>
      </build>
    </profile>
  </profiles>

CBI also provides plugins for signing Windows and Mac binaries via the eclipse-winsigner-plugin and eclipse-macsigner-plugin. Further details on these plugins can be found in the README for the cbi-plugins repository: http://git.eclipse.org/c/cbi/org.eclipse.cbi.maven.plugins.git/tree/README

On to Hudson

Once your project is building successfully from the command line, it can be moved into a new Hudson job, where it can be built periodically based on a pre-determined schedule. A build can also be triggered by a Git commit or from a Gerrit verification job.

Further Reading

About the Authors