Skip to content

Commit a6c49eb

Browse files
authored
refactor: replace error strings in reporter with ExecutionError enum (#159)
## Summary - Add typed `ExecutionError` enum (with `thiserror`) to replace the four hardcoded error format strings passed through `LeafExecutionReporter::finish()` - Combine cache lookup and cache update failures into a single `Cache { kind, source }` variant with a `CacheErrorKind` sub-enum - Reporter converts the error chain to a display string at the boundary using anyhow's `{:#}` formatter, preserving existing output format
1 parent d47a293 commit a6c49eb

File tree

5 files changed

+68
-20
lines changed

5 files changed

+68
-20
lines changed

crates/vite_task/src/session/event.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,47 @@ use std::{process::ExitStatus, time::Duration};
22

33
use super::cache::CacheMiss;
44

5+
/// The cache operation that failed.
6+
#[derive(Debug)]
7+
pub enum CacheErrorKind {
8+
/// Cache lookup (`try_hit`) failed.
9+
Lookup,
10+
/// Writing the cache entry failed after successful execution.
11+
Update,
12+
}
13+
14+
impl std::fmt::Display for CacheErrorKind {
15+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
16+
match self {
17+
Self::Lookup => f.write_str("lookup"),
18+
Self::Update => f.write_str("update"),
19+
}
20+
}
21+
}
22+
23+
/// Error that occurred during a leaf execution.
24+
///
25+
/// Reported through [`super::reporter::LeafExecutionReporter::finish()`] and
26+
/// displayed by the reporter.
27+
#[derive(Debug, thiserror::Error)]
28+
pub enum ExecutionError {
29+
/// A cache operation failed.
30+
#[error("Cache {kind} failed")]
31+
Cache {
32+
kind: CacheErrorKind,
33+
#[source]
34+
source: anyhow::Error,
35+
},
36+
37+
/// The OS failed to spawn the child process (e.g., command not found).
38+
#[error("Failed to spawn process")]
39+
Spawn(#[source] anyhow::Error),
40+
41+
/// Creating the post-run fingerprint failed after successful execution.
42+
#[error("Failed to create post-run fingerprint")]
43+
PostRunFingerprint(#[source] anyhow::Error),
44+
}
45+
546
#[derive(Debug)]
647
pub enum OutputKind {
748
Stdout,

crates/vite_task/src/session/execute/mod.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ use self::{
1414
use super::{
1515
cache::{CommandCacheValue, ExecutionCache},
1616
event::{
17-
CacheDisabledReason, CacheNotUpdatedReason, CacheStatus, CacheUpdateStatus, OutputKind,
17+
CacheDisabledReason, CacheErrorKind, CacheNotUpdatedReason, CacheStatus, CacheUpdateStatus,
18+
ExecutionError, OutputKind,
1819
},
1920
reporter::{
2021
ExitStatus, GraphExecutionReporter, GraphExecutionReporterBuilder, LeafExecutionPath,
@@ -186,7 +187,7 @@ pub async fn execute_spawn(
186187
leaf_reporter.finish(
187188
None,
188189
CacheUpdateStatus::NotUpdated(CacheNotUpdatedReason::CacheDisabled),
189-
Some(vite_str::format!("Cache lookup failed: {err}")),
190+
Some(ExecutionError::Cache { kind: CacheErrorKind::Lookup, source: err }),
190191
);
191192
return SpawnOutcome::Failed;
192193
}
@@ -263,7 +264,7 @@ pub async fn execute_spawn(
263264
leaf_reporter.finish(
264265
None,
265266
CacheUpdateStatus::NotUpdated(CacheNotUpdatedReason::CacheDisabled),
266-
Some(vite_str::format!("Failed to spawn process: {err}")),
267+
Some(ExecutionError::Spawn(err)),
267268
);
268269
return SpawnOutcome::Failed;
269270
}
@@ -293,13 +294,16 @@ pub async fn execute_spawn(
293294
Ok(()) => (CacheUpdateStatus::Updated, None),
294295
Err(err) => (
295296
CacheUpdateStatus::NotUpdated(CacheNotUpdatedReason::CacheDisabled),
296-
Some(vite_str::format!("Failed to update cache: {err}")),
297+
Some(ExecutionError::Cache {
298+
kind: CacheErrorKind::Update,
299+
source: err,
300+
}),
297301
),
298302
}
299303
}
300304
Err(err) => (
301305
CacheUpdateStatus::NotUpdated(CacheNotUpdatedReason::CacheDisabled),
302-
Some(vite_str::format!("Failed to create post-run fingerprint: {err}")),
306+
Some(ExecutionError::PostRunFingerprint(err)),
303307
),
304308
}
305309
} else {

crates/vite_task/src/session/reporter/labeled.rs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use super::{
2525
};
2626
use crate::session::{
2727
cache::format_cache_status_summary,
28-
event::{CacheStatus, CacheUpdateStatus, OutputKind, exit_status_to_code},
28+
event::{CacheStatus, CacheUpdateStatus, ExecutionError, OutputKind, exit_status_to_code},
2929
};
3030

3131
/// Information tracked for each leaf execution, used in the final summary.
@@ -273,29 +273,32 @@ impl<W: Write> LeafExecutionReporter for LabeledLeafReporter<W> {
273273
self: Box<Self>,
274274
status: Option<StdExitStatus>,
275275
_cache_update_status: CacheUpdateStatus,
276-
error: Option<Str>,
276+
error: Option<ExecutionError>,
277277
) {
278278
let mut shared = self.shared.borrow_mut();
279279

280-
// Handle errors
281-
if let Some(ref message) = error {
282-
write_error_message(&mut shared.writer, message);
280+
// Handle errors — format the full error chain using anyhow's `{:#}` formatter
281+
// (joins cause chain with `: ` separators).
282+
let has_error = error.is_some();
283+
if let Some(error) = error {
284+
let message: Str = vite_str::format!("{:#}", anyhow::Error::from(error));
285+
write_error_message(&mut shared.writer, &message);
283286

284287
// Update the execution info if start() was called (an entry was pushed).
285288
// Without the `self.started` guard, `last_mut()` would return a
286289
// *different* execution's entry, corrupting its error_message.
287290
if self.started
288291
&& let Some(exec) = shared.executions.last_mut()
289292
{
290-
exec.error_message = Some(message.clone());
293+
exec.error_message = Some(message);
291294
}
292295

293296
shared.stats.failed += 1;
294297
}
295298

296299
// Update failure statistics for non-zero exit status (not an error, just a failed task)
297300
// None means success (cache hit or in-process), Some checks the actual exit status
298-
if error.is_none() && status.is_some_and(|s| !s.success()) {
301+
if !has_error && status.is_some_and(|s| !s.success()) {
299302
shared.stats.failed += 1;
300303
}
301304

crates/vite_task/src/session/reporter/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ use vite_task_plan::{ExecutionGraph, ExecutionItem, ExecutionItemDisplay, Execut
4242

4343
use super::{
4444
cache::format_cache_status_inline,
45-
event::{CacheStatus, CacheUpdateStatus, OutputKind},
45+
event::{CacheStatus, CacheUpdateStatus, ExecutionError, OutputKind},
4646
};
4747

4848
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
@@ -241,7 +241,7 @@ pub trait LeafExecutionReporter {
241241
self: Box<Self>,
242242
status: Option<StdExitStatus>,
243243
cache_update_status: CacheUpdateStatus,
244-
error: Option<Str>,
244+
error: Option<ExecutionError>,
245245
);
246246
}
247247

crates/vite_task/src/session/reporter/plain.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,9 @@
66
use std::io::Write;
77

88
use bstr::BString;
9-
use vite_str::Str;
109

1110
use super::{LeafExecutionReporter, StdinSuggestion, write_cache_hit_message, write_error_message};
12-
use crate::session::event::{CacheStatus, CacheUpdateStatus, OutputKind};
11+
use crate::session::event::{CacheStatus, CacheUpdateStatus, ExecutionError, OutputKind};
1312

1413
/// A self-contained [`LeafExecutionReporter`] for single-leaf executions
1514
/// (e.g., `execute_synthetic`).
@@ -71,11 +70,12 @@ impl<W: Write> LeafExecutionReporter for PlainReporter<W> {
7170
mut self: Box<Self>,
7271
_status: Option<std::process::ExitStatus>,
7372
_cache_update_status: CacheUpdateStatus,
74-
error: Option<Str>,
73+
error: Option<ExecutionError>,
7574
) {
76-
// Handle errors — print inline error message
77-
if let Some(ref message) = error {
78-
write_error_message(&mut self.writer, message);
75+
// Handle errors — format the full error chain and print inline.
76+
if let Some(error) = error {
77+
let message = vite_str::format!("{:#}", anyhow::Error::from(error));
78+
write_error_message(&mut self.writer, &message);
7979
return;
8080
}
8181

0 commit comments

Comments
 (0)