Home

Awesome

Run linters and formatters under Bazel

This ruleset integrates linting and formatting as first-class concepts under Bazel.

Features:

Supported tools

New tools are being added frequently, so check this page again!

LanguageFormatterLinter(s)
C / C++clang-formatclang-tidy
Cudaclang-format
CSS, Less, SassPrettierStylelint
Gogofmt or gofumpt
GraphQLPrettier
HCL (Hashicorp Config)terraform fmt
HTMLPrettier
JSONPrettier
Javagoogle-java-formatpmd , Checkstyle, Spotbugs
JavaScriptPrettierESLint
Jsonnetjsonnetfmt
Kotlinktfmtktlint
MarkdownPrettierVale
Protocol Bufferbufbuf lint
Pythonruffflake8, ruff
Rustrustfmt
SQLprettier-plugin-sql
Scalascalafmt
Shellshfmtshellcheck
StarlarkBuildifier
SwiftSwiftFormat (1)
TSXPrettierESLint
TypeScriptPrettierESLint
YAMLyamlfmt
  1. Non-hermetic: requires that a swift toolchain is installed on the machine. See https://github.com/bazelbuild/rules_swift#1-install-swift

To add a tool, please follow the steps in lint/README.md or format/README.md and then send us a PR. Thanks!!

Installation

Follow instructions from the release you wish to use: https://github.com/aspect-build/rules_lint/releases

Usage

Formatting and Linting are inherently different, which leads to differences in how they are used in rules_lint.

FormatterLinter
Only one per language, since they could conflict with each other.Many per language is fine; results compose.
Invariant: program's behavior is never changed.Suggested fixes may change behavior.
Developer has no choices. Always blindly accept result.Fix may be manual, or select from multiple auto-fixes.
Changes must be applied.Violations can be suppressed.
Operates on a single file at a time.Can require the dependency graph.
Can always format just changed files / regionsNew violations might be introduced in unchanged files.
Fast enough to put in a pre-commit workflow.Some are slow.

Format

To format files, run the target you create when you install rules_lint.

We recommend using a Git pre-commit hook to format changed files, and Aspect Workflows to provide the check on CI.

See Formatting for more ways to use the formatter.

Demo: pre-commit format

Lint

To lint code, we recommend using the Aspect CLI to get the missing lint command, and Aspect Workflows to provide first-class support for "linters as code reviewers".

For example, running bazel lint //src:all prints lint warnings to the terminal for all targets in the //src package. Suggested fixes from the linter tools are presented interactively.

See Linting for more ways to use the linter.

Demo: bazel lint demo

Ignoring files

The linters only visit files that are part of the Bazel dependency graph (listed as srcs to some library target).

The formatter honors the .gitignore and .gitattributes files. Otherwise use the affordance provided by the tool, for example .prettierignore for files to be ignored by Prettier.

Sometimes engineers want to ignore a file with a certain extension because the content isn't actually valid syntax for the corresponding language. For example, you might write a template for YAML and name it my-template.yaml even though it needs to have some interpolated values inserted before it's syntactically valid. We recommend instead fixing the file extension. In this example, my.yaml.tmpl or my-template.yaml_ might be better.

Using with your editor

We believe that existing editor plugins should just work as-is. They may download or bundle their own copy of the tools, which can lead to some version skew in lint/format rules.

For formatting, we believe it's a waste of time to configure these in the editor, because developers should just rely on formatting happening when they commit and not care what the code looks like before that point. But we're not trying to stop anyone, either!

You could probably configure the editor to always run the same Bazel command, any time a file is changed. Instructions to do this are out-of-scope for this repo, particularly since they have to be formulated and updated for so many editors.

FAQ

What about type-checking?

We consider type-checkers as a build tool, not as a linter. This is for a few reasons: