Skip to content

refactor: improve watch mode - #9859

Merged
ematipico merged 1 commit into
nextfrom
feat/improve-watch-mode
Apr 8, 2026
Merged

refactor: improve watch mode#9859
ematipico merged 1 commit into
nextfrom
feat/improve-watch-mode

Conversation

@ematipico

@ematipico ematipico commented Apr 8, 2026

Copy link
Copy Markdown
Member

Summary

This PR improves the recently merged watcher mode by making it testable and predictable.

It also improves error handling by capturing possible errors emitted during the polling

Test Plan

Added a new test

Docs

@github-actions github-actions Bot added A-CLI Area: CLI A-Diagnostic Area: diagnostocis labels Apr 8, 2026
@ematipico
ematipico requested review from a team April 8, 2026 11:48
@codspeed-hq

codspeed-hq Bot commented Apr 8, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 58 untouched benchmarks
⏩ 168 skipped benchmarks1


Comparing feat/improve-watch-mode (6ec0d30) with next (e7872bf)

Open in CodSpeed

Footnotes

  1. 168 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@ematipico ematipico added this to the Biome v2.5 milestone Apr 8, 2026

@siketyan siketyan left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thank you!

@coderabbitai

coderabbitai Bot commented Apr 8, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

This pull request refactors the file watcher infrastructure in the Biome CLI. It introduces a trait-based watcher abstraction with improved error handling by replacing a simple event struct with an enum distinguishing between Changed and Error variants. The CommandRunner trait's generic watcher type constraint is removed in favour of boxed trait objects. A new MockWatcher implementation enables testing with injected events. The notify crate is added as an optional dependency with corresponding feature flags in both biome_cli and biome_diagnostics crates, along with a new WatcherDiagnostic type for file-watching errors. Test infrastructure is extended with a watcher factory injection helper.

Possibly related PRs

Suggested labels

A-CLI, A-Project

Suggested reviewers

  • dyc3
🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarises the main objective: refactoring the watch mode implementation to improve testability and error handling.
Description check ✅ Passed The description is directly related to the changeset, explaining the motivation for improving watch mode testability and error handling, and mentions a new test.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/improve-watch-mode

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (1)
crates/biome_cli/src/runner/diagnostics.rs (1)

152-155: Consider tightening visibility on WatcherDiagnostic.

Given runner is crate-private, pub(crate) here would better signal intent and avoid accidental API creep.

