diff --git a/Cargo.lock b/Cargo.lock index cc0b85be..fb99639a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1176,6 +1176,7 @@ dependencies = [ "test-log", "thiserror 2.0.18", "tokio", + "tokio-util", "which", "winapi", "winsafe 0.0.24", @@ -1200,6 +1201,7 @@ dependencies = [ "rustc-hash", "serde", "tokio", + "tokio-util", "toml", ] @@ -3874,6 +3876,7 @@ dependencies = [ "nix 0.30.1", "once_cell", "owo-colors", + "petgraph", "pty_terminal_test_client", "rayon", "rusqlite", @@ -3883,6 +3886,7 @@ dependencies = [ "tempfile", "thiserror 2.0.18", "tokio", + "tokio-util", "tracing", "twox-hash", "vite_path", diff --git a/crates/fspy/Cargo.toml b/crates/fspy/Cargo.toml index 6b5869bc..1c50bbbc 100644 --- a/crates/fspy/Cargo.toml +++ b/crates/fspy/Cargo.toml @@ -19,7 +19,8 @@ rand = { workspace = true } rustc-hash = { workspace = true } tempfile = { workspace = true } thiserror = { workspace = true } -tokio = { workspace = true, features = ["net", "process", "io-util", "sync", "rt"] } +tokio = { workspace = true, features = ["net", "process", "io-util", "sync", "rt", "macros"] } +tokio-util = { workspace = true } which = { workspace = true, features = ["tracing"] } xxhash-rust = { workspace = true } diff --git a/crates/fspy/examples/cli.rs b/crates/fspy/examples/cli.rs index 1de519c0..4ae34790 100644 --- a/crates/fspy/examples/cli.rs +++ b/crates/fspy/examples/cli.rs @@ -18,7 +18,7 @@ async fn main() -> anyhow::Result<()> { let mut command = fspy::Command::new(program); command.envs(std::env::vars_os()).args(args); - let child = command.spawn().await?; + let child = command.spawn(tokio_util::sync::CancellationToken::new()).await?; let termination = child.wait_handle.await?; let mut path_count = 0usize; diff --git a/crates/fspy/src/command.rs b/crates/fspy/src/command.rs index 5e9900c9..7010560b 100644 --- a/crates/fspy/src/command.rs +++ b/crates/fspy/src/command.rs @@ -8,6 +8,7 @@ use std::{ use fspy_shared_unix::exec::Exec; use rustc_hash::FxHashMap; use tokio::process::Command as TokioCommand; +use tokio_util::sync::CancellationToken; use crate::{SPY_IMPL, TrackedChild, error::SpawnError}; @@ -167,9 +168,12 @@ impl Command { /// # Errors /// /// Returns [`SpawnError`] if program resolution fails or the process cannot be spawned. - pub async fn spawn(mut self) -> Result { + pub async fn spawn( + mut self, + cancel_token: CancellationToken, + ) -> Result { self.resolve_program()?; - SPY_IMPL.spawn(self).await + SPY_IMPL.spawn(self, cancel_token).await } /// Resolve program name to full path using `PATH` and cwd. diff --git a/crates/fspy/src/unix/mod.rs b/crates/fspy/src/unix/mod.rs index 96583f04..cdf6253e 100644 --- a/crates/fspy/src/unix/mod.rs +++ b/crates/fspy/src/unix/mod.rs @@ -67,7 +67,11 @@ impl SpyImpl { }) } - pub(crate) async fn spawn(&self, mut command: Command) -> Result { + pub(crate) async fn spawn( + &self, + mut command: Command, + cancel_token: tokio_util::sync::CancellationToken, + ) -> Result { #[cfg(target_os = "linux")] let supervisor = supervise::().map_err(SpawnError::Supervisor)?; @@ -129,7 +133,13 @@ impl SpyImpl { // Keep polling for the child to exit in the background even if `wait_handle` is not awaited, // because we need to stop the supervisor and lock the channel as soon as the child exits. wait_handle: tokio::spawn(async move { - let status = child.wait().await?; + let status = tokio::select! { + status = child.wait() => status?, + () = cancel_token.cancelled() => { + let _ = child.start_kill(); + child.wait().await? + } + }; let arenas = std::iter::once(exec_resolve_accesses); // Stop the supervisor and collect path accesses from it. diff --git a/crates/fspy/src/windows/mod.rs b/crates/fspy/src/windows/mod.rs index b4f1c75e..8da5333b 100644 --- a/crates/fspy/src/windows/mod.rs +++ b/crates/fspy/src/windows/mod.rs @@ -73,7 +73,11 @@ impl SpyImpl { } #[expect(clippy::unused_async, reason = "async signature required by SpyImpl trait")] - pub(crate) async fn spawn(&self, mut command: Command) -> Result { + pub(crate) async fn spawn( + &self, + mut command: Command, + cancel_token: tokio_util::sync::CancellationToken, + ) -> Result { let ansi_dll_path_with_nul = Arc::clone(&self.ansi_dll_path_with_nul); command.env("FSPY", "1"); let mut command = command.into_tokio_command(); @@ -142,7 +146,13 @@ impl SpyImpl { // Keep polling for the child to exit in the background even if `wait_handle` is not awaited, // because we need to stop the supervisor and lock the channel as soon as the child exits. wait_handle: tokio::spawn(async move { - let status = child.wait().await?; + let status = tokio::select! { + status = child.wait() => status?, + () = cancel_token.cancelled() => { + let _ = child.start_kill(); + child.wait().await? + } + }; // Lock the ipc channel after the child has exited. // We are not interested in path accesses from descendants after the main child has exited. let ipc_receiver_lock_guard = OwnedReceiverLockGuard::lock_async(receiver).await?; diff --git a/crates/fspy/tests/node_fs.rs b/crates/fspy/tests/node_fs.rs index bbbb2bb5..6f2afb95 100644 --- a/crates/fspy/tests/node_fs.rs +++ b/crates/fspy/tests/node_fs.rs @@ -16,7 +16,7 @@ async fn track_node_script(script: &str, args: &[&OsStr]) -> anyhow::Result anyhow::Result) -> PathAccessIterable cmd.current_dir(cwd); } cmd.args(args); - let tracked_child = cmd.spawn().await.unwrap(); + let tracked_child = cmd.spawn(tokio_util::sync::CancellationToken::new()).await.unwrap(); let termination = tracked_child.wait_handle.await.unwrap(); assert!(termination.status.success()); diff --git a/crates/fspy/tests/test_utils/mod.rs b/crates/fspy/tests/test_utils/mod.rs index 20e7a2c4..cfa46c4a 100644 --- a/crates/fspy/tests/test_utils/mod.rs +++ b/crates/fspy/tests/test_utils/mod.rs @@ -78,7 +78,11 @@ macro_rules! track_fn { )] #[allow(dead_code, reason = "used by track_fn! macro; not all test files use this macro")] pub async fn spawn_command(cmd: subprocess_test::Command) -> anyhow::Result { - let termination = fspy::Command::from(cmd).spawn().await?.wait_handle.await?; + let termination = fspy::Command::from(cmd) + .spawn(tokio_util::sync::CancellationToken::new()) + .await? + .wait_handle + .await?; assert!(termination.status.success()); Ok(termination.path_accesses) } diff --git a/crates/fspy_e2e/Cargo.toml b/crates/fspy_e2e/Cargo.toml index db8833ee..90ece05e 100644 --- a/crates/fspy_e2e/Cargo.toml +++ b/crates/fspy_e2e/Cargo.toml @@ -9,6 +9,7 @@ fspy = { workspace = true } rustc-hash = { workspace = true } serde = { workspace = true, features = ["derive"] } tokio = { workspace = true, features = ["full"] } +tokio-util = { workspace = true } toml = { workspace = true } [lints] diff --git a/crates/fspy_e2e/src/main.rs b/crates/fspy_e2e/src/main.rs index 8e9f1c59..9d6a3052 100644 --- a/crates/fspy_e2e/src/main.rs +++ b/crates/fspy_e2e/src/main.rs @@ -84,7 +84,8 @@ async fn main() { .stderr(Stdio::piped()) .current_dir(&dir); - let mut tracked_child = cmd.spawn().await.unwrap(); + let mut tracked_child = + cmd.spawn(tokio_util::sync::CancellationToken::new()).await.unwrap(); let mut stdout_bytes = Vec::::new(); tracked_child.stdout.take().unwrap().read_to_end(&mut stdout_bytes).await.unwrap(); diff --git a/crates/vite_task/Cargo.toml b/crates/vite_task/Cargo.toml index 8d33be3c..933be0cc 100644 --- a/crates/vite_task/Cargo.toml +++ b/crates/vite_task/Cargo.toml @@ -22,6 +22,7 @@ fspy = { workspace = true } futures-util = { workspace = true } once_cell = { workspace = true } owo-colors = { workspace = true } +petgraph = { workspace = true } pty_terminal_test_client = { workspace = true } rayon = { workspace = true } rusqlite = { workspace = true, features = ["bundled"] } @@ -30,6 +31,7 @@ serde = { workspace = true, features = ["derive", "rc"] } serde_json = { workspace = true } thiserror = { workspace = true } tokio = { workspace = true, features = ["rt-multi-thread", "io-std", "io-util", "macros", "sync"] } +tokio-util = { workspace = true } tracing = { workspace = true } twox-hash = { workspace = true } vite_path = { workspace = true } diff --git a/crates/vite_task/src/cli/mod.rs b/crates/vite_task/src/cli/mod.rs index 07ca39c2..bf0ec65f 100644 --- a/crates/vite_task/src/cli/mod.rs +++ b/crates/vite_task/src/cli/mod.rs @@ -1,4 +1,4 @@ -use std::sync::Arc; +use std::{num::NonZeroUsize, str::FromStr, sync::Arc}; use clap::Parser; use vite_path::AbsolutePath; @@ -7,6 +7,35 @@ use vite_task_graph::{TaskSpecifier, query::TaskQuery}; use vite_task_plan::plan_request::{CacheOverride, PlanOptions, QueryPlanRequest}; use vite_workspace::package_filter::{PackageQueryArgs, PackageQueryError}; +/// Parsed `--concurrency` value: a positive integer or a percentage of logical CPUs. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct Concurrency(pub usize); + +impl FromStr for Concurrency { + type Err = ConcurrencyParseError; + + fn from_str(s: &str) -> Result { + if let Some(pct) = s.strip_suffix('%') { + let pct_val: u32 = pct.parse().map_err(|_| ConcurrencyParseError(s.into()))?; + let cpus = std::thread::available_parallelism().map(NonZeroUsize::get).unwrap_or(1); + let result = (cpus as u64 * u64::from(pct_val) / 100).max(1) as usize; + Ok(Self(result)) + } else { + let val: usize = s.parse().map_err(|_| ConcurrencyParseError(s.into()))?; + if val == 0 { + return Err(ConcurrencyParseError(s.into())); + } + Ok(Self(val)) + } + } +} + +#[derive(Debug, thiserror::Error)] +#[error( + "invalid concurrency value '{0}': expected a positive integer or a percentage (e.g. '4' or '50%')" +)] +pub struct ConcurrencyParseError(Str); + #[derive(Debug, Clone, clap::Subcommand)] pub enum CacheSubcommand { /// Clean up all the cache @@ -35,6 +64,11 @@ pub struct RunFlags { /// Force caching off for all tasks and scripts. #[clap(long, conflicts_with = "cache")] pub no_cache: bool, + + /// Maximum number of tasks to run concurrently (default: 10). + /// Accepts a number (e.g. 4) or a percentage of logical CPUs (e.g. 50%). + #[clap(long)] + pub concurrency: Option, } impl RunFlags { @@ -193,6 +227,7 @@ impl ResolvedRunCommand { plan_options: PlanOptions { extra_args: self.additional_args.into(), cache_override, + concurrency: self.flags.concurrency.map(|c| c.0), }, }, is_cwd_only, diff --git a/crates/vite_task/src/session/execute/mod.rs b/crates/vite_task/src/session/execute/mod.rs index 9ec9cbe3..082d59df 100644 --- a/crates/vite_task/src/session/execute/mod.rs +++ b/crates/vite_task/src/session/execute/mod.rs @@ -2,14 +2,17 @@ pub mod fingerprint; pub mod glob_inputs; pub mod spawn; -use std::{collections::BTreeMap, process::Stdio, sync::Arc}; +use std::{cell::RefCell, collections::BTreeMap, process::Stdio, rc::Rc, sync::Arc}; -use futures_util::FutureExt; +use futures_util::{FutureExt, StreamExt as _, stream::FuturesUnordered}; +use petgraph::Direction; +use rustc_hash::FxHashMap; use tokio::io::AsyncWriteExt as _; +use tokio_util::sync::CancellationToken; use vite_path::AbsolutePath; use vite_task_plan::{ ExecutionGraph, ExecutionItemDisplay, ExecutionItemKind, LeafExecutionKind, SpawnCommand, - SpawnExecution, + SpawnExecution, execution_graph::ExecutionNodeIndex, }; use self::{ @@ -25,7 +28,7 @@ use super::{ }, reporter::{ ExitStatus, GraphExecutionReporter, GraphExecutionReporterBuilder, LeafExecutionReporter, - StdioSuggestion, + LeafFinishStatus, StdioMode, }, }; use crate::{Session, collections::HashMap}; @@ -46,90 +49,212 @@ pub enum SpawnOutcome { Failed, } -/// Holds mutable references needed during graph execution. +/// Holds shared references needed during graph execution. /// -/// The `reporter` field is used to create leaf reporters for individual executions. +/// The `reporter` field is wrapped in `Rc>` to allow concurrent task +/// futures to create leaf reporters from the shared graph reporter. /// Cache fields are passed through to [`execute_spawn`] for cache-aware execution. struct ExecutionContext<'a> { /// The graph-level reporter, used to create leaf reporters via `new_leaf_execution()`. - reporter: &'a mut dyn GraphExecutionReporter, + /// Wrapped in `Rc>` so concurrent task futures can briefly borrow it + /// to create leaf reporters without holding the borrow across await points. + reporter: Rc>, /// The execution cache for looking up and storing cached results. cache: &'a ExecutionCache, /// Base path for resolving relative paths in cache entries. /// Typically the workspace root. cache_base_path: &'a Arc, + /// Shared cancellation token used for fail-fast across all nested graph executions. + /// When a task fails, this token is cancelled to signal all in-flight tasks to stop. + cancel_token: CancellationToken, } impl ExecutionContext<'_> { - /// Execute all tasks in an execution graph in dependency order. + /// Execute all tasks in an execution graph, respecting dependency order + /// and the graph's concurrency limit. /// - /// `ExecutionGraph` guarantees acyclicity at construction time. - /// We compute a topological order and iterate in reverse to get execution order - /// (dependencies before dependents). + /// **Single-node fast path:** When the graph has at most one node, tasks are + /// executed sequentially to preserve `StdioMode::Inherited` (allowing + /// direct terminal I/O for a single task). /// - /// `all_ancestors_single_node` tracks whether every graph in the ancestry chain - /// (from the root down to this level) contains exactly one node. The initial call - /// passes `graph.node_count() == 1`; recursive calls AND with the nested graph's - /// node count. + /// **Multi-node concurrent path:** Independent tasks (no dependency relationship) + /// run concurrently up to `graph.concurrency`. A task only starts after all its + /// dependencies have completed. On any failure, all in-flight tasks are cancelled + /// and no new tasks are started (fail-fast). /// - /// Leaf-level errors are reported through the reporter and do not abort the graph. - /// Cycle detection is handled at plan time, so this function cannot encounter cycles. + /// Returns `true` if all tasks succeeded, `false` if any task failed. #[tracing::instrument(level = "debug", skip_all)] #[expect(clippy::future_not_send, reason = "uses !Send types internally")] async fn execute_expanded_graph( - &mut self, + &self, graph: &ExecutionGraph, all_ancestors_single_node: bool, - ) { - // `compute_topological_order()` returns nodes in topological order: for every - // edge A→B, A appears before B. Since our edges mean "A depends on B", - // dependencies (B) appear after their dependents (A). We iterate in reverse - // to get execution order where dependencies run first. - - // Execute tasks in dependency-first order. Each task may have multiple items - // (from `&&`-split commands), which are executed sequentially. - let topo_order = graph.compute_topological_order(); - for &node_ix in topo_order.iter().rev() { - let task_execution = &graph[node_ix]; - - for item in &task_execution.items { - match &item.kind { - ExecutionItemKind::Leaf(leaf_kind) => { - self.execute_leaf( - &item.execution_item_display, - leaf_kind, - all_ancestors_single_node, - ) - .boxed_local() - .await; - } - ExecutionItemKind::Expanded(nested_graph) => { - self.execute_expanded_graph( - nested_graph, - all_ancestors_single_node && nested_graph.node_count() == 1, - ) - .boxed_local() - .await; + ) -> bool { + // Single-node fast path: preserve Inherited stdio for the sole task. + if graph.graph.node_count() <= 1 { + if let Some(node_ix) = graph.graph.node_indices().next() + && !self.execute_node(graph, node_ix, all_ancestors_single_node).boxed_local().await + { + return false; + } + return true; + } + + // Multi-node concurrent execution. + self.execute_concurrent(graph).await + } + + /// Concurrent scheduler: runs independent tasks in parallel up to the concurrency limit. + /// + /// Uses a ready-queue + `FuturesUnordered` approach: + /// 1. Compute initial dependency counts (outgoing neighbor count per node). + /// 2. Seed the ready queue with nodes that have zero dependencies. + /// 3. Launch ready tasks into `FuturesUnordered`, up to the concurrency limit. + /// 4. When a task completes, decrement dependency counts for its dependents + /// (incoming neighbors) and enqueue newly-ready tasks. + /// 5. On failure: drop `FuturesUnordered` to cancel all in-flight tasks (fail-fast). + #[tracing::instrument(level = "debug", skip_all)] + #[expect(clippy::future_not_send, reason = "uses !Send types internally")] + async fn execute_concurrent(&self, graph: &ExecutionGraph) -> bool { + let concurrency = graph.concurrency; + + // Compute dependency counts: for each node, count outgoing neighbors (dependencies). + let mut remaining_deps = FxHashMap::::with_capacity_and_hasher( + graph.graph.node_count(), + rustc_hash::FxBuildHasher, + ); + let mut ready: Vec = Vec::new(); + + for node_ix in graph.graph.node_indices() { + let dep_count = graph.graph.neighbors_directed(node_ix, Direction::Outgoing).count(); + if dep_count == 0 { + ready.push(node_ix); + } else { + remaining_deps.insert(node_ix, dep_count); + } + } + + let mut in_flight = FuturesUnordered::new(); + + loop { + // Fill up to concurrency limit from the ready queue. + while in_flight.len() < concurrency { + if let Some(node_ix) = ready.pop() { + // Multi-node graph: all_ancestors_single_node is always false. + in_flight.push( + async move { + let success = self.execute_node(graph, node_ix, false).await; + (node_ix, success) + } + .boxed_local(), + ); + } else { + break; + } + } + + if in_flight.is_empty() { + break; + } + + // Wait for any task to complete. + let Some((completed_ix, success)) = in_flight.next().await else { + break; + }; + + if !success { + // Fail-fast: cancel all in-flight tasks so they can kill their + // processes and call finish() with is_cancelled before returning. + self.cancel_token.cancel(); + // Drain remaining futures — each will see cancellation, kill its + // process via start_kill(), and call finish(Cancelled). + in_flight.for_each(|_| async {}).await; + return false; + } + + // Notify dependents: decrement their remaining dependency counts. + // Incoming neighbors of `completed_ix` are nodes that depend on it. + for dependent in graph.graph.neighbors_directed(completed_ix, Direction::Incoming) { + if let Some(count) = remaining_deps.get_mut(&dependent) { + *count -= 1; + if *count == 0 { + remaining_deps.remove(&dependent); + ready.push(dependent); } } } } + + true + } + + /// Execute all items within a single task node sequentially. + /// + /// A task's command may be split by `&&` into multiple items. Each item is + /// executed in order; if any item fails, the remaining items are skipped. + /// + /// Returns `true` if all items succeeded, `false` if any failed. + #[expect(clippy::future_not_send, reason = "uses !Send types internally")] + async fn execute_node( + &self, + graph: &ExecutionGraph, + node_ix: ExecutionNodeIndex, + all_ancestors_single_node: bool, + ) -> bool { + let task_execution = &graph.graph[node_ix]; + + for item in &task_execution.items { + // Don't start new items if cancellation has been requested. + if self.cancel_token.is_cancelled() { + return false; + } + + let success = match &item.kind { + ExecutionItemKind::Leaf(leaf_kind) => { + self.execute_leaf( + &item.execution_item_display, + leaf_kind, + all_ancestors_single_node, + ) + .boxed_local() + .await + } + ExecutionItemKind::Expanded(nested_graph) => { + self.execute_expanded_graph( + nested_graph, + all_ancestors_single_node && nested_graph.graph.node_count() == 1, + ) + .boxed_local() + .await + } + }; + if !success { + return false; + } + } + true } /// Execute a single leaf item (in-process command or spawned process). /// - /// Creates a [`LeafExecutionReporter`] from the graph reporter and delegates - /// to the appropriate execution method. + /// Creates a [`LeafExecutionReporter`] from the graph reporter (briefly borrowing + /// the `RefCell`) and delegates to the appropriate execution method. + /// + /// Returns `true` on success, `false` on failure. #[tracing::instrument(level = "debug", skip_all)] #[expect(clippy::future_not_send, reason = "uses !Send types internally")] async fn execute_leaf( - &mut self, + &self, display: &ExecutionItemDisplay, leaf_kind: &LeafExecutionKind, all_ancestors_single_node: bool, - ) { - let mut leaf_reporter = - self.reporter.new_leaf_execution(display, leaf_kind, all_ancestors_single_node); + ) -> bool { + // Briefly borrow the reporter to create a leaf reporter, then drop the borrow. + let mut leaf_reporter = self.reporter.borrow_mut().new_leaf_execution( + display, + leaf_kind, + all_ancestors_single_node, + ); match leaf_kind { LeafExecutionKind::InProcess(in_process_execution) => { @@ -144,21 +269,32 @@ impl ExecutionContext<'_> { let _ = stdio_config.stdout_writer.flush().await; leaf_reporter - .finish( - None, - CacheUpdateStatus::NotUpdated(CacheNotUpdatedReason::CacheDisabled), - None, - ) + .finish(LeafFinishStatus::Completed { + cache_update_status: CacheUpdateStatus::NotUpdated( + CacheNotUpdatedReason::CacheDisabled, + ), + }) .await; + true } LeafExecutionKind::Spawn(spawn_execution) => { #[expect( clippy::large_futures, reason = "spawn execution with cache management creates large futures" )] - let _ = - execute_spawn(leaf_reporter, spawn_execution, self.cache, self.cache_base_path) - .await; + match execute_spawn( + leaf_reporter, + spawn_execution, + self.cache, + self.cache_base_path, + &self.cancel_token, + ) + .await + { + SpawnOutcome::CacheHit => true, + SpawnOutcome::Spawned(status) => status.success(), + SpawnOutcome::Failed => false, + } } } } @@ -189,6 +325,7 @@ pub async fn execute_spawn( spawn_execution: &SpawnExecution, cache: &ExecutionCache, cache_base_path: &Arc, + cancel_token: &CancellationToken, ) -> SpawnOutcome { let cache_metadata = spawn_execution.cache_metadata.as_ref(); @@ -207,11 +344,12 @@ pub async fn execute_spawn( Ok(inputs) => inputs, Err(err) => { leaf_reporter - .finish( - None, - CacheUpdateStatus::NotUpdated(CacheNotUpdatedReason::CacheDisabled), - Some(ExecutionError::Cache { kind: CacheErrorKind::Lookup, source: err }), - ) + .finish(LeafFinishStatus::Error { + error: ExecutionError::Cache { kind: CacheErrorKind::Lookup, source: err }, + cache_update_status: CacheUpdateStatus::NotUpdated( + CacheNotUpdatedReason::CacheDisabled, + ), + }) .await; return SpawnOutcome::Failed; } @@ -234,11 +372,12 @@ pub async fn execute_spawn( // Cache lookup error — report through finish. // Note: start() is NOT called because we don't have a valid cache status. leaf_reporter - .finish( - None, - CacheUpdateStatus::NotUpdated(CacheNotUpdatedReason::CacheDisabled), - Some(ExecutionError::Cache { kind: CacheErrorKind::Lookup, source: err }), - ) + .finish(LeafFinishStatus::Error { + error: ExecutionError::Cache { kind: CacheErrorKind::Lookup, source: err }, + cache_update_status: CacheUpdateStatus::NotUpdated( + CacheNotUpdatedReason::CacheDisabled, + ), + }) .await; return SpawnOutcome::Failed; } @@ -264,7 +403,9 @@ pub async fn execute_spawn( let _ = writer.flush().await; } leaf_reporter - .finish(None, CacheUpdateStatus::NotUpdated(CacheNotUpdatedReason::CacheHit), None) + .finish(LeafFinishStatus::Completed { + cache_update_status: CacheUpdateStatus::NotUpdated(CacheNotUpdatedReason::CacheHit), + }) .await; return SpawnOutcome::CacheHit; } @@ -273,8 +414,7 @@ pub async fn execute_spawn( // Inherited stdio is only used when the reporter suggests it AND caching is // completely disabled (no cache_metadata). If caching is enabled but missed, // we still need piped mode to capture output for the cache update. - let use_inherited = - stdio_config.suggestion == StdioSuggestion::Inherited && cache_metadata.is_none(); + let use_inherited = stdio_config.stdio_mode == StdioMode::Inherited && cache_metadata.is_none(); if use_inherited { // Inherited mode: all three stdio FDs (stdin, stdout, stderr) are inherited @@ -283,24 +423,28 @@ pub async fn execute_spawn( // while the child also writes to the same FD. drop(stdio_config); - match spawn_inherited(&spawn_execution.spawn_command).await { + match spawn_inherited(&spawn_execution.spawn_command, cancel_token).await { Ok(result) => { leaf_reporter - .finish( - Some(result.exit_status), - CacheUpdateStatus::NotUpdated(CacheNotUpdatedReason::CacheDisabled), - None, - ) + .finish(LeafFinishStatus::Spawned { + exit_status: result.exit_status, + cache_update_status: CacheUpdateStatus::NotUpdated( + CacheNotUpdatedReason::CacheDisabled, + ), + is_cancelled: cancel_token.is_cancelled(), + infra_error: None, + }) .await; return SpawnOutcome::Spawned(result.exit_status); } Err(err) => { leaf_reporter - .finish( - None, - CacheUpdateStatus::NotUpdated(CacheNotUpdatedReason::CacheDisabled), - Some(ExecutionError::Spawn(err)), - ) + .finish(LeafFinishStatus::Error { + error: ExecutionError::Spawn(err), + cache_update_status: CacheUpdateStatus::NotUpdated( + CacheNotUpdatedReason::CacheDisabled, + ), + }) .await; return SpawnOutcome::Failed; } @@ -333,11 +477,12 @@ pub async fn execute_spawn( Ok(negs) => negs, Err(err) => { leaf_reporter - .finish( - None, - CacheUpdateStatus::NotUpdated(CacheNotUpdatedReason::CacheDisabled), - Some(ExecutionError::PostRunFingerprint(err)), - ) + .finish(LeafFinishStatus::Error { + error: ExecutionError::PostRunFingerprint(err), + cache_update_status: CacheUpdateStatus::NotUpdated( + CacheNotUpdatedReason::CacheDisabled, + ), + }) .await; return SpawnOutcome::Failed; } @@ -358,17 +503,19 @@ pub async fn execute_spawn( std_outputs.as_mut(), path_accesses.as_mut(), &resolved_negatives, + cancel_token, ) .await { Ok(result) => result, Err(err) => { leaf_reporter - .finish( - None, - CacheUpdateStatus::NotUpdated(CacheNotUpdatedReason::CacheDisabled), - Some(ExecutionError::Spawn(err)), - ) + .finish(LeafFinishStatus::Error { + error: ExecutionError::Spawn(err), + cache_update_status: CacheUpdateStatus::NotUpdated( + CacheNotUpdatedReason::CacheDisabled, + ), + }) .await; return SpawnOutcome::Failed; } @@ -421,7 +568,14 @@ pub async fn execute_spawn( // 7. Finish the leaf execution with the result and optional cache error. // Cache update/fingerprint failures are reported but do not affect the outcome — // the process ran, so we return its actual exit status. - leaf_reporter.finish(Some(result.exit_status), cache_update_status, cache_error).await; + leaf_reporter + .finish(LeafFinishStatus::Spawned { + exit_status: result.exit_status, + cache_update_status, + is_cancelled: cancel_token.is_cancelled(), + infra_error: cache_error, + }) + .await; SpawnOutcome::Spawned(result.exit_status) } @@ -436,7 +590,10 @@ pub async fn execute_spawn( /// The child process will see `is_terminal() == true` for stdout/stderr when the /// parent is running in a terminal. This is expected behavior. #[tracing::instrument(level = "debug", skip_all)] -async fn spawn_inherited(spawn_command: &SpawnCommand) -> anyhow::Result { +async fn spawn_inherited( + spawn_command: &SpawnCommand, + cancel_token: &CancellationToken, +) -> anyhow::Result { let mut cmd = fspy::Command::new(spawn_command.program_path.as_path()); cmd.args(spawn_command.args.iter().map(vite_str::Str::as_str)); cmd.envs(spawn_command.all_envs.iter()); @@ -478,7 +635,13 @@ async fn spawn_inherited(spawn_command: &SpawnCommand) -> anyhow::Result status?, + () = cancel_token.cancelled() => { + let _ = child.start_kill(); + child.wait().await? + } + }; Ok(SpawnResult { exit_status, duration: start.elapsed() }) } @@ -513,17 +676,22 @@ impl Session<'_> { let mut reporter = builder.build(); - let mut execution_context = ExecutionContext { - reporter: &mut *reporter, + let execution_context = ExecutionContext { + reporter: Rc::new(RefCell::new(&mut *reporter)), cache, cache_base_path: &self.workspace_path, + cancel_token: CancellationToken::new(), }; - // Execute the graph. Leaf-level errors are reported through the reporter - // and do not abort the graph. Cycle detection is handled at plan time. - let all_single_node = execution_graph.node_count() == 1; + // Execute the graph. On failure, remaining tasks are cancelled (fail-fast). + // Cycle detection is handled at plan time. + let all_single_node = execution_graph.graph.node_count() == 1; execution_context.execute_expanded_graph(&execution_graph, all_single_node).await; + // Drop the execution context before finishing the reporter so the + // cancellation token is dropped before the reporter's finish(). + drop(execution_context); + // Leaf-level errors and non-zero exit statuses are tracked internally // by the reporter. reporter.finish().await diff --git a/crates/vite_task/src/session/execute/spawn.rs b/crates/vite_task/src/session/execute/spawn.rs index 7c78d621..42903a0f 100644 --- a/crates/vite_task/src/session/execute/spawn.rs +++ b/crates/vite_task/src/session/execute/spawn.rs @@ -11,6 +11,7 @@ use fspy::AccessMode; use rustc_hash::FxHashSet; use serde::Serialize; use tokio::io::{AsyncReadExt as _, AsyncWrite, AsyncWriteExt as _}; +use tokio_util::sync::CancellationToken; use vite_path::{AbsolutePath, RelativePathBuf}; use vite_task_plan::SpawnCommand; use wax::Program as _; @@ -70,6 +71,10 @@ pub struct TrackedPathAccesses { clippy::too_many_lines, reason = "spawn logic is inherently sequential and splitting would reduce clarity" )] +#[expect( + clippy::too_many_arguments, + reason = "cancel_token is a temporary addition until ChildProcess API is implemented" +)] pub async fn spawn_with_tracking( spawn_command: &SpawnCommand, workspace_root: &AbsolutePath, @@ -78,6 +83,7 @@ pub async fn spawn_with_tracking( std_outputs: Option<&mut Vec>, path_accesses: Option<&mut TrackedPathAccesses>, resolved_negatives: &[wax::Glob<'static>], + cancel_token: &CancellationToken, ) -> anyhow::Result { /// The tracking state of the spawned process. /// Determined by whether `path_accesses` is `Some` (fspy enabled) or `None` (fspy disabled). @@ -97,7 +103,7 @@ pub async fn spawn_with_tracking( let mut tracking_state = if path_accesses.is_some() { // path_accesses is Some, spawn with fspy tracking enabled - TrackingState::FspyEnabled(cmd.spawn().await?) + TrackingState::FspyEnabled(cmd.spawn(cancel_token.clone()).await?) } else { // path_accesses is None, spawn without fspy TrackingState::FspyDisabled(cmd.into_tokio_command().spawn()?) @@ -122,6 +128,7 @@ pub async fn spawn_with_tracking( let start = Instant::now(); // Read from both stdout and stderr concurrently using select! + // Also monitors the cancellation token to kill the child on fast-fail. loop { tokio::select! { result = child_stdout.read(&mut stdout_buf), if !stdout_done => { @@ -166,6 +173,22 @@ pub async fn spawn_with_tracking( } } } + () = cancel_token.cancelled(), if !stdout_done || !stderr_done => { + // Fast-fail: kill the child process so it exits quickly. + // The process pipes will close, ending the I/O loop naturally. + match &mut tracking_state { + TrackingState::FspyEnabled(tracked_child) => { + // fspy TrackedChild doesn't expose a kill method. + // Drop stdin to signal the child; the wait_handle task + // will see the process exit. + drop(tracked_child.stdin.take()); + } + TrackingState::FspyDisabled(tokio_child) => { + let _ = tokio_child.start_kill(); + } + } + break; + } else => break, } } diff --git a/crates/vite_task/src/session/mod.rs b/crates/vite_task/src/session/mod.rs index e9eca149..3e5b480c 100644 --- a/crates/vite_task/src/session/mod.rs +++ b/crates/vite_task/src/session/mod.rs @@ -284,7 +284,7 @@ impl<'a> Session<'a> { let (graph, is_cwd_only) = self.plan_from_cli_run_resolved(cwd, run_command.clone()).await?; - if graph.node_count() == 0 { + if graph.graph.node_count() == 0 { // No tasks matched. With is_cwd_only (no scope flags) the // task name is a typo — show the selector. Otherwise error. if is_cwd_only { @@ -493,6 +493,7 @@ impl<'a> Session<'a> { plan_options: PlanOptions { extra_args: run_command.additional_args.clone().into(), cache_override: run_command.flags.cache_override(), + concurrency: run_command.flags.concurrency.map(|c| c.0), }, }) } @@ -624,12 +625,15 @@ impl<'a> Session<'a> { let plain_reporter = reporter::PlainReporter::new(silent_if_cache_hit, Box::new(tokio::io::stdout())); - // Execute the spawn directly using the free function, bypassing the graph pipeline + // Execute the spawn directly using the free function, bypassing the graph pipeline. + // Synthetic executions are standalone — no concurrent graph, no cancellation. + let cancel_token = tokio_util::sync::CancellationToken::new(); let outcome = execute::execute_spawn( Box::new(plain_reporter), &spawn_execution, cache, &self.workspace_path, + &cancel_token, ) .await; match outcome { diff --git a/crates/vite_task/src/session/reporter/labeled.rs b/crates/vite_task/src/session/reporter/labeled.rs index 15e95b24..f5b5a007 100644 --- a/crates/vite_task/src/session/reporter/labeled.rs +++ b/crates/vite_task/src/session/reporter/labeled.rs @@ -6,19 +6,27 @@ //! Tracks statistics across multiple leaf executions, prints command lines with cache //! status indicators, and renders a summary with per-task details at the end. -use std::{cell::RefCell, process::ExitStatus as StdExitStatus, rc::Rc, sync::Arc}; +use std::{ + cell::RefCell, + io, + pin::Pin, + rc::Rc, + sync::Arc, + task::{Context, Poll}, +}; -use tokio::io::{AsyncWrite, AsyncWriteExt as _}; +use tokio::io::AsyncWrite; use vite_path::AbsolutePath; use vite_str::Str; use vite_task_plan::{ExecutionItemDisplay, LeafExecutionKind}; use super::{ ExitStatus, GraphExecutionReporter, GraphExecutionReporterBuilder, LeafExecutionReporter, - StdioConfig, StdioSuggestion, format_command_with_cache_status, format_error_message, + LeafFinishStatus, StdioConfig, StdioMode, format_cancel_line, format_command_with_cache_status, + format_error_message, format_exit_status_line, }; use crate::session::{ - event::{CacheStatus, CacheUpdateStatus, ExecutionError}, + event::{CacheStatus, exit_status_to_code}, reporter::summary::{ LastRunSummary, SavedExecutionError, SpawnOutcome, TaskResult, TaskSummary, format_compact_summary, format_full_summary, @@ -28,13 +36,74 @@ use crate::session::{ /// Callback type for persisting the summary (e.g., writing `last-summary.json`). type WriteSummaryFn = Box; +/// An in-memory async writer that collects all writes into a shared buffer. +/// +/// Used to buffer a task's output (header + stdout + stderr) during concurrent +/// execution so it can be flushed atomically when the task finishes. +struct BufferedAsyncWriter { + buffer: Rc>>, +} + +impl AsyncWrite for BufferedAsyncWriter { + fn poll_write( + self: Pin<&mut Self>, + _cx: &mut Context<'_>, + buf: &[u8], + ) -> Poll> { + self.get_mut().buffer.borrow_mut().extend_from_slice(buf); + Poll::Ready(Ok(buf.len())) + } + + fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { + Poll::Ready(Ok(())) + } + + fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { + Poll::Ready(Ok(())) + } +} + +/// Write data to the shared writer with exclusive ownership. +/// +/// Takes the writer out of the `RefCell>` so that no other future can +/// poll the same writer concurrently. This prevents corruption of the writer's +/// internal state machine (e.g., `tokio::io::Blocking`) when multiple +/// concurrent tasks in `FuturesUnordered` try to write through the same shared writer. +/// +/// If the writer is already taken by another future, yields and retries. +#[expect(clippy::future_not_send, reason = "used only in !Send reporter async contexts")] +async fn write_and_flush_shared( + writer_cell: &RefCell>>, + data: &[u8], +) { + use tokio::io::AsyncWriteExt as _; + + // Take exclusive ownership of the writer. + let mut writer = loop { + if let Some(w) = writer_cell.borrow_mut().take() { + break w; + } + // Another future has the writer — yield and retry. + tokio::task::yield_now().await; + }; + + if !data.is_empty() { + let _ = writer.write_all(data).await; + } + let _ = writer.flush().await; + + // Return the writer. + *writer_cell.borrow_mut() = Some(writer); +} + /// Mutable state shared between [`LabeledGraphReporter`] and its [`LabeledLeafReporter`] instances /// via `Rc>`. -/// -/// This is safe because execution is single-threaded and sequential — only one leaf -/// reporter is active at a time. struct SharedReporterState { tasks: Vec, + /// Number of leaf reporters currently between `start()` and `finish()`. + /// Used to decide streaming vs buffering: the first task (idle → 0) streams + /// directly; subsequent concurrent tasks buffer their output. + active_count: usize, } /// Builder for the labeled graph reporter. @@ -83,9 +152,12 @@ impl LabeledReporterBuilder { impl GraphExecutionReporterBuilder for LabeledReporterBuilder { fn build(self: Box) -> Box { - let writer = Rc::new(RefCell::new(self.writer)); + let writer = Rc::new(RefCell::new(Some(self.writer))); Box::new(LabeledGraphReporter { - shared: Rc::new(RefCell::new(SharedReporterState { tasks: Vec::new() })), + shared: Rc::new(RefCell::new(SharedReporterState { + tasks: Vec::new(), + active_count: 0, + })), writer, workspace_path: self.workspace_path, show_details: self.show_details, @@ -101,7 +173,7 @@ impl GraphExecutionReporterBuilder for LabeledReporterBuilder { /// share mutable state with this reporter via `Rc>`. pub struct LabeledGraphReporter { shared: Rc>, - writer: Rc>>, + writer: Rc>>>, workspace_path: Arc, show_details: bool, write_summary: Option, @@ -109,11 +181,6 @@ pub struct LabeledGraphReporter { } #[async_trait::async_trait(?Send)] -#[expect( - clippy::await_holding_refcell_ref, - reason = "writer RefCell borrow across await is safe: reporter is !Send, single-threaded, \ - and finish() is called once after all leaf reporters are dropped" -)] impl GraphExecutionReporter for LabeledGraphReporter { fn new_leaf_execution( &mut self, @@ -122,9 +189,9 @@ impl GraphExecutionReporter for LabeledGraphReporter { all_ancestors_single_node: bool, ) -> Box { let display = display.clone(); - let stdio_suggestion = match leaf_kind { - LeafExecutionKind::Spawn(_) if all_ancestors_single_node => StdioSuggestion::Inherited, - _ => StdioSuggestion::Piped, + let stdio_mode = match leaf_kind { + LeafExecutionKind::Spawn(_) if all_ancestors_single_node => StdioMode::Inherited, + _ => StdioMode::Piped, }; Box::new(LabeledLeafReporter { @@ -132,8 +199,9 @@ impl GraphExecutionReporter for LabeledGraphReporter { writer: Rc::clone(&self.writer), display, workspace_path: Arc::clone(&self.workspace_path), - stdio_suggestion, + stdio_mode, cache_status: None, + output_buffer: None, }) } @@ -150,7 +218,7 @@ impl GraphExecutionReporter for LabeledGraphReporter { let failed_exit_codes: Vec = tasks .iter() .filter_map(|t| match &t.result { - TaskResult::Spawned { outcome: SpawnOutcome::Failed { exit_code }, .. } => { + TaskResult::Spawned { outcome: SpawnOutcome::Failed { exit_code, .. }, .. } => { Some(exit_code.get()) } _ => None, @@ -194,13 +262,7 @@ impl GraphExecutionReporter for LabeledGraphReporter { // Always flush the writer — even when the summary is empty, a preceding // spawned process may have written to the same fd via Stdio::inherit() // and the data must be flushed before the caller reads the output. - { - let mut writer = self.writer.borrow_mut(); - if !summary_buf.is_empty() { - let _ = writer.write_all(&summary_buf).await; - } - let _ = writer.flush().await; - } + write_and_flush_shared(&self.writer, &summary_buf).await; result } @@ -212,23 +274,22 @@ impl GraphExecutionReporter for LabeledGraphReporter { /// [`TaskSummary`] entries that are pushed to [`SharedReporterState`] on completion. struct LabeledLeafReporter { shared: Rc>, - writer: Rc>>, + writer: Rc>>>, /// Display info for this execution, looked up from the graph via the path. display: ExecutionItemDisplay, workspace_path: Arc, /// Stdio suggestion precomputed from this leaf's graph path. - stdio_suggestion: StdioSuggestion, + stdio_mode: StdioMode, /// Cache status, set at `start()` time. `None` means `start()` was never called /// (e.g., cache lookup failure). Consumed in `finish()` to build [`TaskSummary`]. cache_status: Option, + /// Output buffer for concurrent task execution. + /// `None` when streaming directly (first task while reporter is idle). + /// `Some(buffer)` when output needs buffering (other tasks running concurrently). + output_buffer: Option>>>, } #[async_trait::async_trait(?Send)] -#[expect( - clippy::await_holding_refcell_ref, - reason = "writer RefCell borrow across await is safe: reporter is !Send, single-threaded, \ - and only one leaf is active at a time (no re-entrant access during write_all)" -)] impl LeafExecutionReporter for LabeledLeafReporter { async fn start(&mut self, cache_status: CacheStatus) -> StdioConfig { // Format command line with cache status before storing it. @@ -237,30 +298,63 @@ impl LeafExecutionReporter for LabeledLeafReporter { self.cache_status = Some(cache_status); - let mut writer = self.writer.borrow_mut(); - let _ = writer.write_all(line.as_bytes()).await; - let _ = writer.flush().await; + // Decide streaming vs buffering based on whether other tasks are active. + let is_idle = { + let mut shared = self.shared.borrow_mut(); + let idle = shared.active_count == 0; + shared.active_count += 1; + idle + }; + + if is_idle { + // Stream directly — write header immediately, output goes to real stdout/stderr. + write_and_flush_shared(&self.writer, line.as_bytes()).await; - StdioConfig { - suggestion: self.stdio_suggestion, - stdout_writer: Box::new(tokio::io::stdout()), - stderr_writer: Box::new(tokio::io::stderr()), + StdioConfig { + stdio_mode: self.stdio_mode, + stdout_writer: Box::new(tokio::io::stdout()), + stderr_writer: Box::new(tokio::io::stderr()), + } + } else { + // Buffer output — header + stdout + stderr collected for atomic flush in finish(). + let buffer = Rc::new(RefCell::new(Vec::new())); + buffer.borrow_mut().extend_from_slice(line.as_bytes()); + self.output_buffer = Some(Rc::clone(&buffer)); + + StdioConfig { + stdio_mode: self.stdio_mode, + stdout_writer: Box::new(BufferedAsyncWriter { buffer: Rc::clone(&buffer) }), + stderr_writer: Box::new(BufferedAsyncWriter { buffer }), + } } } - async fn finish( - self: Box, - status: Option, - _cache_update_status: CacheUpdateStatus, - error: Option, - ) { - // Convert error before consuming it (need the original for display formatting). - let saved_error = error.as_ref().map(SavedExecutionError::from_execution_error); + async fn finish(self: Box, status: LeafFinishStatus) { + // Extract error and exit status info from the finish status. + let (exit_status, error, is_cancelled) = match &status { + LeafFinishStatus::Spawned { exit_status, is_cancelled, infra_error, .. } => { + (Some(*exit_status), infra_error.as_ref(), *is_cancelled) + } + LeafFinishStatus::Completed { .. } => (None, None, false), + LeafFinishStatus::Error { error, .. } => (None, Some(error), false), + }; + + let cache_update_status = match &status { + LeafFinishStatus::Spawned { cache_update_status, .. } + | LeafFinishStatus::Completed { cache_update_status } + | LeafFinishStatus::Error { cache_update_status, .. } => cache_update_status, + }; + let _ = cache_update_status; // used only for summary (via TaskResult) + + // Convert error for summary persistence and format display string. + // Both are derived from the same borrowed error reference. + let saved_error = error.map(SavedExecutionError::from_execution_error); let error_display: Option = - error.map(|e| vite_str::format!("{:#}", anyhow::Error::from(e))); + saved_error.as_ref().map(SavedExecutionError::display_message); // Destructure self to avoid partial-move issues with Box. - let Self { shared, writer, display, workspace_path, cache_status, .. } = *self; + let Self { shared, writer, display, workspace_path, cache_status, output_buffer, .. } = + *self; let started = cache_status.is_some(); // Build TaskSummary and push to shared state if start() was called. @@ -276,30 +370,62 @@ impl LeafExecutionReporter for LabeledLeafReporter { task_name: display.task_display.task_name.clone(), command: display.command.clone(), cwd: cwd_relative, - result: TaskResult::from_execution(&cache_status, status, saved_error.as_ref()), + result: TaskResult::from_execution( + &cache_status, + exit_status, + is_cancelled, + saved_error.as_ref(), + ), }; shared.borrow_mut().tasks.push(task_summary); } - // Build all display output into a buffer, then write once asynchronously. - let mut buf = Vec::new(); + // Determine if we should show inline status (only in multi-task execution). + let is_multi_task = { + let shared_ref = shared.borrow(); + shared_ref.tasks.len() + shared_ref.active_count > 1 + }; + + // Decrement active count if start() was called (active_count was incremented). + if started { + shared.borrow_mut().active_count -= 1; + } + + // Build trailing output (inline status + error message + separator newline). + let mut trailing = Vec::new(); + + // Inline exit status or cancellation (only for multi-task execution). + if is_multi_task && is_cancelled { + trailing.extend_from_slice(format_cancel_line().as_bytes()); + } else if is_multi_task + && let Some(exit_status) = exit_status + && !exit_status.success() + { + let code = exit_status_to_code(exit_status); + trailing.extend_from_slice(format_exit_status_line(code).as_bytes()); + } if let Some(ref message) = error_display { - buf.extend_from_slice(format_error_message(message).as_bytes()); + trailing.extend_from_slice(format_error_message(message).as_bytes()); } // Add a trailing newline after each task's output for readability. // Skip if start() was never called (e.g. cache lookup failure) — there's // no task output to separate. if started { - buf.push(b'\n'); + trailing.push(b'\n'); } - if !buf.is_empty() { - let mut writer = writer.borrow_mut(); - let _ = writer.write_all(&buf).await; - let _ = writer.flush().await; + if let Some(output_buffer) = output_buffer { + // Buffered mode: concatenate header + captured output + trailing into a single + // write for atomicity, then flush. Take the buffer in-place to avoid copying. + let mut data = std::mem::take(&mut *output_buffer.borrow_mut()); + data.extend_from_slice(&trailing); + write_and_flush_shared(&writer, &data).await; + } else if !trailing.is_empty() { + // Streaming mode: only write trailing (header + output already written directly). + write_and_flush_shared(&writer, &trailing).await; } } } @@ -312,7 +438,7 @@ mod tests { use crate::session::{ event::CacheDisabledReason, reporter::{ - LeafExecutionReporter, StdioSuggestion, + LeafExecutionReporter, StdioMode, test_fixtures::{in_process_task, spawn_task, test_path}, }, }; @@ -350,11 +476,11 @@ mod tests { display: &ExecutionItemDisplay, leaf_kind: &LeafExecutionKind, all_ancestors_single_node: bool, - ) -> StdioSuggestion { + ) -> StdioMode { let mut leaf = build_labeled_leaf(display, leaf_kind, all_ancestors_single_node); let stdio_config = leaf.start(CacheStatus::Disabled(CacheDisabledReason::NoCacheMetadata)).await; - stdio_config.suggestion + stdio_config.stdio_mode } #[tokio::test] @@ -363,7 +489,7 @@ mod tests { let item = &task.items[0]; assert_eq!( suggestion_for(&item.execution_item_display, leaf_kind(item), true).await, - StdioSuggestion::Inherited + StdioMode::Inherited ); } @@ -373,7 +499,7 @@ mod tests { let item = &task.items[0]; assert_eq!( suggestion_for(&item.execution_item_display, leaf_kind(item), false).await, - StdioSuggestion::Piped + StdioMode::Piped ); } @@ -383,7 +509,7 @@ mod tests { let item = &task.items[0]; assert_eq!( suggestion_for(&item.execution_item_display, leaf_kind(item), true).await, - StdioSuggestion::Piped + StdioMode::Piped ); } @@ -393,7 +519,7 @@ mod tests { let item = &task.items[0]; assert_eq!( suggestion_for(&item.execution_item_display, leaf_kind(item), false).await, - StdioSuggestion::Piped + StdioMode::Piped ); } } diff --git a/crates/vite_task/src/session/reporter/mod.rs b/crates/vite_task/src/session/reporter/mod.rs index 2759373f..db908782 100644 --- a/crates/vite_task/src/session/reporter/mod.rs +++ b/crates/vite_task/src/session/reporter/mod.rs @@ -57,19 +57,19 @@ impl ExitStatus { } // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -// Stdio suggestion and configuration +// Stdio mode and configuration // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -/// Suggestion from the reporter about what stdio mode to use for a spawned process. +/// Stdio mode for a spawned process. /// /// The actual stdio mode is determined by [`execute_spawn`](super::execute::execute_spawn) -/// based on this suggestion AND whether caching is enabled for the task: +/// based on the reporter's suggestion AND whether caching is enabled for the task: /// - `Inherited` is only honoured when caching is disabled (`cache_metadata` is `None`). /// With caching enabled, the execution engine overrides to `Piped` so that output can /// be captured for the cache. /// - `Piped` is always respected as-is. #[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum StdioSuggestion { +pub enum StdioMode { /// stdin is `/dev/null`, stdout and stderr are piped into the reporter's /// [`AsyncWrite`] streams. Used when multiple tasks run concurrently and /// stdio should not be shared. @@ -82,14 +82,14 @@ pub enum StdioSuggestion { /// Stdio configuration returned by [`LeafExecutionReporter::start`]. /// -/// Contains the reporter's suggestion for the stdio mode together with two +/// Contains the reporter's suggested stdio mode together with two /// async writers that receive the child process's stdout and stderr when the /// execution engine decides to use piped mode. The writers are always provided /// because the engine may override the suggestion (e.g. when caching forces /// piped mode even though the reporter suggested inherited). pub struct StdioConfig { /// The reporter's preferred stdio mode. - pub suggestion: StdioSuggestion, + pub stdio_mode: StdioMode, /// Async writer for the child process's stdout (used in piped mode and cache replay). pub stdout_writer: Box, /// Async writer for the child process's stderr (used in piped mode and cache replay). @@ -139,6 +139,27 @@ pub trait GraphExecutionReporter { async fn finish(self: Box) -> Result<(), ExitStatus>; } +/// The outcome of a leaf execution, passed to [`LeafExecutionReporter::finish`]. +/// +/// Designed so that invalid states are unrepresentable: +/// - `is_cancelled` is only possible when a process was actually spawned. +/// - `exit_status` is always present when spawned, never present otherwise. +pub enum LeafFinishStatus { + /// A process was spawned and exited (normally or killed via cancellation). + Spawned { + exit_status: StdExitStatus, + cache_update_status: CacheUpdateStatus, + is_cancelled: bool, + /// Post-execution infrastructure error (cache update or fingerprint failure). + /// Only possible after a successful spawn; does not affect the exit status. + infra_error: Option, + }, + /// Completed without spawning a process (cache hit replay, in-process command). + Completed { cache_update_status: CacheUpdateStatus }, + /// An error prevented normal completion (spawn failure, cache lookup failure, etc.) + Error { error: ExecutionError, cache_update_status: CacheUpdateStatus }, +} + /// Reporter for a single leaf execution (one spawned process or in-process command). /// /// Lifecycle: `start()` → `finish()`. @@ -151,30 +172,20 @@ pub trait LeafExecutionReporter { /// /// Called after the cache lookup completes, before any output is produced. /// Returns a [`StdioConfig`] containing: - /// - The reporter's stdio mode suggestion (inherited or piped). + /// - The reporter's stdio mode (inherited or piped). /// - Two [`AsyncWrite`] streams for receiving the child's stdout and stderr /// (used when the execution engine decides on piped mode, or for cache replay). /// - /// The execution engine decides the actual stdio mode based on the suggestion + /// The execution engine decides the actual stdio mode based on the mode /// AND whether caching is enabled — inherited stdio is only used when the - /// suggestion is [`StdioSuggestion::Inherited`] AND the task has no cache + /// mode is [`StdioMode::Inherited`] AND the task has no cache /// metadata (caching disabled). async fn start(&mut self, cache_status: CacheStatus) -> StdioConfig; /// Finalize this leaf execution. /// - /// - `status`: The process exit status, or `None` for cache hits and in-process commands. - /// - `cache_update_status`: Whether the cache was updated after execution. - /// - `error`: If `Some`, an error occurred during this leaf's execution (cache lookup - /// failure, spawn failure, fingerprint creation failure, cache update failure). - /// /// This method consumes the reporter — no further calls are possible after `finish()`. - async fn finish( - self: Box, - status: Option, - cache_update_status: CacheUpdateStatus, - error: Option, - ); + async fn finish(self: Box, status: LeafFinishStatus); } // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ @@ -264,6 +275,24 @@ fn format_cache_hit_message() -> Str { vite_str::format!("{}\n", "✓ cache hit, logs replayed".style(Style::new().green().dimmed())) } +/// Format an inline exit status line (e.g., `✗ exit code 1`). +fn format_exit_status_line(code: i32) -> Str { + vite_str::format!( + "{} {}\n", + "✗".style(Style::new().red().bold()), + vite_str::format!("exit code {code}").style(Style::new().red()) + ) +} + +/// Format a cancellation line (e.g., `✗ cancelled`). +fn format_cancel_line() -> Str { + vite_str::format!( + "{} {}\n", + "✗".style(Style::new().red().bold()), + "cancelled".style(Style::new().red()) + ) +} + // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // Test fixtures (shared by child module tests) // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ diff --git a/crates/vite_task/src/session/reporter/plain.rs b/crates/vite_task/src/session/reporter/plain.rs index 94e74ee0..d4da7a59 100644 --- a/crates/vite_task/src/session/reporter/plain.rs +++ b/crates/vite_task/src/session/reporter/plain.rs @@ -6,10 +6,10 @@ use tokio::io::{AsyncWrite, AsyncWriteExt as _}; use super::{ - LeafExecutionReporter, StdioConfig, StdioSuggestion, format_cache_hit_message, + LeafExecutionReporter, LeafFinishStatus, StdioConfig, StdioMode, format_cache_hit_message, format_error_message, }; -use crate::session::event::{CacheStatus, CacheUpdateStatus, ExecutionError}; +use crate::session::event::CacheStatus; /// A self-contained [`LeafExecutionReporter`] for single-leaf executions /// (e.g., `execute_synthetic`). @@ -62,27 +62,22 @@ impl LeafExecutionReporter for PlainReporter { // to suppress replayed output. if self.silent_if_cache_hit && self.is_cache_hit { StdioConfig { - suggestion: StdioSuggestion::Inherited, + stdio_mode: StdioMode::Inherited, stdout_writer: Box::new(tokio::io::sink()), stderr_writer: Box::new(tokio::io::sink()), } } else { StdioConfig { - suggestion: StdioSuggestion::Inherited, + stdio_mode: StdioMode::Inherited, stdout_writer: Box::new(tokio::io::stdout()), stderr_writer: Box::new(tokio::io::stderr()), } } } - async fn finish( - mut self: Box, - _status: Option, - _cache_update_status: CacheUpdateStatus, - error: Option, - ) { + async fn finish(mut self: Box, status: LeafFinishStatus) { // Handle errors — format the full error chain and print inline. - if let Some(error) = error { + if let LeafFinishStatus::Error { error, .. } = status { let message = vite_str::format!("{:#}", anyhow::Error::from(error)); let line = format_error_message(&message); let _ = self.writer.write_all(line.as_bytes()).await; @@ -109,7 +104,7 @@ mod tests { let mut reporter = PlainReporter::new(false, Box::new(tokio::io::sink())); let stdio_config = reporter.start(CacheStatus::Disabled(CacheDisabledReason::NoCacheMetadata)).await; - assert_eq!(stdio_config.suggestion, StdioSuggestion::Inherited); + assert_eq!(stdio_config.stdio_mode, StdioMode::Inherited); } #[tokio::test] @@ -117,6 +112,6 @@ mod tests { let mut reporter = PlainReporter::new(true, Box::new(tokio::io::sink())); let stdio_config = reporter.start(CacheStatus::Disabled(CacheDisabledReason::NoCacheMetadata)).await; - assert_eq!(stdio_config.suggestion, StdioSuggestion::Inherited); + assert_eq!(stdio_config.stdio_mode, StdioMode::Inherited); } } diff --git a/crates/vite_task/src/session/reporter/summary.rs b/crates/vite_task/src/session/reporter/summary.rs index 05e82130..f82f38d2 100644 --- a/crates/vite_task/src/session/reporter/summary.rs +++ b/crates/vite_task/src/session/reporter/summary.rs @@ -99,7 +99,7 @@ pub enum SpawnOutcome { /// Process exited with non-zero status. /// [`NonZeroI32`] enforces that exit code 0 is unrepresentable here. /// No `infra_error` field: cache operations are skipped on non-zero exit. - Failed { exit_code: NonZeroI32 }, + Failed { exit_code: NonZeroI32, is_cancelled: bool }, /// Could not start the process (e.g., command not found). SpawnError(SavedExecutionError), @@ -146,6 +146,7 @@ struct SummaryStats { cache_misses: usize, cache_disabled: usize, failed: usize, + cancelled: usize, total_saved: Duration, } @@ -157,6 +158,7 @@ impl SummaryStats { cache_misses: 0, cache_disabled: 0, failed: 0, + cancelled: 0, total_saved: Duration::ZERO, }; @@ -175,6 +177,7 @@ impl SummaryStats { SpawnedCacheStatus::Disabled => stats.cache_disabled += 1, } match outcome { + SpawnOutcome::Failed { is_cancelled: true, .. } => stats.cancelled += 1, SpawnOutcome::Success { infra_error: Some(_) } | SpawnOutcome::Failed { .. } | SpawnOutcome::SpawnError(_) => stats.failed += 1, @@ -213,7 +216,7 @@ impl SavedExecutionError { } /// Format the full error message for display. - fn display_message(&self) -> Str { + pub(super) fn display_message(&self) -> Str { match self { Self::Cache { kind, message } => { let kind_str = match kind { @@ -254,10 +257,12 @@ impl TaskResult { /// /// `cache_status`: the cache status determined at `start()` time. /// `exit_status`: the process exit status, or `None` for cache hit / in-process. + /// `is_cancelled`: whether the task was cancelled due to another task's failure. /// `saved_error`: an optional pre-converted execution error. pub fn from_execution( cache_status: &CacheStatus, exit_status: Option, + is_cancelled: bool, saved_error: Option<&SavedExecutionError>, ) -> Self { match cache_status { @@ -267,13 +272,13 @@ impl TaskResult { CacheStatus::Disabled(CacheDisabledReason::InProcessExecution) => Self::InProcess, CacheStatus::Disabled(CacheDisabledReason::NoCacheMetadata) => Self::Spawned { cache_status: SpawnedCacheStatus::Disabled, - outcome: spawn_outcome_from_execution(exit_status, saved_error), + outcome: spawn_outcome_from_execution(exit_status, is_cancelled, saved_error), }, CacheStatus::Miss(cache_miss) => Self::Spawned { cache_status: SpawnedCacheStatus::Miss(SavedCacheMissReason::from_cache_miss( cache_miss, )), - outcome: spawn_outcome_from_execution(exit_status, saved_error), + outcome: spawn_outcome_from_execution(exit_status, is_cancelled, saved_error), }, } } @@ -282,6 +287,7 @@ impl TaskResult { /// Build a [`SpawnOutcome`] from process exit status and optional pre-converted error. fn spawn_outcome_from_execution( exit_status: Option, + is_cancelled: bool, saved_error: Option<&SavedExecutionError>, ) -> SpawnOutcome { match (exit_status, saved_error) { @@ -299,6 +305,7 @@ fn spawn_outcome_from_execution( // implementation: always positive, non-zero for non-success status). // NonZeroI32::new returns None only for 0, which cannot happen here. exit_code: NonZeroI32::new(code).unwrap_or(NonZeroI32::MIN), + is_cancelled, } } // No exit status, no error — this is the cache hit / in-process path, @@ -546,6 +553,16 @@ pub fn format_full_summary(summary: &LastRunSummary) -> Vec { if !failed_str.is_empty() { let _ = write!(buf, " {failed_str}"); } + + let cancelled_str = if stats.cancelled > 0 { + let n = stats.cancelled; + Str::from(vite_str::format!("• {n} cancelled").style(Style::new().red()).to_string()) + } else { + Str::default() + }; + if !cancelled_str.is_empty() { + let _ = write!(buf, " {cancelled_str}"); + } let _ = writeln!(buf); // Performance line @@ -607,16 +624,27 @@ pub fn format_full_summary(summary: &LastRunSummary) -> Vec { // Exit icon if task.result.is_success() { let _ = write!(buf, " {}", "✓".style(Style::new().green().bold())); - } else if let TaskResult::Spawned { outcome: SpawnOutcome::Failed { exit_code }, .. } = - &task.result + } else if let TaskResult::Spawned { + outcome: SpawnOutcome::Failed { exit_code, is_cancelled }, + .. + } = &task.result { - let code = exit_code.get(); - let _ = write!( - buf, - " {} {}", - "✗".style(Style::new().red().bold()), - vite_str::format!("(exit code: {code})").style(Style::new().red()) - ); + if *is_cancelled { + let _ = write!( + buf, + " {} {}", + "✗".style(Style::new().red().bold()), + "(cancelled)".style(Style::new().red()) + ); + } else { + let code = exit_code.get(); + let _ = write!( + buf, + " {} {}", + "✗".style(Style::new().red().bold()), + vite_str::format!("(exit code: {code})").style(Style::new().red()) + ); + } } let _ = writeln!(buf); @@ -727,6 +755,11 @@ pub fn format_compact_summary(summary: &LastRunSummary, program_name: &str) -> V let _ = write!(buf, ", {} failed", n.style(Style::new().red())); } + if stats.cancelled > 0 { + let n = stats.cancelled; + let _ = write!(buf, ", {} cancelled", n.style(Style::new().red())); + } + let last_details_cmd = vite_str::format!("`{program_name} run --last-details`"); let _ = write!(buf, ". {}", "(Run ".style(Style::new().bright_black())); let _ = write!(buf, "{}", last_details_cmd.as_str().style(COMMAND_STYLE)); diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/builtin-non-zero-exit/snapshots/builtin command with non-zero exit does not show cache not updated.snap b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/builtin-non-zero-exit/snapshots/builtin command with non-zero exit does not show cache not updated.snap index 71a5760e..1c5186de 100644 --- a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/builtin-non-zero-exit/snapshots/builtin command with non-zero exit does not show cache not updated.snap +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/builtin-non-zero-exit/snapshots/builtin command with non-zero exit does not show cache not updated.snap @@ -14,6 +14,7 @@ $ vt lint -D no-debugger Found 0 warnings and 1 error. Finished in on 1 file with 90 rules using threads. +✗ exit code 1 [1]> vt run lint -- -D no-debugger $ vt lint -D no-debugger @@ -26,3 +27,4 @@ $ vt lint -D no-debugger Found 0 warnings and 1 error. Finished in on 1 file with 90 rules using threads. +✗ exit code 1 diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/exit-codes/snapshots.toml b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/exit-codes/snapshots.toml index 7364a489..6eb67f56 100644 --- a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/exit-codes/snapshots.toml +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/exit-codes/snapshots.toml @@ -7,7 +7,8 @@ steps = [ ] [[e2e]] -name = "multiple task failures returns exit code 1" +name = "recursive failure fast-fails and returns task exit code" +# --concurrency=1: deterministic execution order for snapshot stability steps = [ - "vt run -r fail # multiple failures -> exit code 1", + "vt run -r fail --concurrency=1 # fast-fail: only first failure runs", ] diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/exit-codes/snapshots/multiple task failures returns exit code 1.snap b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/exit-codes/snapshots/multiple task failures returns exit code 1.snap deleted file mode 100644 index 9aa35d37..00000000 --- a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/exit-codes/snapshots/multiple task failures returns exit code 1.snap +++ /dev/null @@ -1,11 +0,0 @@ ---- -source: crates/vite_task_bin/tests/e2e_snapshots/main.rs -expression: e2e_outputs ---- -[1]> vt run -r fail # multiple failures -> exit code 1 -~/packages/pkg-a$ node -e "process.exit(42)" - -~/packages/pkg-b$ node -e "process.exit(7)" - ---- -vt run: 0/2 cache hit (0%), 2 failed. (Run `vt run --last-details` for full details) diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/exit-codes/snapshots/recursive failure fast-fails and returns task exit code.snap b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/exit-codes/snapshots/recursive failure fast-fails and returns task exit code.snap new file mode 100644 index 00000000..c60adc07 --- /dev/null +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/exit-codes/snapshots/recursive failure fast-fails and returns task exit code.snap @@ -0,0 +1,7 @@ +--- +source: crates/vite_task_bin/tests/e2e_snapshots/main.rs +expression: e2e_outputs +--- +[7]> vt run -r fail --concurrency=1 # fast-fail: only first failure runs +~/packages/pkg-b$ node -e "process.exit(7)" +✗ exit code 7 diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/exit-codes/snapshots/single task failure returns task exit code.snap b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/exit-codes/snapshots/single task failure returns task exit code.snap index a8e9d7fb..322b417c 100644 --- a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/exit-codes/snapshots/single task failure returns task exit code.snap +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/exit-codes/snapshots/single task failure returns task exit code.snap @@ -4,3 +4,4 @@ expression: e2e_outputs --- [42]> vt run pkg-a#fail # exits with code 42 ~/packages/pkg-a$ node -e "process.exit(42)" +✗ exit code 42 diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/fast-fail/package.json b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/fast-fail/package.json new file mode 100644 index 00000000..b290e21c --- /dev/null +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/fast-fail/package.json @@ -0,0 +1,4 @@ +{ + "name": "fast-fail-test", + "private": true +} diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/fast-fail/packages/pkg-a/package.json b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/fast-fail/packages/pkg-a/package.json new file mode 100644 index 00000000..eadfae71 --- /dev/null +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/fast-fail/packages/pkg-a/package.json @@ -0,0 +1,10 @@ +{ + "name": "pkg-a", + "dependencies": { + "pkg-b": "workspace:*", + "pkg-c": "workspace:*" + }, + "scripts": { + "build": "echo 'Building A'" + } +} diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/fast-fail/packages/pkg-b/package.json b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/fast-fail/packages/pkg-b/package.json new file mode 100644 index 00000000..f67265bb --- /dev/null +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/fast-fail/packages/pkg-b/package.json @@ -0,0 +1,6 @@ +{ + "name": "pkg-b", + "scripts": { + "build": "node -e \"process.exit(1)\"" + } +} diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/fast-fail/packages/pkg-c/package.json b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/fast-fail/packages/pkg-c/package.json new file mode 100644 index 00000000..a3883103 --- /dev/null +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/fast-fail/packages/pkg-c/package.json @@ -0,0 +1,6 @@ +{ + "name": "pkg-c", + "scripts": { + "build": "node -e \"setTimeout(() => {}, 999999)\"" + } +} diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/fast-fail/pnpm-workspace.yaml b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/fast-fail/pnpm-workspace.yaml new file mode 100644 index 00000000..924b55f4 --- /dev/null +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/fast-fail/pnpm-workspace.yaml @@ -0,0 +1,2 @@ +packages: + - packages/* diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/fast-fail/snapshots.toml b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/fast-fail/snapshots.toml new file mode 100644 index 00000000..04aa0a9f --- /dev/null +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/fast-fail/snapshots.toml @@ -0,0 +1,10 @@ +# Tests fast-fail: execution stops on first failure and cancels in-flight tasks. +# Dependency graph: pkg-a depends on pkg-b and pkg-c. +# pkg-b#build exits immediately with 1, pkg-c#build hangs forever. +# Expected: pkg-b fails, pkg-c is cancelled, pkg-a never starts. + +[[e2e]] +name = "failure cancels in-flight tasks and skips dependents" +steps = [ + "vp run -r build # pkg-b fails, pkg-c cancelled, pkg-a skipped", +] diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/fast-fail/snapshots/failure cancels in-flight tasks and skips dependents.snap b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/fast-fail/snapshots/failure cancels in-flight tasks and skips dependents.snap new file mode 100644 index 00000000..c7f72c58 --- /dev/null +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/fast-fail/snapshots/failure cancels in-flight tasks and skips dependents.snap @@ -0,0 +1,13 @@ +--- +source: crates/vite_task_bin/tests/e2e_snapshots/main.rs +expression: e2e_outputs +--- +[1]> vp run -r build # pkg-b fails, pkg-c cancelled, pkg-a skipped +~/packages/pkg-b$ node -e "process.exit(1)" ⊘ cache disabled +✗ exit code 1 + +~/packages/pkg-c$ node -e "setTimeout(() => {}, 999999)" ⊘ cache disabled +✗ cancelled + +--- +[vp run] 0/2 cache hit (0%), 1 failed, 1 cancelled. (Run `vp run --last-details` for full details) diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/fast-fail/vite-task.json b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/fast-fail/vite-task.json new file mode 100644 index 00000000..b39113d0 --- /dev/null +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/fast-fail/vite-task.json @@ -0,0 +1,3 @@ +{ + "cache": false +} diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/signal-exit/snapshots/signal terminated task returns non-zero exit code.snap b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/signal-exit/snapshots/signal terminated task returns non-zero exit code.snap index 2916a7ab..86d45881 100644 --- a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/signal-exit/snapshots/signal terminated task returns non-zero exit code.snap +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/signal-exit/snapshots/signal terminated task returns non-zero exit code.snap @@ -4,3 +4,4 @@ expression: e2e_outputs --- [134]> vt run abort # SIGABRT -> exit code 134 $ node -e "process.kill(process.pid, 6)" +✗ exit code 134 diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdin-inheritance/snapshots.toml b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdin-inheritance/snapshots.toml index d5ade7ac..99e72c8f 100644 --- a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdin-inheritance/snapshots.toml +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdin-inheritance/snapshots.toml @@ -27,6 +27,7 @@ steps = [ name = "multiple tasks get null stdin" # Multiple spawn leaves → stdin is null regardless of cache setting # The piped "from-stdin" should NOT appear in any task's output +# --concurrency=1: deterministic output ordering for snapshot stability steps = [ - "echo from-stdin | vt run -r read-stdin", + "echo from-stdin | vt run -r read-stdin --concurrency=1", ] diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdin-inheritance/snapshots/multiple tasks get null stdin.snap b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdin-inheritance/snapshots/multiple tasks get null stdin.snap index fcb59106..de29cc14 100644 --- a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdin-inheritance/snapshots/multiple tasks get null stdin.snap +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdin-inheritance/snapshots/multiple tasks get null stdin.snap @@ -2,10 +2,10 @@ source: crates/vite_task_bin/tests/e2e_snapshots/main.rs expression: e2e_outputs --- -> echo from-stdin | vt run -r read-stdin -~/packages/other$ read-stdin - +> echo from-stdin | vt run -r read-stdin --concurrency=1 $ read-stdin ⊘ cache disabled +~/packages/other$ read-stdin + --- vt run: 0/2 cache hit (0%). (Run `vt run --last-details` for full details) diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdio-detection/snapshots.toml b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdio-detection/snapshots.toml index d8fabfb1..2fe290d6 100644 --- a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdio-detection/snapshots.toml +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdio-detection/snapshots.toml @@ -37,21 +37,24 @@ steps = [ [[e2e]] name = "multiple tasks, cache disabled" # Expect: stdio piped for labeled output (not-tty) +# --concurrency=1: deterministic output ordering for snapshot stability steps = [ - "vt run -r check-tty", + "vt run -r check-tty --concurrency=1", ] [[e2e]] name = "multiple tasks, cache miss" # Expect: stdio piped (not-tty) +# --concurrency=1: deterministic output ordering for snapshot stability steps = [ - "vt run -r check-tty-cached", + "vt run -r check-tty-cached --concurrency=1", ] [[e2e]] name = "multiple tasks, cache hit" # Expect: first run is a miss (not-tty), second run replays cached output +# --concurrency=1: deterministic output ordering for snapshot stability steps = [ - "vt run -r check-tty-cached", - "vt run -r check-tty-cached", + "vt run -r check-tty-cached --concurrency=1", + "vt run -r check-tty-cached --concurrency=1", ] diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdio-detection/snapshots/multiple tasks, cache disabled.snap b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdio-detection/snapshots/multiple tasks, cache disabled.snap index 6ff4287b..aee4dbd2 100644 --- a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdio-detection/snapshots/multiple tasks, cache disabled.snap +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdio-detection/snapshots/multiple tasks, cache disabled.snap @@ -2,13 +2,13 @@ source: crates/vite_task_bin/tests/e2e_snapshots/main.rs expression: e2e_outputs --- -> vt run -r check-tty -~/packages/other$ check-tty +> vt run -r check-tty --concurrency=1 +$ check-tty ⊘ cache disabled stdin:not-tty stdout:not-tty stderr:not-tty -$ check-tty ⊘ cache disabled +~/packages/other$ check-tty stdin:not-tty stdout:not-tty stderr:not-tty diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdio-detection/snapshots/multiple tasks, cache hit.snap b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdio-detection/snapshots/multiple tasks, cache hit.snap index d3328fdc..d30d46e6 100644 --- a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdio-detection/snapshots/multiple tasks, cache hit.snap +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdio-detection/snapshots/multiple tasks, cache hit.snap @@ -2,26 +2,26 @@ source: crates/vite_task_bin/tests/e2e_snapshots/main.rs expression: e2e_outputs --- -> vt run -r check-tty-cached -~/packages/other$ check-tty +> vt run -r check-tty-cached --concurrency=1 +$ check-tty stdin:not-tty stdout:not-tty stderr:not-tty -$ check-tty +~/packages/other$ check-tty stdin:not-tty stdout:not-tty stderr:not-tty --- vt run: 0/2 cache hit (0%). (Run `vt run --last-details` for full details) -> vt run -r check-tty-cached -~/packages/other$ check-tty ✓ cache hit, replaying +> vt run -r check-tty-cached --concurrency=1 +$ check-tty ✓ cache hit, replaying stdin:not-tty stdout:not-tty stderr:not-tty -$ check-tty ✓ cache hit, replaying +~/packages/other$ check-tty ✓ cache hit, replaying stdin:not-tty stdout:not-tty stderr:not-tty diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdio-detection/snapshots/multiple tasks, cache miss.snap b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdio-detection/snapshots/multiple tasks, cache miss.snap index b775978f..d8c7c10f 100644 --- a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdio-detection/snapshots/multiple tasks, cache miss.snap +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdio-detection/snapshots/multiple tasks, cache miss.snap @@ -2,13 +2,13 @@ source: crates/vite_task_bin/tests/e2e_snapshots/main.rs expression: e2e_outputs --- -> vt run -r check-tty-cached -~/packages/other$ check-tty +> vt run -r check-tty-cached --concurrency=1 +$ check-tty stdin:not-tty stdout:not-tty stderr:not-tty -$ check-tty +~/packages/other$ check-tty stdin:not-tty stdout:not-tty stderr:not-tty diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdio-graph-criteria/snapshots.toml b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdio-graph-criteria/snapshots.toml index 54375790..d2d9efd3 100644 --- a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdio-graph-criteria/snapshots.toml +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdio-graph-criteria/snapshots.toml @@ -8,12 +8,14 @@ [[e2e]] name = "single-node chains inherit even with multi-node sibling graph" +# --concurrency=1: deterministic output ordering for snapshot stability steps = [ - "vt run foo", + "vt run foo --concurrency=1", ] [[e2e]] name = "multi-node ancestor forces piped for nested single-node graph" +# --concurrency=1: deterministic output ordering for snapshot stability steps = [ - "vt run -r foo-nested", + "vt run -r foo-nested --concurrency=1", ] diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdio-graph-criteria/snapshots/multi-node ancestor forces piped for nested single-node graph.snap b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdio-graph-criteria/snapshots/multi-node ancestor forces piped for nested single-node graph.snap index 266dc666..0c12b665 100644 --- a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdio-graph-criteria/snapshots/multi-node ancestor forces piped for nested single-node graph.snap +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdio-graph-criteria/snapshots/multi-node ancestor forces piped for nested single-node graph.snap @@ -2,13 +2,13 @@ source: crates/vite_task_bin/tests/e2e_snapshots/main.rs expression: e2e_outputs --- -> vt run -r foo-nested -~/packages/other$ check-tty ⊘ cache disabled +> vt run -r foo-nested --concurrency=1 +$ check-tty ⊘ cache disabled stdin:not-tty stdout:not-tty stderr:not-tty -$ check-tty ⊘ cache disabled +~/packages/other$ check-tty ⊘ cache disabled stdin:not-tty stdout:not-tty stderr:not-tty diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdio-graph-criteria/snapshots/single-node chains inherit even with multi-node sibling graph.snap b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdio-graph-criteria/snapshots/single-node chains inherit even with multi-node sibling graph.snap index 0e80e8cf..d2af740f 100644 --- a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdio-graph-criteria/snapshots/single-node chains inherit even with multi-node sibling graph.snap +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdio-graph-criteria/snapshots/single-node chains inherit even with multi-node sibling graph.snap @@ -2,7 +2,7 @@ source: crates/vite_task_bin/tests/e2e_snapshots/main.rs expression: e2e_outputs --- -> vt run foo +> vt run foo --concurrency=1 $ check-tty ⊘ cache disabled stdin:tty stdout:tty @@ -13,12 +13,12 @@ stdin:tty stdout:tty stderr:tty -~/packages/other$ check-tty ⊘ cache disabled +$ check-tty ⊘ cache disabled stdin:not-tty stdout:not-tty stderr:not-tty -$ check-tty ⊘ cache disabled +~/packages/other$ check-tty ⊘ cache disabled stdin:not-tty stdout:not-tty stderr:not-tty diff --git a/crates/vite_task_plan/src/context.rs b/crates/vite_task_plan/src/context.rs index 119d68af..0ef0c6f1 100644 --- a/crates/vite_task_plan/src/context.rs +++ b/crates/vite_task_plan/src/context.rs @@ -48,9 +48,14 @@ pub struct PlanContext<'a> { /// The query that caused the current expansion. /// Used by the skip rule to detect and skip duplicate nested expansions. parent_query: Arc, + + /// Maximum number of tasks to run concurrently in the execution graph. + /// Inherited by nested expansions unless overridden by an explicit `--concurrency` flag. + concurrency: usize, } impl<'a> PlanContext<'a> { + #[expect(clippy::too_many_arguments, reason = "context bundles all planning state")] pub fn new( workspace_path: &'a Arc, cwd: Arc, @@ -59,6 +64,7 @@ impl<'a> PlanContext<'a> { indexed_task_graph: &'a IndexedTaskGraph, resolved_global_cache: ResolvedGlobalCacheConfig, parent_query: Arc, + concurrency: usize, ) -> Self { Self { workspace_path, @@ -70,6 +76,7 @@ impl<'a> PlanContext<'a> { extra_args: Arc::default(), resolved_global_cache, parent_query, + concurrency, } } @@ -144,6 +151,14 @@ impl<'a> PlanContext<'a> { self.parent_query = query; } + pub const fn concurrency(&self) -> usize { + self.concurrency + } + + pub const fn set_concurrency(&mut self, concurrency: usize) { + self.concurrency = concurrency; + } + /// Returns the task currently being expanded (whose command triggered a nested query). /// This is the last task on the call stack, or `None` at the top level. pub fn expanding_task(&self) -> Option { @@ -161,6 +176,7 @@ impl<'a> PlanContext<'a> { extra_args: Arc::clone(&self.extra_args), resolved_global_cache: self.resolved_global_cache, parent_query: Arc::clone(&self.parent_query), + concurrency: self.concurrency, } } } diff --git a/crates/vite_task_plan/src/execution_graph.rs b/crates/vite_task_plan/src/execution_graph.rs index 5a884296..b1a99af0 100644 --- a/crates/vite_task_plan/src/execution_graph.rs +++ b/crates/vite_task_plan/src/execution_graph.rs @@ -155,8 +155,31 @@ impl Index> for AcyclicGraph { } } -/// The execution graph type alias, specialized for task execution. -pub type ExecutionGraph = AcyclicGraph; +/// The execution graph: a DAG of task executions with a resolved concurrency limit. +/// +/// Concurrency is always a concrete `usize` — inheritance from parent `PlanContext` +/// is resolved at plan time before storing here. +#[derive(Debug, Serialize)] +pub struct ExecutionGraph { + /// The underlying acyclic graph of task executions. + pub graph: AcyclicGraph, + /// Maximum number of tasks to run concurrently in this graph. + pub concurrency: usize, +} + +impl ExecutionGraph { + /// Validate that `inner_graph` is acyclic and wrap it with the given concurrency. + /// + /// # Errors + /// + /// Returns [`CycleError`] if the graph contains a cycle. + pub fn try_from_graph( + inner_graph: InnerExecutionGraph, + concurrency: usize, + ) -> Result> { + Ok(Self { graph: AcyclicGraph::try_from_graph(inner_graph)?, concurrency }) + } +} impl Serialize for AcyclicGraph { fn serialize(&self, serializer: S) -> Result { diff --git a/crates/vite_task_plan/src/lib.rs b/crates/vite_task_plan/src/lib.rs index 8ab7aa7e..88942b54 100644 --- a/crates/vite_task_plan/src/lib.rs +++ b/crates/vite_task_plan/src/lib.rs @@ -23,6 +23,9 @@ use vite_path::AbsolutePath; use vite_str::Str; use vite_task_graph::{TaskGraphLoadError, display::TaskDisplay}; +/// Default number of concurrent tasks when `--concurrency` is not specified. +const DEFAULT_CONCURRENCY: usize = 10; + /// A resolved spawn execution. /// /// Unlike tasks in `vite_task_graph`, this struct contains all information needed for execution, @@ -206,6 +209,7 @@ pub async fn plan_query( ); let QueryPlanRequest { query, plan_options } = query_plan_request; + let concurrency = plan_options.concurrency; let query = Arc::new(query); let context = PlanContext::new( workspace_path, @@ -215,6 +219,7 @@ pub async fn plan_query( indexed_task_graph, resolved_global_cache, Arc::clone(&query), + concurrency.unwrap_or(DEFAULT_CONCURRENCY), ); plan_query_request(query, plan_options, context).await } diff --git a/crates/vite_task_plan/src/plan.rs b/crates/vite_task_plan/src/plan.rs index a78addfc..222da75f 100644 --- a/crates/vite_task_plan/src/plan.rs +++ b/crates/vite_task_plan/src/plan.rs @@ -231,7 +231,7 @@ async fn plan_task_as_execution_node( // An empty execution graph means no tasks matched the query. // At the top level the session shows the task selector UI, // but in a nested context there is no UI — propagate as an error. - if execution_graph.node_count() == 0 { + if execution_graph.graph.node_count() == 0 { return Err(Error::NestPlan { task_display: task_node.task_display.clone(), command: Str::from(&command_str[add_item_span]), @@ -610,6 +610,11 @@ pub async fn plan_query_request( ); context.set_resolved_global_cache(final_cache); } + // Apply concurrency override from `--concurrency` flag on this request. + // When `None`, keep the parent context's concurrency (inheritance). + if let Some(c) = plan_options.concurrency { + context.set_concurrency(c); + } context.set_extra_args(plan_options.extra_args); context.set_parent_query(Arc::clone(&query)); @@ -688,7 +693,7 @@ pub async fn plan_query_request( // Validate the graph is acyclic. // `try_from_graph` performs a DFS; if a cycle is found, it returns // `CycleError` containing the full cycle path as node indices. - ExecutionGraph::try_from_graph(inner_graph).map_err(|cycle| { + ExecutionGraph::try_from_graph(inner_graph, context.concurrency()).map_err(|cycle| { // Map each execution node index in the cycle path to its human-readable TaskDisplay. // Every node in the cycle was added via `inner_graph.add_node()` above, // with a corresponding entry in `execution_node_indices_by_task_index`. diff --git a/crates/vite_task_plan/src/plan_request.rs b/crates/vite_task_plan/src/plan_request.rs index eb5716f5..b28aaf27 100644 --- a/crates/vite_task_plan/src/plan_request.rs +++ b/crates/vite_task_plan/src/plan_request.rs @@ -49,6 +49,10 @@ pub enum CacheOverride { pub struct PlanOptions { pub extra_args: Arc<[Str]>, pub cache_override: CacheOverride, + /// Maximum number of tasks to run concurrently. + /// `None` means inherit from the parent `PlanContext` (for nested `vp run`). + /// Top-level callers should always set `Some(N)`. + pub concurrency: Option, } #[derive(Debug)] diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/additional-env/snapshots/query - env-test synthetic task in user task.snap b/crates/vite_task_plan/tests/plan_snapshots/fixtures/additional-env/snapshots/query - env-test synthetic task in user task.snap index 0aae6b1d..76a62b5e 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/additional-env/snapshots/query - env-test synthetic task in user task.snap +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/additional-env/snapshots/query - env-test synthetic task in user task.snap @@ -7,84 +7,87 @@ info: - env-test input_file: crates/vite_task_plan/tests/plan_snapshots/fixtures/additional-env --- -[ - { - "key": [ - "/", - "env-test" - ], - "node": { - "task_display": { - "package_name": "additional-envs", - "task_name": "env-test", - "package_path": "/" - }, - "items": [ - { - "execution_item_display": { - "task_display": { - "package_name": "additional-envs", - "task_name": "env-test", - "package_path": "/" +{ + "graph": [ + { + "key": [ + "/", + "env-test" + ], + "node": { + "task_display": { + "package_name": "additional-envs", + "task_name": "env-test", + "package_path": "/" + }, + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "additional-envs", + "task_name": "env-test", + "package_path": "/" + }, + "command": "vt env-test TEST_VAR hello_world", + "and_item_index": null, + "cwd": "/" }, - "command": "vt env-test TEST_VAR hello_world", - "and_item_index": null, - "cwd": "/" - }, - "kind": { - "Leaf": { - "Spawn": { - "cache_metadata": { - "spawn_fingerprint": { - "cwd": "", - "program_fingerprint": { - "OutsideWorkspace": { - "program_name": "print-env" + "kind": { + "Leaf": { + "Spawn": { + "cache_metadata": { + "spawn_fingerprint": { + "cwd": "", + "program_fingerprint": { + "OutsideWorkspace": { + "program_name": "print-env" + } + }, + "args": [ + "TEST_VAR" + ], + "env_fingerprints": { + "fingerprinted_envs": {}, + "untracked_env_config": [ + "TEST_VAR", + "" + ] + } + }, + "execution_cache_key": { + "UserTask": { + "task_name": "env-test", + "and_item_index": 0, + "extra_args": [], + "package_path": "" } }, + "input_config": { + "includes_auto": true, + "positive_globs": [], + "negative_globs": [] + } + }, + "spawn_command": { + "program_path": "/node_modules/.bin/print-env", "args": [ "TEST_VAR" ], - "env_fingerprints": { - "fingerprinted_envs": {}, - "untracked_env_config": [ - "TEST_VAR", - "" - ] - } - }, - "execution_cache_key": { - "UserTask": { - "task_name": "env-test", - "and_item_index": 0, - "extra_args": [], - "package_path": "" - } - }, - "input_config": { - "includes_auto": true, - "positive_globs": [], - "negative_globs": [] + "all_envs": { + "NO_COLOR": "1", + "PATH": "/node_modules/.bin:/node_modules/.bin", + "TEST_VAR": "hello_world" + }, + "cwd": "/" } - }, - "spawn_command": { - "program_path": "/node_modules/.bin/print-env", - "args": [ - "TEST_VAR" - ], - "all_envs": { - "NO_COLOR": "1", - "PATH": "/node_modules/.bin:/node_modules/.bin", - "TEST_VAR": "hello_world" - }, - "cwd": "/" } } } } - } - ] - }, - "neighbors": [] - } -] + ] + }, + "neighbors": [] + } + ], + "concurrency": 10 +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-cli-override/snapshots/query - --cache does not override per-task cache false.snap b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-cli-override/snapshots/query - --cache does not override per-task cache false.snap index 56305ec9..d88884b0 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-cli-override/snapshots/query - --cache does not override per-task cache false.snap +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-cli-override/snapshots/query - --cache does not override per-task cache false.snap @@ -8,51 +8,54 @@ info: - deploy input_file: crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-cli-override --- -[ - { - "key": [ - "/", - "deploy" - ], - "node": { - "task_display": { - "package_name": "@test/cache-cli-override", - "task_name": "deploy", - "package_path": "/" - }, - "items": [ - { - "execution_item_display": { - "task_display": { - "package_name": "@test/cache-cli-override", - "task_name": "deploy", - "package_path": "/" +{ + "graph": [ + { + "key": [ + "/", + "deploy" + ], + "node": { + "task_display": { + "package_name": "@test/cache-cli-override", + "task_name": "deploy", + "package_path": "/" + }, + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "@test/cache-cli-override", + "task_name": "deploy", + "package_path": "/" + }, + "command": "print-file vite-task.json", + "and_item_index": null, + "cwd": "/" }, - "command": "print-file vite-task.json", - "and_item_index": null, - "cwd": "/" - }, - "kind": { - "Leaf": { - "Spawn": { - "cache_metadata": null, - "spawn_command": { - "program_path": "/node_modules/.bin/print-file", - "args": [ - "vite-task.json" - ], - "all_envs": { - "NO_COLOR": "1", - "PATH": "/node_modules/.bin:/node_modules/.bin" - }, - "cwd": "/" + "kind": { + "Leaf": { + "Spawn": { + "cache_metadata": null, + "spawn_command": { + "program_path": "/node_modules/.bin/print-file", + "args": [ + "vite-task.json" + ], + "all_envs": { + "NO_COLOR": "1", + "PATH": "/node_modules/.bin:/node_modules/.bin" + }, + "cwd": "/" + } } } } } - } - ] - }, - "neighbors": [] - } -] + ] + }, + "neighbors": [] + } + ], + "concurrency": 10 +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-cli-override/snapshots/query - --cache enables script caching.snap b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-cli-override/snapshots/query - --cache enables script caching.snap index 121aa6e4..f488a94f 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-cli-override/snapshots/query - --cache enables script caching.snap +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-cli-override/snapshots/query - --cache enables script caching.snap @@ -8,82 +8,85 @@ info: - test input_file: crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-cli-override --- -[ - { - "key": [ - "/", - "test" - ], - "node": { - "task_display": { - "package_name": "@test/cache-cli-override", - "task_name": "test", - "package_path": "/" - }, - "items": [ - { - "execution_item_display": { - "task_display": { - "package_name": "@test/cache-cli-override", - "task_name": "test", - "package_path": "/" +{ + "graph": [ + { + "key": [ + "/", + "test" + ], + "node": { + "task_display": { + "package_name": "@test/cache-cli-override", + "task_name": "test", + "package_path": "/" + }, + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "@test/cache-cli-override", + "task_name": "test", + "package_path": "/" + }, + "command": "print-file package.json", + "and_item_index": null, + "cwd": "/" }, - "command": "print-file package.json", - "and_item_index": null, - "cwd": "/" - }, - "kind": { - "Leaf": { - "Spawn": { - "cache_metadata": { - "spawn_fingerprint": { - "cwd": "", - "program_fingerprint": { - "OutsideWorkspace": { - "program_name": "print-file" + "kind": { + "Leaf": { + "Spawn": { + "cache_metadata": { + "spawn_fingerprint": { + "cwd": "", + "program_fingerprint": { + "OutsideWorkspace": { + "program_name": "print-file" + } + }, + "args": [ + "package.json" + ], + "env_fingerprints": { + "fingerprinted_envs": {}, + "untracked_env_config": [ + "" + ] + } + }, + "execution_cache_key": { + "UserTask": { + "task_name": "test", + "and_item_index": 0, + "extra_args": [], + "package_path": "" } }, + "input_config": { + "includes_auto": true, + "positive_globs": [], + "negative_globs": [] + } + }, + "spawn_command": { + "program_path": "/node_modules/.bin/print-file", "args": [ "package.json" ], - "env_fingerprints": { - "fingerprinted_envs": {}, - "untracked_env_config": [ - "" - ] - } - }, - "execution_cache_key": { - "UserTask": { - "task_name": "test", - "and_item_index": 0, - "extra_args": [], - "package_path": "" - } - }, - "input_config": { - "includes_auto": true, - "positive_globs": [], - "negative_globs": [] + "all_envs": { + "NO_COLOR": "1", + "PATH": "/node_modules/.bin:/node_modules/.bin" + }, + "cwd": "/" } - }, - "spawn_command": { - "program_path": "/node_modules/.bin/print-file", - "args": [ - "package.json" - ], - "all_envs": { - "NO_COLOR": "1", - "PATH": "/node_modules/.bin:/node_modules/.bin" - }, - "cwd": "/" } } } } - } - ] - }, - "neighbors": [] - } -] + ] + }, + "neighbors": [] + } + ], + "concurrency": 10 +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-cli-override/snapshots/query - --cache enables task caching even when cache.tasks is false.snap b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-cli-override/snapshots/query - --cache enables task caching even when cache.tasks is false.snap index d4c3cd11..a94db36b 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-cli-override/snapshots/query - --cache enables task caching even when cache.tasks is false.snap +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-cli-override/snapshots/query - --cache enables task caching even when cache.tasks is false.snap @@ -8,82 +8,85 @@ info: - build input_file: crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-cli-override --- -[ - { - "key": [ - "/", - "build" - ], - "node": { - "task_display": { - "package_name": "@test/cache-cli-override", - "task_name": "build", - "package_path": "/" - }, - "items": [ - { - "execution_item_display": { - "task_display": { - "package_name": "@test/cache-cli-override", - "task_name": "build", - "package_path": "/" +{ + "graph": [ + { + "key": [ + "/", + "build" + ], + "node": { + "task_display": { + "package_name": "@test/cache-cli-override", + "task_name": "build", + "package_path": "/" + }, + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "@test/cache-cli-override", + "task_name": "build", + "package_path": "/" + }, + "command": "print-file package.json", + "and_item_index": null, + "cwd": "/" }, - "command": "print-file package.json", - "and_item_index": null, - "cwd": "/" - }, - "kind": { - "Leaf": { - "Spawn": { - "cache_metadata": { - "spawn_fingerprint": { - "cwd": "", - "program_fingerprint": { - "OutsideWorkspace": { - "program_name": "print-file" + "kind": { + "Leaf": { + "Spawn": { + "cache_metadata": { + "spawn_fingerprint": { + "cwd": "", + "program_fingerprint": { + "OutsideWorkspace": { + "program_name": "print-file" + } + }, + "args": [ + "package.json" + ], + "env_fingerprints": { + "fingerprinted_envs": {}, + "untracked_env_config": [ + "" + ] + } + }, + "execution_cache_key": { + "UserTask": { + "task_name": "build", + "and_item_index": 0, + "extra_args": [], + "package_path": "" } }, + "input_config": { + "includes_auto": true, + "positive_globs": [], + "negative_globs": [] + } + }, + "spawn_command": { + "program_path": "/node_modules/.bin/print-file", "args": [ "package.json" ], - "env_fingerprints": { - "fingerprinted_envs": {}, - "untracked_env_config": [ - "" - ] - } - }, - "execution_cache_key": { - "UserTask": { - "task_name": "build", - "and_item_index": 0, - "extra_args": [], - "package_path": "" - } - }, - "input_config": { - "includes_auto": true, - "positive_globs": [], - "negative_globs": [] + "all_envs": { + "NO_COLOR": "1", + "PATH": "/node_modules/.bin:/node_modules/.bin" + }, + "cwd": "/" } - }, - "spawn_command": { - "program_path": "/node_modules/.bin/print-file", - "args": [ - "package.json" - ], - "all_envs": { - "NO_COLOR": "1", - "PATH": "/node_modules/.bin:/node_modules/.bin" - }, - "cwd": "/" } } } } - } - ] - }, - "neighbors": [] - } -] + ] + }, + "neighbors": [] + } + ], + "concurrency": 10 +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-cli-override/snapshots/query - --cache on task with per-task cache true enables caching.snap b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-cli-override/snapshots/query - --cache on task with per-task cache true enables caching.snap index e9e9bcce..725417d6 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-cli-override/snapshots/query - --cache on task with per-task cache true enables caching.snap +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-cli-override/snapshots/query - --cache on task with per-task cache true enables caching.snap @@ -8,82 +8,85 @@ info: - check input_file: crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-cli-override --- -[ - { - "key": [ - "/", - "check" - ], - "node": { - "task_display": { - "package_name": "@test/cache-cli-override", - "task_name": "check", - "package_path": "/" - }, - "items": [ - { - "execution_item_display": { - "task_display": { - "package_name": "@test/cache-cli-override", - "task_name": "check", - "package_path": "/" +{ + "graph": [ + { + "key": [ + "/", + "check" + ], + "node": { + "task_display": { + "package_name": "@test/cache-cli-override", + "task_name": "check", + "package_path": "/" + }, + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "@test/cache-cli-override", + "task_name": "check", + "package_path": "/" + }, + "command": "print-file package.json", + "and_item_index": null, + "cwd": "/" }, - "command": "print-file package.json", - "and_item_index": null, - "cwd": "/" - }, - "kind": { - "Leaf": { - "Spawn": { - "cache_metadata": { - "spawn_fingerprint": { - "cwd": "", - "program_fingerprint": { - "OutsideWorkspace": { - "program_name": "print-file" + "kind": { + "Leaf": { + "Spawn": { + "cache_metadata": { + "spawn_fingerprint": { + "cwd": "", + "program_fingerprint": { + "OutsideWorkspace": { + "program_name": "print-file" + } + }, + "args": [ + "package.json" + ], + "env_fingerprints": { + "fingerprinted_envs": {}, + "untracked_env_config": [ + "" + ] + } + }, + "execution_cache_key": { + "UserTask": { + "task_name": "check", + "and_item_index": 0, + "extra_args": [], + "package_path": "" } }, + "input_config": { + "includes_auto": true, + "positive_globs": [], + "negative_globs": [] + } + }, + "spawn_command": { + "program_path": "/node_modules/.bin/print-file", "args": [ "package.json" ], - "env_fingerprints": { - "fingerprinted_envs": {}, - "untracked_env_config": [ - "" - ] - } - }, - "execution_cache_key": { - "UserTask": { - "task_name": "check", - "and_item_index": 0, - "extra_args": [], - "package_path": "" - } - }, - "input_config": { - "includes_auto": true, - "positive_globs": [], - "negative_globs": [] + "all_envs": { + "NO_COLOR": "1", + "PATH": "/node_modules/.bin:/node_modules/.bin" + }, + "cwd": "/" } - }, - "spawn_command": { - "program_path": "/node_modules/.bin/print-file", - "args": [ - "package.json" - ], - "all_envs": { - "NO_COLOR": "1", - "PATH": "/node_modules/.bin:/node_modules/.bin" - }, - "cwd": "/" } } } } - } - ] - }, - "neighbors": [] - } -] + ] + }, + "neighbors": [] + } + ], + "concurrency": 10 +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-cli-override/snapshots/query - --no-cache disables task caching.snap b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-cli-override/snapshots/query - --no-cache disables task caching.snap index 115f4b49..481a08f8 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-cli-override/snapshots/query - --no-cache disables task caching.snap +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-cli-override/snapshots/query - --no-cache disables task caching.snap @@ -8,51 +8,54 @@ info: - build input_file: crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-cli-override --- -[ - { - "key": [ - "/", - "build" - ], - "node": { - "task_display": { - "package_name": "@test/cache-cli-override", - "task_name": "build", - "package_path": "/" - }, - "items": [ - { - "execution_item_display": { - "task_display": { - "package_name": "@test/cache-cli-override", - "task_name": "build", - "package_path": "/" +{ + "graph": [ + { + "key": [ + "/", + "build" + ], + "node": { + "task_display": { + "package_name": "@test/cache-cli-override", + "task_name": "build", + "package_path": "/" + }, + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "@test/cache-cli-override", + "task_name": "build", + "package_path": "/" + }, + "command": "print-file package.json", + "and_item_index": null, + "cwd": "/" }, - "command": "print-file package.json", - "and_item_index": null, - "cwd": "/" - }, - "kind": { - "Leaf": { - "Spawn": { - "cache_metadata": null, - "spawn_command": { - "program_path": "/node_modules/.bin/print-file", - "args": [ - "package.json" - ], - "all_envs": { - "NO_COLOR": "1", - "PATH": "/node_modules/.bin:/node_modules/.bin" - }, - "cwd": "/" + "kind": { + "Leaf": { + "Spawn": { + "cache_metadata": null, + "spawn_command": { + "program_path": "/node_modules/.bin/print-file", + "args": [ + "package.json" + ], + "all_envs": { + "NO_COLOR": "1", + "PATH": "/node_modules/.bin:/node_modules/.bin" + }, + "cwd": "/" + } } } } } - } - ] - }, - "neighbors": [] - } -] + ] + }, + "neighbors": [] + } + ], + "concurrency": 10 +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-cli-override/snapshots/query - --no-cache overrides per-task cache true.snap b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-cli-override/snapshots/query - --no-cache overrides per-task cache true.snap index 17c00630..7f42f246 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-cli-override/snapshots/query - --no-cache overrides per-task cache true.snap +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-cli-override/snapshots/query - --no-cache overrides per-task cache true.snap @@ -8,51 +8,54 @@ info: - check input_file: crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-cli-override --- -[ - { - "key": [ - "/", - "check" - ], - "node": { - "task_display": { - "package_name": "@test/cache-cli-override", - "task_name": "check", - "package_path": "/" - }, - "items": [ - { - "execution_item_display": { - "task_display": { - "package_name": "@test/cache-cli-override", - "task_name": "check", - "package_path": "/" +{ + "graph": [ + { + "key": [ + "/", + "check" + ], + "node": { + "task_display": { + "package_name": "@test/cache-cli-override", + "task_name": "check", + "package_path": "/" + }, + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "@test/cache-cli-override", + "task_name": "check", + "package_path": "/" + }, + "command": "print-file package.json", + "and_item_index": null, + "cwd": "/" }, - "command": "print-file package.json", - "and_item_index": null, - "cwd": "/" - }, - "kind": { - "Leaf": { - "Spawn": { - "cache_metadata": null, - "spawn_command": { - "program_path": "/node_modules/.bin/print-file", - "args": [ - "package.json" - ], - "all_envs": { - "NO_COLOR": "1", - "PATH": "/node_modules/.bin:/node_modules/.bin" - }, - "cwd": "/" + "kind": { + "Leaf": { + "Spawn": { + "cache_metadata": null, + "spawn_command": { + "program_path": "/node_modules/.bin/print-file", + "args": [ + "package.json" + ], + "all_envs": { + "NO_COLOR": "1", + "PATH": "/node_modules/.bin:/node_modules/.bin" + }, + "cwd": "/" + } } } } } - } - ] - }, - "neighbors": [] - } -] + ] + }, + "neighbors": [] + } + ], + "concurrency": 10 +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-cli-override/snapshots/query - baseline - tasks not cached when cache.tasks is false.snap b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-cli-override/snapshots/query - baseline - tasks not cached when cache.tasks is false.snap index 222b403f..5dfcd655 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-cli-override/snapshots/query - baseline - tasks not cached when cache.tasks is false.snap +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-cli-override/snapshots/query - baseline - tasks not cached when cache.tasks is false.snap @@ -7,51 +7,54 @@ info: - build input_file: crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-cli-override --- -[ - { - "key": [ - "/", - "build" - ], - "node": { - "task_display": { - "package_name": "@test/cache-cli-override", - "task_name": "build", - "package_path": "/" - }, - "items": [ - { - "execution_item_display": { - "task_display": { - "package_name": "@test/cache-cli-override", - "task_name": "build", - "package_path": "/" +{ + "graph": [ + { + "key": [ + "/", + "build" + ], + "node": { + "task_display": { + "package_name": "@test/cache-cli-override", + "task_name": "build", + "package_path": "/" + }, + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "@test/cache-cli-override", + "task_name": "build", + "package_path": "/" + }, + "command": "print-file package.json", + "and_item_index": null, + "cwd": "/" }, - "command": "print-file package.json", - "and_item_index": null, - "cwd": "/" - }, - "kind": { - "Leaf": { - "Spawn": { - "cache_metadata": null, - "spawn_command": { - "program_path": "/node_modules/.bin/print-file", - "args": [ - "package.json" - ], - "all_envs": { - "NO_COLOR": "1", - "PATH": "/node_modules/.bin:/node_modules/.bin" - }, - "cwd": "/" + "kind": { + "Leaf": { + "Spawn": { + "cache_metadata": null, + "spawn_command": { + "program_path": "/node_modules/.bin/print-file", + "args": [ + "package.json" + ], + "all_envs": { + "NO_COLOR": "1", + "PATH": "/node_modules/.bin:/node_modules/.bin" + }, + "cwd": "/" + } } } } } - } - ] - }, - "neighbors": [] - } -] + ] + }, + "neighbors": [] + } + ], + "concurrency": 10 +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-keys/snapshots/query - echo and lint with extra args.snap b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-keys/snapshots/query - echo and lint with extra args.snap index 1dafd5a9..8bf50e8b 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-keys/snapshots/query - echo and lint with extra args.snap +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-keys/snapshots/query - echo and lint with extra args.snap @@ -8,110 +8,113 @@ info: - "--fix" input_file: crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-keys --- -[ - { - "key": [ - "/", - "echo-and-lint" - ], - "node": { - "task_display": { - "package_name": "", - "task_name": "echo-and-lint", - "package_path": "/" - }, - "items": [ - { - "execution_item_display": { - "task_display": { - "package_name": "", - "task_name": "echo-and-lint", - "package_path": "/" +{ + "graph": [ + { + "key": [ + "/", + "echo-and-lint" + ], + "node": { + "task_display": { + "package_name": "", + "task_name": "echo-and-lint", + "package_path": "/" + }, + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "", + "task_name": "echo-and-lint", + "package_path": "/" + }, + "command": "echo Linting", + "and_item_index": 0, + "cwd": "/" }, - "command": "echo Linting", - "and_item_index": 0, - "cwd": "/" - }, - "kind": { - "Leaf": { - "InProcess": { - "kind": { - "Echo": { - "strings": [ - "Linting" - ], - "trailing_newline": true + "kind": { + "Leaf": { + "InProcess": { + "kind": { + "Echo": { + "strings": [ + "Linting" + ], + "trailing_newline": true + } } } } } - } - }, - { - "execution_item_display": { - "task_display": { - "package_name": "", - "task_name": "echo-and-lint", - "package_path": "/" - }, - "command": "vt lint --fix", - "and_item_index": 1, - "cwd": "/" }, - "kind": { - "Leaf": { - "Spawn": { - "cache_metadata": { - "spawn_fingerprint": { - "cwd": "", - "program_fingerprint": { - "OutsideWorkspace": { - "program_name": "oxlint" + { + "execution_item_display": { + "task_display": { + "package_name": "", + "task_name": "echo-and-lint", + "package_path": "/" + }, + "command": "vt lint --fix", + "and_item_index": 1, + "cwd": "/" + }, + "kind": { + "Leaf": { + "Spawn": { + "cache_metadata": { + "spawn_fingerprint": { + "cwd": "", + "program_fingerprint": { + "OutsideWorkspace": { + "program_name": "oxlint" + } + }, + "args": [ + "--fix" + ], + "env_fingerprints": { + "fingerprinted_envs": {}, + "untracked_env_config": [ + "" + ] } }, + "execution_cache_key": { + "UserTask": { + "task_name": "echo-and-lint", + "and_item_index": 1, + "extra_args": [ + "--fix" + ], + "package_path": "" + } + }, + "input_config": { + "includes_auto": true, + "positive_globs": [], + "negative_globs": [] + } + }, + "spawn_command": { + "program_path": "/node_modules/.bin/oxlint", "args": [ "--fix" ], - "env_fingerprints": { - "fingerprinted_envs": {}, - "untracked_env_config": [ - "" - ] - } - }, - "execution_cache_key": { - "UserTask": { - "task_name": "echo-and-lint", - "and_item_index": 1, - "extra_args": [ - "--fix" - ], - "package_path": "" - } - }, - "input_config": { - "includes_auto": true, - "positive_globs": [], - "negative_globs": [] + "all_envs": { + "NO_COLOR": "1", + "PATH": "/node_modules/.bin:/node_modules/.bin" + }, + "cwd": "/" } - }, - "spawn_command": { - "program_path": "/node_modules/.bin/oxlint", - "args": [ - "--fix" - ], - "all_envs": { - "NO_COLOR": "1", - "PATH": "/node_modules/.bin:/node_modules/.bin" - }, - "cwd": "/" } } } } - } - ] - }, - "neighbors": [] - } -] + ] + }, + "neighbors": [] + } + ], + "concurrency": 10 +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-keys/snapshots/query - lint and echo with extra args.snap b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-keys/snapshots/query - lint and echo with extra args.snap index 0478d727..f7142977 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-keys/snapshots/query - lint and echo with extra args.snap +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-keys/snapshots/query - lint and echo with extra args.snap @@ -8,104 +8,107 @@ info: - Linting complete input_file: crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-keys --- -[ - { - "key": [ - "/", - "lint-and-echo" - ], - "node": { - "task_display": { - "package_name": "", - "task_name": "lint-and-echo", - "package_path": "/" - }, - "items": [ - { - "execution_item_display": { - "task_display": { - "package_name": "", - "task_name": "lint-and-echo", - "package_path": "/" +{ + "graph": [ + { + "key": [ + "/", + "lint-and-echo" + ], + "node": { + "task_display": { + "package_name": "", + "task_name": "lint-and-echo", + "package_path": "/" + }, + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "", + "task_name": "lint-and-echo", + "package_path": "/" + }, + "command": "vt lint", + "and_item_index": 0, + "cwd": "/" }, - "command": "vt lint", - "and_item_index": 0, - "cwd": "/" - }, - "kind": { - "Leaf": { - "Spawn": { - "cache_metadata": { - "spawn_fingerprint": { - "cwd": "", - "program_fingerprint": { - "OutsideWorkspace": { - "program_name": "oxlint" + "kind": { + "Leaf": { + "Spawn": { + "cache_metadata": { + "spawn_fingerprint": { + "cwd": "", + "program_fingerprint": { + "OutsideWorkspace": { + "program_name": "oxlint" + } + }, + "args": [], + "env_fingerprints": { + "fingerprinted_envs": {}, + "untracked_env_config": [ + "" + ] } }, - "args": [], - "env_fingerprints": { - "fingerprinted_envs": {}, - "untracked_env_config": [ - "" - ] - } - }, - "execution_cache_key": { - "UserTask": { - "task_name": "lint-and-echo", - "and_item_index": 0, - "extra_args": [], - "package_path": "" + "execution_cache_key": { + "UserTask": { + "task_name": "lint-and-echo", + "and_item_index": 0, + "extra_args": [], + "package_path": "" + } + }, + "input_config": { + "includes_auto": true, + "positive_globs": [], + "negative_globs": [] } }, - "input_config": { - "includes_auto": true, - "positive_globs": [], - "negative_globs": [] + "spawn_command": { + "program_path": "/node_modules/.bin/oxlint", + "args": [], + "all_envs": { + "NO_COLOR": "1", + "PATH": "/node_modules/.bin:/node_modules/.bin" + }, + "cwd": "/" } - }, - "spawn_command": { - "program_path": "/node_modules/.bin/oxlint", - "args": [], - "all_envs": { - "NO_COLOR": "1", - "PATH": "/node_modules/.bin:/node_modules/.bin" - }, - "cwd": "/" } } } - } - }, - { - "execution_item_display": { - "task_display": { - "package_name": "", - "task_name": "lint-and-echo", - "package_path": "/" - }, - "command": "echo 'Linting complete'", - "and_item_index": 1, - "cwd": "/" }, - "kind": { - "Leaf": { - "InProcess": { - "kind": { - "Echo": { - "strings": [ - "Linting complete" - ], - "trailing_newline": true + { + "execution_item_display": { + "task_display": { + "package_name": "", + "task_name": "lint-and-echo", + "package_path": "/" + }, + "command": "echo 'Linting complete'", + "and_item_index": 1, + "cwd": "/" + }, + "kind": { + "Leaf": { + "InProcess": { + "kind": { + "Echo": { + "strings": [ + "Linting complete" + ], + "trailing_newline": true + } } } } } } - } - ] - }, - "neighbors": [] - } -] + ] + }, + "neighbors": [] + } + ], + "concurrency": 10 +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-keys/snapshots/query - normal task with extra args.snap b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-keys/snapshots/query - normal task with extra args.snap index 7a141feb..d69bdc0a 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-keys/snapshots/query - normal task with extra args.snap +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-keys/snapshots/query - normal task with extra args.snap @@ -8,84 +8,87 @@ info: - a.txt input_file: crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-keys --- -[ - { - "key": [ - "/", - "hello" - ], - "node": { - "task_display": { - "package_name": "", - "task_name": "hello", - "package_path": "/" - }, - "items": [ - { - "execution_item_display": { - "task_display": { - "package_name": "", - "task_name": "hello", - "package_path": "/" +{ + "graph": [ + { + "key": [ + "/", + "hello" + ], + "node": { + "task_display": { + "package_name": "", + "task_name": "hello", + "package_path": "/" + }, + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "", + "task_name": "hello", + "package_path": "/" + }, + "command": "print-file a.txt", + "and_item_index": null, + "cwd": "/" }, - "command": "print-file a.txt", - "and_item_index": null, - "cwd": "/" - }, - "kind": { - "Leaf": { - "Spawn": { - "cache_metadata": { - "spawn_fingerprint": { - "cwd": "", - "program_fingerprint": { - "OutsideWorkspace": { - "program_name": "print-file" + "kind": { + "Leaf": { + "Spawn": { + "cache_metadata": { + "spawn_fingerprint": { + "cwd": "", + "program_fingerprint": { + "OutsideWorkspace": { + "program_name": "print-file" + } + }, + "args": [ + "a.txt" + ], + "env_fingerprints": { + "fingerprinted_envs": {}, + "untracked_env_config": [ + "" + ] + } + }, + "execution_cache_key": { + "UserTask": { + "task_name": "hello", + "and_item_index": 0, + "extra_args": [ + "a.txt" + ], + "package_path": "" } }, + "input_config": { + "includes_auto": true, + "positive_globs": [], + "negative_globs": [] + } + }, + "spawn_command": { + "program_path": "/node_modules/.bin/print-file", "args": [ "a.txt" ], - "env_fingerprints": { - "fingerprinted_envs": {}, - "untracked_env_config": [ - "" - ] - } - }, - "execution_cache_key": { - "UserTask": { - "task_name": "hello", - "and_item_index": 0, - "extra_args": [ - "a.txt" - ], - "package_path": "" - } - }, - "input_config": { - "includes_auto": true, - "positive_globs": [], - "negative_globs": [] + "all_envs": { + "NO_COLOR": "1", + "PATH": "/node_modules/.bin:/node_modules/.bin" + }, + "cwd": "/" } - }, - "spawn_command": { - "program_path": "/node_modules/.bin/print-file", - "args": [ - "a.txt" - ], - "all_envs": { - "NO_COLOR": "1", - "PATH": "/node_modules/.bin:/node_modules/.bin" - }, - "cwd": "/" } } } } - } - ] - }, - "neighbors": [] - } -] + ] + }, + "neighbors": [] + } + ], + "concurrency": 10 +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-keys/snapshots/query - synthetic task in user task with cwd.snap b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-keys/snapshots/query - synthetic task in user task with cwd.snap index 325b4859..ad1b64c8 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-keys/snapshots/query - synthetic task in user task with cwd.snap +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-keys/snapshots/query - synthetic task in user task with cwd.snap @@ -8,78 +8,81 @@ info: cwd: subdir input_file: crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-keys --- -[ - { - "key": [ - "/", - "lint" - ], - "node": { - "task_display": { - "package_name": "", - "task_name": "lint", - "package_path": "/" - }, - "items": [ - { - "execution_item_display": { - "task_display": { - "package_name": "", - "task_name": "lint", - "package_path": "/" +{ + "graph": [ + { + "key": [ + "/", + "lint" + ], + "node": { + "task_display": { + "package_name": "", + "task_name": "lint", + "package_path": "/" + }, + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "", + "task_name": "lint", + "package_path": "/" + }, + "command": "vt lint", + "and_item_index": null, + "cwd": "/" }, - "command": "vt lint", - "and_item_index": null, - "cwd": "/" - }, - "kind": { - "Leaf": { - "Spawn": { - "cache_metadata": { - "spawn_fingerprint": { - "cwd": "", - "program_fingerprint": { - "OutsideWorkspace": { - "program_name": "oxlint" + "kind": { + "Leaf": { + "Spawn": { + "cache_metadata": { + "spawn_fingerprint": { + "cwd": "", + "program_fingerprint": { + "OutsideWorkspace": { + "program_name": "oxlint" + } + }, + "args": [], + "env_fingerprints": { + "fingerprinted_envs": {}, + "untracked_env_config": [ + "" + ] } }, - "args": [], - "env_fingerprints": { - "fingerprinted_envs": {}, - "untracked_env_config": [ - "" - ] - } - }, - "execution_cache_key": { - "UserTask": { - "task_name": "lint", - "and_item_index": 0, - "extra_args": [], - "package_path": "" + "execution_cache_key": { + "UserTask": { + "task_name": "lint", + "and_item_index": 0, + "extra_args": [], + "package_path": "" + } + }, + "input_config": { + "includes_auto": true, + "positive_globs": [], + "negative_globs": [] } }, - "input_config": { - "includes_auto": true, - "positive_globs": [], - "negative_globs": [] + "spawn_command": { + "program_path": "/node_modules/.bin/oxlint", + "args": [], + "all_envs": { + "NO_COLOR": "1", + "PATH": "/node_modules/.bin:/node_modules/.bin" + }, + "cwd": "/" } - }, - "spawn_command": { - "program_path": "/node_modules/.bin/oxlint", - "args": [], - "all_envs": { - "NO_COLOR": "1", - "PATH": "/node_modules/.bin:/node_modules/.bin" - }, - "cwd": "/" } } } } - } - ] - }, - "neighbors": [] - } -] + ] + }, + "neighbors": [] + } + ], + "concurrency": 10 +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-keys/snapshots/query - synthetic task in user task.snap b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-keys/snapshots/query - synthetic task in user task.snap index 13746051..1b73805f 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-keys/snapshots/query - synthetic task in user task.snap +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-keys/snapshots/query - synthetic task in user task.snap @@ -7,78 +7,81 @@ info: - lint input_file: crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-keys --- -[ - { - "key": [ - "/", - "lint" - ], - "node": { - "task_display": { - "package_name": "", - "task_name": "lint", - "package_path": "/" - }, - "items": [ - { - "execution_item_display": { - "task_display": { - "package_name": "", - "task_name": "lint", - "package_path": "/" +{ + "graph": [ + { + "key": [ + "/", + "lint" + ], + "node": { + "task_display": { + "package_name": "", + "task_name": "lint", + "package_path": "/" + }, + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "", + "task_name": "lint", + "package_path": "/" + }, + "command": "vt lint", + "and_item_index": null, + "cwd": "/" }, - "command": "vt lint", - "and_item_index": null, - "cwd": "/" - }, - "kind": { - "Leaf": { - "Spawn": { - "cache_metadata": { - "spawn_fingerprint": { - "cwd": "", - "program_fingerprint": { - "OutsideWorkspace": { - "program_name": "oxlint" + "kind": { + "Leaf": { + "Spawn": { + "cache_metadata": { + "spawn_fingerprint": { + "cwd": "", + "program_fingerprint": { + "OutsideWorkspace": { + "program_name": "oxlint" + } + }, + "args": [], + "env_fingerprints": { + "fingerprinted_envs": {}, + "untracked_env_config": [ + "" + ] } }, - "args": [], - "env_fingerprints": { - "fingerprinted_envs": {}, - "untracked_env_config": [ - "" - ] - } - }, - "execution_cache_key": { - "UserTask": { - "task_name": "lint", - "and_item_index": 0, - "extra_args": [], - "package_path": "" + "execution_cache_key": { + "UserTask": { + "task_name": "lint", + "and_item_index": 0, + "extra_args": [], + "package_path": "" + } + }, + "input_config": { + "includes_auto": true, + "positive_globs": [], + "negative_globs": [] } }, - "input_config": { - "includes_auto": true, - "positive_globs": [], - "negative_globs": [] + "spawn_command": { + "program_path": "/node_modules/.bin/oxlint", + "args": [], + "all_envs": { + "NO_COLOR": "1", + "PATH": "/node_modules/.bin:/node_modules/.bin" + }, + "cwd": "/" } - }, - "spawn_command": { - "program_path": "/node_modules/.bin/oxlint", - "args": [], - "all_envs": { - "NO_COLOR": "1", - "PATH": "/node_modules/.bin:/node_modules/.bin" - }, - "cwd": "/" } } } } - } - ] - }, - "neighbors": [] - } -] + ] + }, + "neighbors": [] + } + ], + "concurrency": 10 +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-keys/snapshots/query - synthetic task with extra args in user task.snap b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-keys/snapshots/query - synthetic task with extra args in user task.snap index 5efaabce..abc73a69 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-keys/snapshots/query - synthetic task with extra args in user task.snap +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-keys/snapshots/query - synthetic task with extra args in user task.snap @@ -8,84 +8,87 @@ info: - "--fix" input_file: crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-keys --- -[ - { - "key": [ - "/", - "lint" - ], - "node": { - "task_display": { - "package_name": "", - "task_name": "lint", - "package_path": "/" - }, - "items": [ - { - "execution_item_display": { - "task_display": { - "package_name": "", - "task_name": "lint", - "package_path": "/" +{ + "graph": [ + { + "key": [ + "/", + "lint" + ], + "node": { + "task_display": { + "package_name": "", + "task_name": "lint", + "package_path": "/" + }, + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "", + "task_name": "lint", + "package_path": "/" + }, + "command": "vt lint --fix", + "and_item_index": null, + "cwd": "/" }, - "command": "vt lint --fix", - "and_item_index": null, - "cwd": "/" - }, - "kind": { - "Leaf": { - "Spawn": { - "cache_metadata": { - "spawn_fingerprint": { - "cwd": "", - "program_fingerprint": { - "OutsideWorkspace": { - "program_name": "oxlint" + "kind": { + "Leaf": { + "Spawn": { + "cache_metadata": { + "spawn_fingerprint": { + "cwd": "", + "program_fingerprint": { + "OutsideWorkspace": { + "program_name": "oxlint" + } + }, + "args": [ + "--fix" + ], + "env_fingerprints": { + "fingerprinted_envs": {}, + "untracked_env_config": [ + "" + ] + } + }, + "execution_cache_key": { + "UserTask": { + "task_name": "lint", + "and_item_index": 0, + "extra_args": [ + "--fix" + ], + "package_path": "" } }, + "input_config": { + "includes_auto": true, + "positive_globs": [], + "negative_globs": [] + } + }, + "spawn_command": { + "program_path": "/node_modules/.bin/oxlint", "args": [ "--fix" ], - "env_fingerprints": { - "fingerprinted_envs": {}, - "untracked_env_config": [ - "" - ] - } - }, - "execution_cache_key": { - "UserTask": { - "task_name": "lint", - "and_item_index": 0, - "extra_args": [ - "--fix" - ], - "package_path": "" - } - }, - "input_config": { - "includes_auto": true, - "positive_globs": [], - "negative_globs": [] + "all_envs": { + "NO_COLOR": "1", + "PATH": "/node_modules/.bin:/node_modules/.bin" + }, + "cwd": "/" } - }, - "spawn_command": { - "program_path": "/node_modules/.bin/oxlint", - "args": [ - "--fix" - ], - "all_envs": { - "NO_COLOR": "1", - "PATH": "/node_modules/.bin:/node_modules/.bin" - }, - "cwd": "/" } } } } - } - ] - }, - "neighbors": [] - } -] + ] + }, + "neighbors": [] + } + ], + "concurrency": 10 +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-default/snapshots/query - script not cached by default.snap b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-default/snapshots/query - script not cached by default.snap index 675d76d8..5fca2e34 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-default/snapshots/query - script not cached by default.snap +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-default/snapshots/query - script not cached by default.snap @@ -7,51 +7,54 @@ info: - build input_file: crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-default --- -[ - { - "key": [ - "/", - "build" - ], - "node": { - "task_display": { - "package_name": "@test/cache-scripts-default", - "task_name": "build", - "package_path": "/" - }, - "items": [ - { - "execution_item_display": { - "task_display": { - "package_name": "@test/cache-scripts-default", - "task_name": "build", - "package_path": "/" +{ + "graph": [ + { + "key": [ + "/", + "build" + ], + "node": { + "task_display": { + "package_name": "@test/cache-scripts-default", + "task_name": "build", + "package_path": "/" + }, + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "@test/cache-scripts-default", + "task_name": "build", + "package_path": "/" + }, + "command": "print-file package.json", + "and_item_index": null, + "cwd": "/" }, - "command": "print-file package.json", - "and_item_index": null, - "cwd": "/" - }, - "kind": { - "Leaf": { - "Spawn": { - "cache_metadata": null, - "spawn_command": { - "program_path": "/node_modules/.bin/print-file", - "args": [ - "package.json" - ], - "all_envs": { - "NO_COLOR": "1", - "PATH": "/node_modules/.bin:/node_modules/.bin" - }, - "cwd": "/" + "kind": { + "Leaf": { + "Spawn": { + "cache_metadata": null, + "spawn_command": { + "program_path": "/node_modules/.bin/print-file", + "args": [ + "package.json" + ], + "all_envs": { + "NO_COLOR": "1", + "PATH": "/node_modules/.bin:/node_modules/.bin" + }, + "cwd": "/" + } } } } } - } - ] - }, - "neighbors": [] - } -] + ] + }, + "neighbors": [] + } + ], + "concurrency": 10 +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-task-override/snapshots/query - another task cached by default.snap b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-task-override/snapshots/query - another task cached by default.snap index 4ed9a5a3..3f396d97 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-task-override/snapshots/query - another task cached by default.snap +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-task-override/snapshots/query - another task cached by default.snap @@ -7,82 +7,85 @@ info: - deploy input_file: crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-task-override --- -[ - { - "key": [ - "/", - "deploy" - ], - "node": { - "task_display": { - "package_name": "@test/cache-scripts-task-override", - "task_name": "deploy", - "package_path": "/" - }, - "items": [ - { - "execution_item_display": { - "task_display": { - "package_name": "@test/cache-scripts-task-override", - "task_name": "deploy", - "package_path": "/" +{ + "graph": [ + { + "key": [ + "/", + "deploy" + ], + "node": { + "task_display": { + "package_name": "@test/cache-scripts-task-override", + "task_name": "deploy", + "package_path": "/" + }, + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "@test/cache-scripts-task-override", + "task_name": "deploy", + "package_path": "/" + }, + "command": "print-file package.json", + "and_item_index": null, + "cwd": "/" }, - "command": "print-file package.json", - "and_item_index": null, - "cwd": "/" - }, - "kind": { - "Leaf": { - "Spawn": { - "cache_metadata": { - "spawn_fingerprint": { - "cwd": "", - "program_fingerprint": { - "OutsideWorkspace": { - "program_name": "print-file" + "kind": { + "Leaf": { + "Spawn": { + "cache_metadata": { + "spawn_fingerprint": { + "cwd": "", + "program_fingerprint": { + "OutsideWorkspace": { + "program_name": "print-file" + } + }, + "args": [ + "package.json" + ], + "env_fingerprints": { + "fingerprinted_envs": {}, + "untracked_env_config": [ + "" + ] + } + }, + "execution_cache_key": { + "UserTask": { + "task_name": "deploy", + "and_item_index": 0, + "extra_args": [], + "package_path": "" } }, + "input_config": { + "includes_auto": true, + "positive_globs": [], + "negative_globs": [] + } + }, + "spawn_command": { + "program_path": "/node_modules/.bin/print-file", "args": [ "package.json" ], - "env_fingerprints": { - "fingerprinted_envs": {}, - "untracked_env_config": [ - "" - ] - } - }, - "execution_cache_key": { - "UserTask": { - "task_name": "deploy", - "and_item_index": 0, - "extra_args": [], - "package_path": "" - } - }, - "input_config": { - "includes_auto": true, - "positive_globs": [], - "negative_globs": [] + "all_envs": { + "NO_COLOR": "1", + "PATH": "/node_modules/.bin:/node_modules/.bin" + }, + "cwd": "/" } - }, - "spawn_command": { - "program_path": "/node_modules/.bin/print-file", - "args": [ - "package.json" - ], - "all_envs": { - "NO_COLOR": "1", - "PATH": "/node_modules/.bin:/node_modules/.bin" - }, - "cwd": "/" } } } } - } - ] - }, - "neighbors": [] - } -] + ] + }, + "neighbors": [] + } + ], + "concurrency": 10 +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-task-override/snapshots/query - script not cached by default.snap b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-task-override/snapshots/query - script not cached by default.snap index dafc235f..a5982584 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-task-override/snapshots/query - script not cached by default.snap +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-task-override/snapshots/query - script not cached by default.snap @@ -7,51 +7,54 @@ info: - test input_file: crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-task-override --- -[ - { - "key": [ - "/", - "test" - ], - "node": { - "task_display": { - "package_name": "@test/cache-scripts-task-override", - "task_name": "test", - "package_path": "/" - }, - "items": [ - { - "execution_item_display": { - "task_display": { - "package_name": "@test/cache-scripts-task-override", - "task_name": "test", - "package_path": "/" +{ + "graph": [ + { + "key": [ + "/", + "test" + ], + "node": { + "task_display": { + "package_name": "@test/cache-scripts-task-override", + "task_name": "test", + "package_path": "/" + }, + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "@test/cache-scripts-task-override", + "task_name": "test", + "package_path": "/" + }, + "command": "print-file package.json", + "and_item_index": null, + "cwd": "/" }, - "command": "print-file package.json", - "and_item_index": null, - "cwd": "/" - }, - "kind": { - "Leaf": { - "Spawn": { - "cache_metadata": null, - "spawn_command": { - "program_path": "/node_modules/.bin/print-file", - "args": [ - "package.json" - ], - "all_envs": { - "NO_COLOR": "1", - "PATH": "/node_modules/.bin:/node_modules/.bin" - }, - "cwd": "/" + "kind": { + "Leaf": { + "Spawn": { + "cache_metadata": null, + "spawn_command": { + "program_path": "/node_modules/.bin/print-file", + "args": [ + "package.json" + ], + "all_envs": { + "NO_COLOR": "1", + "PATH": "/node_modules/.bin:/node_modules/.bin" + }, + "cwd": "/" + } } } } } - } - ] - }, - "neighbors": [] - } -] + ] + }, + "neighbors": [] + } + ], + "concurrency": 10 +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-task-override/snapshots/query - task cached by default.snap b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-task-override/snapshots/query - task cached by default.snap index d38e2b72..09272f06 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-task-override/snapshots/query - task cached by default.snap +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-task-override/snapshots/query - task cached by default.snap @@ -7,82 +7,85 @@ info: - build input_file: crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-task-override --- -[ - { - "key": [ - "/", - "build" - ], - "node": { - "task_display": { - "package_name": "@test/cache-scripts-task-override", - "task_name": "build", - "package_path": "/" - }, - "items": [ - { - "execution_item_display": { - "task_display": { - "package_name": "@test/cache-scripts-task-override", - "task_name": "build", - "package_path": "/" +{ + "graph": [ + { + "key": [ + "/", + "build" + ], + "node": { + "task_display": { + "package_name": "@test/cache-scripts-task-override", + "task_name": "build", + "package_path": "/" + }, + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "@test/cache-scripts-task-override", + "task_name": "build", + "package_path": "/" + }, + "command": "print-file package.json", + "and_item_index": null, + "cwd": "/" }, - "command": "print-file package.json", - "and_item_index": null, - "cwd": "/" - }, - "kind": { - "Leaf": { - "Spawn": { - "cache_metadata": { - "spawn_fingerprint": { - "cwd": "", - "program_fingerprint": { - "OutsideWorkspace": { - "program_name": "print-file" + "kind": { + "Leaf": { + "Spawn": { + "cache_metadata": { + "spawn_fingerprint": { + "cwd": "", + "program_fingerprint": { + "OutsideWorkspace": { + "program_name": "print-file" + } + }, + "args": [ + "package.json" + ], + "env_fingerprints": { + "fingerprinted_envs": {}, + "untracked_env_config": [ + "" + ] + } + }, + "execution_cache_key": { + "UserTask": { + "task_name": "build", + "and_item_index": 0, + "extra_args": [], + "package_path": "" } }, + "input_config": { + "includes_auto": true, + "positive_globs": [], + "negative_globs": [] + } + }, + "spawn_command": { + "program_path": "/node_modules/.bin/print-file", "args": [ "package.json" ], - "env_fingerprints": { - "fingerprinted_envs": {}, - "untracked_env_config": [ - "" - ] - } - }, - "execution_cache_key": { - "UserTask": { - "task_name": "build", - "and_item_index": 0, - "extra_args": [], - "package_path": "" - } - }, - "input_config": { - "includes_auto": true, - "positive_globs": [], - "negative_globs": [] + "all_envs": { + "NO_COLOR": "1", + "PATH": "/node_modules/.bin:/node_modules/.bin" + }, + "cwd": "/" } - }, - "spawn_command": { - "program_path": "/node_modules/.bin/print-file", - "args": [ - "package.json" - ], - "all_envs": { - "NO_COLOR": "1", - "PATH": "/node_modules/.bin:/node_modules/.bin" - }, - "cwd": "/" } } } } - } - ] - }, - "neighbors": [] - } -] + ] + }, + "neighbors": [] + } + ], + "concurrency": 10 +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-subcommand/snapshots/query - cache clean in script.snap b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-subcommand/snapshots/query - cache clean in script.snap index 99041f9a..b115efc5 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-subcommand/snapshots/query - cache clean in script.snap +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-subcommand/snapshots/query - cache clean in script.snap @@ -7,52 +7,55 @@ info: - clean-cache input_file: crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-subcommand --- -[ - { - "key": [ - "/", - "clean-cache" - ], - "node": { - "task_display": { - "package_name": "@test/cache-subcommand", - "task_name": "clean-cache", - "package_path": "/" - }, - "items": [ - { - "execution_item_display": { - "task_display": { - "package_name": "@test/cache-subcommand", - "task_name": "clean-cache", - "package_path": "/" +{ + "graph": [ + { + "key": [ + "/", + "clean-cache" + ], + "node": { + "task_display": { + "package_name": "@test/cache-subcommand", + "task_name": "clean-cache", + "package_path": "/" + }, + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "@test/cache-subcommand", + "task_name": "clean-cache", + "package_path": "/" + }, + "command": "vt cache clean", + "and_item_index": null, + "cwd": "/" }, - "command": "vt cache clean", - "and_item_index": null, - "cwd": "/" - }, - "kind": { - "Leaf": { - "Spawn": { - "cache_metadata": null, - "spawn_command": { - "program_path": "/node_modules/.bin/vt", - "args": [ - "cache", - "clean" - ], - "all_envs": { - "NO_COLOR": "1", - "PATH": "/node_modules/.bin:/node_modules/.bin" - }, - "cwd": "/" + "kind": { + "Leaf": { + "Spawn": { + "cache_metadata": null, + "spawn_command": { + "program_path": "/node_modules/.bin/vt", + "args": [ + "cache", + "clean" + ], + "all_envs": { + "NO_COLOR": "1", + "PATH": "/node_modules/.bin:/node_modules/.bin" + }, + "cwd": "/" + } } } } } - } - ] - }, - "neighbors": [] - } -] + ] + }, + "neighbors": [] + } + ], + "concurrency": 10 +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-tasks-disabled/snapshots/query - per-task cache true still disabled by cache.tasks false.snap b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-tasks-disabled/snapshots/query - per-task cache true still disabled by cache.tasks false.snap index 9118bb90..c944727e 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-tasks-disabled/snapshots/query - per-task cache true still disabled by cache.tasks false.snap +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-tasks-disabled/snapshots/query - per-task cache true still disabled by cache.tasks false.snap @@ -7,51 +7,54 @@ info: - deploy input_file: crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-tasks-disabled --- -[ - { - "key": [ - "/", - "deploy" - ], - "node": { - "task_display": { - "package_name": "@test/cache-tasks-disabled", - "task_name": "deploy", - "package_path": "/" - }, - "items": [ - { - "execution_item_display": { - "task_display": { - "package_name": "@test/cache-tasks-disabled", - "task_name": "deploy", - "package_path": "/" +{ + "graph": [ + { + "key": [ + "/", + "deploy" + ], + "node": { + "task_display": { + "package_name": "@test/cache-tasks-disabled", + "task_name": "deploy", + "package_path": "/" + }, + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "@test/cache-tasks-disabled", + "task_name": "deploy", + "package_path": "/" + }, + "command": "print-file package.json", + "and_item_index": null, + "cwd": "/" }, - "command": "print-file package.json", - "and_item_index": null, - "cwd": "/" - }, - "kind": { - "Leaf": { - "Spawn": { - "cache_metadata": null, - "spawn_command": { - "program_path": "/node_modules/.bin/print-file", - "args": [ - "package.json" - ], - "all_envs": { - "NO_COLOR": "1", - "PATH": "/node_modules/.bin:/node_modules/.bin" - }, - "cwd": "/" + "kind": { + "Leaf": { + "Spawn": { + "cache_metadata": null, + "spawn_command": { + "program_path": "/node_modules/.bin/print-file", + "args": [ + "package.json" + ], + "all_envs": { + "NO_COLOR": "1", + "PATH": "/node_modules/.bin:/node_modules/.bin" + }, + "cwd": "/" + } } } } } - } - ] - }, - "neighbors": [] - } -] + ] + }, + "neighbors": [] + } + ], + "concurrency": 10 +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-tasks-disabled/snapshots/query - script not cached.snap b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-tasks-disabled/snapshots/query - script not cached.snap index af460270..b7f0ed68 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-tasks-disabled/snapshots/query - script not cached.snap +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-tasks-disabled/snapshots/query - script not cached.snap @@ -7,51 +7,54 @@ info: - test input_file: crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-tasks-disabled --- -[ - { - "key": [ - "/", - "test" - ], - "node": { - "task_display": { - "package_name": "@test/cache-tasks-disabled", - "task_name": "test", - "package_path": "/" - }, - "items": [ - { - "execution_item_display": { - "task_display": { - "package_name": "@test/cache-tasks-disabled", - "task_name": "test", - "package_path": "/" +{ + "graph": [ + { + "key": [ + "/", + "test" + ], + "node": { + "task_display": { + "package_name": "@test/cache-tasks-disabled", + "task_name": "test", + "package_path": "/" + }, + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "@test/cache-tasks-disabled", + "task_name": "test", + "package_path": "/" + }, + "command": "print-file package.json", + "and_item_index": null, + "cwd": "/" }, - "command": "print-file package.json", - "and_item_index": null, - "cwd": "/" - }, - "kind": { - "Leaf": { - "Spawn": { - "cache_metadata": null, - "spawn_command": { - "program_path": "/node_modules/.bin/print-file", - "args": [ - "package.json" - ], - "all_envs": { - "NO_COLOR": "1", - "PATH": "/node_modules/.bin:/node_modules/.bin" - }, - "cwd": "/" + "kind": { + "Leaf": { + "Spawn": { + "cache_metadata": null, + "spawn_command": { + "program_path": "/node_modules/.bin/print-file", + "args": [ + "package.json" + ], + "all_envs": { + "NO_COLOR": "1", + "PATH": "/node_modules/.bin:/node_modules/.bin" + }, + "cwd": "/" + } } } } } - } - ] - }, - "neighbors": [] - } -] + ] + }, + "neighbors": [] + } + ], + "concurrency": 10 +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-tasks-disabled/snapshots/query - task not cached when cache.tasks is false.snap b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-tasks-disabled/snapshots/query - task not cached when cache.tasks is false.snap index f4406214..5ab5b428 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-tasks-disabled/snapshots/query - task not cached when cache.tasks is false.snap +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-tasks-disabled/snapshots/query - task not cached when cache.tasks is false.snap @@ -7,51 +7,54 @@ info: - build input_file: crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-tasks-disabled --- -[ - { - "key": [ - "/", - "build" - ], - "node": { - "task_display": { - "package_name": "@test/cache-tasks-disabled", - "task_name": "build", - "package_path": "/" - }, - "items": [ - { - "execution_item_display": { - "task_display": { - "package_name": "@test/cache-tasks-disabled", - "task_name": "build", - "package_path": "/" +{ + "graph": [ + { + "key": [ + "/", + "build" + ], + "node": { + "task_display": { + "package_name": "@test/cache-tasks-disabled", + "task_name": "build", + "package_path": "/" + }, + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "@test/cache-tasks-disabled", + "task_name": "build", + "package_path": "/" + }, + "command": "print-file package.json", + "and_item_index": null, + "cwd": "/" }, - "command": "print-file package.json", - "and_item_index": null, - "cwd": "/" - }, - "kind": { - "Leaf": { - "Spawn": { - "cache_metadata": null, - "spawn_command": { - "program_path": "/node_modules/.bin/print-file", - "args": [ - "package.json" - ], - "all_envs": { - "NO_COLOR": "1", - "PATH": "/node_modules/.bin:/node_modules/.bin" - }, - "cwd": "/" + "kind": { + "Leaf": { + "Spawn": { + "cache_metadata": null, + "spawn_command": { + "program_path": "/node_modules/.bin/print-file", + "args": [ + "package.json" + ], + "all_envs": { + "NO_COLOR": "1", + "PATH": "/node_modules/.bin:/node_modules/.bin" + }, + "cwd": "/" + } } } } } - } - ] - }, - "neighbors": [] - } -] + ] + }, + "neighbors": [] + } + ], + "concurrency": 10 +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-true-no-force-enable/snapshots/query - script cached when global cache true.snap b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-true-no-force-enable/snapshots/query - script cached when global cache true.snap index c74c1ccf..73cca6e6 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-true-no-force-enable/snapshots/query - script cached when global cache true.snap +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-true-no-force-enable/snapshots/query - script cached when global cache true.snap @@ -7,82 +7,85 @@ info: - test input_file: crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-true-no-force-enable --- -[ - { - "key": [ - "/", - "test" - ], - "node": { - "task_display": { - "package_name": "@test/cache-true-no-force-enable", - "task_name": "test", - "package_path": "/" - }, - "items": [ - { - "execution_item_display": { - "task_display": { - "package_name": "@test/cache-true-no-force-enable", - "task_name": "test", - "package_path": "/" +{ + "graph": [ + { + "key": [ + "/", + "test" + ], + "node": { + "task_display": { + "package_name": "@test/cache-true-no-force-enable", + "task_name": "test", + "package_path": "/" + }, + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "@test/cache-true-no-force-enable", + "task_name": "test", + "package_path": "/" + }, + "command": "print-file package.json", + "and_item_index": null, + "cwd": "/" }, - "command": "print-file package.json", - "and_item_index": null, - "cwd": "/" - }, - "kind": { - "Leaf": { - "Spawn": { - "cache_metadata": { - "spawn_fingerprint": { - "cwd": "", - "program_fingerprint": { - "OutsideWorkspace": { - "program_name": "print-file" + "kind": { + "Leaf": { + "Spawn": { + "cache_metadata": { + "spawn_fingerprint": { + "cwd": "", + "program_fingerprint": { + "OutsideWorkspace": { + "program_name": "print-file" + } + }, + "args": [ + "package.json" + ], + "env_fingerprints": { + "fingerprinted_envs": {}, + "untracked_env_config": [ + "" + ] + } + }, + "execution_cache_key": { + "UserTask": { + "task_name": "test", + "and_item_index": 0, + "extra_args": [], + "package_path": "" } }, + "input_config": { + "includes_auto": true, + "positive_globs": [], + "negative_globs": [] + } + }, + "spawn_command": { + "program_path": "/node_modules/.bin/print-file", "args": [ "package.json" ], - "env_fingerprints": { - "fingerprinted_envs": {}, - "untracked_env_config": [ - "" - ] - } - }, - "execution_cache_key": { - "UserTask": { - "task_name": "test", - "and_item_index": 0, - "extra_args": [], - "package_path": "" - } - }, - "input_config": { - "includes_auto": true, - "positive_globs": [], - "negative_globs": [] + "all_envs": { + "NO_COLOR": "1", + "PATH": "/node_modules/.bin:/node_modules/.bin" + }, + "cwd": "/" } - }, - "spawn_command": { - "program_path": "/node_modules/.bin/print-file", - "args": [ - "package.json" - ], - "all_envs": { - "NO_COLOR": "1", - "PATH": "/node_modules/.bin:/node_modules/.bin" - }, - "cwd": "/" } } } } - } - ] - }, - "neighbors": [] - } -] + ] + }, + "neighbors": [] + } + ], + "concurrency": 10 +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-true-no-force-enable/snapshots/query - task cached when global cache true.snap b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-true-no-force-enable/snapshots/query - task cached when global cache true.snap index c8fc56e7..feacf0c0 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-true-no-force-enable/snapshots/query - task cached when global cache true.snap +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-true-no-force-enable/snapshots/query - task cached when global cache true.snap @@ -7,82 +7,85 @@ info: - deploy input_file: crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-true-no-force-enable --- -[ - { - "key": [ - "/", - "deploy" - ], - "node": { - "task_display": { - "package_name": "@test/cache-true-no-force-enable", - "task_name": "deploy", - "package_path": "/" - }, - "items": [ - { - "execution_item_display": { - "task_display": { - "package_name": "@test/cache-true-no-force-enable", - "task_name": "deploy", - "package_path": "/" +{ + "graph": [ + { + "key": [ + "/", + "deploy" + ], + "node": { + "task_display": { + "package_name": "@test/cache-true-no-force-enable", + "task_name": "deploy", + "package_path": "/" + }, + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "@test/cache-true-no-force-enable", + "task_name": "deploy", + "package_path": "/" + }, + "command": "print-file package.json", + "and_item_index": null, + "cwd": "/" }, - "command": "print-file package.json", - "and_item_index": null, - "cwd": "/" - }, - "kind": { - "Leaf": { - "Spawn": { - "cache_metadata": { - "spawn_fingerprint": { - "cwd": "", - "program_fingerprint": { - "OutsideWorkspace": { - "program_name": "print-file" + "kind": { + "Leaf": { + "Spawn": { + "cache_metadata": { + "spawn_fingerprint": { + "cwd": "", + "program_fingerprint": { + "OutsideWorkspace": { + "program_name": "print-file" + } + }, + "args": [ + "package.json" + ], + "env_fingerprints": { + "fingerprinted_envs": {}, + "untracked_env_config": [ + "" + ] + } + }, + "execution_cache_key": { + "UserTask": { + "task_name": "deploy", + "and_item_index": 0, + "extra_args": [], + "package_path": "" } }, + "input_config": { + "includes_auto": true, + "positive_globs": [], + "negative_globs": [] + } + }, + "spawn_command": { + "program_path": "/node_modules/.bin/print-file", "args": [ "package.json" ], - "env_fingerprints": { - "fingerprinted_envs": {}, - "untracked_env_config": [ - "" - ] - } - }, - "execution_cache_key": { - "UserTask": { - "task_name": "deploy", - "and_item_index": 0, - "extra_args": [], - "package_path": "" - } - }, - "input_config": { - "includes_auto": true, - "positive_globs": [], - "negative_globs": [] + "all_envs": { + "NO_COLOR": "1", + "PATH": "/node_modules/.bin:/node_modules/.bin" + }, + "cwd": "/" } - }, - "spawn_command": { - "program_path": "/node_modules/.bin/print-file", - "args": [ - "package.json" - ], - "all_envs": { - "NO_COLOR": "1", - "PATH": "/node_modules/.bin:/node_modules/.bin" - }, - "cwd": "/" } } } } - } - ] - }, - "neighbors": [] - } -] + ] + }, + "neighbors": [] + } + ], + "concurrency": 10 +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-true-no-force-enable/snapshots/query - task with cache false not cached despite global cache true.snap b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-true-no-force-enable/snapshots/query - task with cache false not cached despite global cache true.snap index 301ceab8..e0faff3a 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-true-no-force-enable/snapshots/query - task with cache false not cached despite global cache true.snap +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-true-no-force-enable/snapshots/query - task with cache false not cached despite global cache true.snap @@ -7,51 +7,54 @@ info: - build input_file: crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-true-no-force-enable --- -[ - { - "key": [ - "/", - "build" - ], - "node": { - "task_display": { - "package_name": "@test/cache-true-no-force-enable", - "task_name": "build", - "package_path": "/" - }, - "items": [ - { - "execution_item_display": { - "task_display": { - "package_name": "@test/cache-true-no-force-enable", - "task_name": "build", - "package_path": "/" +{ + "graph": [ + { + "key": [ + "/", + "build" + ], + "node": { + "task_display": { + "package_name": "@test/cache-true-no-force-enable", + "task_name": "build", + "package_path": "/" + }, + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "@test/cache-true-no-force-enable", + "task_name": "build", + "package_path": "/" + }, + "command": "print-file package.json", + "and_item_index": null, + "cwd": "/" }, - "command": "print-file package.json", - "and_item_index": null, - "cwd": "/" - }, - "kind": { - "Leaf": { - "Spawn": { - "cache_metadata": null, - "spawn_command": { - "program_path": "/node_modules/.bin/print-file", - "args": [ - "package.json" - ], - "all_envs": { - "NO_COLOR": "1", - "PATH": "/node_modules/.bin:/node_modules/.bin" - }, - "cwd": "/" + "kind": { + "Leaf": { + "Spawn": { + "cache_metadata": null, + "spawn_command": { + "program_path": "/node_modules/.bin/print-file", + "args": [ + "package.json" + ], + "all_envs": { + "NO_COLOR": "1", + "PATH": "/node_modules/.bin:/node_modules/.bin" + }, + "cwd": "/" + } } } } } - } - ] - }, - "neighbors": [] - } -] + ] + }, + "neighbors": [] + } + ], + "concurrency": 10 +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cd-in-scripts/snapshots/query - cd before vt lint should put synthetic task under cwd.snap b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cd-in-scripts/snapshots/query - cd before vt lint should put synthetic task under cwd.snap index d708a120..258e4efd 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cd-in-scripts/snapshots/query - cd before vt lint should put synthetic task under cwd.snap +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cd-in-scripts/snapshots/query - cd before vt lint should put synthetic task under cwd.snap @@ -7,78 +7,81 @@ info: - cd-lint input_file: crates/vite_task_plan/tests/plan_snapshots/fixtures/cd-in-scripts --- -[ - { - "key": [ - "/", - "cd-lint" - ], - "node": { - "task_display": { - "package_name": "", - "task_name": "cd-lint", - "package_path": "/" - }, - "items": [ - { - "execution_item_display": { - "task_display": { - "package_name": "", - "task_name": "cd-lint", - "package_path": "/" +{ + "graph": [ + { + "key": [ + "/", + "cd-lint" + ], + "node": { + "task_display": { + "package_name": "", + "task_name": "cd-lint", + "package_path": "/" + }, + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "", + "task_name": "cd-lint", + "package_path": "/" + }, + "command": "vt lint", + "and_item_index": 1, + "cwd": "/src" }, - "command": "vt lint", - "and_item_index": 1, - "cwd": "/src" - }, - "kind": { - "Leaf": { - "Spawn": { - "cache_metadata": { - "spawn_fingerprint": { - "cwd": "src", - "program_fingerprint": { - "OutsideWorkspace": { - "program_name": "oxlint" + "kind": { + "Leaf": { + "Spawn": { + "cache_metadata": { + "spawn_fingerprint": { + "cwd": "src", + "program_fingerprint": { + "OutsideWorkspace": { + "program_name": "oxlint" + } + }, + "args": [], + "env_fingerprints": { + "fingerprinted_envs": {}, + "untracked_env_config": [ + "" + ] } }, - "args": [], - "env_fingerprints": { - "fingerprinted_envs": {}, - "untracked_env_config": [ - "" - ] - } - }, - "execution_cache_key": { - "UserTask": { - "task_name": "cd-lint", - "and_item_index": 1, - "extra_args": [], - "package_path": "" + "execution_cache_key": { + "UserTask": { + "task_name": "cd-lint", + "and_item_index": 1, + "extra_args": [], + "package_path": "" + } + }, + "input_config": { + "includes_auto": true, + "positive_globs": [], + "negative_globs": [] } }, - "input_config": { - "includes_auto": true, - "positive_globs": [], - "negative_globs": [] + "spawn_command": { + "program_path": "/node_modules/.bin/oxlint", + "args": [], + "all_envs": { + "NO_COLOR": "1", + "PATH": "/node_modules/.bin:/node_modules/.bin" + }, + "cwd": "/src" } - }, - "spawn_command": { - "program_path": "/node_modules/.bin/oxlint", - "args": [], - "all_envs": { - "NO_COLOR": "1", - "PATH": "/node_modules/.bin:/node_modules/.bin" - }, - "cwd": "/src" } } } } - } - ] - }, - "neighbors": [] - } -] + ] + }, + "neighbors": [] + } + ], + "concurrency": 10 +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cd-in-scripts/snapshots/query - cd before vt run should not affect expanded task cwd.snap b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cd-in-scripts/snapshots/query - cd before vt run should not affect expanded task cwd.snap index 62ef0659..8e04eed9 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cd-in-scripts/snapshots/query - cd before vt run should not affect expanded task cwd.snap +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cd-in-scripts/snapshots/query - cd before vt run should not affect expanded task cwd.snap @@ -7,114 +7,120 @@ info: - cd-build input_file: crates/vite_task_plan/tests/plan_snapshots/fixtures/cd-in-scripts --- -[ - { - "key": [ - "/", - "cd-build" - ], - "node": { - "task_display": { - "package_name": "", - "task_name": "cd-build", - "package_path": "/" - }, - "items": [ - { - "execution_item_display": { - "task_display": { - "package_name": "", - "task_name": "cd-build", - "package_path": "/" +{ + "graph": [ + { + "key": [ + "/", + "cd-build" + ], + "node": { + "task_display": { + "package_name": "", + "task_name": "cd-build", + "package_path": "/" + }, + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "", + "task_name": "cd-build", + "package_path": "/" + }, + "command": "vt run build", + "and_item_index": 1, + "cwd": "/src" }, - "command": "vt run build", - "and_item_index": 1, - "cwd": "/src" - }, - "kind": { - "Expanded": [ - { - "key": [ - "/", - "build" - ], - "node": { - "task_display": { - "package_name": "", - "task_name": "build", - "package_path": "/" - }, - "items": [ - { - "execution_item_display": { - "task_display": { - "package_name": "", - "task_name": "build", - "package_path": "/" - }, - "command": "print-file package.json", - "and_item_index": null, - "cwd": "/" + "kind": { + "Expanded": { + "graph": [ + { + "key": [ + "/", + "build" + ], + "node": { + "task_display": { + "package_name": "", + "task_name": "build", + "package_path": "/" }, - "kind": { - "Leaf": { - "Spawn": { - "cache_metadata": { - "spawn_fingerprint": { - "cwd": "", - "program_fingerprint": { - "OutsideWorkspace": { - "program_name": "print-file" + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "", + "task_name": "build", + "package_path": "/" + }, + "command": "print-file package.json", + "and_item_index": null, + "cwd": "/" + }, + "kind": { + "Leaf": { + "Spawn": { + "cache_metadata": { + "spawn_fingerprint": { + "cwd": "", + "program_fingerprint": { + "OutsideWorkspace": { + "program_name": "print-file" + } + }, + "args": [ + "package.json" + ], + "env_fingerprints": { + "fingerprinted_envs": {}, + "untracked_env_config": [ + "" + ] + } + }, + "execution_cache_key": { + "UserTask": { + "task_name": "build", + "and_item_index": 0, + "extra_args": [], + "package_path": "" + } + }, + "input_config": { + "includes_auto": true, + "positive_globs": [], + "negative_globs": [] } }, - "args": [ - "package.json" - ], - "env_fingerprints": { - "fingerprinted_envs": {}, - "untracked_env_config": [ - "" - ] - } - }, - "execution_cache_key": { - "UserTask": { - "task_name": "build", - "and_item_index": 0, - "extra_args": [], - "package_path": "" + "spawn_command": { + "program_path": "/node_modules/.bin/print-file", + "args": [ + "package.json" + ], + "all_envs": { + "NO_COLOR": "1", + "PATH": "/node_modules/.bin:/node_modules/.bin" + }, + "cwd": "/" } - }, - "input_config": { - "includes_auto": true, - "positive_globs": [], - "negative_globs": [] } - }, - "spawn_command": { - "program_path": "/node_modules/.bin/print-file", - "args": [ - "package.json" - ], - "all_envs": { - "NO_COLOR": "1", - "PATH": "/node_modules/.bin:/node_modules/.bin" - }, - "cwd": "/" } } } - } - } - ] - }, - "neighbors": [] + ] + }, + "neighbors": [] + } + ], + "concurrency": 10 } - ] + } } - } - ] - }, - "neighbors": [] - } -] + ] + }, + "neighbors": [] + } + ], + "concurrency": 10 +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-cache-override/snapshots/query - nested --cache enables inner task caching.snap b/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-cache-override/snapshots/query - nested --cache enables inner task caching.snap index 9f530779..e73d0243 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-cache-override/snapshots/query - nested --cache enables inner task caching.snap +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-cache-override/snapshots/query - nested --cache enables inner task caching.snap @@ -7,114 +7,120 @@ info: - outer-cache input_file: crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-cache-override --- -[ - { - "key": [ - "/", - "outer-cache" - ], - "node": { - "task_display": { - "package_name": "@test/nested-cache-override", - "task_name": "outer-cache", - "package_path": "/" - }, - "items": [ - { - "execution_item_display": { - "task_display": { - "package_name": "@test/nested-cache-override", - "task_name": "outer-cache", - "package_path": "/" +{ + "graph": [ + { + "key": [ + "/", + "outer-cache" + ], + "node": { + "task_display": { + "package_name": "@test/nested-cache-override", + "task_name": "outer-cache", + "package_path": "/" + }, + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "@test/nested-cache-override", + "task_name": "outer-cache", + "package_path": "/" + }, + "command": "vt run --cache inner", + "and_item_index": null, + "cwd": "/" }, - "command": "vt run --cache inner", - "and_item_index": null, - "cwd": "/" - }, - "kind": { - "Expanded": [ - { - "key": [ - "/", - "inner" - ], - "node": { - "task_display": { - "package_name": "@test/nested-cache-override", - "task_name": "inner", - "package_path": "/" - }, - "items": [ - { - "execution_item_display": { - "task_display": { - "package_name": "@test/nested-cache-override", - "task_name": "inner", - "package_path": "/" - }, - "command": "print-file package.json", - "and_item_index": null, - "cwd": "/" + "kind": { + "Expanded": { + "graph": [ + { + "key": [ + "/", + "inner" + ], + "node": { + "task_display": { + "package_name": "@test/nested-cache-override", + "task_name": "inner", + "package_path": "/" }, - "kind": { - "Leaf": { - "Spawn": { - "cache_metadata": { - "spawn_fingerprint": { - "cwd": "", - "program_fingerprint": { - "OutsideWorkspace": { - "program_name": "print-file" + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "@test/nested-cache-override", + "task_name": "inner", + "package_path": "/" + }, + "command": "print-file package.json", + "and_item_index": null, + "cwd": "/" + }, + "kind": { + "Leaf": { + "Spawn": { + "cache_metadata": { + "spawn_fingerprint": { + "cwd": "", + "program_fingerprint": { + "OutsideWorkspace": { + "program_name": "print-file" + } + }, + "args": [ + "package.json" + ], + "env_fingerprints": { + "fingerprinted_envs": {}, + "untracked_env_config": [ + "" + ] + } + }, + "execution_cache_key": { + "UserTask": { + "task_name": "inner", + "and_item_index": 0, + "extra_args": [], + "package_path": "" + } + }, + "input_config": { + "includes_auto": true, + "positive_globs": [], + "negative_globs": [] } }, - "args": [ - "package.json" - ], - "env_fingerprints": { - "fingerprinted_envs": {}, - "untracked_env_config": [ - "" - ] - } - }, - "execution_cache_key": { - "UserTask": { - "task_name": "inner", - "and_item_index": 0, - "extra_args": [], - "package_path": "" + "spawn_command": { + "program_path": "/node_modules/.bin/print-file", + "args": [ + "package.json" + ], + "all_envs": { + "NO_COLOR": "1", + "PATH": "/node_modules/.bin:/node_modules/.bin" + }, + "cwd": "/" } - }, - "input_config": { - "includes_auto": true, - "positive_globs": [], - "negative_globs": [] } - }, - "spawn_command": { - "program_path": "/node_modules/.bin/print-file", - "args": [ - "package.json" - ], - "all_envs": { - "NO_COLOR": "1", - "PATH": "/node_modules/.bin:/node_modules/.bin" - }, - "cwd": "/" } } } - } - } - ] - }, - "neighbors": [] + ] + }, + "neighbors": [] + } + ], + "concurrency": 10 } - ] + } } - } - ] - }, - "neighbors": [] - } -] + ] + }, + "neighbors": [] + } + ], + "concurrency": 10 +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-cache-override/snapshots/query - nested --no-cache disables inner task caching.snap b/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-cache-override/snapshots/query - nested --no-cache disables inner task caching.snap index 94c58825..6d717184 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-cache-override/snapshots/query - nested --no-cache disables inner task caching.snap +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-cache-override/snapshots/query - nested --no-cache disables inner task caching.snap @@ -7,83 +7,89 @@ info: - outer-no-cache input_file: crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-cache-override --- -[ - { - "key": [ - "/", - "outer-no-cache" - ], - "node": { - "task_display": { - "package_name": "@test/nested-cache-override", - "task_name": "outer-no-cache", - "package_path": "/" - }, - "items": [ - { - "execution_item_display": { - "task_display": { - "package_name": "@test/nested-cache-override", - "task_name": "outer-no-cache", - "package_path": "/" +{ + "graph": [ + { + "key": [ + "/", + "outer-no-cache" + ], + "node": { + "task_display": { + "package_name": "@test/nested-cache-override", + "task_name": "outer-no-cache", + "package_path": "/" + }, + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "@test/nested-cache-override", + "task_name": "outer-no-cache", + "package_path": "/" + }, + "command": "vt run --no-cache inner", + "and_item_index": null, + "cwd": "/" }, - "command": "vt run --no-cache inner", - "and_item_index": null, - "cwd": "/" - }, - "kind": { - "Expanded": [ - { - "key": [ - "/", - "inner" - ], - "node": { - "task_display": { - "package_name": "@test/nested-cache-override", - "task_name": "inner", - "package_path": "/" - }, - "items": [ - { - "execution_item_display": { - "task_display": { - "package_name": "@test/nested-cache-override", - "task_name": "inner", - "package_path": "/" - }, - "command": "print-file package.json", - "and_item_index": null, - "cwd": "/" + "kind": { + "Expanded": { + "graph": [ + { + "key": [ + "/", + "inner" + ], + "node": { + "task_display": { + "package_name": "@test/nested-cache-override", + "task_name": "inner", + "package_path": "/" }, - "kind": { - "Leaf": { - "Spawn": { - "cache_metadata": null, - "spawn_command": { - "program_path": "/node_modules/.bin/print-file", - "args": [ - "package.json" - ], - "all_envs": { - "NO_COLOR": "1", - "PATH": "/node_modules/.bin:/node_modules/.bin" - }, - "cwd": "/" + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "@test/nested-cache-override", + "task_name": "inner", + "package_path": "/" + }, + "command": "print-file package.json", + "and_item_index": null, + "cwd": "/" + }, + "kind": { + "Leaf": { + "Spawn": { + "cache_metadata": null, + "spawn_command": { + "program_path": "/node_modules/.bin/print-file", + "args": [ + "package.json" + ], + "all_envs": { + "NO_COLOR": "1", + "PATH": "/node_modules/.bin:/node_modules/.bin" + }, + "cwd": "/" + } + } } } } - } - } - ] - }, - "neighbors": [] + ] + }, + "neighbors": [] + } + ], + "concurrency": 10 } - ] + } } - } - ] - }, - "neighbors": [] - } -] + ] + }, + "neighbors": [] + } + ], + "concurrency": 10 +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-cache-override/snapshots/query - nested run without flags inherits parent cache.snap b/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-cache-override/snapshots/query - nested run without flags inherits parent cache.snap index 8a79b3af..4865e4d5 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-cache-override/snapshots/query - nested run without flags inherits parent cache.snap +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-cache-override/snapshots/query - nested run without flags inherits parent cache.snap @@ -7,83 +7,89 @@ info: - outer-inherit input_file: crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-cache-override --- -[ - { - "key": [ - "/", - "outer-inherit" - ], - "node": { - "task_display": { - "package_name": "@test/nested-cache-override", - "task_name": "outer-inherit", - "package_path": "/" - }, - "items": [ - { - "execution_item_display": { - "task_display": { - "package_name": "@test/nested-cache-override", - "task_name": "outer-inherit", - "package_path": "/" +{ + "graph": [ + { + "key": [ + "/", + "outer-inherit" + ], + "node": { + "task_display": { + "package_name": "@test/nested-cache-override", + "task_name": "outer-inherit", + "package_path": "/" + }, + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "@test/nested-cache-override", + "task_name": "outer-inherit", + "package_path": "/" + }, + "command": "vt run inner", + "and_item_index": null, + "cwd": "/" }, - "command": "vt run inner", - "and_item_index": null, - "cwd": "/" - }, - "kind": { - "Expanded": [ - { - "key": [ - "/", - "inner" - ], - "node": { - "task_display": { - "package_name": "@test/nested-cache-override", - "task_name": "inner", - "package_path": "/" - }, - "items": [ - { - "execution_item_display": { - "task_display": { - "package_name": "@test/nested-cache-override", - "task_name": "inner", - "package_path": "/" - }, - "command": "print-file package.json", - "and_item_index": null, - "cwd": "/" + "kind": { + "Expanded": { + "graph": [ + { + "key": [ + "/", + "inner" + ], + "node": { + "task_display": { + "package_name": "@test/nested-cache-override", + "task_name": "inner", + "package_path": "/" }, - "kind": { - "Leaf": { - "Spawn": { - "cache_metadata": null, - "spawn_command": { - "program_path": "/node_modules/.bin/print-file", - "args": [ - "package.json" - ], - "all_envs": { - "NO_COLOR": "1", - "PATH": "/node_modules/.bin:/node_modules/.bin" - }, - "cwd": "/" + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "@test/nested-cache-override", + "task_name": "inner", + "package_path": "/" + }, + "command": "print-file package.json", + "and_item_index": null, + "cwd": "/" + }, + "kind": { + "Leaf": { + "Spawn": { + "cache_metadata": null, + "spawn_command": { + "program_path": "/node_modules/.bin/print-file", + "args": [ + "package.json" + ], + "all_envs": { + "NO_COLOR": "1", + "PATH": "/node_modules/.bin:/node_modules/.bin" + }, + "cwd": "/" + } + } } } } - } - } - ] - }, - "neighbors": [] + ] + }, + "neighbors": [] + } + ], + "concurrency": 10 } - ] + } } - } - ] - }, - "neighbors": [] - } -] + ] + }, + "neighbors": [] + } + ], + "concurrency": 10 +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-cache-override/snapshots/query - outer --cache propagates to nested run without flags.snap b/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-cache-override/snapshots/query - outer --cache propagates to nested run without flags.snap index c64bcdda..b3d68f8c 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-cache-override/snapshots/query - outer --cache propagates to nested run without flags.snap +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-cache-override/snapshots/query - outer --cache propagates to nested run without flags.snap @@ -8,114 +8,120 @@ info: - outer-inherit input_file: crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-cache-override --- -[ - { - "key": [ - "/", - "outer-inherit" - ], - "node": { - "task_display": { - "package_name": "@test/nested-cache-override", - "task_name": "outer-inherit", - "package_path": "/" - }, - "items": [ - { - "execution_item_display": { - "task_display": { - "package_name": "@test/nested-cache-override", - "task_name": "outer-inherit", - "package_path": "/" +{ + "graph": [ + { + "key": [ + "/", + "outer-inherit" + ], + "node": { + "task_display": { + "package_name": "@test/nested-cache-override", + "task_name": "outer-inherit", + "package_path": "/" + }, + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "@test/nested-cache-override", + "task_name": "outer-inherit", + "package_path": "/" + }, + "command": "vt run inner", + "and_item_index": null, + "cwd": "/" }, - "command": "vt run inner", - "and_item_index": null, - "cwd": "/" - }, - "kind": { - "Expanded": [ - { - "key": [ - "/", - "inner" - ], - "node": { - "task_display": { - "package_name": "@test/nested-cache-override", - "task_name": "inner", - "package_path": "/" - }, - "items": [ - { - "execution_item_display": { - "task_display": { - "package_name": "@test/nested-cache-override", - "task_name": "inner", - "package_path": "/" - }, - "command": "print-file package.json", - "and_item_index": null, - "cwd": "/" + "kind": { + "Expanded": { + "graph": [ + { + "key": [ + "/", + "inner" + ], + "node": { + "task_display": { + "package_name": "@test/nested-cache-override", + "task_name": "inner", + "package_path": "/" }, - "kind": { - "Leaf": { - "Spawn": { - "cache_metadata": { - "spawn_fingerprint": { - "cwd": "", - "program_fingerprint": { - "OutsideWorkspace": { - "program_name": "print-file" + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "@test/nested-cache-override", + "task_name": "inner", + "package_path": "/" + }, + "command": "print-file package.json", + "and_item_index": null, + "cwd": "/" + }, + "kind": { + "Leaf": { + "Spawn": { + "cache_metadata": { + "spawn_fingerprint": { + "cwd": "", + "program_fingerprint": { + "OutsideWorkspace": { + "program_name": "print-file" + } + }, + "args": [ + "package.json" + ], + "env_fingerprints": { + "fingerprinted_envs": {}, + "untracked_env_config": [ + "" + ] + } + }, + "execution_cache_key": { + "UserTask": { + "task_name": "inner", + "and_item_index": 0, + "extra_args": [], + "package_path": "" + } + }, + "input_config": { + "includes_auto": true, + "positive_globs": [], + "negative_globs": [] } }, - "args": [ - "package.json" - ], - "env_fingerprints": { - "fingerprinted_envs": {}, - "untracked_env_config": [ - "" - ] - } - }, - "execution_cache_key": { - "UserTask": { - "task_name": "inner", - "and_item_index": 0, - "extra_args": [], - "package_path": "" + "spawn_command": { + "program_path": "/node_modules/.bin/print-file", + "args": [ + "package.json" + ], + "all_envs": { + "NO_COLOR": "1", + "PATH": "/node_modules/.bin:/node_modules/.bin" + }, + "cwd": "/" } - }, - "input_config": { - "includes_auto": true, - "positive_globs": [], - "negative_globs": [] } - }, - "spawn_command": { - "program_path": "/node_modules/.bin/print-file", - "args": [ - "package.json" - ], - "all_envs": { - "NO_COLOR": "1", - "PATH": "/node_modules/.bin:/node_modules/.bin" - }, - "cwd": "/" } } } - } - } - ] - }, - "neighbors": [] + ] + }, + "neighbors": [] + } + ], + "concurrency": 10 } - ] + } } - } - ] - }, - "neighbors": [] - } -] + ] + }, + "neighbors": [] + } + ], + "concurrency": 10 +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-cache-override/snapshots/query - outer --no-cache does not propagate into nested --cache.snap b/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-cache-override/snapshots/query - outer --no-cache does not propagate into nested --cache.snap index 1155dabd..36ec7cba 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-cache-override/snapshots/query - outer --no-cache does not propagate into nested --cache.snap +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-cache-override/snapshots/query - outer --no-cache does not propagate into nested --cache.snap @@ -8,114 +8,120 @@ info: - outer-cache input_file: crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-cache-override --- -[ - { - "key": [ - "/", - "outer-cache" - ], - "node": { - "task_display": { - "package_name": "@test/nested-cache-override", - "task_name": "outer-cache", - "package_path": "/" - }, - "items": [ - { - "execution_item_display": { - "task_display": { - "package_name": "@test/nested-cache-override", - "task_name": "outer-cache", - "package_path": "/" +{ + "graph": [ + { + "key": [ + "/", + "outer-cache" + ], + "node": { + "task_display": { + "package_name": "@test/nested-cache-override", + "task_name": "outer-cache", + "package_path": "/" + }, + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "@test/nested-cache-override", + "task_name": "outer-cache", + "package_path": "/" + }, + "command": "vt run --cache inner", + "and_item_index": null, + "cwd": "/" }, - "command": "vt run --cache inner", - "and_item_index": null, - "cwd": "/" - }, - "kind": { - "Expanded": [ - { - "key": [ - "/", - "inner" - ], - "node": { - "task_display": { - "package_name": "@test/nested-cache-override", - "task_name": "inner", - "package_path": "/" - }, - "items": [ - { - "execution_item_display": { - "task_display": { - "package_name": "@test/nested-cache-override", - "task_name": "inner", - "package_path": "/" - }, - "command": "print-file package.json", - "and_item_index": null, - "cwd": "/" + "kind": { + "Expanded": { + "graph": [ + { + "key": [ + "/", + "inner" + ], + "node": { + "task_display": { + "package_name": "@test/nested-cache-override", + "task_name": "inner", + "package_path": "/" }, - "kind": { - "Leaf": { - "Spawn": { - "cache_metadata": { - "spawn_fingerprint": { - "cwd": "", - "program_fingerprint": { - "OutsideWorkspace": { - "program_name": "print-file" + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "@test/nested-cache-override", + "task_name": "inner", + "package_path": "/" + }, + "command": "print-file package.json", + "and_item_index": null, + "cwd": "/" + }, + "kind": { + "Leaf": { + "Spawn": { + "cache_metadata": { + "spawn_fingerprint": { + "cwd": "", + "program_fingerprint": { + "OutsideWorkspace": { + "program_name": "print-file" + } + }, + "args": [ + "package.json" + ], + "env_fingerprints": { + "fingerprinted_envs": {}, + "untracked_env_config": [ + "" + ] + } + }, + "execution_cache_key": { + "UserTask": { + "task_name": "inner", + "and_item_index": 0, + "extra_args": [], + "package_path": "" + } + }, + "input_config": { + "includes_auto": true, + "positive_globs": [], + "negative_globs": [] } }, - "args": [ - "package.json" - ], - "env_fingerprints": { - "fingerprinted_envs": {}, - "untracked_env_config": [ - "" - ] - } - }, - "execution_cache_key": { - "UserTask": { - "task_name": "inner", - "and_item_index": 0, - "extra_args": [], - "package_path": "" + "spawn_command": { + "program_path": "/node_modules/.bin/print-file", + "args": [ + "package.json" + ], + "all_envs": { + "NO_COLOR": "1", + "PATH": "/node_modules/.bin:/node_modules/.bin" + }, + "cwd": "/" } - }, - "input_config": { - "includes_auto": true, - "positive_globs": [], - "negative_globs": [] } - }, - "spawn_command": { - "program_path": "/node_modules/.bin/print-file", - "args": [ - "package.json" - ], - "all_envs": { - "NO_COLOR": "1", - "PATH": "/node_modules/.bin:/node_modules/.bin" - }, - "cwd": "/" } } } - } - } - ] - }, - "neighbors": [] + ] + }, + "neighbors": [] + } + ], + "concurrency": 10 } - ] + } } - } - ] - }, - "neighbors": [] - } -] + ] + }, + "neighbors": [] + } + ], + "concurrency": 10 +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-cache-override/snapshots/query - outer --no-cache propagates to nested run without flags.snap b/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-cache-override/snapshots/query - outer --no-cache propagates to nested run without flags.snap index 48c4826a..dbb249ba 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-cache-override/snapshots/query - outer --no-cache propagates to nested run without flags.snap +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-cache-override/snapshots/query - outer --no-cache propagates to nested run without flags.snap @@ -8,83 +8,89 @@ info: - outer-inherit input_file: crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-cache-override --- -[ - { - "key": [ - "/", - "outer-inherit" - ], - "node": { - "task_display": { - "package_name": "@test/nested-cache-override", - "task_name": "outer-inherit", - "package_path": "/" - }, - "items": [ - { - "execution_item_display": { - "task_display": { - "package_name": "@test/nested-cache-override", - "task_name": "outer-inherit", - "package_path": "/" +{ + "graph": [ + { + "key": [ + "/", + "outer-inherit" + ], + "node": { + "task_display": { + "package_name": "@test/nested-cache-override", + "task_name": "outer-inherit", + "package_path": "/" + }, + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "@test/nested-cache-override", + "task_name": "outer-inherit", + "package_path": "/" + }, + "command": "vt run inner", + "and_item_index": null, + "cwd": "/" }, - "command": "vt run inner", - "and_item_index": null, - "cwd": "/" - }, - "kind": { - "Expanded": [ - { - "key": [ - "/", - "inner" - ], - "node": { - "task_display": { - "package_name": "@test/nested-cache-override", - "task_name": "inner", - "package_path": "/" - }, - "items": [ - { - "execution_item_display": { - "task_display": { - "package_name": "@test/nested-cache-override", - "task_name": "inner", - "package_path": "/" - }, - "command": "print-file package.json", - "and_item_index": null, - "cwd": "/" + "kind": { + "Expanded": { + "graph": [ + { + "key": [ + "/", + "inner" + ], + "node": { + "task_display": { + "package_name": "@test/nested-cache-override", + "task_name": "inner", + "package_path": "/" }, - "kind": { - "Leaf": { - "Spawn": { - "cache_metadata": null, - "spawn_command": { - "program_path": "/node_modules/.bin/print-file", - "args": [ - "package.json" - ], - "all_envs": { - "NO_COLOR": "1", - "PATH": "/node_modules/.bin:/node_modules/.bin" - }, - "cwd": "/" + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "@test/nested-cache-override", + "task_name": "inner", + "package_path": "/" + }, + "command": "print-file package.json", + "and_item_index": null, + "cwd": "/" + }, + "kind": { + "Leaf": { + "Spawn": { + "cache_metadata": null, + "spawn_command": { + "program_path": "/node_modules/.bin/print-file", + "args": [ + "package.json" + ], + "all_envs": { + "NO_COLOR": "1", + "PATH": "/node_modules/.bin:/node_modules/.bin" + }, + "cwd": "/" + } + } } } } - } - } - ] - }, - "neighbors": [] + ] + }, + "neighbors": [] + } + ], + "concurrency": 10 } - ] + } } - } - ] - }, - "neighbors": [] - } -] + ] + }, + "neighbors": [] + } + ], + "concurrency": 10 +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-concurrency/package.json b/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-concurrency/package.json new file mode 100644 index 00000000..ca76ead1 --- /dev/null +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-concurrency/package.json @@ -0,0 +1,8 @@ +{ + "name": "@test/nested-concurrency", + "scripts": { + "inner": "print-file package.json", + "outer-concurrency-2": "vp run --concurrency=2 inner", + "outer-inherit": "vp run inner" + } +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-concurrency/snapshots.toml b/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-concurrency/snapshots.toml new file mode 100644 index 00000000..a3711703 --- /dev/null +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-concurrency/snapshots.toml @@ -0,0 +1,16 @@ +# Tests concurrency inheritance in nested vp run commands + +# Nested vp run --concurrency=2 sets inner graph concurrency +[[plan]] +name = "nested --concurrency=2 sets inner graph concurrency" +args = ["run", "outer-concurrency-2"] + +# Nested vp run without --concurrency inherits parent default (10) +[[plan]] +name = "nested run without --concurrency inherits parent" +args = ["run", "outer-inherit"] + +# Outer --concurrency=4 propagates to nested run without flags +[[plan]] +name = "outer --concurrency=4 propagates to nested run without flags" +args = ["run", "--concurrency=4", "outer-inherit"] diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-concurrency/snapshots/query - nested --concurrency=2 sets inner graph concurrency.snap b/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-concurrency/snapshots/query - nested --concurrency=2 sets inner graph concurrency.snap new file mode 100644 index 00000000..fd1e6cc1 --- /dev/null +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-concurrency/snapshots/query - nested --concurrency=2 sets inner graph concurrency.snap @@ -0,0 +1,95 @@ +--- +source: crates/vite_task_plan/tests/plan_snapshots/main.rs +expression: "&plan_json" +info: + args: + - run + - outer-concurrency-2 +input_file: crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-concurrency +--- +{ + "graph": [ + { + "key": [ + "/", + "outer-concurrency-2" + ], + "node": { + "task_display": { + "package_name": "@test/nested-concurrency", + "task_name": "outer-concurrency-2", + "package_path": "/" + }, + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "@test/nested-concurrency", + "task_name": "outer-concurrency-2", + "package_path": "/" + }, + "command": "vp run --concurrency=2 inner", + "and_item_index": null, + "cwd": "/" + }, + "kind": { + "Expanded": { + "graph": [ + { + "key": [ + "/", + "inner" + ], + "node": { + "task_display": { + "package_name": "@test/nested-concurrency", + "task_name": "inner", + "package_path": "/" + }, + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "@test/nested-concurrency", + "task_name": "inner", + "package_path": "/" + }, + "command": "print-file package.json", + "and_item_index": null, + "cwd": "/" + }, + "kind": { + "Leaf": { + "Spawn": { + "cache_metadata": null, + "spawn_command": { + "program_path": "/node_modules/.bin/print-file", + "args": [ + "package.json" + ], + "all_envs": { + "NO_COLOR": "1", + "PATH": "/node_modules/.bin:/node_modules/.bin" + }, + "cwd": "/" + } + } + } + } + } + ] + }, + "neighbors": [] + } + ], + "concurrency": 2 + } + } + } + ] + }, + "neighbors": [] + } + ], + "concurrency": 10 +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-concurrency/snapshots/query - nested run without --concurrency inherits parent.snap b/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-concurrency/snapshots/query - nested run without --concurrency inherits parent.snap new file mode 100644 index 00000000..c1345c68 --- /dev/null +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-concurrency/snapshots/query - nested run without --concurrency inherits parent.snap @@ -0,0 +1,95 @@ +--- +source: crates/vite_task_plan/tests/plan_snapshots/main.rs +expression: "&plan_json" +info: + args: + - run + - outer-inherit +input_file: crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-concurrency +--- +{ + "graph": [ + { + "key": [ + "/", + "outer-inherit" + ], + "node": { + "task_display": { + "package_name": "@test/nested-concurrency", + "task_name": "outer-inherit", + "package_path": "/" + }, + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "@test/nested-concurrency", + "task_name": "outer-inherit", + "package_path": "/" + }, + "command": "vp run inner", + "and_item_index": null, + "cwd": "/" + }, + "kind": { + "Expanded": { + "graph": [ + { + "key": [ + "/", + "inner" + ], + "node": { + "task_display": { + "package_name": "@test/nested-concurrency", + "task_name": "inner", + "package_path": "/" + }, + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "@test/nested-concurrency", + "task_name": "inner", + "package_path": "/" + }, + "command": "print-file package.json", + "and_item_index": null, + "cwd": "/" + }, + "kind": { + "Leaf": { + "Spawn": { + "cache_metadata": null, + "spawn_command": { + "program_path": "/node_modules/.bin/print-file", + "args": [ + "package.json" + ], + "all_envs": { + "NO_COLOR": "1", + "PATH": "/node_modules/.bin:/node_modules/.bin" + }, + "cwd": "/" + } + } + } + } + } + ] + }, + "neighbors": [] + } + ], + "concurrency": 10 + } + } + } + ] + }, + "neighbors": [] + } + ], + "concurrency": 10 +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-concurrency/snapshots/query - outer --concurrency=4 propagates to nested run without flags.snap b/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-concurrency/snapshots/query - outer --concurrency=4 propagates to nested run without flags.snap new file mode 100644 index 00000000..c0feebc3 --- /dev/null +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-concurrency/snapshots/query - outer --concurrency=4 propagates to nested run without flags.snap @@ -0,0 +1,96 @@ +--- +source: crates/vite_task_plan/tests/plan_snapshots/main.rs +expression: "&plan_json" +info: + args: + - run + - "--concurrency=4" + - outer-inherit +input_file: crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-concurrency +--- +{ + "graph": [ + { + "key": [ + "/", + "outer-inherit" + ], + "node": { + "task_display": { + "package_name": "@test/nested-concurrency", + "task_name": "outer-inherit", + "package_path": "/" + }, + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "@test/nested-concurrency", + "task_name": "outer-inherit", + "package_path": "/" + }, + "command": "vp run inner", + "and_item_index": null, + "cwd": "/" + }, + "kind": { + "Expanded": { + "graph": [ + { + "key": [ + "/", + "inner" + ], + "node": { + "task_display": { + "package_name": "@test/nested-concurrency", + "task_name": "inner", + "package_path": "/" + }, + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "@test/nested-concurrency", + "task_name": "inner", + "package_path": "/" + }, + "command": "print-file package.json", + "and_item_index": null, + "cwd": "/" + }, + "kind": { + "Leaf": { + "Spawn": { + "cache_metadata": null, + "spawn_command": { + "program_path": "/node_modules/.bin/print-file", + "args": [ + "package.json" + ], + "all_envs": { + "NO_COLOR": "1", + "PATH": "/node_modules/.bin:/node_modules/.bin" + }, + "cwd": "/" + } + } + } + } + } + ] + }, + "neighbors": [] + } + ], + "concurrency": 4 + } + } + } + ] + }, + "neighbors": [] + } + ], + "concurrency": 4 +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-concurrency/snapshots/task graph.snap b/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-concurrency/snapshots/task graph.snap new file mode 100644 index 00000000..2dd35dd3 --- /dev/null +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-concurrency/snapshots/task graph.snap @@ -0,0 +1,109 @@ +--- +source: crates/vite_task_plan/tests/plan_snapshots/main.rs +expression: task_graph_json +input_file: crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-concurrency +--- +[ + { + "key": [ + "/", + "inner" + ], + "node": { + "task_display": { + "package_name": "@test/nested-concurrency", + "task_name": "inner", + "package_path": "/" + }, + "resolved_config": { + "command": "print-file package.json", + "resolved_options": { + "cwd": "/", + "cache_config": { + "env_config": { + "fingerprinted_envs": [], + "untracked_env": [ + "" + ] + }, + "input_config": { + "includes_auto": true, + "positive_globs": [], + "negative_globs": [] + } + } + } + }, + "source": "PackageJsonScript" + }, + "neighbors": [] + }, + { + "key": [ + "/", + "outer-concurrency-2" + ], + "node": { + "task_display": { + "package_name": "@test/nested-concurrency", + "task_name": "outer-concurrency-2", + "package_path": "/" + }, + "resolved_config": { + "command": "vp run --concurrency=2 inner", + "resolved_options": { + "cwd": "/", + "cache_config": { + "env_config": { + "fingerprinted_envs": [], + "untracked_env": [ + "" + ] + }, + "input_config": { + "includes_auto": true, + "positive_globs": [], + "negative_globs": [] + } + } + } + }, + "source": "PackageJsonScript" + }, + "neighbors": [] + }, + { + "key": [ + "/", + "outer-inherit" + ], + "node": { + "task_display": { + "package_name": "@test/nested-concurrency", + "task_name": "outer-inherit", + "package_path": "/" + }, + "resolved_config": { + "command": "vp run inner", + "resolved_options": { + "cwd": "/", + "cache_config": { + "env_config": { + "fingerprinted_envs": [], + "untracked_env": [ + "" + ] + }, + "input_config": { + "includes_auto": true, + "positive_globs": [], + "negative_globs": [] + } + } + } + }, + "source": "PackageJsonScript" + }, + "neighbors": [] + } +] diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-concurrency/vite-task.json b/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-concurrency/vite-task.json new file mode 100644 index 00000000..2c63c085 --- /dev/null +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-concurrency/vite-task.json @@ -0,0 +1,2 @@ +{ +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/shell-fallback/snapshots/query - shell fallback for pipe command.snap b/crates/vite_task_plan/tests/plan_snapshots/fixtures/shell-fallback/snapshots/query - shell fallback for pipe command.snap index 109dbe39..403fdcce 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/shell-fallback/snapshots/query - shell fallback for pipe command.snap +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/shell-fallback/snapshots/query - shell fallback for pipe command.snap @@ -7,84 +7,87 @@ info: - pipe-test input_file: crates/vite_task_plan/tests/plan_snapshots/fixtures/shell-fallback --- -[ - { - "key": [ - "/", - "pipe-test" - ], - "node": { - "task_display": { - "package_name": "", - "task_name": "pipe-test", - "package_path": "/" - }, - "items": [ - { - "execution_item_display": { - "task_display": { - "package_name": "", - "task_name": "pipe-test", - "package_path": "/" +{ + "graph": [ + { + "key": [ + "/", + "pipe-test" + ], + "node": { + "task_display": { + "package_name": "", + "task_name": "pipe-test", + "package_path": "/" + }, + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "", + "task_name": "pipe-test", + "package_path": "/" + }, + "command": "echo hello | node -e \"process.stdin.pipe(process.stdout)\"", + "and_item_index": null, + "cwd": "/" }, - "command": "echo hello | node -e \"process.stdin.pipe(process.stdout)\"", - "and_item_index": null, - "cwd": "/" - }, - "kind": { - "Leaf": { - "Spawn": { - "cache_metadata": { - "spawn_fingerprint": { - "cwd": "", - "program_fingerprint": { - "OutsideWorkspace": { - "program_name": "" + "kind": { + "Leaf": { + "Spawn": { + "cache_metadata": { + "spawn_fingerprint": { + "cwd": "", + "program_fingerprint": { + "OutsideWorkspace": { + "program_name": "" + } + }, + "args": [ + "", + "echo hello | node -e \"process.stdin.pipe(process.stdout)\"" + ], + "env_fingerprints": { + "fingerprinted_envs": {}, + "untracked_env_config": [ + "" + ] + } + }, + "execution_cache_key": { + "UserTask": { + "task_name": "pipe-test", + "and_item_index": 0, + "extra_args": [], + "package_path": "" } }, + "input_config": { + "includes_auto": true, + "positive_globs": [], + "negative_globs": [] + } + }, + "spawn_command": { + "program_path": "", "args": [ "", "echo hello | node -e \"process.stdin.pipe(process.stdout)\"" ], - "env_fingerprints": { - "fingerprinted_envs": {}, - "untracked_env_config": [ - "" - ] - } - }, - "execution_cache_key": { - "UserTask": { - "task_name": "pipe-test", - "and_item_index": 0, - "extra_args": [], - "package_path": "" - } - }, - "input_config": { - "includes_auto": true, - "positive_globs": [], - "negative_globs": [] + "all_envs": { + "NO_COLOR": "1", + "PATH": "/node_modules/.bin:/node_modules/.bin" + }, + "cwd": "/" } - }, - "spawn_command": { - "program_path": "", - "args": [ - "", - "echo hello | node -e \"process.stdin.pipe(process.stdout)\"" - ], - "all_envs": { - "NO_COLOR": "1", - "PATH": "/node_modules/.bin:/node_modules/.bin" - }, - "cwd": "/" } } } } - } - ] - }, - "neighbors": [] - } -] + ] + }, + "neighbors": [] + } + ], + "concurrency": 10 +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic-cache-disabled/snapshots/query - parent cache false does not affect expanded query tasks.snap b/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic-cache-disabled/snapshots/query - parent cache false does not affect expanded query tasks.snap index 3dad35d5..ba5187fe 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic-cache-disabled/snapshots/query - parent cache false does not affect expanded query tasks.snap +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic-cache-disabled/snapshots/query - parent cache false does not affect expanded query tasks.snap @@ -7,110 +7,116 @@ info: - run-build-no-cache input_file: crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic-cache-disabled --- -[ - { - "key": [ - "/", - "run-build-no-cache" - ], - "node": { - "task_display": { - "package_name": "@test/synthetic-cache-disabled", - "task_name": "run-build-no-cache", - "package_path": "/" - }, - "items": [ - { - "execution_item_display": { - "task_display": { - "package_name": "@test/synthetic-cache-disabled", - "task_name": "run-build-no-cache", - "package_path": "/" +{ + "graph": [ + { + "key": [ + "/", + "run-build-no-cache" + ], + "node": { + "task_display": { + "package_name": "@test/synthetic-cache-disabled", + "task_name": "run-build-no-cache", + "package_path": "/" + }, + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "@test/synthetic-cache-disabled", + "task_name": "run-build-no-cache", + "package_path": "/" + }, + "command": "vt run build", + "and_item_index": null, + "cwd": "/" }, - "command": "vt run build", - "and_item_index": null, - "cwd": "/" - }, - "kind": { - "Expanded": [ - { - "key": [ - "/", - "build" - ], - "node": { - "task_display": { - "package_name": "@test/synthetic-cache-disabled", - "task_name": "build", - "package_path": "/" - }, - "items": [ - { - "execution_item_display": { - "task_display": { - "package_name": "@test/synthetic-cache-disabled", - "task_name": "build", - "package_path": "/" - }, - "command": "vt lint", - "and_item_index": null, - "cwd": "/" + "kind": { + "Expanded": { + "graph": [ + { + "key": [ + "/", + "build" + ], + "node": { + "task_display": { + "package_name": "@test/synthetic-cache-disabled", + "task_name": "build", + "package_path": "/" }, - "kind": { - "Leaf": { - "Spawn": { - "cache_metadata": { - "spawn_fingerprint": { - "cwd": "", - "program_fingerprint": { - "OutsideWorkspace": { - "program_name": "oxlint" + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "@test/synthetic-cache-disabled", + "task_name": "build", + "package_path": "/" + }, + "command": "vt lint", + "and_item_index": null, + "cwd": "/" + }, + "kind": { + "Leaf": { + "Spawn": { + "cache_metadata": { + "spawn_fingerprint": { + "cwd": "", + "program_fingerprint": { + "OutsideWorkspace": { + "program_name": "oxlint" + } + }, + "args": [], + "env_fingerprints": { + "fingerprinted_envs": {}, + "untracked_env_config": [ + "" + ] + } + }, + "execution_cache_key": { + "UserTask": { + "task_name": "build", + "and_item_index": 0, + "extra_args": [], + "package_path": "" + } + }, + "input_config": { + "includes_auto": true, + "positive_globs": [], + "negative_globs": [] } }, - "args": [], - "env_fingerprints": { - "fingerprinted_envs": {}, - "untracked_env_config": [ - "" - ] - } - }, - "execution_cache_key": { - "UserTask": { - "task_name": "build", - "and_item_index": 0, - "extra_args": [], - "package_path": "" + "spawn_command": { + "program_path": "/node_modules/.bin/oxlint", + "args": [], + "all_envs": { + "NO_COLOR": "1", + "PATH": "/node_modules/.bin:/node_modules/.bin" + }, + "cwd": "/" } - }, - "input_config": { - "includes_auto": true, - "positive_globs": [], - "negative_globs": [] } - }, - "spawn_command": { - "program_path": "/node_modules/.bin/oxlint", - "args": [], - "all_envs": { - "NO_COLOR": "1", - "PATH": "/node_modules/.bin:/node_modules/.bin" - }, - "cwd": "/" } } } - } - } - ] - }, - "neighbors": [] + ] + }, + "neighbors": [] + } + ], + "concurrency": 10 } - ] + } } - } - ] - }, - "neighbors": [] - } -] + ] + }, + "neighbors": [] + } + ], + "concurrency": 10 +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic-cache-disabled/snapshots/query - script cache false does not affect expanded synthetic cache.snap b/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic-cache-disabled/snapshots/query - script cache false does not affect expanded synthetic cache.snap index 25b6b8a2..3a7cc5e8 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic-cache-disabled/snapshots/query - script cache false does not affect expanded synthetic cache.snap +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic-cache-disabled/snapshots/query - script cache false does not affect expanded synthetic cache.snap @@ -7,110 +7,116 @@ info: - run-build-cache-false input_file: crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic-cache-disabled --- -[ - { - "key": [ - "/", - "run-build-cache-false" - ], - "node": { - "task_display": { - "package_name": "@test/synthetic-cache-disabled", - "task_name": "run-build-cache-false", - "package_path": "/" - }, - "items": [ - { - "execution_item_display": { - "task_display": { - "package_name": "@test/synthetic-cache-disabled", - "task_name": "run-build-cache-false", - "package_path": "/" +{ + "graph": [ + { + "key": [ + "/", + "run-build-cache-false" + ], + "node": { + "task_display": { + "package_name": "@test/synthetic-cache-disabled", + "task_name": "run-build-cache-false", + "package_path": "/" + }, + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "@test/synthetic-cache-disabled", + "task_name": "run-build-cache-false", + "package_path": "/" + }, + "command": "vt run build", + "and_item_index": null, + "cwd": "/" }, - "command": "vt run build", - "and_item_index": null, - "cwd": "/" - }, - "kind": { - "Expanded": [ - { - "key": [ - "/", - "build" - ], - "node": { - "task_display": { - "package_name": "@test/synthetic-cache-disabled", - "task_name": "build", - "package_path": "/" - }, - "items": [ - { - "execution_item_display": { - "task_display": { - "package_name": "@test/synthetic-cache-disabled", - "task_name": "build", - "package_path": "/" - }, - "command": "vt lint", - "and_item_index": null, - "cwd": "/" + "kind": { + "Expanded": { + "graph": [ + { + "key": [ + "/", + "build" + ], + "node": { + "task_display": { + "package_name": "@test/synthetic-cache-disabled", + "task_name": "build", + "package_path": "/" }, - "kind": { - "Leaf": { - "Spawn": { - "cache_metadata": { - "spawn_fingerprint": { - "cwd": "", - "program_fingerprint": { - "OutsideWorkspace": { - "program_name": "oxlint" + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "@test/synthetic-cache-disabled", + "task_name": "build", + "package_path": "/" + }, + "command": "vt lint", + "and_item_index": null, + "cwd": "/" + }, + "kind": { + "Leaf": { + "Spawn": { + "cache_metadata": { + "spawn_fingerprint": { + "cwd": "", + "program_fingerprint": { + "OutsideWorkspace": { + "program_name": "oxlint" + } + }, + "args": [], + "env_fingerprints": { + "fingerprinted_envs": {}, + "untracked_env_config": [ + "" + ] + } + }, + "execution_cache_key": { + "UserTask": { + "task_name": "build", + "and_item_index": 0, + "extra_args": [], + "package_path": "" + } + }, + "input_config": { + "includes_auto": true, + "positive_globs": [], + "negative_globs": [] } }, - "args": [], - "env_fingerprints": { - "fingerprinted_envs": {}, - "untracked_env_config": [ - "" - ] - } - }, - "execution_cache_key": { - "UserTask": { - "task_name": "build", - "and_item_index": 0, - "extra_args": [], - "package_path": "" + "spawn_command": { + "program_path": "/node_modules/.bin/oxlint", + "args": [], + "all_envs": { + "NO_COLOR": "1", + "PATH": "/node_modules/.bin:/node_modules/.bin" + }, + "cwd": "/" } - }, - "input_config": { - "includes_auto": true, - "positive_globs": [], - "negative_globs": [] } - }, - "spawn_command": { - "program_path": "/node_modules/.bin/oxlint", - "args": [], - "all_envs": { - "NO_COLOR": "1", - "PATH": "/node_modules/.bin:/node_modules/.bin" - }, - "cwd": "/" } } } - } - } - ] - }, - "neighbors": [] + ] + }, + "neighbors": [] + } + ], + "concurrency": 10 } - ] + } } - } - ] - }, - "neighbors": [] - } -] + ] + }, + "neighbors": [] + } + ], + "concurrency": 10 +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic-cache-disabled/snapshots/query - script without cache.scripts defaults to no cache.snap b/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic-cache-disabled/snapshots/query - script without cache.scripts defaults to no cache.snap index f96f49c2..8b7e75a8 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic-cache-disabled/snapshots/query - script without cache.scripts defaults to no cache.snap +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic-cache-disabled/snapshots/query - script without cache.scripts defaults to no cache.snap @@ -7,49 +7,52 @@ info: - lint input_file: crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic-cache-disabled --- -[ - { - "key": [ - "/", - "lint" - ], - "node": { - "task_display": { - "package_name": "@test/synthetic-cache-disabled", - "task_name": "lint", - "package_path": "/" - }, - "items": [ - { - "execution_item_display": { - "task_display": { - "package_name": "@test/synthetic-cache-disabled", - "task_name": "lint", - "package_path": "/" +{ + "graph": [ + { + "key": [ + "/", + "lint" + ], + "node": { + "task_display": { + "package_name": "@test/synthetic-cache-disabled", + "task_name": "lint", + "package_path": "/" + }, + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "@test/synthetic-cache-disabled", + "task_name": "lint", + "package_path": "/" + }, + "command": "vt lint", + "and_item_index": null, + "cwd": "/" }, - "command": "vt lint", - "and_item_index": null, - "cwd": "/" - }, - "kind": { - "Leaf": { - "Spawn": { - "cache_metadata": null, - "spawn_command": { - "program_path": "/node_modules/.bin/oxlint", - "args": [], - "all_envs": { - "NO_COLOR": "1", - "PATH": "/node_modules/.bin:/node_modules/.bin" - }, - "cwd": "/" + "kind": { + "Leaf": { + "Spawn": { + "cache_metadata": null, + "spawn_command": { + "program_path": "/node_modules/.bin/oxlint", + "args": [], + "all_envs": { + "NO_COLOR": "1", + "PATH": "/node_modules/.bin:/node_modules/.bin" + }, + "cwd": "/" + } } } } } - } - ] - }, - "neighbors": [] - } -] + ] + }, + "neighbors": [] + } + ], + "concurrency": 10 +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic-cache-disabled/snapshots/query - task untrackedEnv inherited by synthetic.snap b/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic-cache-disabled/snapshots/query - task untrackedEnv inherited by synthetic.snap index 4369d9c3..80fff558 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic-cache-disabled/snapshots/query - task untrackedEnv inherited by synthetic.snap +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic-cache-disabled/snapshots/query - task untrackedEnv inherited by synthetic.snap @@ -7,79 +7,82 @@ info: - lint-with-untracked-env input_file: crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic-cache-disabled --- -[ - { - "key": [ - "/", - "lint-with-untracked-env" - ], - "node": { - "task_display": { - "package_name": "@test/synthetic-cache-disabled", - "task_name": "lint-with-untracked-env", - "package_path": "/" - }, - "items": [ - { - "execution_item_display": { - "task_display": { - "package_name": "@test/synthetic-cache-disabled", - "task_name": "lint-with-untracked-env", - "package_path": "/" +{ + "graph": [ + { + "key": [ + "/", + "lint-with-untracked-env" + ], + "node": { + "task_display": { + "package_name": "@test/synthetic-cache-disabled", + "task_name": "lint-with-untracked-env", + "package_path": "/" + }, + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "@test/synthetic-cache-disabled", + "task_name": "lint-with-untracked-env", + "package_path": "/" + }, + "command": "vt lint", + "and_item_index": null, + "cwd": "/" }, - "command": "vt lint", - "and_item_index": null, - "cwd": "/" - }, - "kind": { - "Leaf": { - "Spawn": { - "cache_metadata": { - "spawn_fingerprint": { - "cwd": "", - "program_fingerprint": { - "OutsideWorkspace": { - "program_name": "oxlint" + "kind": { + "Leaf": { + "Spawn": { + "cache_metadata": { + "spawn_fingerprint": { + "cwd": "", + "program_fingerprint": { + "OutsideWorkspace": { + "program_name": "oxlint" + } + }, + "args": [], + "env_fingerprints": { + "fingerprinted_envs": {}, + "untracked_env_config": [ + "CUSTOM_VAR", + "" + ] } }, - "args": [], - "env_fingerprints": { - "fingerprinted_envs": {}, - "untracked_env_config": [ - "CUSTOM_VAR", - "" - ] - } - }, - "execution_cache_key": { - "UserTask": { - "task_name": "lint-with-untracked-env", - "and_item_index": 0, - "extra_args": [], - "package_path": "" + "execution_cache_key": { + "UserTask": { + "task_name": "lint-with-untracked-env", + "and_item_index": 0, + "extra_args": [], + "package_path": "" + } + }, + "input_config": { + "includes_auto": true, + "positive_globs": [], + "negative_globs": [] } }, - "input_config": { - "includes_auto": true, - "positive_globs": [], - "negative_globs": [] + "spawn_command": { + "program_path": "/node_modules/.bin/oxlint", + "args": [], + "all_envs": { + "NO_COLOR": "1", + "PATH": "/node_modules/.bin:/node_modules/.bin" + }, + "cwd": "/" } - }, - "spawn_command": { - "program_path": "/node_modules/.bin/oxlint", - "args": [], - "all_envs": { - "NO_COLOR": "1", - "PATH": "/node_modules/.bin:/node_modules/.bin" - }, - "cwd": "/" } } } } - } - ] - }, - "neighbors": [] - } -] + ] + }, + "neighbors": [] + } + ], + "concurrency": 10 +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic-cache-disabled/snapshots/query - task with cache false disables synthetic cache.snap b/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic-cache-disabled/snapshots/query - task with cache false disables synthetic cache.snap index ca6c71f5..db56b4f8 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic-cache-disabled/snapshots/query - task with cache false disables synthetic cache.snap +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic-cache-disabled/snapshots/query - task with cache false disables synthetic cache.snap @@ -7,49 +7,52 @@ info: - lint-no-cache input_file: crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic-cache-disabled --- -[ - { - "key": [ - "/", - "lint-no-cache" - ], - "node": { - "task_display": { - "package_name": "@test/synthetic-cache-disabled", - "task_name": "lint-no-cache", - "package_path": "/" - }, - "items": [ - { - "execution_item_display": { - "task_display": { - "package_name": "@test/synthetic-cache-disabled", - "task_name": "lint-no-cache", - "package_path": "/" +{ + "graph": [ + { + "key": [ + "/", + "lint-no-cache" + ], + "node": { + "task_display": { + "package_name": "@test/synthetic-cache-disabled", + "task_name": "lint-no-cache", + "package_path": "/" + }, + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "@test/synthetic-cache-disabled", + "task_name": "lint-no-cache", + "package_path": "/" + }, + "command": "vt lint", + "and_item_index": null, + "cwd": "/" }, - "command": "vt lint", - "and_item_index": null, - "cwd": "/" - }, - "kind": { - "Leaf": { - "Spawn": { - "cache_metadata": null, - "spawn_command": { - "program_path": "/node_modules/.bin/oxlint", - "args": [], - "all_envs": { - "NO_COLOR": "1", - "PATH": "/node_modules/.bin:/node_modules/.bin" - }, - "cwd": "/" + "kind": { + "Leaf": { + "Spawn": { + "cache_metadata": null, + "spawn_command": { + "program_path": "/node_modules/.bin/oxlint", + "args": [], + "all_envs": { + "NO_COLOR": "1", + "PATH": "/node_modules/.bin:/node_modules/.bin" + }, + "cwd": "/" + } } } } } - } - ] - }, - "neighbors": [] - } -] + ] + }, + "neighbors": [] + } + ], + "concurrency": 10 +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic-cache-disabled/snapshots/query - task with cache true enables synthetic cache.snap b/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic-cache-disabled/snapshots/query - task with cache true enables synthetic cache.snap index d2ba7f47..70bfe02f 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic-cache-disabled/snapshots/query - task with cache true enables synthetic cache.snap +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic-cache-disabled/snapshots/query - task with cache true enables synthetic cache.snap @@ -7,78 +7,81 @@ info: - lint-with-cache input_file: crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic-cache-disabled --- -[ - { - "key": [ - "/", - "lint-with-cache" - ], - "node": { - "task_display": { - "package_name": "@test/synthetic-cache-disabled", - "task_name": "lint-with-cache", - "package_path": "/" - }, - "items": [ - { - "execution_item_display": { - "task_display": { - "package_name": "@test/synthetic-cache-disabled", - "task_name": "lint-with-cache", - "package_path": "/" +{ + "graph": [ + { + "key": [ + "/", + "lint-with-cache" + ], + "node": { + "task_display": { + "package_name": "@test/synthetic-cache-disabled", + "task_name": "lint-with-cache", + "package_path": "/" + }, + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "@test/synthetic-cache-disabled", + "task_name": "lint-with-cache", + "package_path": "/" + }, + "command": "vt lint", + "and_item_index": null, + "cwd": "/" }, - "command": "vt lint", - "and_item_index": null, - "cwd": "/" - }, - "kind": { - "Leaf": { - "Spawn": { - "cache_metadata": { - "spawn_fingerprint": { - "cwd": "", - "program_fingerprint": { - "OutsideWorkspace": { - "program_name": "oxlint" + "kind": { + "Leaf": { + "Spawn": { + "cache_metadata": { + "spawn_fingerprint": { + "cwd": "", + "program_fingerprint": { + "OutsideWorkspace": { + "program_name": "oxlint" + } + }, + "args": [], + "env_fingerprints": { + "fingerprinted_envs": {}, + "untracked_env_config": [ + "" + ] } }, - "args": [], - "env_fingerprints": { - "fingerprinted_envs": {}, - "untracked_env_config": [ - "" - ] - } - }, - "execution_cache_key": { - "UserTask": { - "task_name": "lint-with-cache", - "and_item_index": 0, - "extra_args": [], - "package_path": "" + "execution_cache_key": { + "UserTask": { + "task_name": "lint-with-cache", + "and_item_index": 0, + "extra_args": [], + "package_path": "" + } + }, + "input_config": { + "includes_auto": true, + "positive_globs": [], + "negative_globs": [] } }, - "input_config": { - "includes_auto": true, - "positive_globs": [], - "negative_globs": [] + "spawn_command": { + "program_path": "/node_modules/.bin/oxlint", + "args": [], + "all_envs": { + "NO_COLOR": "1", + "PATH": "/node_modules/.bin:/node_modules/.bin" + }, + "cwd": "/" } - }, - "spawn_command": { - "program_path": "/node_modules/.bin/oxlint", - "args": [], - "all_envs": { - "NO_COLOR": "1", - "PATH": "/node_modules/.bin:/node_modules/.bin" - }, - "cwd": "/" } } } } - } - ] - }, - "neighbors": [] - } -] + ] + }, + "neighbors": [] + } + ], + "concurrency": 10 +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic-in-subpackage/snapshots/query - synthetic-in-subpackage.snap b/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic-in-subpackage/snapshots/query - synthetic-in-subpackage.snap index d90a0e00..c13c87eb 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic-in-subpackage/snapshots/query - synthetic-in-subpackage.snap +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic-in-subpackage/snapshots/query - synthetic-in-subpackage.snap @@ -7,110 +7,116 @@ info: - lint input_file: crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic-in-subpackage --- -[ - { - "key": [ - "/", - "lint" - ], - "node": { - "task_display": { - "package_name": "", - "task_name": "lint", - "package_path": "/" - }, - "items": [ - { - "execution_item_display": { - "task_display": { - "package_name": "", - "task_name": "lint", - "package_path": "/" +{ + "graph": [ + { + "key": [ + "/", + "lint" + ], + "node": { + "task_display": { + "package_name": "", + "task_name": "lint", + "package_path": "/" + }, + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "", + "task_name": "lint", + "package_path": "/" + }, + "command": "vt run a#lint", + "and_item_index": null, + "cwd": "/" }, - "command": "vt run a#lint", - "and_item_index": null, - "cwd": "/" - }, - "kind": { - "Expanded": [ - { - "key": [ - "/packages/a", - "lint" - ], - "node": { - "task_display": { - "package_name": "a", - "task_name": "lint", - "package_path": "/packages/a" - }, - "items": [ - { - "execution_item_display": { - "task_display": { - "package_name": "a", - "task_name": "lint", - "package_path": "/packages/a" - }, - "command": "vt lint", - "and_item_index": null, - "cwd": "/packages/a" + "kind": { + "Expanded": { + "graph": [ + { + "key": [ + "/packages/a", + "lint" + ], + "node": { + "task_display": { + "package_name": "a", + "task_name": "lint", + "package_path": "/packages/a" }, - "kind": { - "Leaf": { - "Spawn": { - "cache_metadata": { - "spawn_fingerprint": { - "cwd": "packages/a", - "program_fingerprint": { - "OutsideWorkspace": { - "program_name": "oxlint" + "items": [ + { + "execution_item_display": { + "task_display": { + "package_name": "a", + "task_name": "lint", + "package_path": "/packages/a" + }, + "command": "vt lint", + "and_item_index": null, + "cwd": "/packages/a" + }, + "kind": { + "Leaf": { + "Spawn": { + "cache_metadata": { + "spawn_fingerprint": { + "cwd": "packages/a", + "program_fingerprint": { + "OutsideWorkspace": { + "program_name": "oxlint" + } + }, + "args": [], + "env_fingerprints": { + "fingerprinted_envs": {}, + "untracked_env_config": [ + "" + ] + } + }, + "execution_cache_key": { + "UserTask": { + "task_name": "lint", + "and_item_index": 0, + "extra_args": [], + "package_path": "packages/a" + } + }, + "input_config": { + "includes_auto": true, + "positive_globs": [], + "negative_globs": [] } }, - "args": [], - "env_fingerprints": { - "fingerprinted_envs": {}, - "untracked_env_config": [ - "" - ] - } - }, - "execution_cache_key": { - "UserTask": { - "task_name": "lint", - "and_item_index": 0, - "extra_args": [], - "package_path": "packages/a" + "spawn_command": { + "program_path": "/node_modules/.bin/oxlint", + "args": [], + "all_envs": { + "NO_COLOR": "1", + "PATH": "/packages/a/node_modules/.bin:/node_modules/.bin:/node_modules/.bin" + }, + "cwd": "/packages/a" } - }, - "input_config": { - "includes_auto": true, - "positive_globs": [], - "negative_globs": [] } - }, - "spawn_command": { - "program_path": "/node_modules/.bin/oxlint", - "args": [], - "all_envs": { - "NO_COLOR": "1", - "PATH": "/packages/a/node_modules/.bin:/node_modules/.bin:/node_modules/.bin" - }, - "cwd": "/packages/a" } } } - } - } - ] - }, - "neighbors": [] + ] + }, + "neighbors": [] + } + ], + "concurrency": 10 } - ] + } } - } - ] - }, - "neighbors": [] - } -] + ] + }, + "neighbors": [] + } + ], + "concurrency": 10 +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/main.rs b/crates/vite_task_plan/tests/plan_snapshots/main.rs index 7d99e759..27c3b7cc 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/main.rs +++ b/crates/vite_task_plan/tests/plan_snapshots/main.rs @@ -65,13 +65,16 @@ impl CompactPlan { fn from_execution_graph(graph: &ExecutionGraph, workspace_root: &AbsolutePath) -> Self { use petgraph::visit::EdgeRef as _; let mut map = BTreeMap::::new(); - for node_idx in graph.node_indices() { - let node = &graph[node_idx]; + for node_idx in graph.graph.node_indices() { + let node = &graph.graph[node_idx]; let key = Self::task_key(&node.task_display, workspace_root); let neighbors: BTreeSet = graph + .graph .edges(node_idx) - .map(|edge| Self::task_key(&graph[edge.target()].task_display, workspace_root)) + .map(|edge| { + Self::task_key(&graph.graph[edge.target()].task_display, workspace_root) + }) .collect(); let expanded_items: Vec = node