Support running individual lint checks

Add support for passing `--lint=LINT_TO_RUN` to the lint runner and
add corresponding help message.
pull/30219/head
David Gumberg 7 months ago
parent 457e1846d2
commit 0fcbfdb7ad

@ -26,6 +26,21 @@ Then you can use:
( cd ./test/lint/test_runner/ && cargo fmt && cargo clippy && RUST_BACKTRACE=1 cargo run )
```
If you wish to run individual lint checks, run the test_runner with
`--lint=TEST_TO_RUN` arguments. If running with `cargo run`, arguments after
`--` are passed to the binary you are running e.g.:
```sh
( cd ./test/lint/test_runner/ && RUST_BACKTRACE=1 cargo run -- --lint=doc --lint=trailing_whitespace )
```
To see a list of all individual lint checks available in test_runner, use `-h`
or `--help`:
```sh
( cd ./test/lint/test_runner/ && RUST_BACKTRACE=1 cargo run -- --help )
```
#### Dependencies
| Lint test | Dependency |

@ -12,6 +12,113 @@ type LintError = String;
type LintResult = Result<(), LintError>;
type LintFn = fn() -> LintResult;
struct Linter {
pub description: &'static str,
pub name: &'static str,
pub lint_fn: LintFn,
}
fn get_linter_list() -> Vec<&'static Linter> {
vec![
&Linter {
description: "Check that all command line arguments are documented.",
name: "doc",
lint_fn: lint_doc
},
&Linter {
description: "Check that no symbol from bitcoin-config.h is used without the header being included",
name: "includes_build_config",
lint_fn: lint_includes_build_config
},
&Linter {
description: "Check that markdown links resolve",
name: "markdown",
lint_fn: lint_markdown
},
&Linter {
description: "Check that std::filesystem is not used directly",
name: "std_filesystem",
lint_fn: lint_std_filesystem
},
&Linter {
description: "Check that subtrees are pure subtrees",
name: "subtree",
lint_fn: lint_subtree
},
&Linter {
description: "Check that tabs are not used as whitespace",
name: "tabs_whitespace",
lint_fn: lint_tabs_whitespace
},
&Linter {
description: "Check for trailing whitespace",
name: "trailing_whitespace",
lint_fn: lint_trailing_whitespace
},
&Linter {
description: "Run all linters of the form: test/lint/lint-*.py",
name: "all_python_linters",
lint_fn: run_all_python_linters
},
]
}
fn print_help_and_exit() {
print!(
r#"
Usage: test_runner [--lint=LINTER_TO_RUN]
Runs all linters in the lint test suite, printing any errors
they detect.
If you wish to only run some particular lint tests, pass
'--lint=' with the name of the lint test you wish to run.
You can set as many '--lint=' values as you wish, e.g.:
test_runner --lint=doc --lint=subtree
The individual linters available to run are:
"#
);
for linter in get_linter_list() {
println!("{}: \"{}\"", linter.name, linter.description)
}
std::process::exit(1);
}
fn parse_lint_args(args: &[String]) -> Vec<&'static Linter> {
let linter_list = get_linter_list();
let mut lint_values = Vec::new();
for arg in args {
#[allow(clippy::if_same_then_else)]
if arg.starts_with("--lint=") {
let lint_arg_value = arg
.trim_start_matches("--lint=")
.trim_matches('"')
.trim_matches('\'');
let try_find_linter = linter_list
.iter()
.find(|linter| linter.name == lint_arg_value);
match try_find_linter {
Some(linter) => {
lint_values.push(*linter);
}
None => {
println!("No linter {lint_arg_value} found!");
print_help_and_exit();
}
}
} else if arg.eq("--help") || arg.eq("-h") {
print_help_and_exit();
} else {
print_help_and_exit();
}
}
lint_values
}
/// Return the git command
fn git() -> Command {
let mut git = Command::new("git");
@ -337,7 +444,7 @@ Markdown link errors found:
}
}
fn lint_all() -> LintResult {
fn run_all_python_linters() -> LintResult {
let mut good = true;
let lint_dir = get_git_root().join("test/lint");
for entry in fs::read_dir(lint_dir).unwrap() {
@ -352,7 +459,7 @@ fn lint_all() -> LintResult {
.success()
{
good = false;
println!("^---- failure generated from {}", entry_fn);
println!("^---- ⚠️ Failure generated from {}", entry_fn);
}
}
if good {
@ -363,25 +470,26 @@ fn lint_all() -> LintResult {
}
fn main() -> ExitCode {
let test_list: Vec<(&str, LintFn)> = vec![
("subtree check", lint_subtree),
("std::filesystem check", lint_std_filesystem),
("trailing whitespace check", lint_trailing_whitespace),
("no-tabs check", lint_tabs_whitespace),
("build config includes check", lint_includes_build_config),
("-help=1 documentation check", lint_doc),
("markdown hyperlink check", lint_markdown),
("lint-*.py scripts", lint_all),
];
let linters_to_run: Vec<&Linter> = if env::args().count() > 1 {
let args: Vec<String> = env::args().skip(1).collect();
parse_lint_args(&args)
} else {
// If no arguments are passed, run all linters.
get_linter_list()
};
let git_root = get_git_root();
let mut test_failed = false;
for (lint_name, lint_fn) in test_list {
for linter in linters_to_run {
// chdir to root before each lint test
env::set_current_dir(&git_root).unwrap();
if let Err(err) = lint_fn() {
println!("{err}\n^---- ⚠️ Failure generated from {lint_name}!");
if let Err(err) = (linter.lint_fn)() {
println!(
"{err}\n^---- ⚠️ Failure generated from lint check '{}'!",
linter.name
);
println!("{}", linter.description);
test_failed = true;
}
}

Loading…
Cancel
Save