Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add rust_lint_group and cargo_lints rule to define lint groups #2993

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

ParkMyCar
Copy link
Contributor

@ParkMyCar ParkMyCar commented Nov 10, 2024

Chatted about this previously in Slack. The goal with this PR is to make it easier to define and share lint configurations for your build.

Description

The PR adds two new rules, rust_lint_group and cargo_lints. It also adds a "lints" attr to rust_library and rust_binary rules that expects a new LintsInfo provider.

  • rust_lint_group allows you to define Rust, Clippy, and Rustdoc lints in a BUILD file.
  • cargo_lints automatically generates a set of lints by reading a crate's Cargo.toml, and optionally the workspace's Cargo.toml for workspace inheritance.

Then the rustc, clippy, and rustdoc actions are all updated to check for the LintsInfo provider and appends the correct arguments so the lints take effect.

Design

Honestly this is my first large change to a set of Bazel rules, so I definitely could have done something wrong here!

The change is split into two commits, the first introduces rust_lint_group which IMO is relatively straight forward. Some attributes are defined on a rule which are then formatted into command line flags and passed around with a provider.

The second commit adds cargo_lints and is much larger, a few things worth considering:

  • I was back and forth a bit on using a repository_rule or a regular rule. While the repository_rule maps well to a Cargo Workspace and you'd only need to define it once, not everyone uses workspaces and so I figured a regular rule was more general.
  • Parsing a Cargo.toml is done via a new Rust binary called cargo_toml_info. I tried to keep the external dependencies on this binary to a minimum, it only has one at the moment which is cargo_toml and I based this change largely off of cargo_toml_env_vars: rule for generating env vars from a Cargo.toml file #2772. I tried to make the tool general though so other Cargo metadata rules could use it in the future.

Tests

There aren't any! I wasn't sure where the best place to start was, any guidance here is appreciated!

* allows defining rustc, rustc check-cfg, clippy, and rustdoc lints
* add a 'lints' attribute to the common rust attributes
* rust_doc and rust_clippy rules use the lints from the crate they target
* adds a new Rust binary cargo_toml_info which can parse a Cargo.toml and inherit from the workspace
* adds a new cargo_lints rule which invokes the cargo_toml_info binary to get lints
* update the LintsInfo provider to include CLI args via files
@ParkMyCar ParkMyCar changed the title feat: Add rust_lint_group and cargo_lints rule to define feat: Add rust_lint_group and cargo_lints rule to define lint groups Nov 10, 2024
Copy link
Collaborator

@illicitonion illicitonion left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This generally looks super reasonable, thanks so much for putting it together!

I just have a few comments which are basically all naming.

In terms of testing, one problem we have in Bazel in general is it's pretty hard to write tests that things which should fail do fail (particularly without them being wildly slow).

There are generally three styles of tests you can probably write for this functionality:

I would recommend mostly writing unit tests - you can see an example of how we write unit tests in https://github.com/bazelbuild/rules_rust/tree/main/test/unit/extra_rustc_flags - your test would probably look pretty similar, just testing that some extra flags are present.

For the rust code, you can just write some unit tests like normal.

And you can write a script that checks failing things do fail - we have an example for clippy that runs on CI:

clippy_failure:
name: Negative Clippy Tests
platform: ubuntu2004
run_targets:
- "//test/clippy:clippy_failure_test"
- these ones definitely don't have to be exhaustive, just one example showing each style of thing can fail (and ideally fails with a useful error message) is probably sufficient :)

rust/private/providers.bzl Outdated Show resolved Hide resolved
rust/private/rust.bzl Outdated Show resolved Hide resolved
rust/defs.bzl Outdated
@@ -157,4 +161,7 @@ rustfmt_test = _rustfmt_test
rust_stdlib_filegroup = _rust_stdlib_filegroup
# See @rules_rust//rust:toolchain.bzl for a complete description.

rust_lint_group = _rust_lint_group
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd be include to call this rust_lint_config rather than rust_lint_group - WTDY?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah IMO "config" is definitely better than "group", changed!

@@ -0,0 +1,272 @@
//! Command line tool invoked by Bazel to read metadata out of a `Cargo.toml` file.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's move this file into a private or internal package, maybe cargo/private/cargo_toml_info/main.rs? I don't think we want to advertise this binary's API as something we publicly support and offer compatibility for, it's just an implementation detail of our internals.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done! Also repinned all dependencies which created a number of changes, sorry for the noise in the commit

let manifest = Manifest::from_path(&workspace_path)?;
let workspace_details = Some((&manifest, workspace_path.as_path()));

// TODO(parkmycar): Fix cargo_toml so we inherit lints from our workspace.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh dear, is there an issue we can link to for this? In the mean time, what behaviour do we see?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the meantime we "manually" inherit lints by checking both the manifest and workspace Cargo.toml so the behavior is correct, but ideally this would be handled internally by cargo_toml. Filed an issue upstream and left a comment here

output_rustc_lints: PathBuf,
output_clippy_lints: PathBuf,
output_rustdoc_lints: PathBuf,
// TODO(parkmycar): Support Rust's new --check-cfg once cargo-toml is updated.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we link to an issue?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Filed and linked to cargo_toml#34!

cargo/private/cargo_lints.bzl Outdated Show resolved Hide resolved
* rename fields on the LintsInfo provider
* rename some methods
* add comments linking to cargo_toml issues
* move the cargo_toml_info binary into private
@ParkMyCar
Copy link
Contributor Author

Thanks for the review @illicitonion! Didn't get a chance to add tests (although I did test manually by using this in my project), will follow up with that!

@illicitonion
Copy link
Collaborator

Looks good, thanks! If we can get those tests in, let's get this merged! 🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants