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(cli): execute commands without file paths #2726

Merged
merged 13 commits into from
May 6, 2024
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,15 @@ our [guidelines for writing a good changelog entry](https://github.com/biomejs/b

### CLI

#### Enhancements

- Biome now executes commands (lint, format, check and ci) on the working directory by default. [#2266](https://github.com/biomejs/biome/issues/2266) Contributed by @unvalley

```diff
- biome check .
+ biome check # You can run the command without the path
```

### Configuration

### Editors
Expand Down
30 changes: 21 additions & 9 deletions crates/biome_cli/src/execute/traverse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use crossbeam::channel::{unbounded, Receiver, Sender};
use rustc_hash::FxHashSet;
use std::sync::atomic::AtomicU32;
use std::{
env::current_dir,
ffi::OsString,
panic::catch_unwind,
path::{Path, PathBuf},
Expand All @@ -32,17 +33,28 @@ pub(crate) fn traverse(
execution: &Execution,
session: &mut CliSession,
cli_options: &CliOptions,
inputs: Vec<OsString>,
mut inputs: Vec<OsString>,
) -> Result<(TraversalSummary, Vec<Error>), CliDiagnostic> {
init_thread_pool();
if inputs.is_empty()
&& execution.as_stdin_file().is_none()
&& !cli_options.no_errors_on_unmatched
{
return Err(CliDiagnostic::missing_argument(
"<INPUT>",
format!("{}", execution.traversal_mode),
));

if inputs.is_empty() {
match execution.traversal_mode {
TraversalMode::Check { .. }
unvalley marked this conversation as resolved.
Show resolved Hide resolved
| TraversalMode::Lint { .. }
| TraversalMode::Format { .. }
| TraversalMode::CI { .. } => match current_dir() {
Ok(current_dir) => inputs.push(current_dir.into_os_string()),
Copy link
Contributor

Choose a reason for hiding this comment

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

Could we use the relative path instead of the absolute path here? It seems that our globs don't work well with absolute paths.

Copy link
Member Author

Choose a reason for hiding this comment

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

If we remove the prefix of the current_dir, I think it would be the relative path. I'll check that.

Copy link
Member

Choose a reason for hiding this comment

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

This could also improve hyperlinks in the CLI: generally IDE expects relative paths.

Err(err) => return Err(CliDiagnostic::io_error(err)),
},
_ => {
if execution.as_stdin_file().is_none() && !cli_options.no_errors_on_unmatched {
return Err(CliDiagnostic::missing_argument(
"<INPUT>",
format!("{}", execution.traversal_mode),
));
}
}
}
}

let (interner, recv_files) = PathInterner::new();
Expand Down
25 changes: 25 additions & 0 deletions crates/biome_cli/tests/commands/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2897,3 +2897,28 @@ fn print_json_pretty() {
result,
));
}

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

let file_path = Path::new("check.js");
fs.insert(file_path.into(), LINT_ERROR.as_bytes());

let result: Result<(), biome_cli::CliDiagnostic> = run_cli(
DynRef::Borrowed(&mut fs),
&mut console,
Args::from([("check"), ""].as_slice()),
);

assert!(result.is_err(), "run_cli returned {result:?}");

assert_cli_snapshot(SnapshotPayload::new(
module_path!(),
"lint_error_without_file_paths",
fs,
console,
result,
));
}
25 changes: 25 additions & 0 deletions crates/biome_cli/tests/commands/ci.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1025,3 +1025,28 @@ A = 0;
result,
));
}

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

let file_path = Path::new("ci.js");
fs.insert(file_path.into(), UNFORMATTED.as_bytes());

let result = run_cli(
DynRef::Borrowed(&mut fs),
&mut console,
Args::from([("ci"), ""].as_slice()),
);

assert!(result.is_err(), "run_cli returned {result:?}");

