Skip to content
Rules to resolve and fetch artifacts transitively from Maven repositories
Branch: master
Clone or download
philwo and jin Don't test on Ubuntu 14.04 (#126)
Ubuntu 14.04 is about to be end-of-life and Bazel CI will stop supporting it shortly afterwards.

Context: https://groups.google.com/d/msg/bazel-dev/_D6XzfNkQQE/8TNKiNmsCAAJ
Latest commit d01b966 Apr 23, 2019
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
.bazelci
docs Add API reference doc (#73) Mar 18, 2019
examples
private Bump Coursier to 1.1.0-M14-1 (#122) Apr 18, 2019
scripts Fix migration script and get it working on macOS (#89) Apr 4, 2019
tests
third_party Replace third_party/coursier/coursier bootstrap jar with the standalo… Mar 29, 2019
.gitignore Merge jin/rules_maven (#32) Mar 11, 2019
AUTHORS Add AUTHORS file (#9) Apr 10, 2018
BUILD Delete gmaven code and docs (#106) Apr 15, 2019
CODEOWNERS Add @dkelmer to CODEOWNERS (#45) Mar 13, 2019
CONTRIBUTING.md Add CONTRIBUTING.md (#10) Apr 10, 2018
CONTRIBUTORS Add CONTRIBUTORS (#40) Mar 12, 2019
LICENSE Add Apache 2.0 License Apr 10, 2018
README.md
WORKSPACE Add support for test-jar packaging type (#120) Apr 18, 2019
_config.yml Set theme jekyll-theme-slate Mar 16, 2019
coursier.bzl Don't print rdeps error message if there are no rdeps for the artifact ( Apr 18, 2019
defs.bzl Delete gmaven code and docs (#106) Apr 15, 2019
import_external.bzl Fixes incompatible on Skylark dicts. Fixes #23 Jun 7, 2018
specs.bzl Neverlink support (#97) Apr 15, 2019

README.md

rules_jvm_external

Transitive Maven artifact resolver as a repository rule.

Build Status

Features

  • WORKSPACE configuration
  • JAR, AAR, source JARs
  • Custom Maven repositories
  • Private Maven repositories with HTTP Basic Authentication
  • Artifact version resolution with Coursier
  • Reuse artifacts from a central cache
  • Versionless target labels for simpler dependency management
  • Ability to declare multiple sets of versioned artifacts
  • Supported on Windows, macOS, Linux

Get the latest release here.

Usage

List the top-level Maven artifacts and servers in the WORKSPACE:

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

RULES_JVM_EXTERNAL_TAG = "2.0.1"
RULES_JVM_EXTERNAL_SHA = "55e8d3951647ae3dffde22b4f7f8dee11b3f70f3f89424713debd7076197eaca"

http_archive(
    name = "rules_jvm_external",
    strip_prefix = "rules_jvm_external-%s" % RULES_JVM_EXTERNAL_TAG,
    sha256 = RULES_JVM_EXTERNAL_SHA,
    url = "https://github.com/bazelbuild/rules_jvm_external/archive/%s.zip" % RULES_JVM_EXTERNAL_TAG,
)

load("@rules_jvm_external//:defs.bzl", "maven_install")

maven_install(
    artifacts = [
        "junit:junit:4.12",
        "androidx.test.espresso:espresso-core:3.1.1",
    ],
    repositories = [
        # Private repositories are supported through HTTP Basic auth
        "http://username:password@localhost:8081/artifactory/my-repository",
        "https://jcenter.bintray.com/",
        "https://maven.google.com",
        "https://repo1.maven.org/maven2",
    ],
    # Fetch srcjars. Defaults to False.
    fetch_sources = True,
)

and use them directly in the BUILD file by specifying the versionless target alias label:

android_library(
    name = "test_deps",
    exports = [
        "@maven//:androidx_test_espresso_espresso_core",
        "@maven//:junit_junit",
    ],
)

Generated targets

For the junit:junit example, using bazel query @maven//:all --output=build, we can see that the rule generated these targets:

alias(
  name = "junit_junit",
  actual = "@maven//:junit_junit_4_12",
)

java_import(
  name = "junit_junit_4_12",
  jars = ["@maven//:https/repo1.maven.org/maven2/junit/junit/4.12/junit-4.12.jar"],
  srcjar = "@maven//:https/repo1.maven.org/maven2/junit/junit/4.12/junit-4.12-sources.jar",
  deps = ["@maven//:org_hamcrest_hamcrest_core_1_3"],
  tags = ["maven_coordinates=junit:junit:4.12"],
)

java_import(
  name = "org_hamcrest_hamcrest_core_1_3",
  jars = ["@maven//:https/repo1.maven.org/maven2/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar"],
  srcjar = "@maven//:https/repo1.maven.org/maven2/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3-sources.jar",
  deps = [],
  tags = ["maven_coordinates=org.hamcrest:hamcrest.library:1.3"],
)

The generated tags attribute value also contains the original coordinates of the artifact, which integrates with rules like bazel-common's pom_file for generating POM files. See the pom_file_generation example for more information.

API Reference

You can find the complete API reference at docs/api.md.

Advanced usage

Using a persistent artifact cache

To download artifacts into a shared and persistent directory in your home directory, specify use_unsafe_shared_cache = True in maven_install:

maven_install(
    name = "maven",
    artifacts = [
        # ...
    ],
    repositories = [
        # ...
    ],
    use_unsafe_shared_cache = True,
)

This is not safe as Bazel is currently not able to detect changes in the shared cache. For example, if an artifact is deleted from the shared cache, Bazel will not re-run the repository rule automatically.

The default value of use_unsafe_shared_cache is False. This means that Bazel will create independent caches for each maven_install repository, located at $(bazel info output_base)/external/@repository_name/v1.

artifact helper macro

The artifact macro translates the artifact's group:artifact coordinates to the label of the versionless target. This target is an alias that points to the java_import/aar_import target in the @maven repository, which includes the transitive dependencies specified in the top level artifact's POM file.

For example, @maven//:junit_junit is equivalent to artifact("junit:junit").

To use it, add the load statement to the top of your BUILD file:

load("@rules_jvm_external//:defs.bzl", "artifact")

Note that usage of this macro makes BUILD file refactoring with tools like buildozer more difficult, because the macro hides the actual target label at the syntax level.

Multiple maven_install declarations for isolated artifact version trees

If your WORKSPACE contains several projects that use different versions of the same artifact, you can specify multiple maven_install declarations in the WORKSPACE, with a unique repository name for each of them.

For example, if you want to use the JRE version of Guava for a server app, and the Android version for an Android app, you can specify two maven_install declarations:

maven_install(
    name = "server_app",
    artifacts = [
        "com.google.guava:guava:27.0-jre",
    ],
    repositories = [
        "https://repo1.maven.org/maven2",
    ],
)

maven_install(
    name = "android_app",
    artifacts = [
        "com.google.guava:guava:27.0-android",
    ],
    repositories = [
        "https://repo1.maven.org/maven2",
    ],
)

This way, rules_jvm_external will invoke coursier to resolve artifact versions for both repositories independent of each other. Coursier will fail if it encounters version conflicts that it cannot resolve. The two Guava targets can then be used in BUILD files like so:

java_binary(
    name = "my_server_app",
    srcs = ...
    deps = [
        # a versionless alias to @server_app//:com_google_guava_guava_27_0_jre
        "@server_app//:com_google_guava_guava",
    ]
)

android_binary(
    name = "my_android_app",
    srcs = ...
    deps = [
        # a versionless alias to @android_app//:com_google_guava_guava_27_0_android
        "@android_app//:com_google_guava_guava",
    ]
)

Detailed dependency information specifications

Although you can always give a dependency as a Maven coordinate string, occasionally special handling is required in the form of additional directives to properly situate the artifact in the dependency tree. For example, a given artifact may need to have one of its dependencies excluded to prevent a conflict.

This situation is provided for by allowing the artifact to be specified as a map containing all of the required information. This map can express more information than the coordinate strings can, so internally the coordinate strings are parsed into the artifact map with default values for the additional items. To assist in generating the maps, you can pull in the file specs.bzl alongside defs.bzl and import the maven struct, which provides several helper functions to assist in creating these maps. An example:

load("@rules_jvm_external//:defs.bzl", "artifact")
load("@rules_jvm_external//:specs.bzl", "maven")

maven_install(
    artifacts = [
        maven.artifact(
            group = "com.google.guava",
            artifact = "guava",
            version = "27.0-android",
            exclusions = [
                ...
            ]
        ),
        "junit:junit:4.12",
        ...
    ],
    repositories = [
        maven.repository(
            "https://some.private.maven.re/po",
            user = "johndoe",
            password = "example-password"
        ),
        "https://repo1.maven.org/maven2",
        ...
    ],
)

Artifact exclusion

If you want to exclude an artifact from the transitive closure of a top level artifact, specify its group-id:artifact-id in the exclusions attribute of the maven.artifact helper:

load("@rules_jvm_external//:specs.bzl", "maven")

maven_install(
    artifacts = [
        maven.artifact(
            group = "com.google.guava",
            artifact = "guava",
            version = "27.0-jre",
            exclusions = [
                maven.exclusion(
                    group = "org.codehaus.mojo",
                    artifact = "animal-sniffer-annotations"
                ),
                "com.google.j2objc:j2objc-annotations",
            ]
        ),
        # ...
    ],
    repositories = [
        # ...
    ],
)

You can specify the exclusion using either the maven.exclusion helper or the group-id:artifact-id string directly.

Compile-only dependencies

If you want to mark certain artifacts as compile-only dependencies, use the neverlink attribute in the maven.artifact helper:

load("@rules_jvm_external//:specs.bzl", "maven")

maven_install(
    artifacts = [
        maven.artifact("com.squareup", "javapoet", "1.11.0", neverlink = True),
    ],
    # ...
)

This instructs rules_jvm_external to mark the generated target for com.squareup:javapoet with the neverlink = True attribute, making the artifact available only for compilation and not at runtime.

Proxies

As with other Bazel repository rules, the standard http_proxy, https_proxy and no_proxy environment variables (and their uppercase counterparts) are supported.

Demo

You can find demos in the examples/ directory.

You can’t perform that action at this time.