Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fix-changed-deleted-file.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@biomejs/biome": patch
---

Fix `--changed` and `--staged` flags throwing "No such file or directory" error when a file has been deleted or renamed in the working directory. The CLI now filters out files that no longer exist before processing.
15 changes: 13 additions & 2 deletions crates/biome_cli/src/changed.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::CliDiagnostic;
use biome_configuration::Configuration;
use biome_fs::FileSystem;
use camino::Utf8Path;
use std::ffi::OsString;

pub(crate) fn get_changed_files(
Expand All @@ -26,15 +27,25 @@ pub(crate) fn get_changed_files(

let changed_files = fs.get_changed_files(base)?;

let filtered_changed_files = changed_files.iter().map(OsString::from).collect::<Vec<_>>();
// Filter out files that no longer exist (e.g., deleted or renamed in the working directory)
let filtered_changed_files = changed_files
.iter()
.filter(|file| fs.path_is_file(Utf8Path::new(file)))
.map(OsString::from)
.collect::<Vec<_>>();

Ok(filtered_changed_files)
}

pub(crate) fn get_staged_files(fs: &dyn FileSystem) -> Result<Vec<OsString>, CliDiagnostic> {
let staged_files = fs.get_staged_files()?;

let filtered_staged_files = staged_files.iter().map(OsString::from).collect::<Vec<_>>();
// Filter out files that no longer exist (e.g., deleted or renamed in the working directory)
let filtered_staged_files = staged_files
.iter()
.filter(|file| fs.path_is_file(Utf8Path::new(file)))
.map(OsString::from)
.collect::<Vec<_>>();

Ok(filtered_staged_files)
}
70 changes: 70 additions & 0 deletions crates/biome_cli/tests/commands/lint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3665,6 +3665,76 @@ fn should_error_if_unchanged_files_only_with_changed_flag() {
));
}

#[test]
fn should_skip_nonexistent_changed_files() {
let mut console = BufferConsole::default();
let mut fs = MemoryFileSystem::default();

// Git reports "deleted.js" as changed, but it doesn't exist in the working directory
fs.set_on_get_changed_files(Box::new(|| {
vec![String::from("exists.js"), String::from("deleted.js")]
}));

// Only "exists.js" exists in the file system
fs.insert(
Utf8Path::new("exists.js").into(),
r#"console.log('exists');"#.as_bytes(),
);
// Note: "deleted.js" is NOT inserted - simulating a deleted file

let (fs, result) = run_cli(
fs,
&mut console,
Args::from(["lint", "--changed", "--since=main"].as_slice()),
);

// Should succeed without "No such file or directory" error
assert!(result.is_ok(), "run_cli returned {result:?}");

assert_cli_snapshot(SnapshotPayload::new(
module_path!(),
"should_skip_nonexistent_changed_files",
fs,
console,
result,
));
}

#[test]
fn should_skip_nonexistent_staged_files() {
let mut console = BufferConsole::default();
let mut fs = MemoryFileSystem::default();

// Git reports "deleted.js" as staged, but it doesn't exist in the working directory
fs.set_on_get_staged_files(Box::new(|| {
vec![String::from("exists.js"), String::from("deleted.js")]
}));

// Only "exists.js" exists in the file system
fs.insert(
Utf8Path::new("exists.js").into(),
r#"console.log('exists');"#.as_bytes(),
);
// Note: "deleted.js" is NOT inserted - simulating a deleted file

let (fs, result) = run_cli(
fs,
&mut console,
Args::from(["lint", "--staged"].as_slice()),
);

// Should succeed without "No such file or directory" error
assert!(result.is_ok(), "run_cli returned {result:?}");

assert_cli_snapshot(SnapshotPayload::new(
module_path!(),
"should_skip_nonexistent_staged_files",
fs,
console,
result,
));
}

#[test]
fn linter_shows_the_default_severity_of_rule_on() {
let mut console = BufferConsole::default();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
source: crates/biome_cli/tests/snap_test.rs
expression: redactor(content)
---
## `exists.js`

```js
console.log('exists');
```

# Emitted Messages

```block
Checked 1 file in <TIME>. No fixes applied.
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
source: crates/biome_cli/tests/snap_test.rs
expression: redactor(content)
---
## `exists.js`

```js
console.log('exists');
```

# Emitted Messages

```block
Checked 1 file in <TIME>. No fixes applied.
```