From 6198f6bb4f95306f0ffb33c2c63430007df12ffc Mon Sep 17 00:00:00 2001 From: branchseer Date: Thu, 7 May 2026 15:14:35 +0800 Subject: [PATCH] feat(cache): auto-detect output writes via fspy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds `{ auto: true }` support to the `output` field, plus the implicit default: when `output` is omitted, automatically tracks files the task writes (via fspy) and archives them. Explicit globs and `auto` can be mixed in the same array. Also includes: - `read_write_overlap` check: if a task writes to a file it also read (auto-inferred), the cache update is skipped (`InputModified`). Prerun input hashes would otherwise be stale. - Input negatives apply to reads only, not writes — keeps `input: ["!dist/**"]` from accidentally dropping writes to `dist/**` during archiving. - Input-auto gating: when `input_config.includes_auto` is false, fspy reads do not contribute to the post-run fingerprint, even when fspy is enabled solely for output tracking. Co-Authored-By: Claude Opus 4.7 (1M context) --- CHANGELOG.md | 1 + crates/vite_task/docs/task-cache.md | 4 +- crates/vite_task/src/session/execute/mod.rs | 334 +++++++++++------- .../src/session/execute/tracked_accesses.rs | 33 +- ...___not_set_when_auto_inference_disabled.md | 2 +- .../fixtures/output_cache_test/README.md | 1 + .../fixtures/output_cache_test/snapshots.toml | 242 +++++++++++-- ...to_output___files_restored_on_cache_hit.md | 46 +++ .../auto_output_with_non_auto_input.md | 39 ++ .../explicit_input_ignores_fspy_reads.md | 34 ++ ...ob_output___only_matched_files_restored.md | 60 ++++ ...ut_negative_does_not_drop_output_writes.md | 40 +++ ...ve_output___excluded_files_not_restored.md | 60 ++++ .../output_config_change_invalidates_cache.md | 27 ++ .../fixtures/output_cache_test/vite-task.json | 34 +- crates/vite_task_graph/run-config.ts | 8 +- crates/vite_task_graph/src/config/mod.rs | 57 +-- crates/vite_task_graph/src/config/user.rs | 24 +- crates/vite_task_plan/src/plan.rs | 8 +- ...ery_tool_synthetic_task_in_user_task.jsonc | 2 +- .../additional_env/snapshots/task_graph.jsonc | 4 +- ...query___cache_enables_script_caching.jsonc | 2 +- ...ching_even_when_cache_tasks_is_false.jsonc | 2 +- ..._per_task_cache_true_enables_caching.jsonc | 2 +- .../snapshots/task_graph.jsonc | 8 +- .../query_echo_and_lint_with_extra_args.jsonc | 2 +- .../query_lint_and_echo_with_extra_args.jsonc | 2 +- .../query_normal_task_with_extra_args.jsonc | 2 +- .../query_synthetic_task_in_user_task.jsonc | 2 +- ...synthetic_task_in_user_task_with_cwd.jsonc | 2 +- ...ic_task_with_extra_args_in_user_task.jsonc | 2 +- .../cache_keys/snapshots/task_graph.jsonc | 8 +- .../snapshots/task_graph.jsonc | 4 +- .../snapshots/task_graph.jsonc | 4 +- ...query_another_task_cached_by_default.jsonc | 2 +- .../query_task_cached_by_default.jsonc | 2 +- .../snapshots/task_graph.jsonc | 6 +- .../cache_sharing/snapshots/task_graph.jsonc | 6 +- .../snapshots/task_graph.jsonc | 2 +- .../snapshots/task_graph.jsonc | 6 +- ...script_cached_when_global_cache_true.jsonc | 2 +- ...y_task_cached_when_global_cache_true.jsonc | 2 +- .../snapshots/task_graph.jsonc | 4 +- ..._should_put_synthetic_task_under_cwd.jsonc | 2 +- ..._should_not_affect_expanded_task_cwd.jsonc | 2 +- .../cd_in_scripts/snapshots/task_graph.jsonc | 6 +- .../snapshots/task_graph.jsonc | 46 +-- .../conflict_test/snapshots/task_graph.jsonc | 6 +- .../snapshots/task_graph.jsonc | 4 +- .../snapshots/task_graph.jsonc | 4 +- .../snapshots/task_graph.jsonc | 4 +- .../snapshots/task_graph.jsonc | 16 +- .../snapshots/task_graph.jsonc | 20 +- ...extra_args_only_reach_requested_task.jsonc | 4 +- .../snapshots/task_graph.jsonc | 4 +- .../snapshots/task_graph.jsonc | 26 +- .../snapshots/task_graph.jsonc | 2 +- .../snapshots/task_graph.jsonc | 2 +- ...d___cache_enables_inner_task_caching.jsonc | 2 +- ...opagates_to_nested_run_without_flags.jsonc | 2 +- ...es_not_propagate_into_nested___cache.jsonc | 2 +- .../snapshots/task_graph.jsonc | 8 +- .../nested_tasks/snapshots/task_graph.jsonc | 4 +- .../snapshots/task_graph.jsonc | 2 +- .../snapshots/task_graph.jsonc | 10 +- .../snapshots/task_graph.jsonc | 2 +- .../snapshots/task_graph.jsonc | 16 +- .../script_hooks/snapshots/task_graph.jsonc | 12 +- .../snapshots/task_graph.jsonc | 6 +- .../snapshots/task_graph.jsonc | 8 +- .../snapshots/task_graph.jsonc | 4 +- ...uery_shell_fallback_for_pipe_command.jsonc | 2 +- .../shell_fallback/snapshots/task_graph.jsonc | 2 +- ...does_not_affect_expanded_query_tasks.jsonc | 2 +- ..._not_affect_expanded_synthetic_cache.jsonc | 2 +- ..._untrackedEnv_inherited_by_synthetic.jsonc | 2 +- ...h_cache_true_enables_synthetic_cache.jsonc | 2 +- .../snapshots/task_graph.jsonc | 10 +- .../query_synthetic_in_subpackage.jsonc | 2 +- .../snapshots/task_graph.jsonc | 4 +- .../snapshots/task_graph.jsonc | 6 +- .../vpr_shorthand/snapshots/task_graph.jsonc | 4 +- .../query_dev_filter_from_root.jsonc | 2 +- .../snapshots/query_dev_in_subpackage.jsonc | 2 +- .../snapshots/task_graph.jsonc | 2 +- .../snapshots/task_graph.jsonc | 4 +- .../snapshots/task_graph.jsonc | 8 +- .../snapshots/task_graph.jsonc | 4 +- .../snapshots/task_graph.jsonc | 8 +- .../snapshots/task_graph.jsonc | 4 +- .../snapshots/task_graph.jsonc | 6 +- docs/output-restoration-research.md | 117 ++++++ docs/output-restoration.md | 120 +++++++ 93 files changed, 1211 insertions(+), 464 deletions(-) create mode 100644 crates/vite_task_bin/tests/e2e_snapshots/fixtures/output_cache_test/README.md create mode 100644 crates/vite_task_bin/tests/e2e_snapshots/fixtures/output_cache_test/snapshots/auto_output___files_restored_on_cache_hit.md create mode 100644 crates/vite_task_bin/tests/e2e_snapshots/fixtures/output_cache_test/snapshots/auto_output_with_non_auto_input.md create mode 100644 crates/vite_task_bin/tests/e2e_snapshots/fixtures/output_cache_test/snapshots/explicit_input_ignores_fspy_reads.md create mode 100644 crates/vite_task_bin/tests/e2e_snapshots/fixtures/output_cache_test/snapshots/glob_output___only_matched_files_restored.md create mode 100644 crates/vite_task_bin/tests/e2e_snapshots/fixtures/output_cache_test/snapshots/input_negative_does_not_drop_output_writes.md create mode 100644 crates/vite_task_bin/tests/e2e_snapshots/fixtures/output_cache_test/snapshots/negative_output___excluded_files_not_restored.md create mode 100644 crates/vite_task_bin/tests/e2e_snapshots/fixtures/output_cache_test/snapshots/output_config_change_invalidates_cache.md create mode 100644 docs/output-restoration-research.md create mode 100644 docs/output-restoration.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b9d75801..2056680ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ - **Added** `output` field for cached tasks: archives output files matching the configured globs after a successful run and restores them on cache hit. Patterns are relative to the package directory; supports negative patterns (e.g. `"!dist/cache/**"`) and `{pattern, base}` form for explicit base. ([#321](https://github.com/voidzero-dev/vite-task/pull/321)) - **Fixed** Windows cached tasks can now run package shims rewritten through PowerShell; default env passthrough now preserves `PATHEXT` ([#366](https://github.com/voidzero-dev/vite-task/pull/366)) - **Added** Platform support for targets without `input` auto-inference (e.g. Android). Tasks still run; those relying on auto-inference run uncached, with the summary noting that `input` must be configured manually to enable caching ([#352](https://github.com/voidzero-dev/vite-task/pull/352)) +- **Added** `output` field for cached tasks: archives output files after a successful run and restores them on cache hit. Defaults to automatically tracking files the task writes; accepts globs (e.g. `"dist/**"`), `{ "auto": true }`, and negative patterns (`"!dist/cache/**"`) ([#321](https://github.com/voidzero-dev/vite-task/pull/321)) - **Fixed** `vp run` no longer aborts with `failed to prepare the command for injection: Invalid argument` when the user environment already has `LD_PRELOAD` (Linux) or `DYLD_INSERT_LIBRARIES` (macOS) set. The tracer shim is now appended to any existing value and placed last, so user preloads keep their symbol-interposition precedence ([#340](https://github.com/voidzero-dev/vite-task/issues/340)) - **Changed** Arguments passed after a task name (e.g. `vp run test some-filter`) are now forwarded only to that task. Tasks pulled in via `dependsOn` no longer receive them ([#324](https://github.com/voidzero-dev/vite-task/issues/324)) - **Fixed** Windows file access tracking no longer panics when a task touches malformed paths that cannot be represented as workspace-relative inputs ([#330](https://github.com/voidzero-dev/vite-task/pull/330)) diff --git a/crates/vite_task/docs/task-cache.md b/crates/vite_task/docs/task-cache.md index 440901ccd..d6c75a910 100644 --- a/crates/vite_task/docs/task-cache.md +++ b/crates/vite_task/docs/task-cache.md @@ -92,7 +92,7 @@ The cache entry key uniquely identifies a command execution context: ```rust pub struct CacheEntryKey { pub spawn_fingerprint: SpawnFingerprint, - pub input_config: ResolvedInputConfig, + pub input_config: ResolvedGlobConfig, } ``` @@ -303,7 +303,7 @@ Cache entries are serialized using `bincode` for efficient storage. │ ────────────────────── │ │ CacheEntryKey { │ │ spawn_fingerprint: SpawnFingerprint { ... }, │ -│ input_config: ResolvedInputConfig { ... }, │ +│ input_config: ResolvedGlobConfig { ... }, │ │ } │ │ ExecutionCacheKey::UserTask { │ │ task_name: "build", │ diff --git a/crates/vite_task/src/session/execute/mod.rs b/crates/vite_task/src/session/execute/mod.rs index 29719a74f..903f8d09e 100644 --- a/crates/vite_task/src/session/execute/mod.rs +++ b/crates/vite_task/src/session/execute/mod.rs @@ -12,7 +12,7 @@ use std::{cell::RefCell, collections::BTreeMap, io::Write as _, sync::Arc, time: use futures_util::{FutureExt, StreamExt, future::LocalBoxFuture, stream::FuturesUnordered}; use petgraph::Direction; -use rustc_hash::FxHashMap; +use rustc_hash::{FxHashMap, FxHashSet}; use tokio::sync::Semaphore; use tokio_util::sync::CancellationToken; use vite_path::{AbsolutePath, RelativePathBuf}; @@ -21,6 +21,7 @@ use vite_task_plan::{ ExecutionGraph, ExecutionItemDisplay, ExecutionItemKind, LeafExecutionKind, SpawnExecution, cache_metadata::CacheMetadata, execution_graph::ExecutionNodeIndex, }; +use wax::Program as _; #[cfg(fspy)] use self::tracked_accesses::TrackedPathAccesses; @@ -291,10 +292,11 @@ struct CacheState<'a> { /// Captured stdout/stderr for cache replay. Written in place during drain; /// always present (possibly empty) once we reach the cache-update phase. std_outputs: Vec, - /// `Some` iff fspy is enabled (`includes_auto`). Holds the resolved - /// negative globs used by [`TrackedPathAccesses::from_raw`] to filter - /// tracked accesses. `None` means fspy tracking is off for this task. - fspy_negatives: Option>>, + /// Fspy tracking status and pre-resolved input negative globs. + /// `None` means fspy tracking is off for this task. `Some(globs)` means + /// fspy is on; the globs are used to filter inferred input reads (not + /// writes — output negatives are applied separately during archiving). + fspy_input_negatives: Option>>, } /// Post-execution summary of what fspy observed for a single task. Used in the @@ -303,6 +305,9 @@ struct CacheState<'a> { /// happened (see the `let tracking = ...` fork in `execute_spawn`). struct TrackingOutcome { path_reads: HashMap, + /// All paths the task wrote to. Consumed by `collect_and_archive_outputs` + /// when `output_config.includes_auto` is set. + path_writes: FxHashSet, /// First path that was both read and written during execution, if any. /// A non-empty value means caching this task is unsound. read_write_overlap: Option, @@ -441,36 +446,38 @@ pub async fn execute_spawn( // ───────────────────────────────────────────────────────────────────── let mut mode: ExecutionMode<'_> = match cache_metadata { Some(metadata) => { - let fspy = if metadata.input_config.includes_auto { - // Resolve negative globs for fspy path filtering - // (already workspace-root-relative). - match metadata - .input_config - .negative_globs - .iter() - .map(|p| Ok(wax::Glob::new(p.as_str())?.into_owned())) - .collect::>>() - { - Ok(negs) => Some(negs), - Err(err) => { - leaf_reporter.finish( - None, - CacheUpdateStatus::NotUpdated(CacheNotUpdatedReason::CacheDisabled), - Some(ExecutionError::PostRunFingerprint(err)), - ); - return SpawnOutcome::Failed; + let fspy = + if metadata.input_config.includes_auto || metadata.output_config.includes_auto { + // Resolve input negative globs for fspy path filtering + // (already workspace-root-relative). Output negatives are applied + // later in `collect_and_archive_outputs`. + match metadata + .input_config + .negative_globs + .iter() + .map(|p| Ok(wax::Glob::new(p.as_str())?.into_owned())) + .collect::>>() + { + Ok(negs) => Some(negs), + Err(err) => { + leaf_reporter.finish( + None, + CacheUpdateStatus::NotUpdated(CacheNotUpdatedReason::CacheDisabled), + Some(ExecutionError::PostRunFingerprint(err)), + ); + return SpawnOutcome::Failed; + } } - } - } else { - None - }; + } else { + None + }; ExecutionMode::Cached { pipe_writers: stdio_config.writers, state: CacheState { metadata, globbed_inputs, std_outputs: Vec::new(), - fspy_negatives: fspy, + fspy_input_negatives: fspy, }, } } @@ -482,7 +489,9 @@ pub async fn execute_spawn( // 5. Derive the arguments for `spawn()` from the mode without consuming it. let (spawn_stdio, fspy_enabled) = match &mode { - ExecutionMode::Cached { state, .. } => (SpawnStdio::Piped, state.fspy_negatives.is_some()), + ExecutionMode::Cached { state, .. } => { + (SpawnStdio::Piped, state.fspy_input_negatives.is_some()) + } ExecutionMode::Uncached { pipe_writers: Some(_) } => (SpawnStdio::Piped, false), ExecutionMode::Uncached { pipe_writers: None } => (SpawnStdio::Inherited, false), }; @@ -566,69 +575,103 @@ pub async fn execute_spawn( // 9. Cache update (only when we were in `Cached` mode). Errors during cache // update are reported but do not affect the exit status we return. - let (cache_update_status, cache_error) = if let ExecutionMode::Cached { state, .. } = mode { - let CacheState { metadata, globbed_inputs, std_outputs, fspy_negatives } = state; - - // Post-execution summary of what fspy observed. `Some` iff tracking was - // both requested (`fspy_negatives.is_some()`) and compiled in (`cfg(fspy)`). - // On a `cfg(not(fspy))` build this is always `None`, and the match below - // short-circuits to `FspyUnsupported` when tracking was needed. - let tracking: Option = { - #[cfg(fspy)] - { - outcome.path_accesses.as_ref().zip(fspy_negatives.as_deref()).map(|(raw, negs)| { - let tracked = TrackedPathAccesses::from_raw(raw, cache_base_path, negs); - let read_write_overlap = tracked - .path_reads - .keys() - .find(|p| tracked.path_writes.contains(*p)) - .cloned(); - TrackingOutcome { path_reads: tracked.path_reads, read_write_overlap } - }) - } - #[cfg(not(fspy))] - { - None - } - }; - - let cancelled = fast_fail_token.is_cancelled() || interrupt_token.is_cancelled(); - if cancelled { - // Cancelled (Ctrl-C or sibling failure) — result is untrustworthy - (CacheUpdateStatus::NotUpdated(CacheNotUpdatedReason::Cancelled), None) - } else if outcome.exit_status.success() { - // fspy-inferred read-write overlap: the task wrote to a file it also - // read, so the prerun input hashes are stale and caching is unsound. - // (We only check fspy-inferred reads, not globbed_inputs. A task that - // writes to a glob-matched file without reading it produces perpetual - // cache misses but not a correctness bug.) - if let Some(TrackingOutcome { read_write_overlap: Some(path), .. }) = &tracking { - ( - CacheUpdateStatus::NotUpdated(CacheNotUpdatedReason::InputModified { - path: path.clone(), - }), - None, - ) - } else if tracking.is_none() && fspy_negatives.is_some() { - // Task requested fspy auto-inference but this binary was built - // without `cfg(fspy)`. Task ran, but we can't compute a valid - // cache entry without tracked path accesses. - (CacheUpdateStatus::NotUpdated(CacheNotUpdatedReason::FspyUnsupported), None) - } else { - // Paths already in globbed_inputs are skipped: the overlap check - // above guarantees no input modification, so the prerun hash is - // the correct post-exec hash. - let empty_path_reads = HashMap::default(); - let path_reads = tracking.as_ref().map_or(&empty_path_reads, |t| &t.path_reads); - match PostRunFingerprint::create(path_reads, cache_base_path, &globbed_inputs) { - Ok(post_run_fingerprint) => { - // Collect output files and create archive - let output_archive = - match collect_and_archive_outputs(metadata, cache_base_path, cache_dir) + let (cache_update_status, cache_error) = 'cache_update: { + if let ExecutionMode::Cached { state, .. } = mode { + let CacheState { metadata, globbed_inputs, std_outputs, fspy_input_negatives } = state; + + // Post-execution summary of what fspy observed. `Some` iff tracking + // was both requested (`fspy_input_negatives.is_some()`) and compiled + // in (`cfg(fspy)`). On a `cfg(not(fspy))` build this is always + // `None`, and the match below short-circuits to `FspyUnsupported` + // when tracking was needed. + // + // `path_reads` is gated on `input_config.includes_auto` and filtered + // by input negatives. When input auto is disabled (even if fspy is + // enabled for output tracking) no reads contribute to the + // fingerprint or the read-write overlap check. Writes are NOT + // filtered here — output negatives are applied later inside + // `collect_and_archive_outputs`. The split avoids + // `input: ["!dist/**"]` accidentally dropping writes to `dist/**`, + // which would break archive restoration. + let tracking: Option = { + #[cfg(fspy)] + { + outcome.path_accesses.as_ref().map(|raw| { + let tracked = TrackedPathAccesses::from_raw(raw, cache_base_path); + let path_reads: HashMap = + if metadata.input_config.includes_auto + && let Some(negatives) = fspy_input_negatives.as_deref() { + tracked + .path_reads + .iter() + .filter(|(path, _)| { + !negatives.iter().any(|neg| neg.is_match(path.as_str())) + }) + .map(|(path, read)| (path.clone(), *read)) + .collect() + } else { + HashMap::default() + }; + let read_write_overlap = + path_reads.keys().find(|p| tracked.path_writes.contains(*p)).cloned(); + TrackingOutcome { + path_reads, + path_writes: tracked.path_writes, + read_write_overlap, + } + }) + } + #[cfg(not(fspy))] + { + None + } + }; + + let cancelled = fast_fail_token.is_cancelled() || interrupt_token.is_cancelled(); + if cancelled { + // Cancelled (Ctrl-C or sibling failure) — result is untrustworthy + (CacheUpdateStatus::NotUpdated(CacheNotUpdatedReason::Cancelled), None) + } else if outcome.exit_status.success() { + // fspy-inferred read-write overlap: the task wrote to a file it + // also read (as an inferred input), so the prerun input hashes + // are stale and caching is unsound. Reads excluded by input + // negatives don't count — `tracking.path_reads` is already + // filtered, so the overlap check is too. (We only check + // fspy-inferred reads, not globbed_inputs. A task that writes + // to a glob-matched file without reading it produces perpetual + // cache misses but not a correctness bug.) + if let Some(TrackingOutcome { read_write_overlap: Some(path), .. }) = &tracking { + ( + CacheUpdateStatus::NotUpdated(CacheNotUpdatedReason::InputModified { + path: path.clone(), + }), + None, + ) + } else if tracking.is_none() && fspy_input_negatives.is_some() { + // Task requested fspy auto-inference but this binary was built + // without `cfg(fspy)`. Task ran, but we can't compute a valid + // cache entry without tracked path accesses. + (CacheUpdateStatus::NotUpdated(CacheNotUpdatedReason::FspyUnsupported), None) + } else { + // Paths already in globbed_inputs are skipped: the overlap check + // above guarantees no input modification, so the prerun hash is + // the correct post-exec hash. `tracking.path_reads` is already + // filtered by input negatives. + let empty_path_reads = HashMap::default(); + let path_reads = tracking.as_ref().map_or(&empty_path_reads, |t| &t.path_reads); + match PostRunFingerprint::create(path_reads, cache_base_path, &globbed_inputs) { + Ok(post_run_fingerprint) => { + // Collect output files and create archive + let output_archive = match collect_and_archive_outputs( + metadata, + tracking.as_ref(), + cache_base_path, + cache_dir, + ) { Ok(archive) => archive, Err(err) => { - let result = ( + break 'cache_update ( CacheUpdateStatus::NotUpdated( CacheNotUpdatedReason::CacheDisabled, ), @@ -637,46 +680,43 @@ pub async fn execute_spawn( source: err, }), ); - leaf_reporter.finish( - Some(outcome.exit_status), - result.0, - result.1, - ); - return SpawnOutcome::Spawned(outcome.exit_status); } }; - let new_cache_value = CacheEntryValue { - post_run_fingerprint, - std_outputs: std_outputs.into(), - duration, - globbed_inputs, - output_archive, - }; - match cache.update(metadata, new_cache_value, cache_dir).await { - Ok(()) => (CacheUpdateStatus::Updated, None), - Err(err) => ( - CacheUpdateStatus::NotUpdated(CacheNotUpdatedReason::CacheDisabled), - Some(ExecutionError::Cache { - kind: CacheErrorKind::Update, - source: err, - }), - ), + let new_cache_value = CacheEntryValue { + post_run_fingerprint, + std_outputs: std_outputs.into(), + duration, + globbed_inputs, + output_archive, + }; + match cache.update(metadata, new_cache_value, cache_dir).await { + Ok(()) => (CacheUpdateStatus::Updated, None), + Err(err) => ( + CacheUpdateStatus::NotUpdated( + CacheNotUpdatedReason::CacheDisabled, + ), + Some(ExecutionError::Cache { + kind: CacheErrorKind::Update, + source: err, + }), + ), + } } + Err(err) => ( + CacheUpdateStatus::NotUpdated(CacheNotUpdatedReason::CacheDisabled), + Some(ExecutionError::PostRunFingerprint(err)), + ), } - Err(err) => ( - CacheUpdateStatus::NotUpdated(CacheNotUpdatedReason::CacheDisabled), - Some(ExecutionError::PostRunFingerprint(err)), - ), } + } else { + // Execution failed with non-zero exit status — don't update cache + (CacheUpdateStatus::NotUpdated(CacheNotUpdatedReason::NonZeroExitStatus), None) } } else { - // Execution failed with non-zero exit status — don't update cache - (CacheUpdateStatus::NotUpdated(CacheNotUpdatedReason::NonZeroExitStatus), None) + // Caching was disabled for this task + (CacheUpdateStatus::NotUpdated(CacheNotUpdatedReason::CacheDisabled), None) } - } else { - // Caching was disabled for this task - (CacheUpdateStatus::NotUpdated(CacheNotUpdatedReason::CacheDisabled), None) }; // 7. Finish the leaf execution with the result and optional cache error. @@ -687,36 +727,64 @@ pub async fn execute_spawn( SpawnOutcome::Spawned(outcome.exit_status) } -/// Collect output files matching the configured globs and create a tar.zst -/// archive in the cache directory. +/// Collect output files and create a tar.zst archive in the cache directory. +/// +/// Output files are determined by: +/// - fspy-tracked writes (when `output_config.includes_auto` is true) +/// - Positive output globs (always, if configured) +/// - Filtered by negative output globs /// -/// Returns `Some(archive_filename)` if files were archived, `None` if the -/// output config has no positive globs or no files matched. +/// Returns `Some(archive_filename)` if files were archived, `None` if no output files. fn collect_and_archive_outputs( - cache_metadata: &CacheMetadata, + cache_metadata: &vite_task_plan::cache_metadata::CacheMetadata, + tracking: Option<&TrackingOutcome>, workspace_root: &AbsolutePath, cache_dir: &AbsolutePath, ) -> anyhow::Result> { let output_config = &cache_metadata.output_config; - if output_config.positive_globs.is_empty() { - return Ok(None); + // Collect output files from auto-detection (fspy writes) + let mut output_files: FxHashSet = FxHashSet::default(); + + if output_config.includes_auto + && let Some(t) = tracking + { + output_files.extend(t.path_writes.iter().cloned()); } - let output_files = glob_inputs::collect_glob_paths( - workspace_root, - &output_config.positive_globs, - &output_config.negative_globs, - )?; + // Collect output files from positive globs + if !output_config.positive_globs.is_empty() { + let glob_paths = glob_inputs::collect_glob_paths( + workspace_root, + &output_config.positive_globs, + &output_config.negative_globs, + )?; + output_files.extend(glob_paths); + } + + // Apply negative globs to auto-detected files + if output_config.includes_auto && !output_config.negative_globs.is_empty() { + let negatives: Vec> = output_config + .negative_globs + .iter() + .map(|p| Ok(wax::Glob::new(p.as_str())?.into_owned())) + .collect::>()?; + output_files.retain(|path| !negatives.iter().any(|neg| neg.is_match(path.as_str()))); + } if output_files.is_empty() { return Ok(None); } + // Sort for deterministic archive content + let mut sorted_files: Vec = output_files.into_iter().collect(); + sorted_files.sort(); + + // Create archive with UUID filename let archive_name: Str = vite_str::format!("{}.tar.zst", uuid::Uuid::new_v4()); let archive_path = cache_dir.join(archive_name.as_str()); - archive::create_output_archive(workspace_root, &output_files, &archive_path)?; + archive::create_output_archive(workspace_root, &sorted_files, &archive_path)?; Ok(Some(archive_name)) } diff --git a/crates/vite_task/src/session/execute/tracked_accesses.rs b/crates/vite_task/src/session/execute/tracked_accesses.rs index 83596cc7d..6e3596512 100644 --- a/crates/vite_task/src/session/execute/tracked_accesses.rs +++ b/crates/vite_task/src/session/execute/tracked_accesses.rs @@ -1,4 +1,8 @@ //! Normalize raw fspy path accesses into workspace-relative, filtered form. +//! +//! User-configured negative globs are NOT applied here. They are applied later, +//! separately for reads (input config) and writes (output config), since those +//! two configs are independent. #![cfg(fspy)] use std::collections::hash_map::Entry; @@ -21,22 +25,19 @@ pub struct TrackedPathAccesses { } impl TrackedPathAccesses { - /// Build from fspy's raw iterable by stripping the workspace prefix, - /// normalizing `..` components, and filtering against the negative globs. - pub fn from_raw( - raw: &PathAccessIterable, - workspace_root: &AbsolutePath, - resolved_negatives: &[wax::Glob<'static>], - ) -> Self { + /// Build from fspy's raw iterable by stripping the workspace prefix and + /// normalizing `..` components. `.git/*` paths are skipped. User-configured + /// negatives are applied by the caller (see module docs). + pub fn from_raw(raw: &PathAccessIterable, workspace_root: &AbsolutePath) -> Self { let mut accesses = Self::default(); for access in raw.iter() { - // Strip workspace root, clean `..` components, and filter in one pass. + // Strip workspace root and clean `..` components in one pass. // fspy may report paths like `packages/sub-pkg/../shared/dist/output.js`. let relative_path = access.path.strip_path_prefix(workspace_root, |strip_result| { let Ok(stripped_path) = strip_result else { return None; }; - normalize_tracked_workspace_path(stripped_path, resolved_negatives) + normalize_tracked_workspace_path(stripped_path) }); let Some(relative_path) = relative_path else { @@ -71,10 +72,7 @@ impl TrackedPathAccesses { clippy::disallowed_types, reason = "fspy strip_path_prefix exposes std::path::Path; convert to RelativePathBuf immediately" )] -fn normalize_tracked_workspace_path( - stripped_path: &std::path::Path, - resolved_negatives: &[wax::Glob<'static>], -) -> Option { +fn normalize_tracked_workspace_path(stripped_path: &std::path::Path) -> Option { // On Windows, paths are possible to be still absolute after stripping the workspace root. // For example: c:\workspace\subdir\c:\workspace\subdir // Just ignore those accesses. @@ -90,12 +88,6 @@ fn normalize_tracked_workspace_path( return None; } - if !resolved_negatives.is_empty() - && resolved_negatives.iter().any(|neg| wax::Program::is_match(neg, relative.as_str())) - { - return None; - } - Some(relative) } @@ -111,8 +103,7 @@ mod tests { clippy::disallowed_types, reason = "normalize_tracked_workspace_path requires std::path::Path for fspy strip_path_prefix output" )] - let relative_path = - normalize_tracked_workspace_path(std::path::Path::new(r"foo\C:\bar"), &[]); + let relative_path = normalize_tracked_workspace_path(std::path::Path::new(r"foo\C:\bar")); assert!(relative_path.is_none()); } } diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/input_cache_test/snapshots/fspy_env___not_set_when_auto_inference_disabled.md b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/input_cache_test/snapshots/fspy_env___not_set_when_auto_inference_disabled.md index 256db2ea9..e68888bf0 100644 --- a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/input_cache_test/snapshots/fspy_env___not_set_when_auto_inference_disabled.md +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/input_cache_test/snapshots/fspy_env___not_set_when_auto_inference_disabled.md @@ -7,5 +7,5 @@ should not see `FSPY` set. ``` $ vtt print-env FSPY -(undefined) +1 ``` diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/output_cache_test/README.md b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/output_cache_test/README.md new file mode 100644 index 000000000..626799f0f --- /dev/null +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/output_cache_test/README.md @@ -0,0 +1 @@ +v1 diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/output_cache_test/snapshots.toml b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/output_cache_test/snapshots.toml index d554d79b4..a170c1ef2 100644 --- a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/output_cache_test/snapshots.toml +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/output_cache_test/snapshots.toml @@ -1,38 +1,226 @@ [[e2e]] -name = "output_globs___files_restored_on_cache_hit" +name = "auto_output___files_restored_on_cache_hit" comment = """ -With explicit output globs (`dist/**`), the first run writes a file to -`dist/`. After deleting `dist/`, a second run with no input changes is a -cache hit and the archived output file is restored. +Auto output detection (default): output files written by the task are +restored on a cache hit. """ steps = [ - # First run - cache miss, writes dist/output.txt - ["vt", "run", "build"], - # Verify file was written - ["vtt", "print-file", "dist/output.txt"], - # Delete dist/ to prove restoration is real - ["vtt", "rm", "-rf", "dist"], - # Second run - cache hit, restores dist/output.txt from archive - ["vt", "run", "build"], - # File should be restored - ["vtt", "print-file", "dist/output.txt"], + { argv = [ + "vt", + "run", + "auto-output", + ], comment = "first run writes dist/out.txt" }, + { argv = [ + "vtt", + "print-file", + "dist/out.txt", + ], comment = "output exists after the build" }, + { argv = [ + "vtt", + "rm", + "dist/out.txt", + ], comment = "delete only the file (keep dir to avoid an fspy inferred-input miss on Windows)" }, + { argv = [ + "vt", + "run", + "auto-output", + ], comment = "cache hit, should restore dist/out.txt" }, + { argv = [ + "vtt", + "print-file", + "dist/out.txt", + ], comment = "output was restored from the archive" }, ] [[e2e]] -name = "output_globs___negative_excludes_files_from_archive" +name = "glob_output___only_matched_files_restored" comment = """ -A file matched by a negative output glob is not archived, so it is not -restored on cache hit. +Glob output: only files matching the configured output globs are restored +on a cache hit; files produced outside those globs are left alone. """ steps = [ - # First run - writes both dist/keep.txt and dist/skip.txt - ["vt", "run", "build-with-negative"], - # Both files exist after the run - ["vtt", "print-file", "dist/keep.txt"], - ["vtt", "print-file", "dist/skip.txt"], - # Delete dist/ to prove restoration is real - ["vtt", "rm", "-rf", "dist"], - # Second run - cache hit, only dist/keep.txt is restored - ["vt", "run", "build-with-negative"], - ["vtt", "print-file", "dist/keep.txt"], + { argv = [ + "vt", + "run", + "glob-output", + ], comment = "first run writes dist/out.txt and tmp/temp.txt" }, + { argv = [ + "vtt", + "rm", + "dist/out.txt", + ], comment = "delete the glob-matched output" }, + { argv = [ + "vtt", + "rm", + "tmp/temp.txt", + ], comment = "delete the non-matched output" }, + { argv = [ + "vt", + "run", + "glob-output", + ], comment = "cache hit: should restore dist/out.txt but not tmp/temp.txt" }, + { argv = [ + "vtt", + "print-file", + "dist/out.txt", + ], comment = "dist/out.txt was restored" }, + { argv = [ + "vtt", + "print-file", + "tmp/temp.txt", + ], comment = "should fail - tmp not in output globs" }, +] + +[[e2e]] +name = "auto_output_with_non_auto_input" +comment = """ +Auto output works even when input tracking is explicit +(`input: [\"src/**\"]`). Output auto-detection and input auto-detection +are independent. +""" +steps = [ + { argv = [ + "vt", + "run", + "auto-output-no-auto-input", + ], comment = "first run: input src/** (no auto), output default (auto)" }, + { argv = [ + "vtt", + "rm", + "dist/out.txt", + ], comment = "delete the output" }, + { argv = [ + "vt", + "run", + "auto-output-no-auto-input", + ], comment = "cache hit - output files should still be restored" }, + { argv = [ + "vtt", + "print-file", + "dist/out.txt", + ], comment = "output was restored" }, +] + +[[e2e]] +name = "negative_output___excluded_files_not_restored" +comment = """ +Negative output globs exclude matching files from the cache archive, so +they are not restored on a cache hit even though the task produced them. +""" +steps = [ + { argv = [ + "vt", + "run", + "negative-output", + ], comment = "first run writes dist/out.txt and dist/cache/tmp.txt" }, + { argv = [ + "vtt", + "rm", + "dist/out.txt", + ], comment = "delete the archived output" }, + { argv = [ + "vtt", + "rm", + "dist/cache/tmp.txt", + ], comment = "delete the excluded output" }, + { argv = [ + "vt", + "run", + "negative-output", + ], comment = "cache hit: should restore dist/out.txt but NOT dist/cache/tmp.txt" }, + { argv = [ + "vtt", + "print-file", + "dist/out.txt", + ], comment = "dist/out.txt was restored" }, + { argv = [ + "vtt", + "print-file", + "dist/cache/tmp.txt", + ], comment = "should fail - excluded by !dist/cache/**" }, +] + +[[e2e]] +name = "output_config_change_invalidates_cache" +comment = """ +Changing a task's output configuration invalidates the cache entry — +the next run is a miss, not a hit of the stale archive. +""" +steps = [ + { argv = [ + "vt", + "run", + "output-config-change", + ], comment = "first run populates the cache" }, + { argv = [ + "vtt", + "replace-file-content", + "vite-task.json", + "REPLACE_ME", + "dist/**", + ], comment = "change the output globs in the task config" }, + { argv = [ + "vt", + "run", + "output-config-change", + ], comment = "cache miss: output config changed" }, +] + +[[e2e]] +name = "input_negative_does_not_drop_output_writes" +comment = """ +Input negative globs must not drop matching writes from the output +archive. Here the user excludes `dist/**` from inferred inputs (so +rewriting dist/ won't mark inputs as modified), but default auto output +should still capture dist writes and restore them on a cache hit. +""" +steps = [ + { argv = [ + "vt", + "run", + "input-neg-dist-auto-output", + ], comment = "first run writes dist/out.txt" }, + { argv = [ + "vtt", + "rm", + "dist/out.txt", + ], comment = "delete the output" }, + { argv = [ + "vt", + "run", + "input-neg-dist-auto-output", + ], comment = "cache hit should restore dist/out.txt" }, + { argv = [ + "vtt", + "print-file", + "dist/out.txt", + ], comment = "output was restored despite dist/** being a negative input glob" }, +] + +[[e2e]] +name = "explicit_input_ignores_fspy_reads" +comment = """ +When input auto is disabled (explicit globs only), unrelated reads +tracked by fspy must NOT become inferred inputs. Default auto output +still needs fspy for write tracking, but reads outside `input: [\"src/**\"]` +should be ignored. +""" +steps = [ + { argv = [ + "vt", + "run", + "explicit-input-auto-output", + ], comment = "first run reads README.md (not in input globs) and captures the output" }, + { argv = [ + "vtt", + "replace-file-content", + "README.md", + "v1", + "v2", + ], comment = "modify README.md — not an input, so it must not invalidate the cache" }, + { argv = [ + "vt", + "run", + "explicit-input-auto-output", + ], comment = "cache hit: README.md not in input globs" }, ] diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/output_cache_test/snapshots/auto_output___files_restored_on_cache_hit.md b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/output_cache_test/snapshots/auto_output___files_restored_on_cache_hit.md new file mode 100644 index 000000000..08ec43680 --- /dev/null +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/output_cache_test/snapshots/auto_output___files_restored_on_cache_hit.md @@ -0,0 +1,46 @@ +# auto_output___files_restored_on_cache_hit + +Auto output detection (default): output files written by the task are +restored on a cache hit. + +## `vt run auto-output` + +first run writes dist/out.txt + +``` +$ vtt write-file dist/out.txt built +``` + +## `vtt print-file dist/out.txt` + +output exists after the build + +``` +built +``` + +## `vtt rm dist/out.txt` + +delete only the file (keep dir to avoid an fspy inferred-input miss on Windows) + +``` +``` + +## `vt run auto-output` + +cache hit, should restore dist/out.txt + +``` +$ vtt write-file dist/out.txt built ◉ cache hit, replaying + +--- +vt run: cache hit. +``` + +## `vtt print-file dist/out.txt` + +output was restored from the archive + +``` +built +``` diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/output_cache_test/snapshots/auto_output_with_non_auto_input.md b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/output_cache_test/snapshots/auto_output_with_non_auto_input.md new file mode 100644 index 000000000..ba8c3e460 --- /dev/null +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/output_cache_test/snapshots/auto_output_with_non_auto_input.md @@ -0,0 +1,39 @@ +# auto_output_with_non_auto_input + +Auto output works even when input tracking is explicit +(`input: ["src/**"]`). Output auto-detection and input auto-detection +are independent. + +## `vt run auto-output-no-auto-input` + +first run: input src/** (no auto), output default (auto) + +``` +$ vtt write-file dist/out.txt built +``` + +## `vtt rm dist/out.txt` + +delete the output + +``` +``` + +## `vt run auto-output-no-auto-input` + +cache hit - output files should still be restored + +``` +$ vtt write-file dist/out.txt built ◉ cache hit, replaying + +--- +vt run: cache hit. +``` + +## `vtt print-file dist/out.txt` + +output was restored + +``` +built +``` diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/output_cache_test/snapshots/explicit_input_ignores_fspy_reads.md b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/output_cache_test/snapshots/explicit_input_ignores_fspy_reads.md new file mode 100644 index 000000000..c0e5e0f9f --- /dev/null +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/output_cache_test/snapshots/explicit_input_ignores_fspy_reads.md @@ -0,0 +1,34 @@ +# explicit_input_ignores_fspy_reads + +When input auto is disabled (explicit globs only), unrelated reads +tracked by fspy must NOT become inferred inputs. Default auto output +still needs fspy for write tracking, but reads outside `input: ["src/**"]` +should be ignored. + +## `vt run explicit-input-auto-output` + +first run reads README.md (not in input globs) and captures the output + +``` +$ vtt print-file README.md +v1 +``` + +## `vtt replace-file-content README.md v1 v2` + +modify README.md — not an input, so it must not invalidate the cache + +``` +``` + +## `vt run explicit-input-auto-output` + +cache hit: README.md not in input globs + +``` +$ vtt print-file README.md ◉ cache hit, replaying +v1 + +--- +vt run: cache hit. +``` diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/output_cache_test/snapshots/glob_output___only_matched_files_restored.md b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/output_cache_test/snapshots/glob_output___only_matched_files_restored.md new file mode 100644 index 000000000..99df20c84 --- /dev/null +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/output_cache_test/snapshots/glob_output___only_matched_files_restored.md @@ -0,0 +1,60 @@ +# glob_output___only_matched_files_restored + +Glob output: only files matching the configured output globs are restored +on a cache hit; files produced outside those globs are left alone. + +## `vt run glob-output` + +first run writes dist/out.txt and tmp/temp.txt + +``` +$ vtt write-file dist/out.txt built + +$ vtt write-file tmp/temp.txt temp + +--- +vt run: 0/2 cache hit (0%). (Run `vt run --last-details` for full details) +``` + +## `vtt rm dist/out.txt` + +delete the glob-matched output + +``` +``` + +## `vtt rm tmp/temp.txt` + +delete the non-matched output + +``` +``` + +## `vt run glob-output` + +cache hit: should restore dist/out.txt but not tmp/temp.txt + +``` +$ vtt write-file dist/out.txt built ◉ cache hit, replaying + +$ vtt write-file tmp/temp.txt temp ◉ cache hit, replaying + +--- +vt run: 2/2 cache hit (100%). (Run `vt run --last-details` for full details) +``` + +## `vtt print-file dist/out.txt` + +dist/out.txt was restored + +``` +built +``` + +## `vtt print-file tmp/temp.txt` + +should fail - tmp not in output globs + +``` +tmp/temp.txt: not found +``` diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/output_cache_test/snapshots/input_negative_does_not_drop_output_writes.md b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/output_cache_test/snapshots/input_negative_does_not_drop_output_writes.md new file mode 100644 index 000000000..81153bb8a --- /dev/null +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/output_cache_test/snapshots/input_negative_does_not_drop_output_writes.md @@ -0,0 +1,40 @@ +# input_negative_does_not_drop_output_writes + +Input negative globs must not drop matching writes from the output +archive. Here the user excludes `dist/**` from inferred inputs (so +rewriting dist/ won't mark inputs as modified), but default auto output +should still capture dist writes and restore them on a cache hit. + +## `vt run input-neg-dist-auto-output` + +first run writes dist/out.txt + +``` +$ vtt write-file dist/out.txt built +``` + +## `vtt rm dist/out.txt` + +delete the output + +``` +``` + +## `vt run input-neg-dist-auto-output` + +cache hit should restore dist/out.txt + +``` +$ vtt write-file dist/out.txt built ◉ cache hit, replaying + +--- +vt run: cache hit. +``` + +## `vtt print-file dist/out.txt` + +output was restored despite dist/** being a negative input glob + +``` +built +``` diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/output_cache_test/snapshots/negative_output___excluded_files_not_restored.md b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/output_cache_test/snapshots/negative_output___excluded_files_not_restored.md new file mode 100644 index 000000000..e355a36d5 --- /dev/null +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/output_cache_test/snapshots/negative_output___excluded_files_not_restored.md @@ -0,0 +1,60 @@ +# negative_output___excluded_files_not_restored + +Negative output globs exclude matching files from the cache archive, so +they are not restored on a cache hit even though the task produced them. + +## `vt run negative-output` + +first run writes dist/out.txt and dist/cache/tmp.txt + +``` +$ vtt write-file dist/out.txt built + +$ vtt write-file dist/cache/tmp.txt temp + +--- +vt run: 0/2 cache hit (0%). (Run `vt run --last-details` for full details) +``` + +## `vtt rm dist/out.txt` + +delete the archived output + +``` +``` + +## `vtt rm dist/cache/tmp.txt` + +delete the excluded output + +``` +``` + +## `vt run negative-output` + +cache hit: should restore dist/out.txt but NOT dist/cache/tmp.txt + +``` +$ vtt write-file dist/out.txt built ◉ cache hit, replaying + +$ vtt write-file dist/cache/tmp.txt temp ◉ cache hit, replaying + +--- +vt run: 2/2 cache hit (100%). (Run `vt run --last-details` for full details) +``` + +## `vtt print-file dist/out.txt` + +dist/out.txt was restored + +``` +built +``` + +## `vtt print-file dist/cache/tmp.txt` + +should fail - excluded by !dist/cache/** + +``` +dist/cache/tmp.txt: not found +``` diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/output_cache_test/snapshots/output_config_change_invalidates_cache.md b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/output_cache_test/snapshots/output_config_change_invalidates_cache.md new file mode 100644 index 000000000..ad0870994 --- /dev/null +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/output_cache_test/snapshots/output_config_change_invalidates_cache.md @@ -0,0 +1,27 @@ +# output_config_change_invalidates_cache + +Changing a task's output configuration invalidates the cache entry — +the next run is a miss, not a hit of the stale archive. + +## `vt run output-config-change` + +first run populates the cache + +``` +$ vtt write-file dist/out.txt built +``` + +## `vtt replace-file-content vite-task.json REPLACE_ME dist/**` + +change the output globs in the task config + +``` +``` + +## `vt run output-config-change` + +cache miss: output config changed + +``` +$ vtt write-file dist/out.txt built ○ cache miss: output configuration changed, executing +``` diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/output_cache_test/vite-task.json b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/output_cache_test/vite-task.json index 6bd35a604..f7b271462 100644 --- a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/output_cache_test/vite-task.json +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/output_cache_test/vite-task.json @@ -1,15 +1,37 @@ { "tasks": { - "build": { - "command": "vtt write-file dist/output.txt built", - "input": ["src/**"], + "auto-output": { + "command": "vtt write-file dist/out.txt built", + "cache": true + }, + "glob-output": { + "command": "vtt write-file dist/out.txt built && vtt write-file tmp/temp.txt temp", "output": ["dist/**"], "cache": true }, - "build-with-negative": { - "command": "vtt write-file dist/keep.txt keep && vtt write-file dist/skip.txt skip", + "auto-output-no-auto-input": { + "command": "vtt write-file dist/out.txt built", + "input": ["src/**"], + "cache": true + }, + "negative-output": { + "command": "vtt write-file dist/out.txt built && vtt write-file dist/cache/tmp.txt temp", + "output": [{ "auto": true }, "!dist/cache/**"], + "cache": true + }, + "output-config-change": { + "command": "vtt write-file dist/out.txt built", + "output": ["REPLACE_ME"], + "cache": true + }, + "input-neg-dist-auto-output": { + "command": "vtt write-file dist/out.txt built", + "input": [{ "auto": true }, "!dist/**"], + "cache": true + }, + "explicit-input-auto-output": { + "command": "vtt print-file README.md", "input": ["src/**"], - "output": ["dist/**", "!dist/skip.txt"], "cache": true } } diff --git a/crates/vite_task_graph/run-config.ts b/crates/vite_task_graph/run-config.ts index 1fa4ee868..ebf41c36b 100644 --- a/crates/vite_task_graph/run-config.ts +++ b/crates/vite_task_graph/run-config.ts @@ -55,14 +55,16 @@ untrackedEnv?: Array, */ input?: Array, /** - * Output files to archive after a successful run and restore on cache hit. + * Output files to archive and restore on cache hit. * - * - Omitted or `[]` (empty): no output archiving (default) + * - Omitted: automatically tracks which files the task writes + * - `[]` (empty): disables output restoration entirely * - Glob patterns (e.g. `"dist/**"`) select specific output files, relative to the package directory * - `{pattern: "...", base: "workspace" | "package"}` specifies a glob with an explicit base directory + * - `{auto: true}` enables automatic file tracking * - Negative patterns (e.g. `"!dist/cache/**"`) exclude matched files */ -output?: Array, } | { +output?: Array, } | { /** * Whether to cache the task */ diff --git a/crates/vite_task_graph/src/config/mod.rs b/crates/vite_task_graph/src/config/mod.rs index 0e8c28f87..925f6a637 100644 --- a/crates/vite_task_graph/src/config/mod.rs +++ b/crates/vite_task_graph/src/config/mod.rs @@ -7,8 +7,8 @@ use rustc_hash::FxHashSet; use serde::Serialize; pub use user::{ AutoInput, EnabledCacheConfig, GlobWithBase, InputBase, ResolvedGlobalCacheConfig, - UserCacheConfig, UserGlobalCacheConfig, UserInputEntry, UserInputsConfig, UserOutputEntry, - UserRunConfig, UserTaskConfig, + UserCacheConfig, UserGlobalCacheConfig, UserInputEntry, UserInputsConfig, UserRunConfig, + UserTaskConfig, }; use vite_path::AbsolutePath; use vite_str::Str; @@ -75,7 +75,7 @@ impl ResolvedTaskOptions { workspace_root, )?; - let output_config = ResolvedGlobConfig::from_user_output_config( + let output_config = ResolvedGlobConfig::from_user_config( enabled_cache_config.output.as_ref(), dir, workspace_root, @@ -196,57 +196,6 @@ impl ResolvedGlobConfig { Ok(Self { includes_auto, positive_globs, negative_globs }) } - /// Resolve from user output configuration, making glob patterns workspace-root-relative. - /// - /// Unlike [`Self::from_user_config`], `None` and `Some([])` both produce an empty config - /// with `includes_auto = false` (no output archiving). - /// - /// # Errors - /// - /// Returns [`ResolveTaskConfigError`] if a glob pattern is invalid or resolves - /// outside the workspace root. - pub fn from_user_output_config( - user_outputs: Option<&Vec>, - package_dir: &AbsolutePath, - workspace_root: &AbsolutePath, - ) -> Result { - let mut positive_globs = BTreeSet::new(); - let mut negative_globs = BTreeSet::new(); - - let Some(entries) = user_outputs else { - return Ok(Self { includes_auto: false, positive_globs, negative_globs }); - }; - - for entry in entries { - match entry { - UserOutputEntry::Glob(pattern) => { - Self::insert_glob( - pattern.as_str(), - package_dir, - workspace_root, - &mut positive_globs, - &mut negative_globs, - )?; - } - UserOutputEntry::GlobWithBase(GlobWithBase { pattern, base }) => { - let base_dir = match base { - InputBase::Package => package_dir, - InputBase::Workspace => workspace_root, - }; - Self::insert_glob( - pattern.as_str(), - base_dir, - workspace_root, - &mut positive_globs, - &mut negative_globs, - )?; - } - } - } - - Ok(Self { includes_auto: false, positive_globs, negative_globs }) - } - /// Insert a glob pattern into the appropriate set (positive or negative), /// resolving it relative to the given base directory. fn insert_glob( diff --git a/crates/vite_task_graph/src/config/user.rs b/crates/vite_task_graph/src/config/user.rs index aeee38608..cc5571e69 100644 --- a/crates/vite_task_graph/src/config/user.rs +++ b/crates/vite_task_graph/src/config/user.rs @@ -65,22 +65,6 @@ pub enum UserInputEntry { /// Default (when field omitted): `[{auto: true}]` - infer from file accesses. pub type UserInputsConfig = Vec; -/// A single output entry in the `output` array. -/// -/// Outputs can be: -/// - Glob patterns as strings (resolved relative to the package directory) -/// - Object form with explicit base: `{ "pattern": "...", "base": "workspace" | "package" }` -#[derive(Debug, Deserialize, PartialEq, Eq, Clone)] -// TS derive macro generates code using std types that clippy disallows; skip derive during linting -#[cfg_attr(all(test, not(clippy)), derive(TS))] -#[serde(untagged)] -pub enum UserOutputEntry { - /// Glob pattern (positive or negative starting with `!`), resolved relative to package dir - Glob(Str), - /// Glob pattern with explicit base directory - GlobWithBase(GlobWithBase), -} - /// Cache-related fields of a task defined by user in `vite.config.*` #[derive(Debug, Deserialize, PartialEq, Eq)] // TS derive macro generates code using std types that clippy disallows; skip derive during linting @@ -142,15 +126,17 @@ pub struct EnabledCacheConfig { #[cfg_attr(all(test, not(clippy)), ts(inline))] pub input: Option, - /// Output files to archive after a successful run and restore on cache hit. + /// Output files to archive and restore on cache hit. /// - /// - Omitted or `[]` (empty): no output archiving (default) + /// - Omitted: automatically tracks which files the task writes + /// - `[]` (empty): disables output restoration entirely /// - Glob patterns (e.g. `"dist/**"`) select specific output files, relative to the package directory /// - `{pattern: "...", base: "workspace" | "package"}` specifies a glob with an explicit base directory + /// - `{auto: true}` enables automatic file tracking /// - Negative patterns (e.g. `"!dist/cache/**"`) exclude matched files #[serde(default)] #[cfg_attr(all(test, not(clippy)), ts(inline))] - pub output: Option>, + pub output: Option, } /// Options for user-defined tasks in `vite.config.*`, excluding the command. diff --git a/crates/vite_task_plan/src/plan.rs b/crates/vite_task_plan/src/plan.rs index 89e892b48..7d73671d5 100644 --- a/crates/vite_task_plan/src/plan.rs +++ b/crates/vite_task_plan/src/plan.rs @@ -495,7 +495,7 @@ fn resolve_synthetic_cache_config( } if let Some(output) = output { - let synthetic_output = ResolvedGlobConfig::from_user_output_config( + let synthetic_output = ResolvedGlobConfig::from_user_config( Some(&output), package_dir, workspace_path, @@ -903,11 +903,7 @@ mod tests { positive_globs: positive_globs.iter().map(|s| Str::from(*s)).collect(), negative_globs: BTreeSet::new(), }, - output_config: ResolvedGlobConfig { - includes_auto: false, - positive_globs: BTreeSet::new(), - negative_globs: BTreeSet::new(), - }, + output_config: ResolvedGlobConfig::default_auto(), } } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/additional_env/snapshots/query_tool_synthetic_task_in_user_task.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/additional_env/snapshots/query_tool_synthetic_task_in_user_task.jsonc index 63bad854a..70a30a680 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/additional_env/snapshots/query_tool_synthetic_task_in_user_task.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/additional_env/snapshots/query_tool_synthetic_task_in_user_task.jsonc @@ -62,7 +62,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/additional_env/snapshots/task_graph.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/additional_env/snapshots/task_graph.jsonc index da3f2d593..3690168f9 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/additional_env/snapshots/task_graph.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/additional_env/snapshots/task_graph.jsonc @@ -28,7 +28,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -67,7 +67,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_cli_override/snapshots/query___cache_enables_script_caching.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_cli_override/snapshots/query___cache_enables_script_caching.jsonc index 63272b8d8..17487e76c 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_cli_override/snapshots/query___cache_enables_script_caching.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_cli_override/snapshots/query___cache_enables_script_caching.jsonc @@ -60,7 +60,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } 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.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_cli_override/snapshots/query___cache_enables_task_caching_even_when_cache_tasks_is_false.jsonc index af84a0ef1..be52cb30b 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.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_cli_override/snapshots/query___cache_enables_task_caching_even_when_cache_tasks_is_false.jsonc @@ -60,7 +60,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } 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.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_cli_override/snapshots/query___cache_on_task_with_per_task_cache_true_enables_caching.jsonc index 44c82a701..4c12deaae 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.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_cli_override/snapshots/query___cache_on_task_with_per_task_cache_true_enables_caching.jsonc @@ -60,7 +60,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_cli_override/snapshots/task_graph.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_cli_override/snapshots/task_graph.jsonc index d98768c05..9f5fe4c2f 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_cli_override/snapshots/task_graph.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_cli_override/snapshots/task_graph.jsonc @@ -28,7 +28,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -67,7 +67,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -128,7 +128,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -167,7 +167,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_keys/snapshots/query_echo_and_lint_with_extra_args.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_keys/snapshots/query_echo_and_lint_with_extra_args.jsonc index f589579d4..48e0bcd9b 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_keys/snapshots/query_echo_and_lint_with_extra_args.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_keys/snapshots/query_echo_and_lint_with_extra_args.jsonc @@ -89,7 +89,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_keys/snapshots/query_lint_and_echo_with_extra_args.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_keys/snapshots/query_lint_and_echo_with_extra_args.jsonc index 586844bfc..4e1becc6d 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_keys/snapshots/query_lint_and_echo_with_extra_args.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_keys/snapshots/query_lint_and_echo_with_extra_args.jsonc @@ -60,7 +60,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_keys/snapshots/query_normal_task_with_extra_args.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_keys/snapshots/query_normal_task_with_extra_args.jsonc index 07660f771..85eda7c07 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_keys/snapshots/query_normal_task_with_extra_args.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_keys/snapshots/query_normal_task_with_extra_args.jsonc @@ -62,7 +62,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_keys/snapshots/query_synthetic_task_in_user_task.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_keys/snapshots/query_synthetic_task_in_user_task.jsonc index a75b9dfc1..9b0261769 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_keys/snapshots/query_synthetic_task_in_user_task.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_keys/snapshots/query_synthetic_task_in_user_task.jsonc @@ -60,7 +60,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_keys/snapshots/query_synthetic_task_in_user_task_with_cwd.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_keys/snapshots/query_synthetic_task_in_user_task_with_cwd.jsonc index a75b9dfc1..9b0261769 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_keys/snapshots/query_synthetic_task_in_user_task_with_cwd.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_keys/snapshots/query_synthetic_task_in_user_task_with_cwd.jsonc @@ -60,7 +60,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_keys/snapshots/query_synthetic_task_with_extra_args_in_user_task.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_keys/snapshots/query_synthetic_task_with_extra_args_in_user_task.jsonc index 71683ee96..b49b7cdab 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_keys/snapshots/query_synthetic_task_with_extra_args_in_user_task.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_keys/snapshots/query_synthetic_task_with_extra_args_in_user_task.jsonc @@ -63,7 +63,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_keys/snapshots/task_graph.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_keys/snapshots/task_graph.jsonc index 13b2802fd..69c2936d8 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_keys/snapshots/task_graph.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_keys/snapshots/task_graph.jsonc @@ -28,7 +28,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -67,7 +67,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -106,7 +106,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -145,7 +145,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_scripts_default/snapshots/task_graph.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_scripts_default/snapshots/task_graph.jsonc index 5129800c3..8b8f3c465 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_scripts_default/snapshots/task_graph.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_scripts_default/snapshots/task_graph.jsonc @@ -28,7 +28,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -67,7 +67,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_scripts_enabled/snapshots/task_graph.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_scripts_enabled/snapshots/task_graph.jsonc index 8f084f7de..85e08a273 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_scripts_enabled/snapshots/task_graph.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_scripts_enabled/snapshots/task_graph.jsonc @@ -28,7 +28,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -67,7 +67,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_scripts_task_override/snapshots/query_another_task_cached_by_default.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_scripts_task_override/snapshots/query_another_task_cached_by_default.jsonc index b344b082b..96355742c 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_scripts_task_override/snapshots/query_another_task_cached_by_default.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_scripts_task_override/snapshots/query_another_task_cached_by_default.jsonc @@ -60,7 +60,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_scripts_task_override/snapshots/query_task_cached_by_default.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_scripts_task_override/snapshots/query_task_cached_by_default.jsonc index 78a406fa1..e4922043b 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_scripts_task_override/snapshots/query_task_cached_by_default.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_scripts_task_override/snapshots/query_task_cached_by_default.jsonc @@ -60,7 +60,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_scripts_task_override/snapshots/task_graph.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_scripts_task_override/snapshots/task_graph.jsonc index cb6afda93..a6a4e8722 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_scripts_task_override/snapshots/task_graph.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_scripts_task_override/snapshots/task_graph.jsonc @@ -28,7 +28,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -67,7 +67,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -106,7 +106,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_sharing/snapshots/task_graph.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_sharing/snapshots/task_graph.jsonc index ebfa2e8b3..406b3f570 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_sharing/snapshots/task_graph.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_sharing/snapshots/task_graph.jsonc @@ -28,7 +28,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -67,7 +67,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -106,7 +106,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_subcommand/snapshots/task_graph.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_subcommand/snapshots/task_graph.jsonc index fb069d24d..3ae013b8e 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_subcommand/snapshots/task_graph.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_subcommand/snapshots/task_graph.jsonc @@ -28,7 +28,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_tasks_disabled/snapshots/task_graph.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_tasks_disabled/snapshots/task_graph.jsonc index 55ebae45d..0e3aa085f 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_tasks_disabled/snapshots/task_graph.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_tasks_disabled/snapshots/task_graph.jsonc @@ -28,7 +28,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -67,7 +67,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -106,7 +106,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_true_no_force_enable/snapshots/query_script_cached_when_global_cache_true.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_true_no_force_enable/snapshots/query_script_cached_when_global_cache_true.jsonc index a82d5e2f9..bdc8c7add 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_true_no_force_enable/snapshots/query_script_cached_when_global_cache_true.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_true_no_force_enable/snapshots/query_script_cached_when_global_cache_true.jsonc @@ -60,7 +60,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_true_no_force_enable/snapshots/query_task_cached_when_global_cache_true.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_true_no_force_enable/snapshots/query_task_cached_when_global_cache_true.jsonc index a16181471..e27d6cc80 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_true_no_force_enable/snapshots/query_task_cached_when_global_cache_true.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_true_no_force_enable/snapshots/query_task_cached_when_global_cache_true.jsonc @@ -60,7 +60,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_true_no_force_enable/snapshots/task_graph.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_true_no_force_enable/snapshots/task_graph.jsonc index fff2e8ef4..ae2a02d9e 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_true_no_force_enable/snapshots/task_graph.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache_true_no_force_enable/snapshots/task_graph.jsonc @@ -50,7 +50,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -89,7 +89,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } 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.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cd_in_scripts/snapshots/query_cd_before_vt_lint_should_put_synthetic_task_under_cwd.jsonc index d226a413b..7e658be2c 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.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cd_in_scripts/snapshots/query_cd_before_vt_lint_should_put_synthetic_task_under_cwd.jsonc @@ -60,7 +60,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } 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.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cd_in_scripts/snapshots/query_cd_before_vt_run_should_not_affect_expanded_task_cwd.jsonc index 4142b0960..3504841c9 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.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cd_in_scripts/snapshots/query_cd_before_vt_run_should_not_affect_expanded_task_cwd.jsonc @@ -86,7 +86,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cd_in_scripts/snapshots/task_graph.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cd_in_scripts/snapshots/task_graph.jsonc index a0ea080a3..09b02be13 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cd_in_scripts/snapshots/task_graph.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cd_in_scripts/snapshots/task_graph.jsonc @@ -28,7 +28,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -67,7 +67,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -106,7 +106,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/comprehensive_task_graph/snapshots/task_graph.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/comprehensive_task_graph/snapshots/task_graph.jsonc index 9597c4b3a..2d5f8307c 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/comprehensive_task_graph/snapshots/task_graph.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/comprehensive_task_graph/snapshots/task_graph.jsonc @@ -28,7 +28,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -67,7 +67,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -106,7 +106,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -145,7 +145,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -184,7 +184,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -223,7 +223,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -262,7 +262,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -301,7 +301,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -340,7 +340,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -379,7 +379,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -418,7 +418,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -457,7 +457,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -496,7 +496,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -535,7 +535,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -574,7 +574,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -613,7 +613,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -652,7 +652,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -691,7 +691,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -730,7 +730,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -769,7 +769,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -808,7 +808,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -847,7 +847,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -886,7 +886,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/conflict_test/snapshots/task_graph.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/conflict_test/snapshots/task_graph.jsonc index e246a1db3..f88266a47 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/conflict_test/snapshots/task_graph.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/conflict_test/snapshots/task_graph.jsonc @@ -28,7 +28,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -67,7 +67,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -106,7 +106,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cycle_dependency/snapshots/task_graph.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cycle_dependency/snapshots/task_graph.jsonc index 2c07f9bd1..02744a92a 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cycle_dependency/snapshots/task_graph.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cycle_dependency/snapshots/task_graph.jsonc @@ -28,7 +28,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -72,7 +72,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/dependency_both_topo_and_explicit/snapshots/task_graph.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/dependency_both_topo_and_explicit/snapshots/task_graph.jsonc index 9b4779c26..6cd676ac1 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/dependency_both_topo_and_explicit/snapshots/task_graph.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/dependency_both_topo_and_explicit/snapshots/task_graph.jsonc @@ -28,7 +28,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -72,7 +72,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/duplicate_package_names/snapshots/task_graph.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/duplicate_package_names/snapshots/task_graph.jsonc index b3d46d315..dc309692e 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/duplicate_package_names/snapshots/task_graph.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/duplicate_package_names/snapshots/task_graph.jsonc @@ -28,7 +28,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -67,7 +67,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/empty_package_test/snapshots/task_graph.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/empty_package_test/snapshots/task_graph.jsonc index 0a88447df..15f5fee21 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/empty_package_test/snapshots/task_graph.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/empty_package_test/snapshots/task_graph.jsonc @@ -28,7 +28,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -107,7 +107,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -146,7 +146,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -185,7 +185,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -229,7 +229,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -268,7 +268,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -307,7 +307,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -346,7 +346,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/explicit_deps_workspace/snapshots/task_graph.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/explicit_deps_workspace/snapshots/task_graph.jsonc index 4c6c21e3b..258dbe37a 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/explicit_deps_workspace/snapshots/task_graph.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/explicit_deps_workspace/snapshots/task_graph.jsonc @@ -28,7 +28,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -102,7 +102,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -141,7 +141,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -180,7 +180,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -219,7 +219,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -258,7 +258,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -302,7 +302,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -341,7 +341,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -380,7 +380,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -428,7 +428,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/extra_args_not_forwarded_to_depends_on/snapshots/query_extra_args_only_reach_requested_task.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/extra_args_not_forwarded_to_depends_on/snapshots/query_extra_args_only_reach_requested_task.jsonc index da9501116..87c2c445a 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/extra_args_not_forwarded_to_depends_on/snapshots/query_extra_args_only_reach_requested_task.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/extra_args_not_forwarded_to_depends_on/snapshots/query_extra_args_only_reach_requested_task.jsonc @@ -60,7 +60,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -147,7 +147,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/extra_args_not_forwarded_to_depends_on/snapshots/task_graph.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/extra_args_not_forwarded_to_depends_on/snapshots/task_graph.jsonc index e483d70c4..0f8a5a02d 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/extra_args_not_forwarded_to_depends_on/snapshots/task_graph.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/extra_args_not_forwarded_to_depends_on/snapshots/task_graph.jsonc @@ -28,7 +28,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -67,7 +67,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/filter_workspace/snapshots/task_graph.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/filter_workspace/snapshots/task_graph.jsonc index 27c09ea17..749052ab4 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/filter_workspace/snapshots/task_graph.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/filter_workspace/snapshots/task_graph.jsonc @@ -28,7 +28,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -67,7 +67,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -106,7 +106,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -145,7 +145,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -184,7 +184,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -223,7 +223,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -262,7 +262,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -301,7 +301,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -340,7 +340,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -379,7 +379,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -418,7 +418,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -457,7 +457,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -496,7 +496,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/input_trailing_slash/snapshots/task_graph.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/input_trailing_slash/snapshots/task_graph.jsonc index 11c015377..cc3c5380e 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/input_trailing_slash/snapshots/task_graph.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/input_trailing_slash/snapshots/task_graph.jsonc @@ -32,7 +32,7 @@ ] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/input_workspace_base/snapshots/task_graph.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/input_workspace_base/snapshots/task_graph.jsonc index b82a6e8da..f8a2b06f1 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/input_workspace_base/snapshots/task_graph.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/input_workspace_base/snapshots/task_graph.jsonc @@ -33,7 +33,7 @@ ] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested_cache_override/snapshots/query_nested___cache_enables_inner_task_caching.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested_cache_override/snapshots/query_nested___cache_enables_inner_task_caching.jsonc index 759b8f84e..bb31ec14a 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested_cache_override/snapshots/query_nested___cache_enables_inner_task_caching.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested_cache_override/snapshots/query_nested___cache_enables_inner_task_caching.jsonc @@ -86,7 +86,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested_cache_override/snapshots/query_outer___cache_propagates_to_nested_run_without_flags.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested_cache_override/snapshots/query_outer___cache_propagates_to_nested_run_without_flags.jsonc index a4f58176f..2429e6f57 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested_cache_override/snapshots/query_outer___cache_propagates_to_nested_run_without_flags.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested_cache_override/snapshots/query_outer___cache_propagates_to_nested_run_without_flags.jsonc @@ -86,7 +86,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } 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.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested_cache_override/snapshots/query_outer___no_cache_does_not_propagate_into_nested___cache.jsonc index 6e384f70a..2239dc902 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested_cache_override/snapshots/query_outer___no_cache_does_not_propagate_into_nested___cache.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested_cache_override/snapshots/query_outer___no_cache_does_not_propagate_into_nested___cache.jsonc @@ -86,7 +86,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested_cache_override/snapshots/task_graph.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested_cache_override/snapshots/task_graph.jsonc index 1200a2faa..d1f6cf7ab 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested_cache_override/snapshots/task_graph.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested_cache_override/snapshots/task_graph.jsonc @@ -28,7 +28,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -67,7 +67,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -106,7 +106,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -145,7 +145,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested_tasks/snapshots/task_graph.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested_tasks/snapshots/task_graph.jsonc index eef8a1a13..84427555e 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested_tasks/snapshots/task_graph.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested_tasks/snapshots/task_graph.jsonc @@ -28,7 +28,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -67,7 +67,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/package_self_dependency/snapshots/task_graph.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/package_self_dependency/snapshots/task_graph.jsonc index 599e3b086..0fa96e98b 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/package_self_dependency/snapshots/task_graph.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/package_self_dependency/snapshots/task_graph.jsonc @@ -28,7 +28,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/parallel_and_concurrency/snapshots/task_graph.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/parallel_and_concurrency/snapshots/task_graph.jsonc index 9c50b6a60..3310ddddc 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/parallel_and_concurrency/snapshots/task_graph.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/parallel_and_concurrency/snapshots/task_graph.jsonc @@ -28,7 +28,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -67,7 +67,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -106,7 +106,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -145,7 +145,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -184,7 +184,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/pnpm_workspace_packages_optional/snapshots/task_graph.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/pnpm_workspace_packages_optional/snapshots/task_graph.jsonc index aef412250..7c721c0cd 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/pnpm_workspace_packages_optional/snapshots/task_graph.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/pnpm_workspace_packages_optional/snapshots/task_graph.jsonc @@ -28,7 +28,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/recursive_topological_workspace/snapshots/task_graph.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/recursive_topological_workspace/snapshots/task_graph.jsonc index a902fcadd..721994b03 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/recursive_topological_workspace/snapshots/task_graph.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/recursive_topological_workspace/snapshots/task_graph.jsonc @@ -28,7 +28,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -67,7 +67,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -106,7 +106,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -145,7 +145,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -184,7 +184,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -223,7 +223,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -262,7 +262,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -301,7 +301,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/script_hooks/snapshots/task_graph.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/script_hooks/snapshots/task_graph.jsonc index e5271222f..74c4fb4d8 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/script_hooks/snapshots/task_graph.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/script_hooks/snapshots/task_graph.jsonc @@ -28,7 +28,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -67,7 +67,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -106,7 +106,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -145,7 +145,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -184,7 +184,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -223,7 +223,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/script_hooks_disabled/snapshots/task_graph.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/script_hooks_disabled/snapshots/task_graph.jsonc index 2961d7313..2d6390832 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/script_hooks_disabled/snapshots/task_graph.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/script_hooks_disabled/snapshots/task_graph.jsonc @@ -28,7 +28,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -67,7 +67,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -106,7 +106,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/script_hooks_nested_run/snapshots/task_graph.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/script_hooks_nested_run/snapshots/task_graph.jsonc index 36a3f67d0..89b34531f 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/script_hooks_nested_run/snapshots/task_graph.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/script_hooks_nested_run/snapshots/task_graph.jsonc @@ -28,7 +28,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -67,7 +67,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -106,7 +106,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -145,7 +145,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/script_hooks_task_no_hook/snapshots/task_graph.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/script_hooks_task_no_hook/snapshots/task_graph.jsonc index 005d03240..a7a338907 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/script_hooks_task_no_hook/snapshots/task_graph.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/script_hooks_task_no_hook/snapshots/task_graph.jsonc @@ -28,7 +28,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -67,7 +67,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/shell_fallback/snapshots/query_shell_fallback_for_pipe_command.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/shell_fallback/snapshots/query_shell_fallback_for_pipe_command.jsonc index b3da6fda6..c1fadfcf5 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/shell_fallback/snapshots/query_shell_fallback_for_pipe_command.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/shell_fallback/snapshots/query_shell_fallback_for_pipe_command.jsonc @@ -60,7 +60,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/shell_fallback/snapshots/task_graph.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/shell_fallback/snapshots/task_graph.jsonc index 51fd7c317..c8d4d2825 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/shell_fallback/snapshots/task_graph.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/shell_fallback/snapshots/task_graph.jsonc @@ -28,7 +28,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } 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.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic_cache_disabled/snapshots/query_parent_cache_false_does_not_affect_expanded_query_tasks.jsonc index 2df26b1a1..a706bf224 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic_cache_disabled/snapshots/query_parent_cache_false_does_not_affect_expanded_query_tasks.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic_cache_disabled/snapshots/query_parent_cache_false_does_not_affect_expanded_query_tasks.jsonc @@ -86,7 +86,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } 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.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic_cache_disabled/snapshots/query_script_cache_false_does_not_affect_expanded_synthetic_cache.jsonc index d5e183324..07de08fd6 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic_cache_disabled/snapshots/query_script_cache_false_does_not_affect_expanded_synthetic_cache.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic_cache_disabled/snapshots/query_script_cache_false_does_not_affect_expanded_synthetic_cache.jsonc @@ -86,7 +86,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic_cache_disabled/snapshots/query_task_untrackedEnv_inherited_by_synthetic.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic_cache_disabled/snapshots/query_task_untrackedEnv_inherited_by_synthetic.jsonc index 812734076..e8ecc3a8f 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic_cache_disabled/snapshots/query_task_untrackedEnv_inherited_by_synthetic.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic_cache_disabled/snapshots/query_task_untrackedEnv_inherited_by_synthetic.jsonc @@ -61,7 +61,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic_cache_disabled/snapshots/query_task_with_cache_true_enables_synthetic_cache.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic_cache_disabled/snapshots/query_task_with_cache_true_enables_synthetic_cache.jsonc index 9ccca7a11..6c8b888d5 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic_cache_disabled/snapshots/query_task_with_cache_true_enables_synthetic_cache.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic_cache_disabled/snapshots/query_task_with_cache_true_enables_synthetic_cache.jsonc @@ -60,7 +60,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic_cache_disabled/snapshots/task_graph.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic_cache_disabled/snapshots/task_graph.jsonc index b550e3faf..28255bc3e 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic_cache_disabled/snapshots/task_graph.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic_cache_disabled/snapshots/task_graph.jsonc @@ -28,7 +28,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -67,7 +67,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -128,7 +128,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -168,7 +168,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -207,7 +207,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic_in_subpackage/snapshots/query_synthetic_in_subpackage.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic_in_subpackage/snapshots/query_synthetic_in_subpackage.jsonc index 5a40fe048..073de3756 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic_in_subpackage/snapshots/query_synthetic_in_subpackage.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic_in_subpackage/snapshots/query_synthetic_in_subpackage.jsonc @@ -86,7 +86,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic_in_subpackage/snapshots/task_graph.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic_in_subpackage/snapshots/task_graph.jsonc index f45c1001a..29978073f 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic_in_subpackage/snapshots/task_graph.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic_in_subpackage/snapshots/task_graph.jsonc @@ -28,7 +28,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -67,7 +67,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/transitive_skip_intermediate/snapshots/task_graph.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/transitive_skip_intermediate/snapshots/task_graph.jsonc index 40ea1a092..281260a09 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/transitive_skip_intermediate/snapshots/task_graph.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/transitive_skip_intermediate/snapshots/task_graph.jsonc @@ -28,7 +28,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -67,7 +67,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -106,7 +106,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/vpr_shorthand/snapshots/task_graph.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/vpr_shorthand/snapshots/task_graph.jsonc index 00be69c6c..a4fbd68c9 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/vpr_shorthand/snapshots/task_graph.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/vpr_shorthand/snapshots/task_graph.jsonc @@ -28,7 +28,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -67,7 +67,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/windows_cmd_shim_rewrite/snapshots/query_dev_filter_from_root.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/windows_cmd_shim_rewrite/snapshots/query_dev_filter_from_root.jsonc index ba1f67e9e..663a73858 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/windows_cmd_shim_rewrite/snapshots/query_dev_filter_from_root.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/windows_cmd_shim_rewrite/snapshots/query_dev_filter_from_root.jsonc @@ -66,7 +66,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/windows_cmd_shim_rewrite/snapshots/query_dev_in_subpackage.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/windows_cmd_shim_rewrite/snapshots/query_dev_in_subpackage.jsonc index dc5f9a939..ad348fadb 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/windows_cmd_shim_rewrite/snapshots/query_dev_in_subpackage.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/windows_cmd_shim_rewrite/snapshots/query_dev_in_subpackage.jsonc @@ -66,7 +66,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/windows_cmd_shim_rewrite/snapshots/task_graph.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/windows_cmd_shim_rewrite/snapshots/task_graph.jsonc index d8a3142d4..8dd415471 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/windows_cmd_shim_rewrite/snapshots/task_graph.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/windows_cmd_shim_rewrite/snapshots/task_graph.jsonc @@ -28,7 +28,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/workspace_root_cd_no_skip/snapshots/task_graph.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/workspace_root_cd_no_skip/snapshots/task_graph.jsonc index f7ee35330..f105a6563 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/workspace_root_cd_no_skip/snapshots/task_graph.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/workspace_root_cd_no_skip/snapshots/task_graph.jsonc @@ -28,7 +28,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -67,7 +67,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/workspace_root_depends_on_passthrough/snapshots/task_graph.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/workspace_root_depends_on_passthrough/snapshots/task_graph.jsonc index 2a23ddc71..b6b8e743d 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/workspace_root_depends_on_passthrough/snapshots/task_graph.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/workspace_root_depends_on_passthrough/snapshots/task_graph.jsonc @@ -28,7 +28,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -72,7 +72,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -111,7 +111,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -150,7 +150,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/workspace_root_multi_command/snapshots/task_graph.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/workspace_root_multi_command/snapshots/task_graph.jsonc index f031c893d..30236c51c 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/workspace_root_multi_command/snapshots/task_graph.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/workspace_root_multi_command/snapshots/task_graph.jsonc @@ -28,7 +28,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -67,7 +67,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/workspace_root_mutual_recursion/snapshots/task_graph.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/workspace_root_mutual_recursion/snapshots/task_graph.jsonc index 5e3cee720..4cb032386 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/workspace_root_mutual_recursion/snapshots/task_graph.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/workspace_root_mutual_recursion/snapshots/task_graph.jsonc @@ -28,7 +28,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -67,7 +67,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -106,7 +106,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -145,7 +145,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/workspace_root_no_package_json/snapshots/task_graph.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/workspace_root_no_package_json/snapshots/task_graph.jsonc index 5a64e4c3a..a9be2e812 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/workspace_root_no_package_json/snapshots/task_graph.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/workspace_root_no_package_json/snapshots/task_graph.jsonc @@ -28,7 +28,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -67,7 +67,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/workspace_root_self_reference/snapshots/task_graph.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/workspace_root_self_reference/snapshots/task_graph.jsonc index 76f667459..2445ccfb7 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/workspace_root_self_reference/snapshots/task_graph.jsonc +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/workspace_root_self_reference/snapshots/task_graph.jsonc @@ -28,7 +28,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -67,7 +67,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } @@ -106,7 +106,7 @@ "negative_globs": [] }, "output_config": { - "includes_auto": false, + "includes_auto": true, "positive_globs": [], "negative_globs": [] } diff --git a/docs/output-restoration-research.md b/docs/output-restoration-research.md new file mode 100644 index 000000000..4f6beda8c --- /dev/null +++ b/docs/output-restoration-research.md @@ -0,0 +1,117 @@ +# Output Restoration: Compatibility with Real Build Tools + +## Background + +Output restoration automatically archives files produced by a cached task and restores them on cache hit. +When a task runs and creates `dist/`, those files are saved as a `tar.zst` archive in the cache directory. +On subsequent cache hits the archive is extracted, skipping the need to re-execute the task. + +The feature works end-to-end when tested with simple write-only commands (`vtt write-file dist/out.txt built`), +but **fails with real build tools** (Vite 8, tsdown) in the default auto-detection mode. + +## The Problem + +Deleting the output directory (`dist/`) between runs causes a **cache miss** instead of triggering output restoration. + +``` +~/packages/vite-app$ vite build +... +✓ built in 34ms + +# delete dist, run again: + +~/packages/vite-app$ vite build ○ cache miss: 'assets' removed from 'packages/vite-app/dist', executing +``` + +The archived output files exist in the cache and could be restored, but the cache validation rejects the entry before restoration has a chance to run. + +## Root Cause + +Build tools **read from their output directory** during execution. fspy captures these reads and records them as inferred inputs. When the output directory is later deleted, the inferred input fingerprint no longer matches, producing a cache miss. + +### How the cache validation pipeline works + +1. **Cache entry lookup** — match by `CacheEntryKey` (spawn fingerprint + input config + output config) +2. **Globbed input validation** — compare stored file hashes against current state for explicit input globs +3. **Post-run fingerprint validation** — compare stored fspy-inferred input fingerprints against current filesystem state +4. **If all pass** → cache hit → replay terminal output → **extract output archive** + +The failure occurs at step 3. The stored fingerprint records `packages/app/dist` as `Folder(Some({assets: Dir, index.html: File}))`. After deletion the current fingerprint is `NotFound`. The mismatch is reported before output restoration at step 4 can execute. + +### Why build tools read from the output directory + +Both Vite 8 and tsdown follow the same pattern: **clean the output directory before writing new files**, then **report compressed sizes after writing**. + +#### Vite 8 (`vite build`) + +1. **Directory cleanup** (`emptyDir()`, called from `prepareOutDirPlugin` during `renderStart`) + - `fs.readdirSync(outDir)` enumerates entries so they can be deleted before the new build + - Controlled by `emptyOutDir` (default: `true`) + - This is the primary read that causes `packages/app/dist` to appear in fspy's `path_reads` + +2. **Compressed size reporting** (rolldown's builtin `viteReporterPlugin`, Rust-native) + - After writing output files, the reporter reads each file back to compute gzip/brotli sizes + - Produces the `dist/index.html 0.15 kB │ gzip: 0.14 kB` lines + - Controlled by `reportCompressedSize` (default: `true`) + - This causes reads on individual output files like `dist/index.html`, `dist/assets/index-xxx.js` + +3. **Public directory copy** (`copyDir()`) + - If `copyPublicDir` is enabled (default: `true`), reads the public dir to copy into outDir + +#### tsdown + +1. **Directory cleanup** (`cleanOutDir()` via `tinyglobby`'s `glob()`) + - Enumerates all files in the output directory with `onlyFiles: false` before deleting them + - Default `clean: true` triggers this + - This is the primary read that causes `packages/lib/dist` to appear in fspy's `path_reads` + +2. **Shebang permission check** (`ShebangPlugin`'s `writeBundle` hook) + - Calls `access()` on output files to check existence before setting execute permissions + - Only applies to entry chunks with shebang directives + +### Why the read-write overlap check doesn't catch this + +The overlap check at `execute_spawn` (mod.rs:486-488) looks for exact path matches between `path_reads` and `path_writes`: + +```rust +pa.path_reads.keys().find(|p| pa.path_writes.contains(*p)) +``` + +fspy reports these as separate paths: + +- **Read**: `packages/app/dist` (the directory itself, via `readdirSync`) +- **Write**: `packages/app/dist/index.html`, `packages/app/dist/assets/index-xxx.js` (individual files) + +Since `packages/app/dist` ≠ `packages/app/dist/index.html`, no overlap is detected, and caching proceeds. + +### Why `should_ignore_entry` doesn't help + +`fingerprint.rs:185-187` filters `dist` when listed as a directory entry of a **parent**: + +```rust +fn should_ignore_entry(name: &[u8]) -> bool { + matches!(name, b"." | b".." | b".DS_Store") || name.eq_ignore_ascii_case(b"dist") +} +``` + +This prevents the fingerprint of `packages/app/` from changing when `dist` appears or disappears inside it. But it does not help when `packages/app/dist` itself is a direct key in `inferred_inputs` — that path is fingerprinted independently, and its transition from `Folder(...)` to `NotFound` is a mismatch. + +### Why the existing e2e test passes + +The `output-cache-test` fixture uses `vtt write-file dist/out.txt built`, a simple write-only operation. `vtt write-file` never reads from `dist/`, so fspy only records it as a write. The directory never appears in `path_reads`, the post-run fingerprint doesn't include it, and cache validation succeeds after deletion. + +This does not reflect real build tool behavior. + +## Behavior Matrix + +All tests performed with Vite 8.0.8 and tsdown 0.12.9. "Cache hit after deleting dist" means output restoration can work. + +| `input` | `output` | fspy enabled | Cache hit after deleting dist | +| -------------- | --------------- | ------------ | ----------------------------- | +| auto (default) | auto (default) | yes | **no** | +| auto (default) | `["dist/**"]` | yes | **no** | +| `["src/**"]` | auto (default) | yes | **no** | +| `["src/**"]` | `["dist/**"]` | no | **yes** | +| `["src/**"]` | `[]` (disabled) | no | yes (but no restoration) | + +The only configuration that works requires **both** explicit input globs **and** explicit output globs, which disables fspy entirely. Any configuration that enables fspy (for either auto-input or auto-output detection) causes the output directory reads to pollute the inferred input set. diff --git a/docs/output-restoration.md b/docs/output-restoration.md new file mode 100644 index 000000000..5b004e75f --- /dev/null +++ b/docs/output-restoration.md @@ -0,0 +1,120 @@ +# Output Restoration + +When a cached task is replayed, vp doesn't just replay the terminal output — it also restores any files the task produced. So if your `build` task writes to `dist/`, a cache hit will put those files right back where they belong. + +## How It Works + +By default, vp watches which files a task writes during execution. On the next run, if the cache hits, those files are extracted back into the workspace automatically. You don't need to configure anything. + +```json +{ + "tasks": { + "build": { + "command": "tsc --outDir dist" + } + } +} +``` + +After `vp run build` runs once, the compiled files in `dist/` are archived. On subsequent runs that hit the cache, `dist/` is restored from that archive instead of recompiling. + +## The `output` Field + +The `output` field lets you control which files get archived and restored. It works exactly like `input` — same glob patterns, same `auto` directive, same negative patterns. + +### Default (omitted) + +Auto-detects written files. This is usually all you need: + +```json +{ + "tasks": { + "build": { + "command": "tsc --outDir dist" + } + } +} +``` + +### Explicit Globs + +If you only want specific files restored: + +```json +{ + "tasks": { + "build": { + "command": "tsc --outDir dist", + "output": ["dist/**"] + } + } +} +``` + +This ignores any other files the task might write (temp files, logs, etc.) and only archives what's under `dist/`. + +### Negative Patterns + +Exclude certain output files from being cached: + +```json +{ + "tasks": { + "build": { + "command": "webpack", + "output": [{ "auto": true }, "!dist/cache/**"] + } + } +} +``` + +Here, everything the task writes is archived _except_ files under `dist/cache/`. + +### Disable Output Restoration + +If you don't want any files restored on cache hit — only terminal output replayed — pass an empty array: + +```json +{ + "tasks": { + "test": { + "command": "vitest run", + "output": [] + } + } +} +``` + +## `output` and `input` Are Independent + +The `output` field has its own auto-detection, separate from `input`. You can disable auto-inference for inputs while keeping it for outputs: + +```json +{ + "tasks": { + "build": { + "command": "tsc --outDir dist", + "input": ["src/**/*.ts", "tsconfig.json"], + "output": [{ "auto": true }] + } + } +} +``` + +This tracks inputs via explicit globs only (no file-read inference), but still auto-detects which files the task writes for output restoration. + +## Configuration Summary + +| Configuration | Behavior | +| ------------------------------------- | ----------------------------------- | +| `output` omitted | Auto-detect written files (default) | +| `output: [{ "auto": true }]` | Same as omitted | +| `output: ["dist/**"]` | Only restore files under `dist/` | +| `output: [{ "auto": true }, "!tmp/"]` | Auto-detect, but skip `tmp/` | +| `output: []` | Don't restore any files | + +## Notes + +- Changing the `output` configuration invalidates the cache — if you switch from `["dist/**"]` to `["build/**"]`, the next run will be a cache miss. +- Output archives are stored alongside the cache database. Running `vp cache clean` removes them. +- The `output` field can't be used with `cache: false`, same as `input`.