assert_cli_snapshot(SnapshotPayload::new(
module_path!(),
"does_formatting_error_without_file_paths",
fs,
console,
result,
));
}
27 changes: 27 additions & 0 deletions crates/biome_cli/tests/commands/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3585,3 +3585,30 @@ fn print_json_pretty() {
result,
));
}

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

let file_path = Path::new("format.js");
fs.insert(file_path.into(), UNFORMATTED.as_bytes());

let result: Result<(), biome_cli::CliDiagnostic> = run_cli(
DynRef::Borrowed(&mut fs),
&mut console,
Args::from([("format"), ""].as_slice()),
);

assert!(result.is_err(), "run_cli returned {result:?}");

assert_file_contents(&fs, file_path, UNFORMATTED);

assert_cli_snapshot(SnapshotPayload::new(
module_path!(),
"format_without_file_paths",
fs,
console,
result,
));
}
27 changes: 26 additions & 1 deletion crates/biome_cli/tests/commands/lint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1966,7 +1966,7 @@ fn group_level_recommended_false_enable_specific() {
let code = r#"
function SubmitButton() {
return <button>Submit</button>;
}
}
unvalley marked this conversation as resolved.
Show resolved Hide resolved
"#;

let file_path = Path::new("fix.jsx");
Expand Down Expand Up @@ -3246,3 +3246,28 @@ import "lodash";
result,
));
}

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

let file_path = Path::new("check.js");
fs.insert(file_path.into(), LINT_ERROR.as_bytes());

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

assert!(result.is_err(), "run_cli returned {result:?}");

assert_cli_snapshot(SnapshotPayload::new(
module_path!(),
"lint_error_without_file_paths",
fs,
console,
result,
));
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
---
source: crates/biome_cli/tests/snap_test.rs
expression: content
---
## `check.js`

```js
for(;true;);

```

# Termination Message

```block
check ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

× Some errors were emitted while running checks.



```

# Emitted Messages

```block
check.js:1:1 lint/style/useWhile FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

× Use a while loop instead of a for loop.

> 1 │ for(;true;);
│ ^^^^^^^^^^^
2 │

i Prefer a while loop over a for loop without initialization and update.

i Safe fix: Use a while loop.

1 │ - for(;true;);
1 │ + while(true);
2 2 │


```

```block
check.js:1:6 lint/correctness/noConstantCondition ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

× Unexpected constant condition.

> 1 │ for(;true;);
│ ^^^^
2 │


```

```block
check.js format ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

× Formatter would have printed the following content:

1 │ for·(;·true;·);
│ + + +

```

```block
Checked 1 file in <TIME>. No fixes needed.
Found 3 errors.
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
source: crates/biome_cli/tests/snap_test.rs
expression: content
---
## `ci.js`

```js
statement( )
```

# Termination Message

```block
ci ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

× Some errors were emitted while running checks.



```

# Emitted Messages

```block
ci.js format ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

× File content differs from formatting output

1 │ - ··statement(··)··
1 │ + statement();
2 │ +


```

```block
Checked 1 file in <TIME>. No fixes needed.
Found 1 error.
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
source: crates/biome_cli/tests/snap_test.rs
expression: content
---
## `format.js`

```js
statement( )
```

# Termination Message

```block
format ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

× Some errors were emitted while running checks.



```

# Emitted Messages

```block
format.js format ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

× Formatter would have printed the following content:

1 │ - ··statement(··)··
1 │ + statement();
2 │ +


```

```block
Checked 1 file in <TIME>. No fixes needed.
Found 1 error.
```
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ expression: content

function SubmitButton() {
return <button>Submit</button>;
}
}

```

Expand All @@ -48,7 +48,7 @@ fix.jsx:3:16 lint/a11y/useButtonType ━━━━━━━━━━━━━━
2 │ function SubmitButton() {
> 3 │ return <button>Submit</button>;
│ ^^^^^^^^
4 │ }····
4 │ }
5 │

i The default type of a button is submit, which causes the submission of a form when placed inside a `form` element. This is likely not the behaviour that you want inside a React application.
Expand Down
Loading