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
20 changes: 19 additions & 1 deletion crates/vite_task/src/session/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,24 @@ pub enum CacheDisabledReason {
CycleDetected,
}

#[derive(Debug)]
pub enum CacheNotUpdatedReason {
/// Cache was hit - task was replayed from cache, no update needed
CacheHit,
/// Caching was disabled for this task
CacheDisabled,
/// Execution exited with non-zero status
NonZeroExitStatus,
}

#[derive(Debug)]
pub enum CacheUpdateStatus {
/// Cache was successfully updated with new fingerprint and outputs
Updated,
/// Cache was not updated (with reason)
NotUpdated(CacheNotUpdatedReason),
}

#[derive(Debug)]
pub enum CacheStatus {
Disabled(CacheDisabledReason),
Expand Down Expand Up @@ -50,5 +68,5 @@ pub enum ExecutionEventKind {
Start { display: Option<ExecutionItemDisplay>, cache_status: CacheStatus },
Output { kind: OutputKind, content: BString },
Error { message: String },
Finish { status: Option<i32> },
Finish { status: Option<i32>, cache_update_status: CacheUpdateStatus },
}
97 changes: 59 additions & 38 deletions crates/vite_task/src/session/execute/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ use self::{
use super::{
cache::{CommandCacheValue, ExecutionCache},
event::{
CacheDisabledReason, CacheStatus, ExecutionEvent, ExecutionEventKind, ExecutionId,
ExecutionItemDisplay, OutputKind,
CacheDisabledReason, CacheNotUpdatedReason, CacheStatus, CacheUpdateStatus, ExecutionEvent,
ExecutionEventKind, ExecutionId, ExecutionItemDisplay, OutputKind,
},
reporter::{ExitStatus, Reporter},
};
Expand Down Expand Up @@ -153,10 +153,15 @@ impl ExecutionContext<'_> {
},
});

// Emit Finish WITHOUT cache_status (already in Start event)
// Emit Finish with CacheDisabled status (in-process executions don't cache)
self.event_handler.handle_event(ExecutionEvent {
execution_id,
kind: ExecutionEventKind::Finish { status: Some(0) },
kind: ExecutionEventKind::Finish {
status: Some(0),
cache_update_status: CacheUpdateStatus::NotUpdated(
CacheNotUpdatedReason::CacheDisabled,
),
},
});
}
LeafExecutionKind::Spawn(spawn_execution) => {
Expand Down Expand Up @@ -228,10 +233,15 @@ impl ExecutionContext<'_> {
},
});
}
// Emit Finish without cache_status (status already in Start event)
// Emit Finish with CacheHit status (no cache update needed)
self.event_handler.handle_event(ExecutionEvent {
execution_id,
kind: ExecutionEventKind::Finish { status: Some(0) },
kind: ExecutionEventKind::Finish {
status: Some(0),
cache_update_status: CacheUpdateStatus::NotUpdated(
CacheNotUpdatedReason::CacheHit,
),
},
});
return Ok(());
}
Expand Down Expand Up @@ -276,51 +286,62 @@ impl ExecutionContext<'_> {
}
};

// 5. Update cache if successful
// Only update cache if: (a) tracking was enabled, and (b) execution succeeded
if let Some((track_result, cache_metadata)) = track_result_with_cache_metadata
&& result.exit_status.success()
// 5. Update cache if successful and determine cache update status
let cache_update_status = if let Some((track_result, cache_metadata)) =
track_result_with_cache_metadata
{
let fingerprint_ignores =
cache_metadata.spawn_fingerprint.fingerprint_ignores().map(|v| v.as_slice());
match PostRunFingerprint::create(
&track_result.path_reads,
&*self.cache_base_path,
fingerprint_ignores,
) {
Ok(post_run_fingerprint) => {
let cache_value = CommandCacheValue {
post_run_fingerprint,
std_outputs: track_result.std_outputs.clone().into(),
duration: result.duration,
};
if let Err(err) = self.cache.update(cache_metadata, cache_value).await {
if result.exit_status.success() {
// Execution succeeded, attempt cache update
let fingerprint_ignores =
cache_metadata.spawn_fingerprint.fingerprint_ignores().map(|v| v.as_slice());
match PostRunFingerprint::create(
&track_result.path_reads,
&*self.cache_base_path,
fingerprint_ignores,
) {
Ok(post_run_fingerprint) => {
let cache_value = CommandCacheValue {
post_run_fingerprint,
std_outputs: track_result.std_outputs.clone().into(),
duration: result.duration,
};
if let Err(err) = self.cache.update(cache_metadata, cache_value).await {
self.event_handler.handle_event(ExecutionEvent {
execution_id,
kind: ExecutionEventKind::Error {
message: format!("Failed to update cache: {err}"),
},
});
return Err(ExecutionAborted);
}
CacheUpdateStatus::Updated
}
Err(err) => {
self.event_handler.handle_event(ExecutionEvent {
execution_id,
kind: ExecutionEventKind::Error {
message: format!("Failed to update cache: {err}"),
message: format!("Failed to create post-run fingerprint: {err}"),
},
});
return Err(ExecutionAborted);
}
}
Err(err) => {
self.event_handler.handle_event(ExecutionEvent {
execution_id,
kind: ExecutionEventKind::Error {
message: format!("Failed to create post-run fingerprint: {err}"),
},
});
return Err(ExecutionAborted);
}
} else {
// Execution failed with non-zero exit status, don't update cache
CacheUpdateStatus::NotUpdated(CacheNotUpdatedReason::NonZeroExitStatus)
}
}
} else {
// Caching was disabled for this task
CacheUpdateStatus::NotUpdated(CacheNotUpdatedReason::CacheDisabled)
};

// 6. Emit finish WITHOUT cache_status
// Cache status was already emitted in Start event
// 6. Emit finish with cache_update_status
self.event_handler.handle_event(ExecutionEvent {
execution_id,
kind: ExecutionEventKind::Finish { status: result.exit_status.code() },
kind: ExecutionEventKind::Finish {
status: result.exit_status.code(),
cache_update_status,
},
});

Ok(())
Expand Down
2 changes: 1 addition & 1 deletion crates/vite_task/src/session/reporter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -489,7 +489,7 @@ impl<W: Write> Reporter for LabeledReporter<W> {
ExecutionEventKind::Error { message } => {
self.handle_error(event.execution_id, message);
}
ExecutionEventKind::Finish { status } => {
ExecutionEventKind::Finish { status, cache_update_status: _ } => {
self.handle_finish(event.execution_id, status);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
debugger;
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"name": "builtin-non-zero-exit-test"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[[e2e]]
name = "builtin command with non-zero exit does not show cache not updated"
steps = [
"vite lint -D no-debugger",
"vite lint -D no-debugger",
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
source: crates/vite_task_bin/tests/e2e_snapshots/main.rs
expression: e2e_outputs
input_file: crates/vite_task_bin/tests/e2e_snapshots/fixtures/builtin-non-zero-exit
---
[1]> vite lint -D no-debugger

x eslint(no-debugger): `debugger` statement is not allowed
,-[bad.js:1:1]
1 | debugger;
: ^^^^^^^^^
`----
help: Remove the debugger statement

Found 0 warnings and 1 error.
Finished in <duration> on 1 file with 90 rules using <n> threads.


[1]> vite lint -D no-debugger

x eslint(no-debugger): `debugger` statement is not allowed
,-[bad.js:1:1]
1 | debugger;
: ^^^^^^^^^
`----
help: Remove the debugger statement

Found 0 warnings and 1 error.
Finished in <duration> on 1 file with 90 rules using <n> threads.