diff --git a/docs/checkstyle.md b/docs/checkstyle.md
index b31f630d..91a5d0b1 100644
--- a/docs/checkstyle.md
+++ b/docs/checkstyle.md
@@ -79,7 +79,7 @@ fetch_checkstyle()
load("@aspect_rules_lint//lint:checkstyle.bzl", "lint_checkstyle_aspect")
-lint_checkstyle_aspect(binary, config, data, rule_kinds)
+lint_checkstyle_aspect(binary, config, configs, data, rule_kinds)
A factory function to create a linter aspect.
@@ -105,7 +105,28 @@ Attrs:
| :------------- | :------------- | :------------- |
| binary | -
| none |
| config | -
| none |
+| configs | -
| `{}` |
| data | -
| `[]` |
| rule_kinds | -
| `["java_binary", "java_library"]` |
+
+
+## rebuild_map
+
+
+load("@aspect_rules_lint//lint:checkstyle.bzl", "rebuild_map")
+
+rebuild_map(configs)
+
+
+
+
+**PARAMETERS**
+
+
+| Name | Description | Default Value |
+| :------------- | :------------- | :------------- |
+| configs | -
| none |
+
+
diff --git a/example/BUILD.bazel b/example/BUILD.bazel
index b8d151ee..f9426be4 100644
--- a/example/BUILD.bazel
+++ b/example/BUILD.bazel
@@ -17,6 +17,7 @@ exports_files(
".flake8",
"pmd.xml",
"checkstyle.xml",
+ "checkstyle_subdir.xml",
"checkstyle-suppressions.xml",
".ruff.toml",
".shellcheckrc",
diff --git a/example/checkstyle_subdir.xml b/example/checkstyle_subdir.xml
new file mode 100644
index 00000000..30a3a9c5
--- /dev/null
+++ b/example/checkstyle_subdir.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/example/src/subdir/BUILD.bazel b/example/src/subdir/BUILD.bazel
index 927ce478..1d3dc557 100644
--- a/example/src/subdir/BUILD.bazel
+++ b/example/src/subdir/BUILD.bazel
@@ -24,3 +24,8 @@ ts_project(
"//:node_modules/moment",
],
)
+
+java_library(
+ name = "bar",
+ srcs = ["Bar.java"],
+)
diff --git a/example/src/subdir/Bar.java b/example/src/subdir/Bar.java
new file mode 100644
index 00000000..c8376689
--- /dev/null
+++ b/example/src/subdir/Bar.java
@@ -0,0 +1,10 @@
+package src.subdir;
+
+// Unused imports are suppressed in suppressions.xml, so this should not raise issue.
+import java.util.Objects;
+import java.io.BufferedInputStream;
+
+public class Bar {
+ // Max line length set to 20, so this should raise issue.
+ protected void finalize(int a) {}
+}
diff --git a/example/tools/lint/linters.bzl b/example/tools/lint/linters.bzl
index 0e064715..c5131b89 100644
--- a/example/tools/lint/linters.bzl
+++ b/example/tools/lint/linters.bzl
@@ -52,9 +52,13 @@ pmd = lint_pmd_aspect(
pmd_test = lint_test(aspect = pmd)
checkstyle = lint_checkstyle_aspect(
- binary = Label("@//tools/lint:checkstyle"),
- config = Label("@//:checkstyle.xml"),
- data = [Label("@//:checkstyle-suppressions.xml")],
+ binary = "@@//tools/lint:checkstyle",
+ config = "@@//:checkstyle.xml",
+ configs = {
+ "@@//:checkstyle.xml": "@@//src,@@//test",
+ "@@//:checkstyle_subdir.xml": "@@//src/subdir",
+ },
+ data = ["@@//:checkstyle-suppressions.xml"],
)
checkstyle_test = lint_test(aspect = checkstyle)
diff --git a/lint/checkstyle.bzl b/lint/checkstyle.bzl
index 5c2bef9b..fca11759 100644
--- a/lint/checkstyle.bzl
+++ b/lint/checkstyle.bzl
@@ -32,6 +32,13 @@ load("//lint/private:lint_aspect.bzl", "LintOptionsInfo", "filter_srcs", "noop_l
_MNEMONIC = "AspectRulesLintCheckstyle"
+def rebuild_map(configs):
+ directory_to_config = {}
+ for config, directories in configs.items():
+ for directory in directories.split(","):
+ directory_to_config[directory] = config
+ return directory_to_config
+
def checkstyle_action(ctx, executable, srcs, config, data, stdout, exit_code = None, options = []):
"""Run Checkstyle as an action under Bazel.
@@ -42,6 +49,7 @@ def checkstyle_action(ctx, executable, srcs, config, data, stdout, exit_code = N
executable: label of the the Checkstyle program
srcs: java files to be linted
config: label of the checkstyle.xml file
+ configs: dictionary mapping package label to their respective checkstyle.xml file
data: labels of additional xml files such as suppressions.xml
stdout: output file to generate
exit_code: output file to write the exit code.
@@ -82,6 +90,17 @@ def _checkstyle_aspect_impl(target, ctx):
return []
files_to_lint = filter_srcs(ctx.rule)
+ config_file = ctx.file._config
+ config_maps = rebuild_map(ctx.attr._configs)
+ if ctx.attr._configs:
+ label = str(target.label)
+ keys = sorted(config_maps.keys(), key=len, reverse = True)
+ for key in keys:
+ if label.startswith(key):
+ config = config_maps[key]
+ config_file = config.files.to_list()[0]
+ break
+
outputs, info = output_files(_MNEMONIC, target, ctx)
if len(files_to_lint) == 0:
noop_lint_action(ctx, outputs)
@@ -91,7 +110,7 @@ def _checkstyle_aspect_impl(target, ctx):
ctx,
ctx.executable._checkstyle,
files_to_lint,
- ctx.file._config,
+ config_file,
ctx.files._data,
outputs.human.out,
outputs.human.exit_code,
@@ -101,7 +120,7 @@ def _checkstyle_aspect_impl(target, ctx):
ctx,
ctx.executable._checkstyle,
files_to_lint,
- ctx.file._config,
+ config_file,
ctx.files._data,
outputs.machine.out,
outputs.machine.exit_code,
@@ -109,7 +128,7 @@ def _checkstyle_aspect_impl(target, ctx):
)
return [info]
-def lint_checkstyle_aspect(binary, config, data = [], rule_kinds = ["java_binary", "java_library"]):
+def lint_checkstyle_aspect(binary, config, configs = {}, data = [], rule_kinds = ["java_binary", "java_library"]):
"""A factory function to create a linter aspect.
Attrs:
@@ -147,6 +166,12 @@ def lint_checkstyle_aspect(binary, config, data = [], rule_kinds = ["java_binary
doc = "Config file",
default = config,
),
+ "_configs": attr.label_keyed_string_dict(
+ allow_empty = True,
+ allow_files = True,
+ doc = "Package and configuration files dictionary",
+ default = configs,
+ ),
"_data": attr.label_list(
doc = "Additional files to make available to Checkstyle such as any included XML files",
allow_files = True,