Small visibility tidy-up
-pub struct WatcherDiagnostic {
+pub(crate) struct WatcherDiagnostic {
     #[source]
     pub(crate) source: Option<Error>,
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_cli/src/runner/diagnostics.rs` around lines 152 - 155,
WatcherDiagnostic is declared public but the runner module is crate-private;
change its visibility to pub(crate) and make its field source also pub(crate)
(or keep it private if not accessed outside the crate) to avoid API creep—locate
the struct WatcherDiagnostic and update its declaration and the #[source]
pub(crate) source: Option<Error> visibility accordingly so the type and its
source field are crate-scoped.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@crates/biome_cli/src/runner/impls/watchers/default.rs`:
- Around line 17-21: The constructor new() currently calls
recommended_watcher(tx).expect("watcher created") which panics on failure;
change new() to return a Result<Self, WatcherError> (or the runner's existing
error type) and propagate the error from recommended_watcher instead of
unwrapping, e.g. call recommended_watcher(tx)? and map or convert its error into
the runner/watcher error plumbing; update the type of new, and the caller(s)
that construct DefaultWatcher to handle the Result so the watcher creation error
is surfaced as a diagnostic rather than panicking.

In `@crates/biome_cli/src/runner/watcher.rs`:
- Around line 9-11: The Watcher trait's watch registration can fail but
currently returns ()—change the signature of fn watch(&mut self, paths:
Vec<Utf8PathBuf>) to return a Result (e.g., Result<(), WatchError> or
anyhow::Result<()>) so implementations can surface registration errors; update
all impls of Watcher (and any callers) to propagate or handle that Result, and
ensure the CLI checks the returned Result from watch() and handles failures
before calling or printing the watch banner and before starting poll() (or
calling fn poll(&mut self) if present).

In `@crates/biome_cli/tests/cases/watcher.rs`:
- Around line 21-25: The current test only produces WatcherEvent::Changed and
never exercises the new WatcherEvent::Error branch; add a small companion test
(or extend the existing one) that sets the seed to include
WatcherEvent::Error(...) (using MockWatcher::with_events via the existing
watcher_factory pattern) so the runner's error handling path is hit, then assert
the diagnostic/error message is emitted to the console capture used by the test
(verify the diagnostic string that runner/mod.rs emits). Ensure the test uses
the same Mutex/seed/watcher_factory setup and asserts the expected console
output for the error event.

---

Nitpick comments:
In `@crates/biome_cli/src/runner/diagnostics.rs`:
- Around line 152-155: WatcherDiagnostic is declared public but the runner
module is crate-private; change its visibility to pub(crate) and make its field
source also pub(crate) (or keep it private if not accessed outside the crate) to
avoid API creep—locate the struct WatcherDiagnostic and update its declaration
and the #[source] pub(crate) source: Option<Error> visibility accordingly so the
type and its source field are crate-scoped.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ba534f41-8a90-4d3f-8c56-a3524e9d698b

📥 Commits

Reviewing files that changed from the base of the PR and between e7872bf and 6ec0d30.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock and included by **
📒 Files selected for processing (16)
  • crates/biome_cli/Cargo.toml
  • crates/biome_cli/src/lib.rs
  • crates/biome_cli/src/runner/diagnostics.rs
  • crates/biome_cli/src/runner/impls/commands/custom_execution.rs
  • crates/biome_cli/src/runner/impls/commands/traversal.rs
  • crates/biome_cli/src/runner/impls/watchers/default.rs
  • crates/biome_cli/src/runner/impls/watchers/mock.rs
  • crates/biome_cli/src/runner/impls/watchers/mod.rs
  • crates/biome_cli/src/runner/mod.rs
  • crates/biome_cli/src/runner/watcher.rs
  • crates/biome_cli/tests/cases/mod.rs
  • crates/biome_cli/tests/cases/watcher.rs
  • crates/biome_cli/tests/main.rs
  • crates/biome_diagnostics/Cargo.toml
  • crates/biome_diagnostics/src/adapters.rs
  • crates/biome_diagnostics/src/lib.rs
💤 Files with no reviewable changes (2)
  • crates/biome_cli/src/runner/impls/commands/custom_execution.rs
  • crates/biome_cli/src/runner/impls/commands/traversal.rs

Comment thread crates/biome_cli/src/runner/impls/watchers/default.rs
Comment on lines +9 to +11
pub trait Watcher {
/// Start watching file changes under the paths recursively.
fn watch(&mut self, paths: impl IntoIterator<Item = Utf8PathBuf>);
fn watch(&mut self, paths: Vec<Utf8PathBuf>);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

watch() needs a synchronous error path.

Registering the watch roots can fail before poll() is ever called. With fn watch(&mut self, ...) returning (), implementations have nowhere to surface that, so the CLI can carry on into watch mode after registration already failed. Please return a Result here and handle it before printing the watch banner.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_cli/src/runner/watcher.rs` around lines 9 - 11, The Watcher
trait's watch registration can fail but currently returns ()—change the
signature of fn watch(&mut self, paths: Vec<Utf8PathBuf>) to return a Result
(e.g., Result<(), WatchError> or anyhow::Result<()>) so implementations can
surface registration errors; update all impls of Watcher (and any callers) to
propagate or handle that Result, and ensure the CLI checks the returned Result
from watch() and handles failures before calling or printing the watch banner
and before starting poll() (or calling fn poll(&mut self) if present).

Comment on lines +21 to +25
let seed = Mutex::new(Some(vec![WatcherEvent::Changed(vec![bad_path.clone()])]));
let watcher_factory = Box::new(move || {
let events = seed.lock().unwrap().take().unwrap_or_default();
Box::new(MockWatcher::with_events(events)) as Box<dyn biome_cli::Watcher>
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Please exercise the error branch too.

This only scripts WatcherEvent::Changed(...), so the new WatcherEvent::Error(...) path in crates/biome_cli/src/runner/mod.rs is still unpinned. A tiny companion test that injects one error event and asserts the diagnostic reaches the console would close the gap nicely. As per coding guidelines, "All code changes MUST include appropriate tests".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_cli/tests/cases/watcher.rs` around lines 21 - 25, The current
test only produces WatcherEvent::Changed and never exercises the new
WatcherEvent::Error branch; add a small companion test (or extend the existing
one) that sets the seed to include WatcherEvent::Error(...) (using
MockWatcher::with_events via the existing watcher_factory pattern) so the
runner's error handling path is hit, then assert the diagnostic/error message is
emitted to the console capture used by the test (verify the diagnostic string
that runner/mod.rs emits). Ensure the test uses the same
Mutex/seed/watcher_factory setup and asserts the expected console output for the
error event.

@ematipico
ematipico merged commit e6d7eb0 into next Apr 8, 2026
32 checks passed
@ematipico
ematipico deleted the feat/improve-watch-mode branch April 8, 2026 14:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-CLI Area: CLI A-Diagnostic Area: diagnostocis

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants