Facebook OSS POM
Rationale
A base pom codifies policy for projects. It allows a new Maven project to quickly get off the ground and focus on the project itself and not how to build it. The Facebook OSS POM focuses on building libraries and components that are distributed as jar files through the Maven central repository.
It is possible to use the base pom in a new project without any additional changes and modifications.
Preliminaries
The Facebook OSS POM enforces a minimum version of Maven due to various bugs found in earlier versions.
By default, the Facebook OSS POM enforces JDK 1.7. To use another version, add
<properties>
<project.build.targetJdk>1.6</project.build.targetJdk>
...
</properties>
Local setup required!
To fully leverage the deployment options from the Facebook OSS POM, a number of servers need to be configured in the local ~/.m2/settings.xml
file. If these servers are missing, either artifact or site deployment will fail.
As described on https://docs.sonatype.org/display/Repository/Sonatype+OSS+Maven+Repository+Usage+Guide, the sonatype-nexus-staging
and sonatype-nexus-snapshots
repositories should be configured:
<servers>
...
<server>
<id>sonatype-nexus-snapshots</id>
<username>user</username>
<password>password</password>
</server>
<server>
<id>sonatype-nexus-staging</id>
<username>user</username>
<password>password</password>
</server>
...
</servers>
To support releasing and tagging repositories that are hosted on Github and to allow site deployment to Github, entries for Github and the project site must exist:
<servers>
...
<server>
<id>github</id>
<username>github-id</username>
<password>github-password</password>
</server>
<server>
<id>github-project-site</id>
<username>git</username>
</server>
...
</servers>
The hard-coded username git
and no password for the github-project-site are a limitation of the deployment tool used for the github site. They must exist in the local settings file.
Usage
Add the Facebook OSS POM as the parent to a project:
<parent>
<groupId>com.facebook</groupId>
<artifactId>facebook-oss-pom</artifactId>
<version> ... current pom release version ...</version>
</parent>
Project pom structure
The following elements should be present in a pom using the Facebook OSS POM as parent:
-
groupId
,artifactId
,version
,packaging
,name
,description
andinceptionYear
Define the new project. These elements should always be present. If any of those fields are missing from the project, the values from the Facebook OSS POM are picked up instead.
-
scm
Defines the SCM location and URL for the project. This is required to use the
release:prepare
andrelease:perform
targets to deploy artifacts to Maven Central. -
organization
,developers
,distributionManagement
Empty elements override the values inherited from the Facebook OSS.
This is a sample skeleton pom using the Facebook OSS POM:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.facebook</groupId>
<artifactId>facebook-oss-pom</artifactId>
<version> ... current version ...</version>
</parent>
<groupId> ... group id of the new project ... </groupId>
<artifactId> ... artifact id of the new project ... </artifactId>
<version> ... version of the new project ... </version>
<packaging> ... jar|pom ... </packaging>
<description> ... description of the new project ... </description>
<name>${project.artifactId}</name>
<inceptionYear>2013</inceptionYear>
<scm>
<connection> ... scm read only connection ... </connection>
<developerConnection>... scm read write connection ... </developerConnection>
<url> ... project url ... </url>
</scm>
<distributionManagement/>
<developers/>
<organization/>
...
</project>
Project POM conventions
In large maven projects, especially with multi-module builds, the pom files can become quite large. In many places, properties defined in the <properties>
section of the pom are used.
To avoid confusion with properties, the following conventions are used in the Facebook OSS POM:
- Properties defined in the POM that influence the build configuration are prefixed with
fb
. - Properties that factor out plugin versions (because the plugin is used in multiple places in the POM and the versions should be uniform) start with
dep.plugin
and end withversion
. - Properties that factor out dependency versions (to enforce uniform dependency versions across multiple, related dependencies) start with
dep
and end withversion
.
Examples:
<properties>
<!-- Sets the minimum maven version to build (influences build) -->
<fb.maven.version>3.0.4</fb.maven.version>
<!-- The surefire plugin version -->
<dep.plugin.surefire.version>2.13</dep.plugin.surefire.version>
<!-- The version for all guice related dependencies -->
<dep.guice.version>3.0</dep.guice.version>
<properties>
Deploy to Maven Central (oss.sonatype.org)
The Facebook OSS POM is intended for open source projects that should be deployed to Maven Central.
It inherits from the oss-parent POM and supports the OSS deployment process as outlined at https://docs.sonatype.org/display/Repository/Sonatype+OSS+Maven+Repository+Usage+Guide.
Project Build and Checkers
The Facebook OSS POM hooks various checkers into the build lifecycle and executes them on each build.
Generally speaking, running a set of checks at each build is a good way to catch problems early and any problem reported by a checker should be treated as something that needs to be fixed before releasing.
Checkers are organized in two groups, basic and extended.
Basic checkers
- Maven Enforcer (http://maven.apache.org/enforcer/maven-enforcer-plugin/)
- Maven Dependencies (http://maven.apache.org/plugins/maven-dependency-plugin/)
- Maven Dependency version check (https://github.com/ning/maven-dependency-versions-check-plugin)
- Maven Duplicate finder (https://github.com/ning/maven-duplicate-finder-plugin)
Extended checkers
- Findbugs (http://mojo.codehaus.org/findbugs-maven-plugin/)
- PMD (http://maven.apache.org/plugins/maven-pmd-plugin/)
- License check (http://code.google.com/p/maven-license-plugin/)
- Code coverage (http://www.eclemma.org/jacoco/trunk/doc/maven.html)
All checkers are enabled by default and all checkers will fail the build if a problem is encountered.
Each checker has a switch to turn it on or off and also whether a problem will be a warning or fatal to the build.
...
<properties>
<!-- Do not run the duplicate finder --->
<fb.check.skip-duplicate-finder>true</fb.check.skip-duplicate-finder>
</properties>
...
The following switches exist:
Group | Check | Skip check (Setting to true skips the check) | Fail build (Setting to false only reports a warning) |
---|---|---|---|
Basic | Maven Enforcer | fb.check.skip-enforcer | fb.check.fail-enforcer |
Basic | Maven Dependencies | fb.check.skip-dependency | fb.check.fail-dependency |
Basic | Maven Dependency version check | fb.check.skip-dependency-version-check | fb.check.fail-dependency-version-check |
Basic | Maven Duplicate finder | fb.check.skip-duplicate-finder | fb.check.fail-duplicate-finder |
Extended | Findbugs | fb.check.skip-findbugs | fb.check.fail-findbugs |
Extended | PMD | fb.check.skip-pmd | fb.check.fail-pmd |
Extended | License check | fb.check.skip-license | fb.check.fail-license |
Extended | Code coverage | fb.check.skip-jacoco | fb.check.fail-jacoco |
Checks can be turned on and off in groups:
Group | Skip checks | Fail build |
---|---|---|
All Checks | fb.check.skip-all | fb.check.fail-all |
All Basic checks | fb.check.skip-basic | fb.check.fail-basic |
All Extended Checks | fb.check.skip-extended | fb.check.fail-extended |
A more specific setting (checker specific, then group, then all) overrides a more general setting:
...
<properties>
<fb.check.skip-all>true</fb.check.skip-all>
<fb.check.skip-duplicate-finder>false</fb.check.skip-duplicate-finder>
</properties>
...
will skip all checks except the duplicate finder.
Checker notes
License checker
To ensure that a project has an uniform license header in all source files, the Maven license plugin can be used to check and format license headers.
The plugin expects the license header file as src/license/LICENSE-HEADER.txt
in the root folder of a project.
For a multi-module project, this file should exist only once, in the root pom of the project. In all other sub-modules, add
<properties>
<fb.main.basedir>${project.parent.basedir}</fb.main.basedir>
</properties>
to each pom. This is a limitation of the Maven multi-module build process (see http://stackoverflow.com/questions/1012402/maven2-property-that-indicates-the-parent-directory for details).
Enforcer checker
The Enforcer plugin outlaws a number of dependencies that project might use for various reasons:
Outlawed dependency | Rationale | What to use |
---|---|---|
commons-logging:commons-logging-api | Ill-fated attempt to split commons-logging implementation and commons-logging API. | commons-logging:commons-logging |
cglib:cglib | Has all its dependencies packed inside, therefore leads to duplicate classes. | cglib:cglib-nodep |
junit:junit | Has all its dependencies packed inside, therefore leads to duplicate classes. | junit:junit-dep |
com.google.collections:google-collections | Superseded by Guava, duplicate classes with Guava. | com.google.guava:guava |
com.google.code.findbugs:jsr305 | Subset of the full findbugs annotations, contains only the JSR-305 annotations | com.google.code.findbugs:annotations |
Well known dependencies
The Facebook OSS POM provides a number of dependencies to projects. These dependencies are considered "well known and stable". When a project wants to use any of these dependencies, it can declare them in the project <dependencies>
section without a version and automatically pick up a version from the Facebook OSS POM.
The following dependencies are defined:
Dependency name | Group/Artifact Ids | property |
---|---|---|
Google Guice | com.google.inject:guice com.google.inject.extensions:guice-servlet com.google.inject.extensions:guice-assistedinject com.google.inject.extensions:guice-multibindings com.google.inject.extensions:guice-throwingproviders |
dep.guice.version |
Google Guava | com.google.guava:guava | dep.guava.version |
Joda Time | joda-time:joda-time | dep.joda.version |
Apache Commons Lang 3 | org.apache.commons:commons-lang3 | dep.commons-lang3.version |
Apache Commons Lang | commons-lang:commons-lang | dep.commons-lang.version |
Apache Commons Configuratio | commons-configuration:commons-configuration | dep.commons-configuration.version |
Apache Commons Codec | commons-codec:commons-codec | dep.commons-codec.version |
Apache Commons Collections | commons-collections:commons-collections | dep.commons-collections.version |
Apache Commons IO | commons-io:commons-io | dep.commons-io.version |
Apache Commons Beanutils | commons-beanutils:commons-beanutils | dep.commons-beanutils.version |
Java Inject API | javax.inject:javax.inject | dep.javax-inject.version |
Java Servlet API | javax.servlet:javax.servlet-api | dep.javax-servlet.version |
slf4j (Simple Logging Facade for Java) | org.slf4j:slf4j-api org.slf4j:slf4j-jcl org.slf4j:slf4j-jdk14 org.slf4j:slf4j-log4j12 org.slf4j:slf4j-nop org.slf4j:slf4j-simple org.slf4j:slf4j-ext org.slf4j:jcl-over-slf4j org.slf4j:jul-to-slf4j org.slf4j:log4j-over-slf4j |
dep.slf4j.version |
Logback | ch.qos.logback:logback-core ch.qos.logback:logback-classic |
dep.logback.version |
log4j | log4j:log4j | dep.log4j.version |
Findbugs Annotations | com.google.code.findbugs:annotations | dep.findbugs-annotations.version |
JUnit testing | junit:junit-dep | dep.junit.version |
TestNG testing | org.testng:testng | dep.testng.version |
Easymock Mocking framework | org.easymock:easymock | dep.easymock.version |
Hamcrest matchers | org.hamcrest:hamcrest-core org.hamcrest:hamcrest-library |
dep.hamcrest.version |
Objenesis | org.objenesis:objenesis | dep.objenesis.version |
Lock down a well known dependency
It is possible to "lock down" the version of a dependency so that any Facebook OSS POM updates will not affect the version used by the project. Locking a version is done by adding a property to the <properties>
section of the project POM:
<properties>
<!-- change guice version in the Facebook OSS POM. -->
<dep.guice.version>2.0</dep.guice.version>
...
</properties>
...
<dependencies>
<dependency>
<!-- Use the version from the Facebook OSS POM -->
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
</dependency>
<dependency>
<!-- Use the version from the Facebook OSS POM -->
<groupId>com.google.inject.extensions</groupId>
<artifactId>guice-multibinder</artifactId>
</dependency>
...
</dependency>
to the project POM. This will lock the version of a dependency to the version desired. This can also be used to force a version update to a dependency.
<properties>
<!-- change log4j version in the Facebook OSS POM. -->
<dep.log4j.version>1.2.18-SNAPSHOT</dep.log4j.version>
...
</properties>
...
<dependencies>
<dependency>
<!-- Use the version from the Facebook OSS POM -->
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</dependency>
...
</dependency>
Site deployment to Github
The Facebook OSS POM supports deployment of the maven generated site to Github. See http://khuxtable.github.com/wagon-gitsite/ for more information.
For a first time deployment, it is necessary to generate the gh-pages
branch as described on Github at https://help.github.com/articles/creating-project-pages-manually.
For site deployment, the github user and github project site must be configured in the local ~/.m2/settings.xml
file!
<servers>
...
<server>
<id>github</id>
<username>github-id</username>
<password>github-password</password>
</server>
<server>
<id>github-project-site</id>
<username>git</username>
</server>
...
</servers>
The hard-coded username git
and no password for the github-project-site are a limitation of the deployment tool used for the github site.
Other properties
These are default properties that affect some aspects of the build. All of them can be overriden in the <properties>
section of the project pom.
fb.build.jvmsize
Sets the default heap size for the compiler, javadoc generation and other plugins. Default is 1024M.
fb.release.push-changes
When a project creates a release using the maven-release-plugin and mvn release:prepare
, this switch controls whether the generated tags, modified POM files etc. are pushed automatically to the upstream repository or not. Default is false
(do not push the changes).
fb.maven.version
The minimum version of Maven to build a project.
fb.main.basedir
The 'root' directory of a project. For a simple project, this is identical to project.basedir
. In a multi-module build, it should point at the root project.
For a multi-module project, all other sub-modules must have this explicitly set to the root directory and therefore the following code
<properties>
<fb.main.basedir>${project.parent.basedir}</fb.main.basedir>
</properties>
must be added to each pom. This is a limitation of the Maven multi-module build process (see http://stackoverflow.com/questions/1012402/maven2-property-that-indicates-the-parent-directory for details).
fb.test.fork-mode
Defines the fork mode for running tests. Default is 'once' which is forking one JVM for all tests. Valid values are the same as for the maven-surefire-plugin (once, always, never).