mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-04 18:58:04 +00:00
[ty] Add --config-file CLI arg (#18083)
This commit is contained in:
parent
6453ac9ea1
commit
8d5655a7ba
12 changed files with 300 additions and 63 deletions
|
@ -22,7 +22,7 @@ ty_server = { workspace = true }
|
|||
|
||||
anyhow = { workspace = true }
|
||||
argfile = { workspace = true }
|
||||
clap = { workspace = true, features = ["wrap_help", "string"] }
|
||||
clap = { workspace = true, features = ["wrap_help", "string", "env"] }
|
||||
clap_complete_command = { workspace = true }
|
||||
colored = { workspace = true }
|
||||
countme = { workspace = true, features = ["enable"] }
|
||||
|
|
4
crates/ty/docs/cli.md
generated
4
crates/ty/docs/cli.md
generated
|
@ -47,7 +47,9 @@ ty check [OPTIONS] [PATH]...
|
|||
overriding a specific configuration option.</p>
|
||||
<p>Overrides of individual settings using this option always take precedence
|
||||
over all configuration files.</p>
|
||||
</dd><dt id="ty-check--error"><a href="#ty-check--error"><code>--error</code></a> <i>rule</i></dt><dd><p>Treat the given rule as having severity 'error'. Can be specified multiple times.</p>
|
||||
</dd><dt id="ty-check--config-file"><a href="#ty-check--config-file"><code>--config-file</code></a> <i>path</i></dt><dd><p>The path to a <code>ty.toml</code> file to use for configuration.</p>
|
||||
<p>While ty configuration can be included in a <code>pyproject.toml</code> file, it is not allowed in this context.</p>
|
||||
<p>May also be set with the <code>TY_CONFIG_FILE</code> environment variable.</p></dd><dt id="ty-check--error"><a href="#ty-check--error"><code>--error</code></a> <i>rule</i></dt><dd><p>Treat the given rule as having severity 'error'. Can be specified multiple times.</p>
|
||||
</dd><dt id="ty-check--error-on-warning"><a href="#ty-check--error-on-warning"><code>--error-on-warning</code></a></dt><dd><p>Use exit code 1 if there are any warning-level diagnostics</p>
|
||||
</dd><dt id="ty-check--exit-zero"><a href="#ty-check--exit-zero"><code>--exit-zero</code></a></dt><dd><p>Always use exit code 0, even when there are error-level diagnostics</p>
|
||||
</dd><dt id="ty-check--extra-search-path"><a href="#ty-check--extra-search-path"><code>--extra-search-path</code></a> <i>path</i></dt><dd><p>Additional path to use as a module-resolution source (can be passed multiple times)</p>
|
||||
|
|
|
@ -107,6 +107,12 @@ pub(crate) struct CheckCommand {
|
|||
#[clap(flatten)]
|
||||
pub(crate) config: ConfigsArg,
|
||||
|
||||
/// The path to a `ty.toml` file to use for configuration.
|
||||
///
|
||||
/// While ty configuration can be included in a `pyproject.toml` file, it is not allowed in this context.
|
||||
#[arg(long, env = "TY_CONFIG_FILE", value_name = "PATH")]
|
||||
pub(crate) config_file: Option<SystemPathBuf>,
|
||||
|
||||
/// The format to use for printing diagnostic messages.
|
||||
#[arg(long)]
|
||||
pub(crate) output_format: Option<OutputFormat>,
|
||||
|
|
|
@ -23,7 +23,7 @@ use ruff_db::diagnostic::{Diagnostic, DisplayDiagnosticConfig, Severity};
|
|||
use ruff_db::max_parallelism;
|
||||
use ruff_db::system::{OsSystem, SystemPath, SystemPathBuf};
|
||||
use salsa::plumbing::ZalsaDatabase;
|
||||
use ty_project::metadata::options::Options;
|
||||
use ty_project::metadata::options::ProjectOptionsOverrides;
|
||||
use ty_project::watch::ProjectWatcher;
|
||||
use ty_project::{Db, DummyReporter, Reporter, watch};
|
||||
use ty_project::{ProjectDatabase, ProjectMetadata};
|
||||
|
@ -102,13 +102,21 @@ fn run_check(args: CheckCommand) -> anyhow::Result<ExitStatus> {
|
|||
.map(|path| SystemPath::absolute(path, &cwd))
|
||||
.collect();
|
||||
|
||||
let system = OsSystem::new(cwd);
|
||||
let system = OsSystem::new(&cwd);
|
||||
let watch = args.watch;
|
||||
let exit_zero = args.exit_zero;
|
||||
let config_file = args
|
||||
.config_file
|
||||
.as_ref()
|
||||
.map(|path| SystemPath::absolute(path, &cwd));
|
||||
|
||||
let cli_options = args.into_options();
|
||||
let mut project_metadata = ProjectMetadata::discover(&project_path, &system)?;
|
||||
project_metadata.apply_cli_options(cli_options.clone());
|
||||
let mut project_metadata = match &config_file {
|
||||
Some(config_file) => ProjectMetadata::from_config_file(config_file.clone(), &system)?,
|
||||
None => ProjectMetadata::discover(&project_path, &system)?,
|
||||
};
|
||||
|
||||
let options = args.into_options();
|
||||
project_metadata.apply_options(options.clone());
|
||||
project_metadata.apply_configuration_files(&system)?;
|
||||
|
||||
let mut db = ProjectDatabase::new(project_metadata, system)?;
|
||||
|
@ -117,7 +125,8 @@ fn run_check(args: CheckCommand) -> anyhow::Result<ExitStatus> {
|
|||
db.project().set_included_paths(&mut db, check_paths);
|
||||
}
|
||||
|
||||
let (main_loop, main_loop_cancellation_token) = MainLoop::new(cli_options);
|
||||
let project_options_overrides = ProjectOptionsOverrides::new(config_file, options);
|
||||
let (main_loop, main_loop_cancellation_token) = MainLoop::new(project_options_overrides);
|
||||
|
||||
// Listen to Ctrl+C and abort the watch mode.
|
||||
let main_loop_cancellation_token = Mutex::new(Some(main_loop_cancellation_token));
|
||||
|
@ -178,11 +187,13 @@ struct MainLoop {
|
|||
/// The file system watcher, if running in watch mode.
|
||||
watcher: Option<ProjectWatcher>,
|
||||
|
||||
cli_options: Options,
|
||||
project_options_overrides: ProjectOptionsOverrides,
|
||||
}
|
||||
|
||||
impl MainLoop {
|
||||
fn new(cli_options: Options) -> (Self, MainLoopCancellationToken) {
|
||||
fn new(
|
||||
project_options_overrides: ProjectOptionsOverrides,
|
||||
) -> (Self, MainLoopCancellationToken) {
|
||||
let (sender, receiver) = crossbeam_channel::bounded(10);
|
||||
|
||||
(
|
||||
|
@ -190,7 +201,7 @@ impl MainLoop {
|
|||
sender: sender.clone(),
|
||||
receiver,
|
||||
watcher: None,
|
||||
cli_options,
|
||||
project_options_overrides,
|
||||
},
|
||||
MainLoopCancellationToken { sender },
|
||||
)
|
||||
|
@ -340,7 +351,7 @@ impl MainLoop {
|
|||
MainLoopMessage::ApplyChanges(changes) => {
|
||||
revision += 1;
|
||||
// Automatically cancels any pending queries and waits for them to complete.
|
||||
db.apply_changes(changes, Some(&self.cli_options));
|
||||
db.apply_changes(changes, Some(&self.project_options_overrides));
|
||||
if let Some(watcher) = self.watcher.as_mut() {
|
||||
watcher.update(db);
|
||||
}
|
||||
|
|
|
@ -1700,6 +1700,63 @@ fn check_conda_prefix_var_to_resolve_path() -> anyhow::Result<()> {
|
|||
----- stderr -----
|
||||
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
||||
");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn config_file_override() -> anyhow::Result<()> {
|
||||
// Set `error-on-warning` to true in the configuration file
|
||||
// Explicitly set `--warn unresolved-reference` to ensure the rule warns instead of errors
|
||||
let case = TestCase::with_files(vec![
|
||||
("test.py", r"print(x) # [unresolved-reference]"),
|
||||
(
|
||||
"ty-override.toml",
|
||||
r#"
|
||||
[terminal]
|
||||
error-on-warning = true
|
||||
"#,
|
||||
),
|
||||
])?;
|
||||
|
||||
// Ensure flag works via CLI arg
|
||||
assert_cmd_snapshot!(case.command().arg("--warn").arg("unresolved-reference").arg("--config-file").arg("ty-override.toml"), @r"
|
||||
success: false
|
||||
exit_code: 1
|
||||
----- stdout -----
|
||||
warning[unresolved-reference]: Name `x` used when not defined
|
||||
--> test.py:1:7
|
||||
|
|
||||
1 | print(x) # [unresolved-reference]
|
||||
| ^
|
||||
|
|
||||
info: rule `unresolved-reference` was selected on the command line
|
||||
|
||||
Found 1 diagnostic
|
||||
|
||||
----- stderr -----
|
||||
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
||||
");
|
||||
|
||||
// Ensure the flag works via an environment variable
|
||||
assert_cmd_snapshot!(case.command().arg("--warn").arg("unresolved-reference").env("TY_CONFIG_FILE", "ty-override.toml"), @r"
|
||||
success: false
|
||||
exit_code: 1
|
||||
----- stdout -----
|
||||
warning[unresolved-reference]: Name `x` used when not defined
|
||||
--> test.py:1:7
|
||||
|
|
||||
1 | print(x) # [unresolved-reference]
|
||||
| ^
|
||||
|
|
||||
info: rule `unresolved-reference` was selected on the command line
|
||||
|
||||
Found 1 diagnostic
|
||||
|
||||
----- stderr -----
|
||||
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
|
||||
");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ use ruff_db::system::{
|
|||
};
|
||||
use ruff_db::{Db as _, Upcast};
|
||||
use ruff_python_ast::PythonVersion;
|
||||
use ty_project::metadata::options::{EnvironmentOptions, Options};
|
||||
use ty_project::metadata::options::{EnvironmentOptions, Options, ProjectOptionsOverrides};
|
||||
use ty_project::metadata::pyproject::{PyProject, Tool};
|
||||
use ty_project::metadata::value::{RangedValue, RelativePathBuf};
|
||||
use ty_project::watch::{ChangeEvent, ProjectWatcher, directory_watcher};
|
||||
|
@ -164,8 +164,12 @@ impl TestCase {
|
|||
Ok(all_events)
|
||||
}
|
||||
|
||||
fn apply_changes(&mut self, changes: Vec<ChangeEvent>) {
|
||||
self.db.apply_changes(changes, None);
|
||||
fn apply_changes(
|
||||
&mut self,
|
||||
changes: Vec<ChangeEvent>,
|
||||
project_options_overrides: Option<&ProjectOptionsOverrides>,
|
||||
) {
|
||||
self.db.apply_changes(changes, project_options_overrides);
|
||||
}
|
||||
|
||||
fn update_options(&mut self, options: Options) -> anyhow::Result<()> {
|
||||
|
@ -180,7 +184,7 @@ impl TestCase {
|
|||
.context("Failed to write configuration")?;
|
||||
|
||||
let changes = self.take_watch_changes(event_for_file("pyproject.toml"));
|
||||
self.apply_changes(changes);
|
||||
self.apply_changes(changes, None);
|
||||
|
||||
if let Some(watcher) = &mut self.watcher {
|
||||
watcher.update(&self.db);
|
||||
|
@ -476,7 +480,7 @@ fn new_file() -> anyhow::Result<()> {
|
|||
|
||||
let changes = case.stop_watch(event_for_file("foo.py"));
|
||||
|
||||
case.apply_changes(changes);
|
||||
case.apply_changes(changes, None);
|
||||
|
||||
let foo = case.system_file(&foo_path).expect("foo.py to exist.");
|
||||
|
||||
|
@ -499,7 +503,7 @@ fn new_ignored_file() -> anyhow::Result<()> {
|
|||
|
||||
let changes = case.stop_watch(event_for_file("foo.py"));
|
||||
|
||||
case.apply_changes(changes);
|
||||
case.apply_changes(changes, None);
|
||||
|
||||
assert!(case.system_file(&foo_path).is_ok());
|
||||
case.assert_indexed_project_files([bar_file]);
|
||||
|
@ -535,7 +539,7 @@ fn new_non_project_file() -> anyhow::Result<()> {
|
|||
|
||||
let changes = case.stop_watch(event_for_file("black.py"));
|
||||
|
||||
case.apply_changes(changes);
|
||||
case.apply_changes(changes, None);
|
||||
|
||||
assert!(case.system_file(&black_path).is_ok());
|
||||
|
||||
|
@ -576,7 +580,7 @@ fn new_files_with_explicit_included_paths() -> anyhow::Result<()> {
|
|||
|
||||
let changes = case.stop_watch(event_for_file("test2.py"));
|
||||
|
||||
case.apply_changes(changes);
|
||||
case.apply_changes(changes, None);
|
||||
|
||||
let sub_a_file = case.system_file(&sub_a_path).expect("sub/a.py to exist");
|
||||
|
||||
|
@ -621,7 +625,7 @@ fn new_file_in_included_out_of_project_directory() -> anyhow::Result<()> {
|
|||
|
||||
let changes = case.stop_watch(event_for_file("script2.py"));
|
||||
|
||||
case.apply_changes(changes);
|
||||
case.apply_changes(changes, None);
|
||||
|
||||
let src_a_file = case.system_file(&src_a).unwrap();
|
||||
let outside_b_file = case.system_file(&outside_b_path).unwrap();
|
||||
|
@ -648,7 +652,7 @@ fn changed_file() -> anyhow::Result<()> {
|
|||
|
||||
assert!(!changes.is_empty());
|
||||
|
||||
case.apply_changes(changes);
|
||||
case.apply_changes(changes, None);
|
||||
|
||||
assert_eq!(source_text(case.db(), foo).as_str(), "print('Version 2')");
|
||||
case.assert_indexed_project_files([foo]);
|
||||
|
@ -671,7 +675,7 @@ fn deleted_file() -> anyhow::Result<()> {
|
|||
|
||||
let changes = case.stop_watch(event_for_file("foo.py"));
|
||||
|
||||
case.apply_changes(changes);
|
||||
case.apply_changes(changes, None);
|
||||
|
||||
assert!(!foo.exists(case.db()));
|
||||
case.assert_indexed_project_files([]);
|
||||
|
@ -703,7 +707,7 @@ fn move_file_to_trash() -> anyhow::Result<()> {
|
|||
|
||||
let changes = case.stop_watch(event_for_file("foo.py"));
|
||||
|
||||
case.apply_changes(changes);
|
||||
case.apply_changes(changes, None);
|
||||
|
||||
assert!(!foo.exists(case.db()));
|
||||
case.assert_indexed_project_files([]);
|
||||
|
@ -730,7 +734,7 @@ fn move_file_to_project() -> anyhow::Result<()> {
|
|||
|
||||
let changes = case.stop_watch(event_for_file("foo.py"));
|
||||
|
||||
case.apply_changes(changes);
|
||||
case.apply_changes(changes, None);
|
||||
|
||||
let foo_in_project = case.system_file(&foo_in_project)?;
|
||||
|
||||
|
@ -755,7 +759,7 @@ fn rename_file() -> anyhow::Result<()> {
|
|||
|
||||
let changes = case.stop_watch(event_for_file("bar.py"));
|
||||
|
||||
case.apply_changes(changes);
|
||||
case.apply_changes(changes, None);
|
||||
|
||||
assert!(!foo.exists(case.db()));
|
||||
|
||||
|
@ -796,7 +800,7 @@ fn directory_moved_to_project() -> anyhow::Result<()> {
|
|||
|
||||
let changes = case.stop_watch(event_for_file("sub"));
|
||||
|
||||
case.apply_changes(changes);
|
||||
case.apply_changes(changes, None);
|
||||
|
||||
let init_file = case
|
||||
.system_file(sub_new_path.join("__init__.py"))
|
||||
|
@ -853,7 +857,7 @@ fn directory_moved_to_trash() -> anyhow::Result<()> {
|
|||
|
||||
let changes = case.stop_watch(event_for_file("sub"));
|
||||
|
||||
case.apply_changes(changes);
|
||||
case.apply_changes(changes, None);
|
||||
|
||||
// `import sub.a` should no longer resolve
|
||||
assert!(
|
||||
|
@ -916,7 +920,7 @@ fn directory_renamed() -> anyhow::Result<()> {
|
|||
// Linux and windows only emit an event for the newly created root directory, but not for every new component.
|
||||
let changes = case.stop_watch(event_for_file("sub"));
|
||||
|
||||
case.apply_changes(changes);
|
||||
case.apply_changes(changes, None);
|
||||
|
||||
// `import sub.a` should no longer resolve
|
||||
assert!(
|
||||
|
@ -989,7 +993,7 @@ fn directory_deleted() -> anyhow::Result<()> {
|
|||
|
||||
let changes = case.stop_watch(event_for_file("sub"));
|
||||
|
||||
case.apply_changes(changes);
|
||||
case.apply_changes(changes, None);
|
||||
|
||||
// `import sub.a` should no longer resolve
|
||||
assert!(
|
||||
|
@ -1035,7 +1039,7 @@ fn search_path() -> anyhow::Result<()> {
|
|||
|
||||
let changes = case.stop_watch(event_for_file("a.py"));
|
||||
|
||||
case.apply_changes(changes);
|
||||
case.apply_changes(changes, None);
|
||||
|
||||
assert!(resolve_module(case.db().upcast(), &ModuleName::new_static("a").unwrap()).is_some());
|
||||
case.assert_indexed_project_files([case.system_file(case.project_path("bar.py")).unwrap()]);
|
||||
|
@ -1066,7 +1070,7 @@ fn add_search_path() -> anyhow::Result<()> {
|
|||
|
||||
let changes = case.stop_watch(event_for_file("a.py"));
|
||||
|
||||
case.apply_changes(changes);
|
||||
case.apply_changes(changes, None);
|
||||
|
||||
assert!(resolve_module(case.db().upcast(), &ModuleName::new_static("a").unwrap()).is_some());
|
||||
|
||||
|
@ -1213,7 +1217,7 @@ fn changed_versions_file() -> anyhow::Result<()> {
|
|||
|
||||
let changes = case.stop_watch(event_for_file("VERSIONS"));
|
||||
|
||||
case.apply_changes(changes);
|
||||
case.apply_changes(changes, None);
|
||||
|
||||
assert!(resolve_module(case.db(), &ModuleName::new("os").unwrap()).is_some());
|
||||
|
||||
|
@ -1267,7 +1271,7 @@ fn hard_links_in_project() -> anyhow::Result<()> {
|
|||
|
||||
let changes = case.stop_watch(event_for_file("foo.py"));
|
||||
|
||||
case.apply_changes(changes);
|
||||
case.apply_changes(changes, None);
|
||||
|
||||
assert_eq!(source_text(case.db(), foo).as_str(), "print('Version 2')");
|
||||
|
||||
|
@ -1338,7 +1342,7 @@ fn hard_links_to_target_outside_project() -> anyhow::Result<()> {
|
|||
|
||||
let changes = case.stop_watch(ChangeEvent::is_changed);
|
||||
|
||||
case.apply_changes(changes);
|
||||
case.apply_changes(changes, None);
|
||||
|
||||
assert_eq!(source_text(case.db(), bar).as_str(), "print('Version 2')");
|
||||
|
||||
|
@ -1377,7 +1381,7 @@ mod unix {
|
|||
|
||||
let changes = case.stop_watch(event_for_file("foo.py"));
|
||||
|
||||
case.apply_changes(changes);
|
||||
case.apply_changes(changes, None);
|
||||
|
||||
assert_eq!(
|
||||
foo.permissions(case.db()),
|
||||
|
@ -1460,7 +1464,7 @@ mod unix {
|
|||
|
||||
let changes = case.take_watch_changes(event_for_file("baz.py"));
|
||||
|
||||
case.apply_changes(changes);
|
||||
case.apply_changes(changes, None);
|
||||
|
||||
assert_eq!(
|
||||
source_text(case.db(), baz_file).as_str(),
|
||||
|
@ -1473,7 +1477,7 @@ mod unix {
|
|||
|
||||
let changes = case.stop_watch(event_for_file("baz.py"));
|
||||
|
||||
case.apply_changes(changes);
|
||||
case.apply_changes(changes, None);
|
||||
|
||||
assert_eq!(
|
||||
source_text(case.db(), baz_file).as_str(),
|
||||
|
@ -1544,7 +1548,7 @@ mod unix {
|
|||
|
||||
let changes = case.stop_watch(event_for_file("baz.py"));
|
||||
|
||||
case.apply_changes(changes);
|
||||
case.apply_changes(changes, None);
|
||||
|
||||
// The file watcher is guaranteed to emit one event for the changed file, but it isn't specified
|
||||
// if the event is emitted for the "original" or linked path because both paths are watched.
|
||||
|
@ -1658,7 +1662,7 @@ mod unix {
|
|||
|
||||
let changes = case.stop_watch(event_for_file("baz.py"));
|
||||
|
||||
case.apply_changes(changes);
|
||||
case.apply_changes(changes, None);
|
||||
|
||||
assert_eq!(
|
||||
source_text(case.db(), baz_original_file).as_str(),
|
||||
|
@ -1715,7 +1719,7 @@ fn nested_projects_delete_root() -> anyhow::Result<()> {
|
|||
|
||||
let changes = case.stop_watch(ChangeEvent::is_deleted);
|
||||
|
||||
case.apply_changes(changes);
|
||||
case.apply_changes(changes, None);
|
||||
|
||||
// It should now pick up the outer project.
|
||||
assert_eq!(case.db().project().root(case.db()), case.root_path());
|
||||
|
@ -1781,7 +1785,73 @@ fn changes_to_user_configuration() -> anyhow::Result<()> {
|
|||
|
||||
let changes = case.stop_watch(event_for_file("ty.toml"));
|
||||
|
||||
case.apply_changes(changes);
|
||||
case.apply_changes(changes, None);
|
||||
|
||||
let diagnostics = case.db().check_file(foo);
|
||||
|
||||
assert!(
|
||||
diagnostics.len() == 1,
|
||||
"Expected exactly one diagnostic but got: {diagnostics:#?}"
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn changes_to_config_file_override() -> anyhow::Result<()> {
|
||||
let mut case = setup(|context: &mut SetupContext| {
|
||||
std::fs::write(
|
||||
context.join_project_path("pyproject.toml").as_std_path(),
|
||||
r#"
|
||||
[project]
|
||||
name = "test"
|
||||
"#,
|
||||
)?;
|
||||
|
||||
std::fs::write(
|
||||
context.join_project_path("foo.py").as_std_path(),
|
||||
"a = 10 / 0",
|
||||
)?;
|
||||
|
||||
std::fs::write(
|
||||
context.join_project_path("ty-override.toml").as_std_path(),
|
||||
r#"
|
||||
[rules]
|
||||
division-by-zero = "ignore"
|
||||
"#,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
let foo = case
|
||||
.system_file(case.project_path("foo.py"))
|
||||
.expect("foo.py to exist");
|
||||
let diagnostics = case.db().check_file(foo);
|
||||
|
||||
assert!(
|
||||
diagnostics.is_empty(),
|
||||
"Expected no diagnostics but got: {diagnostics:#?}"
|
||||
);
|
||||
|
||||
// Enable division-by-zero in the explicitly specified configuration with warning severity
|
||||
update_file(
|
||||
case.project_path("ty-override.toml"),
|
||||
r#"
|
||||
[rules]
|
||||
division-by-zero = "warn"
|
||||
"#,
|
||||
)?;
|
||||
|
||||
let changes = case.stop_watch(event_for_file("ty-override.toml"));
|
||||
|
||||
case.apply_changes(
|
||||
changes,
|
||||
Some(&ProjectOptionsOverrides::new(
|
||||
Some(case.project_path("ty-override.toml")),
|
||||
Options::default(),
|
||||
)),
|
||||
);
|
||||
|
||||
let diagnostics = case.db().check_file(foo);
|
||||
|
||||
|
@ -1855,7 +1925,7 @@ fn rename_files_casing_only() -> anyhow::Result<()> {
|
|||
}
|
||||
|
||||
let changes = case.stop_watch(event_for_file("Lib.py"));
|
||||
case.apply_changes(changes);
|
||||
case.apply_changes(changes, None);
|
||||
|
||||
// Resolving `lib` should now fail but `Lib` should now succeed
|
||||
assert_eq!(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue