diff --git a/crates/vite_task/src/session/reporter/labeled.rs b/crates/vite_task/src/session/reporter/labeled.rs index e096dbc0..d548db49 100644 --- a/crates/vite_task/src/session/reporter/labeled.rs +++ b/crates/vite_task/src/session/reporter/labeled.rs @@ -54,27 +54,6 @@ struct ExecutionStats { struct SharedReporterState { executions: Vec, stats: ExecutionStats, - /// Total number of spawned leaf executions in the graph (including nested `Expanded` - /// subgraphs). Computed once at build time and used to determine the stdio suggestion: - /// inherited stdio is only suggested when there is exactly one spawn leaf. - spawn_leaf_count: usize, -} - -/// Count the total number of spawned leaf executions in an execution graph, -/// recursing into nested `Expanded` subgraphs. -/// -/// In-process executions are not counted because they don't spawn child processes -/// and thus don't need stdin. -pub(super) fn count_spawn_leaves(graph: &ExecutionGraph) -> usize { - graph - .node_weights() - .flat_map(|task| task.items.iter()) - .map(|item| match &item.kind { - ExecutionItemKind::Leaf(LeafExecutionKind::Spawn(_)) => 1, - ExecutionItemKind::Leaf(LeafExecutionKind::InProcess(_)) => 0, - ExecutionItemKind::Expanded(nested_graph) => count_spawn_leaves(nested_graph), - }) - .sum() } /// Builder for the labeled graph reporter. @@ -110,13 +89,11 @@ impl LabeledReporterBuilder { impl GraphExecutionReporterBuilder for LabeledReporterBuilder { fn build(self: Box, graph: &Arc) -> Box { - let spawn_leaf_count = count_spawn_leaves(graph); let writer = Rc::new(RefCell::new(self.writer)); Box::new(LabeledGraphReporter { shared: Rc::new(RefCell::new(SharedReporterState { executions: Vec::new(), stats: ExecutionStats::default(), - spawn_leaf_count, })), writer, graph: Arc::clone(graph), @@ -144,12 +121,23 @@ pub struct LabeledGraphReporter { )] impl GraphExecutionReporter for LabeledGraphReporter { fn new_leaf_execution(&mut self, path: &LeafExecutionPath) -> Box { - let display = path.resolve_item(&self.graph).execution_item_display.clone(); + let item = path.resolve_item(&self.graph); + let display = item.execution_item_display.clone(); + let stdio_suggestion = match &item.kind { + ExecutionItemKind::Leaf(LeafExecutionKind::Spawn(_)) + if path.all_containing_graphs_single_node(&self.graph) => + { + StdioSuggestion::Inherited + } + _ => StdioSuggestion::Piped, + }; + Box::new(LabeledLeafReporter { shared: Rc::clone(&self.shared), writer: Rc::clone(&self.writer), display, workspace_path: Arc::clone(&self.workspace_path), + stdio_suggestion, started: false, }) } @@ -221,6 +209,8 @@ struct LabeledLeafReporter { /// 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, /// Whether `start()` has been called. Used to determine if stats should be updated /// in `finish()` and whether to push an `ExecutionInfo` entry. started: bool, @@ -237,7 +227,7 @@ impl LeafExecutionReporter for LabeledLeafReporter { self.started = true; // Update shared state synchronously, then drop the borrow before any async writes. - let suggestion = { + { let mut shared = self.shared.borrow_mut(); // Update statistics based on cache status @@ -254,14 +244,7 @@ impl LeafExecutionReporter for LabeledLeafReporter { exit_status: None, error_message: None, }); - - // Determine stdio suggestion: inherited only when exactly one spawn leaf - if shared.spawn_leaf_count == 1 { - StdioSuggestion::Inherited - } else { - StdioSuggestion::Piped - } - }; + } // shared borrow dropped here // Format command line with cache status (sync), then write asynchronously. @@ -276,7 +259,7 @@ impl LeafExecutionReporter for LabeledLeafReporter { let _ = writer.flush().await; StdioConfig { - suggestion, + suggestion: self.stdio_suggestion, stdout_writer: Box::new(tokio::io::stdout()), stderr_writer: Box::new(tokio::io::stderr()), } @@ -573,7 +556,9 @@ fn format_summary( mod tests { use std::sync::Arc; - use vite_task_plan::ExecutionGraph; + use vite_task_plan::{ + ExecutionGraph, ExecutionItem, TaskExecution, execution_graph::ExecutionNodeIndex, + }; use super::*; use crate::session::{ @@ -584,148 +569,152 @@ mod tests { }, }; - // ──────────────────────────────────────────────────────────── - // count_spawn_leaves tests - // ──────────────────────────────────────────────────────────── - - #[test] - fn count_spawn_leaves_empty_graph() { - let graph = ExecutionGraph::default(); - assert_eq!(count_spawn_leaves(&graph), 0); - } - - #[test] - fn count_spawn_leaves_single_spawn() { - let graph = ExecutionGraph::from_node_list([spawn_task("build")]); - assert_eq!(count_spawn_leaves(&graph), 1); + fn leaf_path(path_items: &[(usize, usize)]) -> LeafExecutionPath { + let mut path = LeafExecutionPath::default(); + for (node_ix, item_ix) in path_items { + path.push(ExecutionNodeIndex::new(*node_ix), *item_ix); + } + path } - #[test] - fn count_spawn_leaves_multiple_spawns() { - let graph = ExecutionGraph::from_node_list([ - spawn_task("build"), - spawn_task("test"), - spawn_task("lint"), - ]); - assert_eq!(count_spawn_leaves(&graph), 3); + fn build_labeled_leaf( + graph: ExecutionGraph, + path: &LeafExecutionPath, + ) -> Box { + let graph_arc = Arc::new(graph); + let builder = + Box::new(LabeledReporterBuilder::new(test_path(), Box::new(tokio::io::sink()))); + let mut reporter = builder.build(&graph_arc); + reporter.new_leaf_execution(path) } - #[test] - fn count_spawn_leaves_in_process_not_counted() { - let graph = ExecutionGraph::from_node_list([in_process_task("echo")]); - assert_eq!(count_spawn_leaves(&graph), 0); + #[expect( + clippy::future_not_send, + reason = "LeafExecutionReporter futures are !Send in single-threaded reporter tests" + )] + async fn suggestion_for_path( + graph: ExecutionGraph, + path: &LeafExecutionPath, + ) -> StdioSuggestion { + let mut leaf = build_labeled_leaf(graph, path); + let stdio_config = + leaf.start(CacheStatus::Disabled(CacheDisabledReason::NoCacheMetadata)).await; + stdio_config.suggestion } - #[test] - fn count_spawn_leaves_mixed_spawn_and_in_process() { - let graph = ExecutionGraph::from_node_list([spawn_task("build"), in_process_task("echo")]); - assert_eq!(count_spawn_leaves(&graph), 1); + fn spawn_item(name: &str) -> ExecutionItem { + let mut task = spawn_task(name); + task.items.pop().expect("spawn_task always has one item") } - #[test] - fn count_spawn_leaves_nested_expanded() { - // Build a nested graph containing two spawns - let nested = - ExecutionGraph::from_node_list([spawn_task("nested-build"), spawn_task("nested-test")]); - - // Outer graph has one expanded item pointing to the nested graph - let graph = ExecutionGraph::from_node_list([expanded_task("expand", nested)]); - assert_eq!(count_spawn_leaves(&graph), 2); + fn expanded_item(name: &str, nested_graph: ExecutionGraph) -> ExecutionItem { + let mut task = expanded_task(name, nested_graph); + task.items.pop().expect("expanded_task always has one item") } - #[test] - fn count_spawn_leaves_nested_with_top_level() { - // Nested graph with one spawn - let nested = ExecutionGraph::from_node_list([spawn_task("nested-lint")]); - - // Top-level graph has one spawn + one expanded - let graph = - ExecutionGraph::from_node_list([spawn_task("build"), expanded_task("expand", nested)]); - assert_eq!(count_spawn_leaves(&graph), 2); + fn task_with_items(name: &str, items: Vec) -> TaskExecution { + let mut task = spawn_task(name); + task.items = items; + task } - // ──────────────────────────────────────────────────────────── - // LabeledLeafReporter stdio suggestion tests - // ──────────────────────────────────────────────────────────── - - /// Build a `LabeledGraphReporter` for the given graph and return a leaf reporter - /// for the first node's first item. - fn build_labeled_leaf(graph: ExecutionGraph) -> Box { - use vite_task_plan::execution_graph::ExecutionNodeIndex; - - let graph_arc = Arc::new(graph); - let builder = - Box::new(LabeledReporterBuilder::new(test_path(), Box::new(tokio::io::sink()))); - let mut reporter = builder.build(&graph_arc); + fn graph_with_mixed_and_siblings() -> ExecutionGraph { + let nested_single_node = ExecutionGraph::from_node_list([spawn_task("bar")]); + let nested_multi_node = + ExecutionGraph::from_node_list([spawn_task("build-a"), spawn_task("build-b")]); + + let root = task_with_items( + "foo", + vec![ + spawn_item("foo-step"), + expanded_item("run-bar", nested_single_node), + expanded_item("run-build-recursive", nested_multi_node), + ], + ); - // Create a leaf reporter for the first node's first item - let mut path = LeafExecutionPath::default(); - path.push(ExecutionNodeIndex::new(0), 0); - reporter.new_leaf_execution(&path) + ExecutionGraph::from_node_list([root]) } #[tokio::test] - async fn labeled_reporter_single_spawn_suggests_inherited() { + async fn labeled_reporter_single_spawn_in_single_node_chain_suggests_inherited() { let graph = ExecutionGraph::from_node_list([spawn_task("build")]); - let mut leaf = build_labeled_leaf(graph); - let stdio_config = - leaf.start(CacheStatus::Disabled(CacheDisabledReason::NoCacheMetadata)).await; - assert_eq!(stdio_config.suggestion, StdioSuggestion::Inherited); + let path = leaf_path(&[(0, 0)]); + + assert_eq!(suggestion_for_path(graph, &path).await, StdioSuggestion::Inherited); } #[tokio::test] - async fn labeled_reporter_multiple_spawns_suggests_piped() { + async fn labeled_reporter_multi_node_root_graph_suggests_piped() { let graph = ExecutionGraph::from_node_list([spawn_task("build"), spawn_task("test")]); - let mut leaf = build_labeled_leaf(graph); - let stdio_config = - leaf.start(CacheStatus::Disabled(CacheDisabledReason::NoCacheMetadata)).await; - assert_eq!(stdio_config.suggestion, StdioSuggestion::Piped); + let path = leaf_path(&[(0, 0)]); + + assert_eq!(suggestion_for_path(graph, &path).await, StdioSuggestion::Piped); } #[tokio::test] - async fn labeled_reporter_single_in_process_suggests_piped() { - // Zero spawn leaves → spawn_leaf_count == 0, so not == 1 → Piped - // This is correct: in-process executions don't spawn child processes, - // so stdio suggestion doesn't apply to them. - let graph = ExecutionGraph::from_node_list([in_process_task("echo")]); - let mut leaf = build_labeled_leaf(graph); - let stdio_config = - leaf.start(CacheStatus::Disabled(CacheDisabledReason::NoCacheMetadata)).await; - assert_eq!(stdio_config.suggestion, StdioSuggestion::Piped); + async fn labeled_reporter_nested_single_node_chain_suggests_inherited() { + let nested = ExecutionGraph::from_node_list([spawn_task("nested-build")]); + let graph = ExecutionGraph::from_node_list([expanded_task("expand", nested)]); + let path = leaf_path(&[(0, 0), (0, 0)]); + + assert_eq!(suggestion_for_path(graph, &path).await, StdioSuggestion::Inherited); } #[tokio::test] - async fn labeled_reporter_one_spawn_one_in_process_suggests_inherited() { - // One spawn leaf + one in-process → spawn_leaf_count == 1 → Inherited - let graph = ExecutionGraph::from_node_list([spawn_task("build"), in_process_task("echo")]); - let mut leaf = build_labeled_leaf(graph); - let stdio_config = - leaf.start(CacheStatus::Disabled(CacheDisabledReason::NoCacheMetadata)).await; - assert_eq!(stdio_config.suggestion, StdioSuggestion::Inherited); + async fn labeled_reporter_nested_multi_node_graph_suggests_piped() { + let nested = + ExecutionGraph::from_node_list([spawn_task("nested-a"), spawn_task("nested-b")]); + let graph = ExecutionGraph::from_node_list([expanded_task("expand", nested)]); + let path = leaf_path(&[(0, 0), (0, 0)]); + + assert_eq!(suggestion_for_path(graph, &path).await, StdioSuggestion::Piped); } #[tokio::test] - async fn labeled_reporter_nested_single_spawn_suggests_inherited() { - // Nested graph with exactly one spawn + async fn labeled_reporter_multi_node_ancestor_forces_piped_for_nested_leaf() { let nested = ExecutionGraph::from_node_list([spawn_task("nested-build")]); + let graph = ExecutionGraph::from_node_list([ + expanded_task("expand", nested), + spawn_task("sibling"), + ]); + let path = leaf_path(&[(0, 0), (0, 0)]); - let graph = ExecutionGraph::from_node_list([expanded_task("expand", nested)]); - let mut leaf = build_labeled_leaf(graph); - let stdio_config = - leaf.start(CacheStatus::Disabled(CacheDisabledReason::NoCacheMetadata)).await; - assert_eq!(stdio_config.suggestion, StdioSuggestion::Inherited); + assert_eq!(suggestion_for_path(graph, &path).await, StdioSuggestion::Piped); } #[tokio::test] - async fn labeled_reporter_nested_multiple_spawns_suggests_piped() { - // Nested graph with two spawns - let nested = - ExecutionGraph::from_node_list([spawn_task("nested-a"), spawn_task("nested-b")]); + async fn labeled_reporter_keeps_inherited_for_single_node_chains_with_multi_node_and_sibling() { + // Root graph has one node and three sequential `&&` items: + // 1) direct spawn leaf + // 2) expanded graph with one node + // 3) expanded graph with multiple nodes + // + // The first two leaves should still suggest inherited stdio because their + // containing graph chain has only one node at every level. The third should + // suggest piped because its containing graph has multiple nodes. + let path_top_level = leaf_path(&[(0, 0)]); + let path_nested_single = leaf_path(&[(0, 1), (0, 0)]); + let path_nested_multi = leaf_path(&[(0, 2), (0, 0)]); + + assert_eq!( + suggestion_for_path(graph_with_mixed_and_siblings(), &path_top_level).await, + StdioSuggestion::Inherited + ); + assert_eq!( + suggestion_for_path(graph_with_mixed_and_siblings(), &path_nested_single).await, + StdioSuggestion::Inherited + ); + assert_eq!( + suggestion_for_path(graph_with_mixed_and_siblings(), &path_nested_multi).await, + StdioSuggestion::Piped + ); + } - let graph = ExecutionGraph::from_node_list([expanded_task("expand", nested)]); - let mut leaf = build_labeled_leaf(graph); - let stdio_config = - leaf.start(CacheStatus::Disabled(CacheDisabledReason::NoCacheMetadata)).await; - assert_eq!(stdio_config.suggestion, StdioSuggestion::Piped); + #[tokio::test] + async fn labeled_reporter_in_process_leaf_suggests_piped() { + let graph = ExecutionGraph::from_node_list([in_process_task("echo")]); + let path = leaf_path(&[(0, 0)]); + + assert_eq!(suggestion_for_path(graph, &path).await, StdioSuggestion::Piped); } } diff --git a/crates/vite_task/src/session/reporter/mod.rs b/crates/vite_task/src/session/reporter/mod.rs index f66f1c04..6ca717d0 100644 --- a/crates/vite_task/src/session/reporter/mod.rs +++ b/crates/vite_task/src/session/reporter/mod.rs @@ -180,6 +180,49 @@ impl LeafExecutionPath { } unreachable!("LeafExecutionPath: empty path") } + + /// Return true when this leaf is contained in a chain of execution graphs where + /// every graph (root + all nested `Expanded` ancestors) has exactly one node. + /// + /// This is used by the labeled reporter to determine whether inherited stdio can + /// be suggested for spawned processes. + /// + /// # Panics + /// + /// - If the path is empty (indicates a bug in path construction). + /// - If an intermediate path element points to a `Leaf` item instead of + /// `Expanded`. + fn all_containing_graphs_single_node(&self, root_graph: &ExecutionGraph) -> bool { + let Some((last_path_item, parent_path_items)) = self.0.split_last() else { + unreachable!("LeafExecutionPath: empty path") + }; + + let mut current_graph = root_graph; + if current_graph.node_count() != 1 { + return false; + } + + for (depth, path_item) in parent_path_items.iter().enumerate() { + let item = path_item.resolve(current_graph); + match &item.kind { + ExecutionItemKind::Expanded(nested_graph) => { + current_graph = nested_graph; + if current_graph.node_count() != 1 { + return false; + } + } + ExecutionItemKind::Leaf(_) => { + unreachable!( + "LeafExecutionPath: intermediate element at depth {depth} is a Leaf, expected Expanded" + ) + } + } + } + + // Validate that the final path item resolves in the containing graph. + let _ = last_path_item.resolve(current_graph); + true + } } impl std::ops::Index<&LeafExecutionPath> for ExecutionGraph { 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 1d25fc3b..7c4dbcc5 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 @@ -1,7 +1,8 @@ # Tests stdin inheritance behavior for spawned tasks. # # Stdin is inherited from the parent process only when BOTH conditions are met: -# 1. The reporter suggests inherited stdin (single spawn leaf in the graph, or synthetic execution) +# 1. The reporter suggests inherited stdin (the leaf is in a single-node graph chain, +# or the execution uses PlainReporter for synthetic execution) # 2. Caching is disabled for the task (cache_metadata is None) # # Otherwise, stdin is set to /dev/null. diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdio-graph-criteria/package.json b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdio-graph-criteria/package.json new file mode 100644 index 00000000..5b2b4e15 --- /dev/null +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdio-graph-criteria/package.json @@ -0,0 +1,4 @@ +{ + "name": "stdio-graph-criteria-test", + "private": true +} diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdio-graph-criteria/packages/other/package.json b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdio-graph-criteria/packages/other/package.json new file mode 100644 index 00000000..2b5e8f26 --- /dev/null +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdio-graph-criteria/packages/other/package.json @@ -0,0 +1,3 @@ +{ + "name": "other" +} diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdio-graph-criteria/packages/other/vite-task.json b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdio-graph-criteria/packages/other/vite-task.json new file mode 100644 index 00000000..e8a9cf09 --- /dev/null +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdio-graph-criteria/packages/other/vite-task.json @@ -0,0 +1,16 @@ +{ + "tasks": { + "check-tty": { + "command": "check-tty", + "cache": false + }, + "bar": { + "command": "check-tty", + "cache": false + }, + "foo-nested": { + "command": "vp run bar", + "cache": false + } + } +} diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdio-graph-criteria/pnpm-workspace.yaml b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdio-graph-criteria/pnpm-workspace.yaml new file mode 100644 index 00000000..924b55f4 --- /dev/null +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdio-graph-criteria/pnpm-workspace.yaml @@ -0,0 +1,2 @@ +packages: + - packages/* 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 new file mode 100644 index 00000000..20bab674 --- /dev/null +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdio-graph-criteria/snapshots.toml @@ -0,0 +1,19 @@ +# Tests stdio suggestion criteria based on graph shape along each leaf path. +# +# Rules under test: +# - Suggest piped when the leaf's containing graph has more than one node, or +# any ancestor graph on its path has more than one node. +# - Suggest inherited only when every graph on the path (root + nested Expanded +# graphs) has exactly one node. + +[[e2e]] +name = "single-node chains inherit even with multi-node sibling graph" +steps = [ + "vp run foo", +] + +[[e2e]] +name = "multi-node ancestor forces piped for nested single-node graph" +steps = [ + "vp run -r foo-nested", +] 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 new file mode 100644 index 00000000..15f23f7d --- /dev/null +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdio-graph-criteria/snapshots/multi-node ancestor forces piped for nested single-node graph.snap @@ -0,0 +1,31 @@ +--- +source: crates/vite_task_bin/tests/e2e_snapshots/main.rs +expression: e2e_outputs +--- +> vp run -r foo-nested +~/packages/other$ check-tty ⊘ cache disabled: no cache config +stdin:not-tty +stdout:not-tty +stderr:not-tty + +$ check-tty ⊘ cache disabled: no cache config +stdin:not-tty +stdout:not-tty +stderr:not-tty + + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + Vite+ Task Runner • Execution Summary +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +Statistics: 2 tasks • 0 cache hits • 0 cache misses • 2 cache disabled +Performance: 0% cache hit rate + +Task Details: +──────────────────────────────────────────────── + [1] other#bar: ~/packages/other$ check-tty ✓ + → Cache disabled in task configuration + ······················································· + [2] stdio-graph-criteria-test#bar: $ check-tty ✓ + → Cache disabled in task configuration +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 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 new file mode 100644 index 00000000..3a9c8bda --- /dev/null +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdio-graph-criteria/snapshots/single-node chains inherit even with multi-node sibling graph.snap @@ -0,0 +1,47 @@ +--- +source: crates/vite_task_bin/tests/e2e_snapshots/main.rs +expression: e2e_outputs +--- +> vp run foo +$ check-tty ⊘ cache disabled: no cache config +stdin:tty +stdout:tty +stderr:tty + +$ check-tty ⊘ cache disabled: no cache config +stdin:tty +stdout:tty +stderr:tty + +~/packages/other$ check-tty ⊘ cache disabled: no cache config +stdin:not-tty +stdout:not-tty +stderr:not-tty + +$ check-tty ⊘ cache disabled: no cache config +stdin:not-tty +stdout:not-tty +stderr:not-tty + + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + Vite+ Task Runner • Execution Summary +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +Statistics: 4 tasks • 0 cache hits • 0 cache misses • 4 cache disabled +Performance: 0% cache hit rate + +Task Details: +──────────────────────────────────────────────── + [1] stdio-graph-criteria-test#foo: $ check-tty ✓ + → Cache disabled in task configuration + ······················································· + [2] stdio-graph-criteria-test#bar: $ check-tty ✓ + → Cache disabled in task configuration + ······················································· + [3] other#check-tty: ~/packages/other$ check-tty ✓ + → Cache disabled in task configuration + ······················································· + [4] stdio-graph-criteria-test#check-tty: $ check-tty ✓ + → Cache disabled in task configuration +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdio-graph-criteria/vite-task.json b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdio-graph-criteria/vite-task.json new file mode 100644 index 00000000..abcca7dd --- /dev/null +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdio-graph-criteria/vite-task.json @@ -0,0 +1,21 @@ +{ + "cacheScripts": true, + "tasks": { + "check-tty": { + "command": "check-tty", + "cache": false + }, + "bar": { + "command": "check-tty", + "cache": false + }, + "foo": { + "command": "check-tty && vp run bar && vp run -r check-tty", + "cache": false + }, + "foo-nested": { + "command": "vp run bar", + "cache": false + } + } +}