blob: c68ec7078eaefe257c3dca9de956813b2f623dc5 [file] [log] [blame] [view]
# Using rules_jvm_external with bzlmod
Bzlmod is the new package manager for Bazel modules, included in Bazel 6.0.
It allows a significantly shorter setup than the `WORKSPACE` file used prior to bzlmod.
Note: this support is new as of early 2023, so expect some brokenness and missing features.
Please do file issues for missing bzlmod support.
See the `/examples/bzlmod` folder in this repository for a complete, tested example.
## Installation
Add the following to your `MODULE.bazel` file, setting the `version` to the latest one
available on https://registry.bazel.build/modules/rules_jvm_external:
```starlark
bazel_dep(name = "rules_jvm_external", version = "...")
maven = use_extension("@rules_jvm_external//:extensions.bzl", "maven")
maven.install(
artifacts = [
# This line is an example coordinate, you'd copy-paste your actual dependencies here
# from your build.gradle or pom.xml file.
"org.seleniumhq.selenium:selenium-java:4.4.0",
],
)
# You can split off individual artifacts to define artifact-specific options (this example sets `neverlink`).
# The `maven.install` and `maven.artifact` tags will be merged automatically.
maven.artifact(
artifact = "javapoet",
group = "com.squareup",
neverlink = True,
version = "1.11.1",
)
use_repo(maven, "maven")
```
Now you can run the `@maven//:pin` program to create a JSON lockfile of the transitive dependencies,
in a format that rules_jvm_external can use later. You'll check this file into the repository.
```sh
$ bazel run @maven//:pin
```
Ignore the instructions printed at the end of the output from this command, as they aren't updated
for bzlmod yet. See [#836](https://github.com/bazelbuild/rules_jvm_external/issues/836)
Due to [#835](https://github.com/bazelbuild/rules_jvm_external/issues/835) this creates a file with
a longer name than it should, so we rename it:
```sh
$ mv rules_jvm_external~4.5~maven~maven_install.json maven_install.json
```
Now that this file exists, we can update the `MODULE.bazel` to reflect that we pinned the
dependencies.
Add a `lock_file` attribute to the `maven.install()` call like so:
```starlark
maven.install(
...
lock_file = "//:maven_install.json",
)
```
Now you'll be able to use the same `REPIN=1 bazel run @maven//:pin` operation described in the
[workspace instructions](/README.md#updating-maven_installjson) to update the dependencies.
## Extension and tag documentation
The extension and tag documentation can be found [in this document](bzlmod-api.md).
## Declaring dependencies in files
It is possible to use a
gradle [version catalog](https://docs.gradle.org/current/userguide/version_catalogs.html)
to declare dependencies. These should be declared in a `libs.versions.toml` file, and can be
imported to your bazel project by using the `from_toml` tag:
```starlark
maven.from_toml(
libs_versions_toml = "//gradle:libs.versions.toml",
)
```
An example `libs.versions.toml` file could look like:
```toml
[versions]
junitJupiter = "5.12.2"
[libraries]
guava = { module = "com.google.guava:guava" }
guavaBom = { module = "com.google.guava:guava-bom", version = "33.4.8-jre" }
junitApi = { module = "org.junit.jupiter:junit-jupiter-api", version.ref = "junitJupiter" }
```
### Declaring BOMs from external files
This can be done by using the `bom_modules` attribute of the `from_toml` tag. This is
a list of gradle modules, matching the `module` in the `libs.versions.toml` file. We
can change our module declaration like so to correctly use the guava bom:
```starlark
maven.from_toml(
libs_versions_toml = "//gradle:libs.versions.toml",
bom_modules = [
"com.google.guava:guava-bom",
],
)
```
## Artifact exclusion
The non-bzlmod instructions for how to configure
`exclusions` [from the README](../README.md#artifact-exclusion)
don't work as shown for bzlmod; it's not possible to "inline" them as shown (it will cause an `ERROR: in tag at
<root>/MODULE.bazel:22:14, error converting value for attribute artifacts: expected value of type 'string' for
element 9 of artifacts, but got None (NoneType)`). Split it like this instead:
```starlark
# https://github.com/grpc/grpc-java/issues/10576
maven.artifact(
artifact = "grpc-core",
exclusions = ["io.grpc:grpc-util"],
group = "io.grpc",
version = "1.58.0", # Keep version in sync with below!
)
maven.install(
artifacts = [
"junit:junit:4.13.2",
...
```
Alternatively, you can use the mechanism outlined below to add exclusions.
## Modifying artifact declarations
Because artifacts are not always declared in the module file, `rules_jvm_external` offers
a mechanism for modifying artifacts that are declared elsewhere (eg. in an `install` or a
`from_toml` tag). This is done using the `amend_artifact` tag:
```starlark
maven.amend_artifact(
coordinates = "io.grpc:grpc-core",
exclusions = ["io.grpc:grpc-util"],
)
```
When matching artifacts that have been declared, only the `group:artifact` tuple is used
for matching.
## Module dependency layering
In order to allow modules to collaborate on required dependencies, the `bzlmod` extension will
collect the artifacts from all tags with the same `name` attribute together before performing a
dependency resolution. You'll know this is happening because a message will be printed to inform
you which modules are contributing to which namespace:
`The maven repository 'multiple_lock_files' has contributions from multiple bzlmod modules, and will be resolved together: ["bzlmod_lock_files", "rules_jvm_external"]`
In the root module, if this is expected and known, you can disable this warning by adding
the list of modules to the `known_contributing_modules` attribute of the `install` tag. The entry
to add will be printed for you as part of the warning.
The default name used is `maven`. Modules that are expected to be included via a `bazel_dep` should
avoid using the default name, and should always set their own (eg. `rules_jvm_external` uses
`rules_jvm_external_deps` for its own dependencies) The exception to this is where a module provides
functionality that would otherwise be obtained using a maven dependency.
Put another way, only projects that are only ever going to be used as root modules should use the
default name.
The message is printed so that should you need to understand why a particular dependency or
transitive dependency is at an unexpected version you'll have the information you need to diagnose
the problem.
When dependencies are layered in this way, you may see a warning similar to:
```
"WARNING: The following maven modules appear in multiple sub-modules with potentially different versions. Consider adding one of these to your root module to ensure consistent versions:
com.google.guava:guava (31.1-jre, 33.2.1-jre)
```
To resolve this issue, ensure that the artifact is listed in the root module. That will be the
version used in the dependency resolution.
## Known issues
- Some error messages print instructions that don't apply under bzlmod,
e.g. https://github.com/bazelbuild/rules_jvm_external/issues/827