Skip to content

A framework for adding lint checks to Bazel projects

License

Notifications You must be signed in to change notification settings

apple/apple_rules_lint

Repository files navigation

apple_rules_lint

A linting framework for Bazel

Users

You must load and configure the linting framework before anything else. This is because later rulesets that depend on the linting framework will attempt to ensure that linters are configured by registering no-op implementations of lint configs. You can do this by:

# WORKSPACE

load("@apple_rules_lint//lint:repositories.bzl", "lint_deps")

lint_deps()

load("@apple_rules_lint//lint:setup.bzl", "lint_setup")

lint_setup({
    "java-checkstyle": "//your:checkstyle-config",
})

Alternatively, using Bzlmod:

# MODULE.bazel
bazel_dep(name = "apple_rules_lint", version = "0.4.0")

linter = use_extension("@apple_rules_lint//lint:extensions.bzl", "linter")
linter.configure(name = "java-checkstyle", config = "//your:checkstyle-config")
use_repo(linter, "apple_linters")

You may override specific lint configurations on a per-package basis by:

# BUILD.bazel

load("@apple_rules_lint//lint:defs.bzl", "package_lint_config")

package_lint_config({
    "java-checkstyle": ":alternative-checkstyle-config",
})

Missing @@apple_linters error

Bazel may report an error like this:

ERROR: Failed to load Starlark extension '@@apple_linters//:defs.bzl'.
Cycle in the workspace file detected. This indicates that a repository is used prior to being defined.
The following chain of repository dependencies lead to the missing definition.
 - @@apple_linters
This could either mean you have to add the '@@apple_linters' repository with a statement like `http_archive` in your WORKSPACE file (note that transitive dependencies are not added automatically), or move an existing definition earlier in your WORKSPACE file.

The @apple_linters repository is defined when lint_setup is called. You'll need to figure out where load("@apple_linters//:defs.bzl, ...) is getting called, and modify your build to ensure that lint_setup is called before linting is loaded.

API Documentation

Can be found in the api docs

Ruleset Authors

WORKSPACE setup

To add linter support to your repo, add this to...

# repositories.bzl
load("@apple_rules_lint//lint:repositories.bzl", "lint_deps")

lint_deps()

Then add this to...

# setup.bzl
load("@apple_rules_lint//lint:setup.bzl", "ruleset_lint_setup")

ruleset_lint_setup()

Bzlmod setup

Add:

# MODULE.bazel

bazel_dep(name = "apple_rules_lint", version = "0.1.1")

linter = use_extension("@apple_rules_lint//lint:extensions.bzl", "linter")
linter.register(name = "java-checkstyle")

Getting the configured config for a linter

To obtain the currently configured config for a ruleset, use:

# your_rules.bzl

load("@apple_rules_lint//lint:defs.bzl", "get_lint_config")

config = get_lint_config("java-checkstyle", tags)
if config != None:
    # set up lint targets
    pass

Where tags are the tags of the rule to check.

Integrating apple_rules_lint With Your Rulesets

For the sake of this example, we'll show how apple_rules_lint is integrated with the Selenium project, but the same process can be followed for any linter:

  1. Wrap the linter with a _test rule, so you can run them with bazel test. In Selenium, this is the spotbugs_test

  2. It is recommended, but not required, that your test return a LinterInfo so that other tooling can detect whether this is a lint test.

  3. Create a config rule or a marker rule of some sort. For example, spotbugs_config

  4. Pick a "well known" name: lang-tool seems to work well (such as java-spotbugs, but you might have go-gofmt or py-black)

  5. Create a macro that uses get_lint_config to look up the config for you. If that's present, create a new instance of your test rule. You can see this in action here.

  6. As you write code, make sure your macro is called. If you're a ruleset author, this can be as lightweight as exporting the macro created above as the default way to call your rules.

  7. ...

  8. Profit!

Users can then use the "well known" name to point to an instance of the config rule in their WORKSPACE files:

lint_setup({
    "java-spotbugs": "//java:spotbugs-config",
})