contrib_rules_jvm
Handy rules for working with JVM-based projects in Bazel.
In order to use these in your own projects, in your WORKSPACE
once
you've used an http_archive
, you can load all the necessary
dependencies by:
load("@contrib_rules_jvm//:repositories.bzl", "contrib_rules_jvm_deps")
contrib_rules_jvm_deps()
load("@contrib_rules_jvm//:setup.bzl", "contrib_rules_jvm_setup")
contrib_rules_jvm_setup()
If you're looking to get started quickly, then take a look at java_test_suite (a macro for generating a test suite from a glob
of java test sources) and java_junit5_test (a drop-in replacement for java_test
that can run JUnit5 tests)
Linting
Many of the features in this repo are designed to be exposed via apple_rules_lint, which provides a framework for integrating linting checks into your builds. To take advantage of this perform the following steps:
# In your WORKSPACE, after loading `apple_rules_lint`
load("@apple_rules_lint//lint:setup.bzl", "lint_setup")
lint_setup({
# Note: this is an example config!
"java-checkstyle": "@contrib_rules_jvm//java:checkstyle-default-config",
"java-pmd": "@contrib_rules_jvm//java:pmd-config",
"java-spotbugs": "@contrib_rules_jvm//java:spotbugs-default-config",
})
You are welcome to include all (or none!) of these rules, and linting
is "opt-in": if there's no lint_setup
call in your repo's
WORKSPACE
then everything will continue working just fine and no
additional lint tests will be generated.
The linters are configured using specific rules. The mappings are:
Requirements
These rules require Java 11 or above.
Java Rules
checkstyle_config
checkstyle_config(name, checkstyle_binary, config_file, data, output_format)
Rule allowing checkstyle to be configured. This is typically
used with the linting rules from @apple_rules_lint
to configure how
checkstyle should run.
ATTRIBUTES
Name |
Description |
Type |
Mandatory |
Default |
name |
A unique name for this target. |
Name |
required |
|
checkstyle_binary |
Checkstyle binary to use. |
Label |
optional |
@contrib_rules_jvm//java:checkstyle_cli |
config_file |
The config file to use for all checkstyle tests |
Label |
required |
|
data |
Additional files to make available to Checkstyle such as any included XML files |
List of labels |
optional |
[] |
output_format |
Output format to use. Defaults to plain |
String |
optional |
"plain" |
checkstyle_test
checkstyle_test(name, config, output_format, srcs)
Use checkstyle to lint the srcs
.
ATTRIBUTES
Name |
Description |
Type |
Mandatory |
Default |
name |
A unique name for this target. |
Name |
required |
|
config |
- |
Label |
optional |
@contrib_rules_jvm//java:checkstyle-default-config |
output_format |
Output Format can be plain or xml. Defaults to plain |
String |
optional |
"plain" |
srcs |
- |
List of labels |
required |
|
pmd_ruleset
pmd_ruleset(name, format, pmd_binary, rulesets, shallow)
Select a rule set for PMD tests.
ATTRIBUTES
Name |
Description |
Type |
Mandatory |
Default |
name |
A unique name for this target. |
Name |
required |
|
format |
Generate report in the given format. One of html, text, or xml (default is xml) |
String |
optional |
"xml" |
pmd_binary |
PMD binary to use. |
Label |
optional |
//java:pmd |
rulesets |
Use these rulesets. |
List of labels |
optional |
[] |
shallow |
Use the targetted output to increase PMD's depth of processing |
Boolean |
optional |
True |
pmd_test
pmd_test(name, ruleset, srcs, target)
Use PMD to lint the srcs
.
ATTRIBUTES
Name |
Description |
Type |
Mandatory |
Default |
name |
A unique name for this target. |
Name |
required |
|
ruleset |
- |
Label |
required |
|
srcs |
- |
List of labels |
optional |
[] |
target |
- |
Label |
optional |
None |
spotbugs_config
spotbugs_config(name, effort, exclude_filter, fail_on_warning, spotbugs_binary)
Configuration used for spotbugs, typically by the //lint
rules.
ATTRIBUTES
Name |
Description |
Type |
Mandatory |
Default |
name |
A unique name for this target. |
Name |
required |
|
effort |
Effort can be min, less, default, more or max. Defaults to default |
String |
optional |
"default" |
exclude_filter |
Report all bug instances except those matching the filter specified by this filter file |
Label |
optional |
None |
fail_on_warning |
Whether to fail on warning, or just create a report. Defaults to True |
Boolean |
optional |
True |
spotbugs_binary |
The spotbugs binary to run. |
Label |
optional |
@contrib_rules_jvm//java:spotbugs_cli |
spotbugs_test
spotbugs_test(name, config, deps, only_output_jars)
Use spotbugs to lint the srcs
.
ATTRIBUTES
Name |
Description |
Type |
Mandatory |
Default |
name |
A unique name for this target. |
Name |
required |
|
config |
- |
Label |
optional |
//java:spotbugs-default-config |
deps |
- |
List of labels |
required |
|
only_output_jars |
If set to true, only the output jar of the target will be analyzed. Otherwise all transitive runtime dependencies will be analyzed |
Boolean |
optional |
True |
checkstyle_binary
checkstyle_binary(name, main_class, deps, runtime_deps, srcs, visibility, kwargs)
Macro for quickly generating a java_binary
target for use with checkstyle_config
.
By default, this will set the main_class
to point to the default one used by checkstyle
but it's ultimately a drop-replacement for straight java_binary
target.
At least one of runtime_deps
, deps
, and srcs
must be specified so that the
java_binary
target will be valid.
An example would be:
checkstyle_binary(
name = "checkstyle_cli",
runtime_deps = [
artifact("com.puppycrawl.tools:checkstyle"),
]
)
PARAMETERS
Name |
Description |
Default Value |
name |
The name of the target |
none |
main_class |
The main class to use for checkstyle. |
"com.puppycrawl.tools.checkstyle.Main" |
deps |
The deps required for compiling this binary. May be omitted. |
None |
runtime_deps |
The deps required by checkstyle at runtime. May be omitted. |
None |
srcs |
If you're compiling your own checkstyle binary, the sources to use. |
None |
visibility |
- |
["//visibility:public"] |
kwargs |
- |
none |
java_binary
java_binary(name, kwargs)
Adds linting tests to Bazel's own java_binary
PARAMETERS
Name |
Description |
Default Value |
name |
- |
none |
kwargs |
- |
none |
java_export
java_export(name, maven_coordinates, pom_template, deploy_env, visibility, kwargs)
Adds linting tests to rules_jvm_external
's java_export
PARAMETERS
Name |
Description |
Default Value |
name |
- |
none |
maven_coordinates |
- |
none |
pom_template |
- |
None |
deploy_env |
- |
None |
visibility |
- |
None |
kwargs |
- |
none |
java_junit5_test
java_junit5_test(name, test_class, runtime_deps, kwargs)
Run junit5 tests using Bazel.
This is designed to be a drop-in replacement for java_test
, but
rather than using a JUnit4 runner it provides support for using
JUnit5 directly. The arguments are the same as used by java_test
.
The generated target does not include any JUnit5 dependencies. If
you are using the standard @maven
namespace for your
maven_install
you can add these to your deps
using JUNIT5_DEPS
or JUNIT5_VINTAGE_DEPS
loaded from //java:defs.bzl
Note: The junit5 runner prevents System.exit
being called
using a SecurityManager
, which means that one test can't
prematurely cause an entire test run to finish unexpectedly.
While the SecurityManager
has been deprecated in recent Java
releases, there's no replacement yet. JEP 411 has this as one of
its goals, but this is not complete or available yet.
PARAMETERS
Name |
Description |
Default Value |
name |
The name of the test. |
none |
test_class |
The Java class to be loaded by the test runner. If not specified, the class name will be inferred from a combination of the current bazel package and the name attribute. |
None |
runtime_deps |
- |
[] |
kwargs |
- |
none |
java_library
java_library(name, kwargs)
Adds linting tests to Bazel's own java_library
PARAMETERS
Name |
Description |
Default Value |
name |
- |
none |
kwargs |
- |
none |
java_test
java_test(name, kwargs)
Adds linting tests to Bazel's own java_test
PARAMETERS
Name |
Description |
Default Value |
name |
- |
none |
kwargs |
- |
none |
java_test_suite
java_test_suite(name, srcs, runner, test_suffixes, package, deps, runtime_deps, tags, visibility,
size, kwargs)
Create a suite of java tests from *Test.java
files.
This rule will create a java_test
for each file which matches
any of the test_suffixes
that are passed to this rule as
srcs
. If any non-test sources are added these will first of all
be compiled into a java_library
which will be added as a
dependency for each test target, allowing common utility functions
to be shared between tests.
The generated java_test
targets will be named after the test file:
FooTest.java
will create a :FooTest
target.
In addition, a test_suite
will be created, named using the name
attribute to allow all the tests to be run in one go.
PARAMETERS
Name |
Description |
Default Value |
name |
A unique name for this rule. Will be used to generate a test_suite |
none |
srcs |
Source files to create test rules for. |
none |
runner |
One of junit4 or junit5 . |
"junit4" |
test_suffixes |
The file name suffix used to identify if a file contains a test class. |
["Test.java"] |
package |
The package name used by the tests. If not set, this is inferred from the current bazel package name. |
None |
deps |
A list of java_* dependencies. |
None |
runtime_deps |
A list of java_* dependencies needed at runtime. |
[] |
tags |
- |
[] |
visibility |
- |
None |
size |
The size of the test, passed to java_test |
None |
kwargs |
- |
none |
pmd_binary
pmd_binary(name, main_class, deps, runtime_deps, srcs, visibility, kwargs)
Macro for quickly generating a java_binary
target for use with pmd_ruleset
.
By default, this will set the main_class
to point to the default one used by PMD
but it's ultimately a drop-replacement for a regular java_binary
target.
At least one of runtime_deps
, deps
, and srcs
must be specified so that the
java_binary
target will be valid.
An example would be:
pmd_binary(
name = "pmd",
runtime_deps = [
artifact("net.sourceforge.pmd:pmd-dist"),
],
)
PARAMETERS
Name |
Description |
Default Value |
name |
The name of the target |
none |
main_class |
The main class to use for PMD. |
"net.sourceforge.pmd.PMD" |
deps |
The deps required for compiling this binary. May be omitted. |
None |
runtime_deps |
The deps required by PMD at runtime. May be omitted. |
None |
srcs |
If you're compiling your own PMD binary, the sources to use. |
None |
visibility |
- |
["//visibility:public"] |
kwargs |
- |
none |
spotbugs_binary
spotbugs_binary(name, main_class, deps, runtime_deps, srcs, visibility, kwargs)
Macro for quickly generating a java_binary
target for use with spotbugs_config
.
By default, this will set the main_class
to point to the default one used by spotbugs
but it's ultimately a drop-replacement for a regular java_binary
target.
At least one of runtime_deps
, deps
, and srcs
must be specified so that the
java_binary
target will be valid.
An example would be:
spotbugs_binary(
name = "spotbugs_cli",
runtime_deps = [
artifact("com.github.spotbugs:spotbugs"),
artifact("org.slf4j:slf4j-jdk14"),
],
)
PARAMETERS
Name |
Description |
Default Value |
name |
The name of the target |
none |
main_class |
The main class to use for spotbugs. |
"edu.umd.cs.findbugs.LaunchAppropriateUI" |
deps |
The deps required for compiling this binary. May be omitted. |
None |
runtime_deps |
The deps required by spotbugs at runtime. May be omitted. |
None |
srcs |
If you're compiling your own spotbugs binary, the sources to use. |
None |
visibility |
- |
["//visibility:public"] |
kwargs |
- |
none |
Freezing Dependencies
At runtime, a handful of dependencies are required by helper classes
in this project. Rather than pollute the default @maven
workspace,
these are loaded into a @contrib_rules_jvm_deps
workspace. These
dependencies are loaded using a call to maven_install
, but we don't
want to force users to remember to load our own dependencies for
us. Instead, to add a new dependency to the project:
- Update
frozen_deps
in the WORKSPACE
file
- Run
./tools/update-dependencies.sh
- Commit the updated files.
Freezing your dependencies
As noted above, if you are building Bazel rules which require Java
parts, and hence Java dependencies, it can be useful to freeze these
dependencies. This process captures the list of dependencies into a
zip file. This zip file is distributed with your Bazel rules. This
makes your rule more hermetic, your rule no longer relies on the user
to supply the correct dependencies, because they get resolved under
their own repository namespace rather than being intermingled with the
user's, and your dependencies no longer conflict with the users
selections. If you would like to create your dependencies as a frozen
file you need to do the following:
- Create a maven install rule with your dependencies and with a
unique name, this should be in or referenced by your WORKSPACE
file.
maven_install(
name = "frozen_deps",
artifacts = [...],
fail_if_repin_required = True,
fetch_sources = True,
maven_install_json = "@workspace//:frozen_deps_install.json",
)
load("@frozen_deps//:defs.bzl", "pinned_maven_install")
pinned_maven_install()
- Run
bazel run //tools:freeze-deps -- --repo <repo name> --zip <path/to/dependency.zip>
. The <repo name>
matches the name used
for the maven_install()
rule above. This will pin the
dependencies then collect them into the zip file.
- Commit the zip file into your repo.
- Add a
zip_repository()
rule to your WORKSPACE to configure the
frozen dependencies:
maybe(
zip_repository,
name = "workspace_deps",
path = "@workspace//path/to:dependency.zip",
)
- Make sure to pin the maven install from the repostitory:
load("@workspace_deps//:defs.bzl", "pinned_maven_install")
pinned_maven_install()
- Use the dependencies for your
java_library
rules from the frozen
deps:
java_library(
name = "my_library",
srcs = glob(["*.java"]),
deps = [
"@workspace_deps//:my_frozen_dep",
],
)
NOTE: If you need to generate the compat_repositories for the
dependencies, usually because your rule depends on another rule which
is still using the older compat repositories, you need to make the
following changes and abide by the following restrictions.
- Add the
generate_compat_repositories = True,
attribute to the
original maven_install()
rule.
- In step 2, add the parameter
--zip-repo workspace_deps
to match
the name used in the zip_repository()
rule (step 4). If you don't
supply this, it uses the base name of the zip file, which may not
be what you want.
- In step 5, add the call to generate the compat_repositories:
load("@workspace_deps//:compat.bzl", "compat_repositories")
compat_repositories()