[red-knot] Add --respect-ignore-files flag (#17645)

Co-authored-by: Micha Reiser <micha@reiser.io>
This commit is contained in:
justin 2025-04-27 05:55:41 -04:00 committed by GitHub
parent b0d475f353
commit 4443f6653c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 111 additions and 3 deletions

View File

@ -105,6 +105,19 @@ pub(crate) struct CheckCommand {
/// Watch files for changes and recheck files related to the changed files.
#[arg(long, short = 'W')]
pub(crate) watch: bool,
/// Respect file exclusions via `.gitignore` and other standard ignore files.
/// Use `--no-respect-gitignore` to disable.
#[arg(
long,
overrides_with("no_respect_ignore_files"),
help_heading = "File selection",
default_missing_value = "true",
num_args = 0..1
)]
respect_ignore_files: Option<bool>,
#[clap(long, overrides_with("respect_ignore_files"), hide = true)]
no_respect_ignore_files: bool,
}
impl CheckCommand {
@ -120,6 +133,13 @@ impl CheckCommand {
)
};
// --no-respect-gitignore defaults to false and is set true by CLI flag. If passed, override config file
// Otherwise, only pass this through if explicitly set (don't default to anything here to
// make sure that doesn't take precedence over an explicitly-set config file value)
let respect_ignore_files = self
.no_respect_ignore_files
.then_some(false)
.or(self.respect_ignore_files);
Options {
environment: Some(EnvironmentOptions {
python_version: self
@ -144,6 +164,7 @@ impl CheckCommand {
error_on_warning: self.error_on_warning,
}),
rules,
respect_ignore_files,
..Default::default()
}
}

View File

@ -5,6 +5,74 @@ use std::path::{Path, PathBuf};
use std::process::Command;
use tempfile::TempDir;
#[test]
fn test_respect_ignore_files() -> anyhow::Result<()> {
// First test that the default option works correctly (the file is skipped)
let case = TestCase::with_files([(".ignore", "test.py"), ("test.py", "~")])?;
assert_cmd_snapshot!(case.command(), @r"
success: true
exit_code: 0
----- stdout -----
All checks passed!
----- stderr -----
WARN No python files found under the given path(s)
");
// Test that we can set to false via CLI
assert_cmd_snapshot!(case.command().arg("--no-respect-ignore-files"), @r"
success: false
exit_code: 1
----- stdout -----
error: invalid-syntax
--> <temp_dir>/test.py:1:2
|
1 | ~
| ^ Expected an expression
|
Found 1 diagnostic
----- stderr -----
");
// Test that we can set to false via config file
case.write_file("knot.toml", "respect-ignore-files = false")?;
assert_cmd_snapshot!(case.command(), @r"
success: false
exit_code: 1
----- stdout -----
error: invalid-syntax
--> <temp_dir>/test.py:1:2
|
1 | ~
| ^ Expected an expression
|
Found 1 diagnostic
----- stderr -----
");
// Ensure CLI takes precedence
case.write_file("knot.toml", "respect-ignore-files = true")?;
assert_cmd_snapshot!(case.command().arg("--no-respect-ignore-files"), @r"
success: false
exit_code: 1
----- stdout -----
error: invalid-syntax
--> <temp_dir>/test.py:1:2
|
1 | ~
| ^ Expected an expression
|
Found 1 diagnostic
----- stderr -----
");
Ok(())
}
/// Specifying an option on the CLI should take precedence over the same setting in the
/// project's configuration. Here, this is tested for the Python version.
#[test]

View File

@ -32,6 +32,9 @@ pub struct Options {
#[serde(skip_serializing_if = "Option::is_none")]
pub terminal: Option<TerminalOptions>,
#[serde(skip_serializing_if = "Option::is_none")]
pub respect_ignore_files: Option<bool>,
}
impl Options {
@ -133,7 +136,7 @@ impl Options {
pub(crate) fn to_settings(&self, db: &dyn Db) -> (Settings, Vec<OptionDiagnostic>) {
let (rules, diagnostics) = self.to_rule_selection(db);
let mut settings = Settings::new(rules);
let mut settings = Settings::new(rules, self.respect_ignore_files);
if let Some(terminal) = self.terminal.as_ref() {
settings.set_terminal(TerminalSettings {

View File

@ -21,13 +21,16 @@ pub struct Settings {
rules: Arc<RuleSelection>,
terminal: TerminalSettings,
respect_ignore_files: bool,
}
impl Settings {
pub fn new(rules: RuleSelection) -> Self {
pub fn new(rules: RuleSelection, respect_ignore_files: Option<bool>) -> Self {
Self {
rules: Arc::new(rules),
terminal: TerminalSettings::default(),
respect_ignore_files: respect_ignore_files.unwrap_or(true),
}
}
@ -35,6 +38,10 @@ impl Settings {
&self.rules
}
pub fn respect_ignore_files(&self) -> bool {
self.respect_ignore_files
}
pub fn to_rules(&self) -> Arc<RuleSelection> {
self.rules.clone()
}

View File

@ -129,7 +129,10 @@ impl<'a> ProjectFilesWalker<'a> {
{
let mut paths = paths.into_iter();
let mut walker = db.system().walk_directory(paths.next()?.as_ref());
let mut walker = db
.system()
.walk_directory(paths.next()?.as_ref())
.standard_filters(db.project().settings(db).respect_ignore_files());
for path in paths {
walker = walker.add(path);

View File

@ -15,6 +15,12 @@
}
]
},
"respect-ignore-files": {
"type": [
"boolean",
"null"
]
},
"rules": {
"description": "Configures the enabled lints and their severity.",
"anyOf": [