Skip to content

Commit 94b5a27

Browse files
committed
Docs
1 parent f9ece02 commit 94b5a27

11 files changed

Lines changed: 643 additions & 111 deletions

File tree

README.md

Lines changed: 72 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ for the [Bazel build system](https://bazel.build).
88
- configuration and baseline files;
99
- HTML, text, XML, Markdown, and SARIF reports;
1010
- [plugins](https://detekt.dev/docs/extensions/extensions/);
11-
- customizable Detekt version;
11+
- customizable Detekt version and JVM flags;
1212
- [persistent workers](https://blog.bazel.build/2015/12/10/java-workers.html) support;
1313
- baseline generation via `detekt_create_baseline`;
1414
- configuration options via [attributes](docs/attrs.md).
@@ -147,11 +147,17 @@ detekt_test(
147147

148148
### Configuration Options
149149

150-
All three rules share the same configuration options. In addition to `srcs`, `cfgs`, `baseline`, `plugins`,
151-
and report options, most attributes correspond directly to Detekt CLI flags and pass them through when explicitly set.
150+
All three rules share the same configuration options. In addition to `srcs`, most attributes correspond directly to
151+
Detekt CLI flags and pass them through when explicitly set.
152152

153-
`max_issues` is retained for Detekt 1.x. Detekt 2.x uses `fail_on_severity` (`Never`, `Info`, `Warning`, or `Error`);
154-
the attributes are mutually exclusive and must match the selected Detekt major version.
153+
`cfgs`, `plugins`, `build_upon_default_config`, `disable_default_rulesets`, `jvm_target`, `language_version`,
154+
`max_issues`, `fail_on_severity`, `parallel`, JVM flags, and the executable wrapper can be configured once on a
155+
toolchain. `srcs`, `deps`, `baseline`, `excludes`, `includes`, `all_rules`, `auto_correct`, `base_path`, `config_resource`,
156+
`is_android`, and report options remain rule-level settings.
157+
158+
`max_issues` is the failure policy for Detekt 1.x. Detekt 2.x uses `fail_on_severity` (`Never`, `Info`, `Warning`, or
159+
`Error`). Both policies cannot be active at the same level; inactive clear values such as `max_issues = -1` may
160+
coexist with the other policy. Choose the active option that matches the selected Detekt major version.
155161

156162
More information can be found in the [attributes](docs/attrs.md).
157163

@@ -212,41 +218,89 @@ use_repo(detekt, "detekt_cli_all")
212218

213219
Each template may contain `{version}` which will be replaced with the version string.
214220

215-
### Toolchain Defaults
221+
### Toolchain Configuration and Profiles
222+
223+
`detekt_toolchain` defines a reusable implementation profile. Its JVM flags, executable wrapper, shared configuration,
224+
plugins, and shared analysis defaults are used by rules that select the profile. The default JVM flags remain
225+
`-Xms16m` and `-Xmx128m`, and the default JVM target remains `1.8`.
216226

217-
`cfgs`, `plugins`, `build_upon_default_config`, `disable_default_rulesets`, `jvm_target`,
218-
`language_version`, `max_issues`, and `parallel` can be set once on a custom
219-
`detekt_toolchain`. Target attributes use those values when left at their rule defaults:
227+
The `detekt_toolchain` rule is the implementation label used by a rule; it is not the native `toolchain()` registration
228+
wrapper. Register one implementation when you want it to be the fallback for rules that do not select a profile:
220229

221230
```python
231+
load("@rules_detekt//detekt:defs.bzl", "detekt_test")
222232
load("@rules_detekt//detekt:toolchain.bzl", "detekt_toolchain")
223233

224234
detekt_toolchain(
225-
name = "detekt_toolchain_impl",
235+
name = "detekt_default_impl",
236+
jvm_flags = ["-Xms16m", "-Xmx512m"],
226237
cfgs = ["//:detekt.yml"],
227-
plugins = ["@maven//:io_gitlab_arturbosch_detekt_detekt_formatting"],
238+
plugins = ["@maven//:dev_detekt_detekt_rules_ktlint_wrapper"],
228239
build_upon_default_config = True,
229240
disable_default_rulesets = True,
230241
jvm_target = "11",
231242
language_version = "2.0",
232-
max_issues = 0,
243+
fail_on_severity = "Error",
233244
parallel = True,
234245
)
235246

236247
toolchain(
237-
name = "detekt_toolchain",
238-
toolchain = ":detekt_toolchain_impl",
248+
name = "detekt_registered",
249+
toolchain = ":detekt_default_impl",
239250
toolchain_type = "@rules_detekt//detekt:toolchain_type",
240251
)
252+
253+
detekt_test(
254+
name = "uses_registered_profile",
255+
srcs = glob(["src/main/kotlin/**/*.kt"]),
256+
)
241257
```
242258

243259
```python
244-
register_toolchains("//tools:detekt_toolchain")
260+
register_toolchains("//:detekt_registered")
245261
```
246262

247-
At the target level, set `cfgs`, `plugins`, `build_upon_default_config`,
248-
`disable_default_rulesets`, `jvm_target`, `language_version`, `max_issues`, or
249-
`parallel = True` to use a target-specific value.
263+
Multiple profiles can coexist in one repository. Select an implementation directly with the rule’s
264+
`detekt_toolchain` attribute; omitting that attribute uses the registered native toolchain:
265+
266+
```python
267+
detekt_toolchain(
268+
name = "detekt_strict_impl",
269+
fail_on_severity = "Error",
270+
)
271+
272+
detekt_toolchain(
273+
name = "detekt_lenient_impl",
274+
fail_on_severity = "Never",
275+
)
276+
277+
detekt_test(
278+
name = "strict_profile",
279+
srcs = glob(["src/main/kotlin/**/*.kt"]),
280+
detekt_toolchain = ":detekt_strict_impl",
281+
)
282+
283+
detekt_test(
284+
name = "lenient_profile",
285+
srcs = glob(["src/main/kotlin/**/*.kt"]),
286+
detekt_toolchain = ":detekt_lenient_impl",
287+
fail_on_severity = "Warning",
288+
)
289+
```
290+
291+
Profiles configure the selected runtime; they do not select a Detekt version. To use the supported Detekt 1.23.8
292+
override, configure that version separately and use its matching 1.x plugins and `max_issues` policy.
293+
294+
For shared options, an omitted rule attribute (or `None` where accepted) inherits from the selected toolchain.
295+
Explicit values always win: `False`, `[]`, an empty `language_version`, or `max_issues = -1` clears an inherited
296+
value; list-valued options replace the toolchain list rather than append to it. A rule-level failure option replaces
297+
the inherited failure-policy pair, so a rule can select either `max_issues` or `fail_on_severity` without inheriting
298+
the other option. Both policies cannot be active at the same level; inactive clear values may coexist with the other
299+
policy.
300+
301+
The profile’s runtime determines which failure policy is valid: use `max_issues` with Detekt 1.23.8 and
302+
`fail_on_severity` with Detekt 2.0.0-alpha.6. JVM and Kotlin language versions are also validated by the selected
303+
runtime, and plugins must be built for the same Detekt major version.
250304

251305
### Plugins
252306

detekt/defs.bzl

Lines changed: 87 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,22 @@ Rule declarations.
44

55
load("@rules_java//java:defs.bzl", "JavaInfo")
66

7+
_SHARED_ATTRS = [
8+
"build_upon_default_config",
9+
"cfgs",
10+
"disable_default_rulesets",
11+
"fail_on_severity",
12+
"jvm_target",
13+
"language_version",
14+
"max_issues",
15+
"parallel",
16+
"plugins",
17+
]
18+
719
_ATTRS = {
20+
"detekt_explicit_attrs": attr.string_list(
21+
default = [],
22+
),
823
"_result_script_template": attr.label(
924
default = Label("//detekt:result_script.sh.tpl"),
1025
allow_single_file = True,
@@ -18,12 +33,12 @@ _ATTRS = {
1833
"plugins": attr.label_list(
1934
default = [],
2035
providers = [JavaInfo],
21-
doc = "Extra paths to plugin jars.",
36+
doc = "Extra paths to plugin jars. If omitted, inherits from the detekt toolchain; an explicit empty list clears toolchain plugins.",
2237
),
2338
"cfgs": attr.label_list(
2439
default = [],
2540
allow_files = [".yml"],
26-
doc = "Path to the config file (path/to/config.yml). Multiple configuration files can be specified.",
41+
doc = "Path to the config file (path/to/config.yml). Multiple configuration files can be specified. If omitted, inherits from the detekt toolchain; an explicit empty list clears toolchain configs.",
2742
),
2843
"config_resource": attr.string(
2944
default = "",
@@ -48,11 +63,11 @@ _ATTRS = {
4863
),
4964
"build_upon_default_config": attr.bool(
5065
default = False,
51-
doc = "Preconfigures detekt with a bunch of rules and some opinionated defaults for you. Allows additional provided configurations to override the defaults.",
66+
doc = "Preconfigures detekt with a bunch of rules and some opinionated defaults for you. If omitted, inherits from the detekt toolchain; explicit False clears the toolchain value.",
5267
),
5368
"disable_default_rulesets": attr.bool(
5469
default = False,
55-
doc = "Disables default rule sets.",
70+
doc = "Disables default rule sets. If omitted, inherits from the detekt toolchain; explicit False clears the toolchain value.",
5671
),
5772
"excludes": attr.string_list(
5873
default = [],
@@ -64,35 +79,35 @@ _ATTRS = {
6479
),
6580
"jvm_target": attr.string(
6681
default = "",
67-
doc = "EXPERIMENTAL: Target version of the generated JVM bytecode that was generated during compilation and is now being used for type resolution (1.8, 9, 10, ..., 26). The selected Detekt version validates this value.",
82+
doc = "EXPERIMENTAL: Target version of the generated JVM bytecode that was generated during compilation and is now being used for type resolution (1.8, 9, 10, ..., 26). If omitted, inherits from the detekt toolchain; explicit values, including empty string, replace it. The selected Detekt version validates this value.",
6883
),
6984
"language_version": attr.string(
7085
default = "",
71-
doc = "EXPERIMENTAL: Compatibility mode for Kotlin language version X.Y, reports errors for all language features that came out later. The selected Detekt version validates this value.",
86+
doc = "EXPERIMENTAL: Compatibility mode for Kotlin language version X.Y, reports errors for all language features that came out later. If omitted, inherits from the detekt toolchain; explicit values, including empty string, replace it. The selected Detekt version validates this value.",
7287
),
7388
"max_issues": attr.int(
7489
default = -1,
75-
doc = "Passes only when found issues count does not exceed specified issues count. Negative values inherit from the detekt toolchain.",
90+
doc = "Detekt 1.x failure threshold: passes only when the found issue count does not exceed this value. If omitted, inherits from the detekt toolchain; explicit -1 clears it. Mutually exclusive with fail_on_severity.",
7691
),
7792
"fail_on_severity": attr.string(
7893
default = "",
79-
doc = "Detekt 2.x failure threshold (Error, Warning, Info, or Never). Mutually exclusive with max_issues.",
94+
doc = "Detekt 2.x failure threshold (Error, Warning, Info, or Never). If omitted, inherits from the detekt toolchain; explicit empty string clears it. Mutually exclusive with max_issues.",
8095
),
8196
"parallel": attr.bool(
8297
default = False,
83-
doc = "Enables parallel compilation and analysis of source files. Defaults to the detekt toolchain value.",
98+
doc = "Enables parallel compilation and analysis of source files. If omitted, inherits from the detekt toolchain; explicit False clears the toolchain value.",
8499
),
85100
"txt_report": attr.bool(
86101
default = False,
87-
doc = "Enables / disables the text report generation. The report file name is `{target_name}_detekt_report.txt`.",
102+
doc = "Enables / disables the text report generation. The report file name is `{target_name}_detekt_report.txt`; Detekt 2.x uses captured console output for this artifact.",
88103
),
89104
"html_report": attr.bool(
90105
default = False,
91106
doc = "Enables / disables the HTML report generation. The report file name is `{target_name}_detekt_report.html`.",
92107
),
93108
"xml_report": attr.bool(
94109
default = False,
95-
doc = "Enables / disables the XML report generation. The report file name is `{target_name}_detekt_report.xml`. FYI Detekt uses the Checkstyle XML reporting format which makes it compatible with tools like SonarQube.",
110+
doc = "Enables / disables the XML report generation. The report file name is `{target_name}_detekt_report.xml`. Detekt 2.x maps this output to its `checkstyle` report ID; the format is compatible with tools like SonarQube.",
96111
),
97112
"md_report": attr.bool(
98113
default = False,
@@ -111,19 +126,36 @@ _ATTRS = {
111126
doc = "Whether detekt target corresponds to android kotlin library or regular jvm library",
112127
default = False,
113128
),
129+
"detekt_toolchain": attr.label(
130+
default = None,
131+
cfg = "exec",
132+
providers = [platform_common.ToolchainInfo],
133+
doc = "Optional label of a target providing platform_common.ToolchainInfo. If omitted, uses the registered detekt toolchain.",
134+
),
114135
}
115136

137+
# Stardoc can consume this schema without exposing the implementation rules.
138+
DETEKT_ATTRIBUTES = _ATTRS
139+
116140
TOOLCHAIN_TYPE = Label("//detekt:toolchain_type")
117141
ANDROID_SDK_TOOLCHAIN_TYPE = Label("@rules_android//toolchains/android_sdk:toolchain_type")
118142
JDK_TOOLCHAIN_TYPE = Label("@bazel_tools//tools/jdk:toolchain_type")
119143

144+
def _uses_rule_attr(ctx, name):
145+
return name in ctx.attr.detekt_explicit_attrs
146+
147+
def _detekt_toolchain(ctx):
148+
if ctx.attr.detekt_toolchain != None:
149+
return ctx.attr.detekt_toolchain[platform_common.ToolchainInfo]
150+
return ctx.toolchains[TOOLCHAIN_TYPE]
151+
120152
def _impl(
121153
ctx,
122154
run_as_test_target = False,
123155
create_baseline = False):
124156
action_inputs = []
125157
action_outputs = []
126-
detekt_toolchain = ctx.toolchains[TOOLCHAIN_TYPE]
158+
detekt_toolchain = _detekt_toolchain(ctx)
127159

128160
java_arguments = ctx.actions.args()
129161

@@ -144,7 +176,7 @@ def _impl(
144176
action_inputs.extend(ctx.files.srcs)
145177
detekt_arguments.add_joined("--input", ctx.files.srcs, join_with = ",")
146178

147-
cfgs = ctx.files.cfgs or detekt_toolchain.cfgs
179+
cfgs = ctx.files.cfgs if _uses_rule_attr(ctx, "cfgs") else detekt_toolchain.cfgs
148180
action_inputs.extend(cfgs)
149181
detekt_arguments.add_joined("--config", cfgs, join_with = ",")
150182

@@ -184,11 +216,11 @@ def _impl(
184216
if ctx.attr.base_path:
185217
detekt_arguments.add("--base-path", ctx.attr.base_path)
186218

187-
build_upon_default_config = ctx.attr.build_upon_default_config or detekt_toolchain.build_upon_default_config
219+
build_upon_default_config = ctx.attr.build_upon_default_config if _uses_rule_attr(ctx, "build_upon_default_config") else detekt_toolchain.build_upon_default_config
188220
if build_upon_default_config:
189221
detekt_arguments.add("--build-upon-default-config")
190222

191-
disable_default_rulesets = ctx.attr.disable_default_rulesets or detekt_toolchain.disable_default_rulesets
223+
disable_default_rulesets = ctx.attr.disable_default_rulesets if _uses_rule_attr(ctx, "disable_default_rulesets") else detekt_toolchain.disable_default_rulesets
192224
if disable_default_rulesets:
193225
detekt_arguments.add("--disable-default-rulesets")
194226

@@ -198,23 +230,30 @@ def _impl(
198230
if ctx.attr.includes:
199231
detekt_arguments.add_joined("--includes", ctx.attr.includes, join_with = ",")
200232

201-
jvm_target = ctx.attr.jvm_target or detekt_toolchain.jvm_target
202-
detekt_arguments.add("--jvm-target", jvm_target)
233+
jvm_target = ctx.attr.jvm_target if _uses_rule_attr(ctx, "jvm_target") else detekt_toolchain.jvm_target
234+
if jvm_target:
235+
detekt_arguments.add("--jvm-target", jvm_target)
203236

204-
language_version = ctx.attr.language_version or detekt_toolchain.language_version
237+
language_version = ctx.attr.language_version if _uses_rule_attr(ctx, "language_version") else detekt_toolchain.language_version
205238
if language_version:
206239
detekt_arguments.add("--language-version", language_version)
207240

208-
max_issues = ctx.attr.max_issues if ctx.attr.max_issues >= 0 else detekt_toolchain.max_issues
241+
rule_policy = _uses_rule_attr(ctx, "max_issues") or _uses_rule_attr(ctx, "fail_on_severity")
242+
max_issues = ctx.attr.max_issues if _uses_rule_attr(ctx, "max_issues") else -1
243+
fail_on_severity = ctx.attr.fail_on_severity if _uses_rule_attr(ctx, "fail_on_severity") else ""
244+
if not rule_policy:
245+
max_issues = detekt_toolchain.max_issues
246+
fail_on_severity = detekt_toolchain.fail_on_severity
247+
209248
if max_issues >= 0:
210-
if ctx.attr.fail_on_severity:
249+
if fail_on_severity:
211250
fail("max_issues and fail_on_severity cannot be used together")
212251
detekt_arguments.add("--max-issues", max_issues)
213252

214-
if ctx.attr.fail_on_severity:
215-
detekt_arguments.add("--fail-on-severity", ctx.attr.fail_on_severity)
253+
if fail_on_severity:
254+
detekt_arguments.add("--fail-on-severity", fail_on_severity)
216255

217-
parallel = ctx.attr.parallel or detekt_toolchain.parallel
256+
parallel = ctx.attr.parallel if _uses_rule_attr(ctx, "parallel") else detekt_toolchain.parallel
218257
if parallel:
219258
detekt_arguments.add("--parallel")
220259

@@ -231,7 +270,7 @@ def _impl(
231270
action_inputs.extend(platform_jar_files + classpath)
232271
detekt_arguments.add("--classpath", ctx.configuration.host_path_separator.join([f.path for f in platform_jar_files] + [f.path for f in classpath]))
233272

234-
plugins = ctx.files.plugins or detekt_toolchain.plugins
273+
plugins = ctx.files.plugins if _uses_rule_attr(ctx, "plugins") else detekt_toolchain.plugins
235274
plugin_jars = [plugin for plugin in plugins if plugin.extension == "jar"]
236275
action_inputs.extend(plugin_jars)
237276
detekt_arguments.add_joined("--plugins", plugin_jars, join_with = ",")
@@ -312,25 +351,46 @@ def _detekt_create_baseline_impl(ctx):
312351
def _detekt_test_impl(ctx):
313352
return _impl(ctx = ctx, run_as_test_target = True)
314353

315-
detekt = rule(
354+
_detekt_rule = rule(
316355
implementation = _detekt_impl,
317356
attrs = _ATTRS,
318357
provides = [DefaultInfo],
319358
toolchains = [TOOLCHAIN_TYPE, ANDROID_SDK_TOOLCHAIN_TYPE, JDK_TOOLCHAIN_TYPE],
320359
)
321360

322-
detekt_create_baseline = rule(
361+
_detekt_create_baseline_rule = rule(
323362
implementation = _detekt_create_baseline_impl,
324363
attrs = _ATTRS,
325364
provides = [DefaultInfo],
326365
toolchains = [TOOLCHAIN_TYPE, ANDROID_SDK_TOOLCHAIN_TYPE, JDK_TOOLCHAIN_TYPE],
327366
executable = True,
328367
)
329368

330-
detekt_test = rule(
369+
_detekt_test = rule(
331370
implementation = _detekt_test_impl,
332371
attrs = _ATTRS,
333372
provides = [DefaultInfo],
334373
toolchains = [TOOLCHAIN_TYPE, ANDROID_SDK_TOOLCHAIN_TYPE, JDK_TOOLCHAIN_TYPE],
335374
test = True,
336375
)
376+
377+
def _declare(native_rule, name, kwargs):
378+
attrs = dict(kwargs)
379+
attrs["detekt_explicit_attrs"] = [
380+
attr_name
381+
for attr_name in _SHARED_ATTRS
382+
if attr_name in kwargs and kwargs[attr_name] != None
383+
]
384+
native_rule(name = name, **attrs)
385+
386+
def detekt(name, **kwargs):
387+
"""Run Detekt analysis for the supplied Kotlin sources."""
388+
_declare(_detekt_rule, name, kwargs)
389+
390+
def detekt_create_baseline(name, **kwargs):
391+
"""Create a Detekt baseline for the supplied Kotlin sources."""
392+
_declare(_detekt_create_baseline_rule, name, kwargs)
393+
394+
def detekt_test(name, **kwargs):
395+
"""Run Detekt analysis as a test for the supplied Kotlin sources."""
396+
_declare(_detekt_test, name, kwargs)

0 commit comments

Comments
 (0)