In the Maven world, a typical project setup consists of a top level pom.xml file with multiple modules in subdirectories. Each module produces a Maven Artifact (typically a jar or a pom.xml).
The pomgen terminology for a top level project with modules is a "library". Subdirectories of the library (the modules) are Bazel Packages that each produce a Maven Artifact (jar or pom). pomgen processes all modules that are part of a library together.
This example has 3 libraries. A library is defined by the presence of a LIBRARY.root marker file.
A Bazel Package that produces a Maven Artifact must have a BUILD.pom file that defines Maven specific metadata. Note that the java_library
target that builds the jar Maven Artifact must be the default target, ie it must have the same name as the directory its BUILD file lives in.
The libraries in this example are, and reference each other in this order:
Make sure you have installed the required external dependencies.
Make sure the pomgen tests pass. From the root of the repository:
bazel test //...
The metadata query script provides information about Libraries and Maven Artifacts in the repository. It also shows information on whether a Library needs to be released or not.
From the root of the repository:
bazel run @pomgen//:query -- --package examples/hello-world/juicer --library_release_plan_tree
The output looks similar to this:
examples/hello-world/juicer ++ 3.0.0-SNAPSHOT
examples/hello-world/healthyfoods ++ 1.0.0-SNAPSHOT
examples/hello-world/wintervegetables ++ 2.0.0-SNAPSHOT
examples/hello-world/healthyfoods ++ 1.0.0-SNAPSHOT
The output shows:
- juicer references wintervegetables, which references healthyfoods
- juicer also references healthyfoods directly
- The version of each library
- Whether the library needs to be released or not
- In this case they all need to be released because pomgen is not aware of any previous release
pomgen can be run directly (bazel run @pomgen//:pomgen -- --help
), however, there's a convenient wrapper script that we'll use instead: it defaults some pomgen flags. Before running, make sure you have the required external dependencies.
bazel run @pomgen//maven -- -a pomgen -l examples/hello-world/juicer
The command above specifies:
- The action to run,
pomgen
in this case (to generate poms) - The library to generate poms for:
examples/hello-world/juicer
pomgen follows refernces between libraries; since juicer
depends on 2 other libraries healthyfoods
and wintervegerables
, pomgen generated pom.xml files for all 3 libraries, ie for all modules that are part of those libraries. Usually this is the right behavior, but if there a lot of upstream libraries, it may be desirable in some cases to not follow library references. This can be accomplished by setting -i
(ignore references) flag:
bazel run @pomgen//maven -- -a pomgen -l examples/hello-world/juicer -i
The Maven Artifacts generated by pomgen can be installed into ~/.m2/repository
so that they are consumable by a local Maven project. Use the install
action:
bazel run @pomgen//maven -- -a install -l examples/hello-world/juicer
If you see this type of error:
ERROR: did not find jar artifact at /Users/stoens/Code/pomgen/bazel-bin/examples/hello-world/juicer/juicer.jar
This error means that pomgen did not find the jar file for the juicer module - this happens when bazel build
did not run. There are 2 solutions:
- Run
bazel build examples/hello-world/...
- If there are many upstream libraries in a large repository, it may be helpful to ask pomgen to build all upstream libraries - use the
build
action:bazel run @pomgen//maven -- -a build -l examples/hello-world/juicer
Once the install
action ran successfully for examples/hello-world/juicer
, you can use the juicer
artifact in a Maven project. Try this pom.xml:
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>g1</groupId>
<artifactId>a1</artifactId>
<version>1.0.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>com.pomgen.example</groupId>
<artifactId>juicer</artifactId>
<version>10.0.0-qual1-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
Then run mvn dependency:tree
:
[INFO] g1:a1:jar:1.0.0-SNAPSHOT
[INFO] \- com.pomgen.example:juicer:jar:10.0.0-qual1-SNAPSHOT:compile
[INFO] +- com.pomgen.example:fruit-api:jar:1.0.0-SNAPSHOT:compile
[INFO] | +- org.antlr:ST4:jar:4.0.7:compile
[INFO] | +- org.antlr:antlr-runtime:jar:3.5:compile
[INFO] | +- org.antlr:stringtemplate:jar:3.2.1:compile
[INFO] | \- antlr:antlr:jar:2.7.6:compile
[INFO] +- com.pomgen.example:vegetable-api:jar:1.0.0-SNAPSHOT:compile
[INFO] +- com.pomgen.example:wintervegetables:jar:20200416.1-SNAPSHOT:compile
[INFO] \- com.google.guava:guava:jar:23.0:compile
pomgen supports custom pom templates for the purpose of generating pom-only artifacts (<packaging>pom</packaging>
). This is typically needed when migrating a Maven project to Bazel that has a parent pom, meant to be inherited from: the parent pom still needs to be generated because existing Maven projects may depend on it.
See this example pom template - note that the corresponding BUILD.pom file must specify that the pom_generation_mode
is template
.
artifact_id, group_id and version from the BUILD.pom file can be referenced in the pom template using the syntax
#{group_id}
#{articat_id}
#{version}
See the example pom template.
The version of known artifacts, both external (maven_install) and internal (BUILD.pom) can be referenced in the pom template using the following syntax:
- For external artifacts:
#{maven_install_label.version}
for example:#{@com_google//:com_google_guava_guava.version}
- For interal artifacts:
#{group_id:artifact_id:version}
See the example pom template.