Revapi Maven Plugin

Maven integration for Revapi.

Sometimes it can be handy to split the configuration of Revapi analysis in separate files - this can be done for various reasons - you might want to keep the config of different extensions separate or you want to compose the config from various contributing locations, etc.

For Revapi, this can be achieved by using the analysisConfigurationFiles configuration element instead of (or in addition to) the analysisConfiguration element which provides the in-POM way of configuring Revapi.

<plugin>
    <groupId>org.revapi</groupId>
    <artifactId>revapi-maven-plugin</artifactId>
    <version>...</version>
    ...
    <configuration>
        <analysisConfigurationFiles>
            <file>${project.basedir}/config/filter.json</file>
            <file>${project.basedir}/config/ignore.xml</file>
        </analysisConfigurationFiles>
    </configuration>
    <executions>
        <execution>
            <goals><goal>check</goal></goals>
        </execution>
    </executions>
</plugin>

Each of the configuration files (e.g. filter.json and ignore.xml in the above example) is a JSON or XML document with the configuration. The maven plugin then merges the files together (in an unspecified order) and uses the result as the final configuration for the analysis.

Using Configuration Defined In Other Modules

It is possible to define a JAR artifact that contains "common" configuration of the Revapi analysis shared by many modules. To reference it, simply add the artifact as a dependency of the revapi maven plugin and reference the configuration file inside that artifact like:

<plugin>
    <groupId>org.revapi</groupId>
    <artifactId>revapi-maven-plugin</artifactId>
    <version>...</version>
    <dependencies>
      ...
      <dependency>
        <groupId>my.group.id</groupId>
        <artifactId>artifact-with-common-config</artifact>
        <version>...</version>
      </dependency>
    </dependencies>
    <configuration>
        <analysisConfigurationFiles>
          <configurationFile>
            <resource>path/to/the/config/file/in/the/shared/artifact</resource>
          </configurationFile>
          ...
        </analysisConfigurationFiles>
        ...
    </configuration>
    ...
</plugin>

Merging Configuration From Multiple Files

When the analysis configuration is split amongst several files, it needs to be merged together before it is applied to the Revapi extensions. This process is slightly complex with the ability for a single extension to be configured multiple times but in the end is somewhat similar to the way Maven merges the executions of a plugin - as long as the executions are defined once in the effective POM, they don’t need to be assigned IDs. If there are multiple executions and you override them in child POMs, they need to have the IDs assigned so that it is clear what executions in child POM need to be merged with what executions in the parent POM.

In Revapi, too, an extension configuration can optionally have an ID. In JSON this is expressed like this:

...
    {
      "extension": "my.extension",
      "id": "id",
      "configuration": ...
    }
...

and in XML like so:

...
    <my.extension id="myid">
      ...
    </my.extension>
...

When merging configurations without an explicit ID, everything works as long as there is at most a single configuration for each extension in each configuration file to be merged. As soon as there is more than one configuration for some extension in one of the configuration files, you need to assign IDs to the configurations of that extension so that it is clear what configs should be merged with what.

Custom Root Element of Configuration

It might sometimes be useful to be able to only use a part of a JSON document as configuration for Revapi. This might be because the same file might be used for holding other data, too, or because the file(s) contain(s) multiple Revapi configurations. Note that the custom root is only applicable to configuration files, not the in-POM configuration.

The below example illustrates the usage of the custom configuration root.

<plugin>
    <groupId>org.revapi</groupId>
    <artifactId>revapi-maven-plugin</artifactId>
    <version>...</version>
    ...
    <configuration>
        <analysisConfigurationFiles>
            <file>${project.basedir}/config/filter.json</file>
            <file>${project.basedir}/config/ignore.json</file>
            <file>
              <path>${project.basedir}/config/json-data-for-many-things.json</path>
              <roots>
                <root>configuration/revapi</root>
              </roots>
            </file>
            <file>
              <path>${project.basedir}/config/xml-data-for-many-things.xml</path>
              <roots>
                <root>configuration/revapi</root>
              </roots>
            </file>
        </analysisConfigurationFiles>
    </configuration>
    <executions>
        <execution>
            <goals><goal>check</goal></goals>
        </execution>
    </executions>
</plugin>

The above would read the configuration from the filter.json and ignore.json files. In addition it would also read the configuration from the json-data-for-many-things.json and xml-data-for-many-things.xml files but would only consider the data from the "configuration/revapi" subpath in those file. E.g. if the files looked like:

{
  "itest-setup": {...},
  "configuration": {
    "our-custom-tool": {
    },
    "revapi": {
      ... HERE WE ARE ...
    }
  }
}
<configuration>
  <ci>...</ci>
  <revapi>
     ... HERE WE ARE ...
  </revapi>
</configuration>

The Revapi configurations would only be read from the "…​ HERE WE ARE …​" part of the documents.

Revapi itself uses this approach to track the changes made to its API across the versions using a single file. Each Revapi module can have a "api-changes.json" file in its base directory. The contents of this file follow this pattern:

{
  "version1": {
    "revapi": {
      "ignore": [
        ...
      ]
    }
  },
  "version2": {
    "revapi": {
      "ignore": [
        ...
      ]
    }
  },
  ...
}

I.e. in that file, the root elements are the released versions of revapi and under them there are configurations for revapi for the particular version to pass the build. Usually, this is just a list of ignored API changes - i.e. the API changes made in that release that are to be purposefully ignored by the tool so that the build passes. To make this work, revapi build contains this profile:

<profile>
    <id>api-check</id>
    <activation>
        <activeByDefault>true</activeByDefault>
    </activation>

    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>build-helper-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <id>parse-version</id>
                        <goals>
                            <goal>parse-version</goal>
                        </goals>
                        <phase>validate</phase>
                    </execution>
                </executions>
            </plugin>

            <plugin>
                <groupId>org.revapi</groupId>
                <artifactId>revapi-maven-plugin</artifactId>
                <version>${self-api-check.maven-version}</version>
                <dependencies>
                    <dependency>
                        <groupId>org.revapi</groupId>
                        <artifactId>revapi-java</artifactId>
                        <version>${self-api-check.java-extension-version}</version>
                    </dependency>
                </dependencies>
                <configuration>
                    <failOnMissingConfigurationFiles>false</failOnMissingConfigurationFiles>
                    <analysisConfigurationFiles>
                        <configurationFile>
                            <path>api-changes.json</path>
                            <roots>
                                <root>${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}</root>
                            </roots>
                        </configurationFile>
                    </analysisConfigurationFiles>
                </configuration>
                <executions>
                    <execution>
                        <id>api-check</id>
                        <goals><goal>check</goal></goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</profile>

Back to top

Msb3 Maven skin by Marek Romanowski.