diff --git a/CHANGELOG.md b/CHANGELOG.md index efcb2029a..7bf7fc0ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ # Changelog +- **Fixed** Prefix environment assignments like `PATH=... command` now affect executable lookup during task planning, so tools provided only by the prefixed `PATH` can be resolved correctly ([#440](https://github.com/voidzero-dev/vite-task/pull/440)) - **Changed** Cache misses caused by a tracked env var now name the env var inline, for example `cache miss: env 'NODE_ENV' changed`, instead of the generic `envs changed` message ([#438](https://github.com/voidzero-dev/vite-task/pull/438)) - **Fixed** The task cache is now stored in a per-schema-version subdirectory (e.g. `node_modules/.vite/task-cache/v13/`), so switching between branches that pin different Vite+ versions no longer fails with `Unrecognized database version`. Each version keeps its own cache directory; a cache from a different version is ignored rather than aborting the run ([#433](https://github.com/voidzero-dev/vite-task/pull/433)) - **Added** A task's `env` and `untrackedEnv` glob patterns now support `!` negation: a `!`-prefixed pattern excludes matching variables (e.g. `["VITE_*", "!VITE_SECRET"]` tracks every `VITE_*` except `VITE_SECRET`) ([#425](https://github.com/voidzero-dev/vite-task/pull/425)) diff --git a/crates/vite_task_plan/src/plan.rs b/crates/vite_task_plan/src/plan.rs index 84faa171a..12bf5c334 100644 --- a/crates/vite_task_plan/src/plan.rs +++ b/crates/vite_task_plan/src/plan.rs @@ -141,6 +141,15 @@ async fn plan_task_as_execution_node( let mut context = context.duplicate(); context.push_stack_frame(task_node_index, add_item_span.clone()); + // This command's env context: extend the planning context with + // the command's prefix envs (`FOO=1 tool ...`). Everything that + // interprets the command reads this one context — program + // lookup, plan-request callbacks, and nested-run planning. The + // per-and-item duplicate above scopes the extension to this + // command, matching shell semantics (`FOO=1 a && b` does not + // set `FOO` for `b`). + context.add_envs(and_item.envs.iter()); + let mut args = and_item.args; let extra_args = if is_last_command && and_item_index == and_item_count - 1 { // For the last and_item of the last command, append extra args from the plan context @@ -247,8 +256,6 @@ async fn plan_task_as_execution_node( // Save task name before consuming the request let task_name = query_plan_request.query.task_name.clone(); - // Add prefix envs to the context - context.add_envs(and_item.envs.iter()); let QueryPlanRequest { query, plan_options } = query_plan_request; let query = Arc::new(query); let nested_plan = diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/prefix_env_path_lookup/package.json b/crates/vite_task_plan/tests/plan_snapshots/fixtures/prefix_env_path_lookup/package.json new file mode 100644 index 000000000..372537b0e --- /dev/null +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/prefix_env_path_lookup/package.json @@ -0,0 +1,5 @@ +{ + "scripts": { + "check": "PATH= vtt" + } +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/prefix_env_path_lookup/snapshots.toml b/crates/vite_task_plan/tests/plan_snapshots/fixtures/prefix_env_path_lookup/snapshots.toml new file mode 100644 index 000000000..2ed5ce8f0 --- /dev/null +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/prefix_env_path_lookup/snapshots.toml @@ -0,0 +1,3 @@ +[[plan]] +name = "prefix_path_hides_tool_binary" +args = ["run", "check"] diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/prefix_env_path_lookup/snapshots/query_prefix_path_hides_tool_binary.snap b/crates/vite_task_plan/tests/plan_snapshots/fixtures/prefix_env_path_lookup/snapshots/query_prefix_path_hides_tool_binary.snap new file mode 100644 index 000000000..ee075ad18 --- /dev/null +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/prefix_env_path_lookup/snapshots/query_prefix_path_hides_tool_binary.snap @@ -0,0 +1 @@ +Failed to find executable vtt under cwd / with PATH: : cannot find binary path \ No newline at end of file diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/prefix_env_path_lookup/snapshots/task_graph.jsonc b/crates/vite_task_plan/tests/plan_snapshots/fixtures/prefix_env_path_lookup/snapshots/task_graph.jsonc new file mode 100644 index 000000000..c898c069b --- /dev/null +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/prefix_env_path_lookup/snapshots/task_graph.jsonc @@ -0,0 +1,44 @@ +// task graph +[ + { + "key": [ + "/", + "check" + ], + "node": { + "task_display": { + "package_name": "", + "task_name": "check", + "package_path": "/" + }, + "resolved_config": { + "commands": [ + "PATH= vtt" + ], + "resolved_options": { + "cwd": "/", + "cache_config": { + "env_config": { + "fingerprinted_envs": [], + "untracked_env": [ + "" + ] + }, + "input_config": { + "includes_auto": true, + "positive_globs": [], + "negative_globs": [] + }, + "output_config": { + "includes_auto": false, + "positive_globs": [], + "negative_globs": [] + } + } + } + }, + "source": "PackageJsonScript" + }, + "neighbors": [] + } +] diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/prefix_env_path_lookup/vite-task.json b/crates/vite_task_plan/tests/plan_snapshots/fixtures/prefix_env_path_lookup/vite-task.json new file mode 100644 index 000000000..d548edfac --- /dev/null +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/prefix_env_path_lookup/vite-task.json @@ -0,0 +1,3 @@ +{ + "cache": true +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/main.rs b/crates/vite_task_plan/tests/plan_snapshots/main.rs index 72641b404..988152ae4 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/main.rs +++ b/crates/vite_task_plan/tests/plan_snapshots/main.rs @@ -193,8 +193,8 @@ fn run_case_inner( "folder '{fixture_name}' should be a workspace root" ); - let fake_bin_dir = std::path::PathBuf::from(std::env::var_os("CARGO_MANIFEST_DIR").unwrap()) - .join("tests/plan_snapshots/fake-bin"); + let manifest_dir = std::path::PathBuf::from(std::env::var_os("CARGO_MANIFEST_DIR").unwrap()); + let fake_bin_dir = manifest_dir.join("tests/plan_snapshots/fake-bin"); let combined_path = Arc::::from(std::ffi::OsString::from(fake_bin_dir.to_str().unwrap())); diff --git a/crates/vite_task_plan/tests/plan_snapshots/redact.rs b/crates/vite_task_plan/tests/plan_snapshots/redact.rs index e34702ab1..b0fdd7230 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/redact.rs +++ b/crates/vite_task_plan/tests/plan_snapshots/redact.rs @@ -105,8 +105,7 @@ pub fn redact_snapshot(value: &impl Serialize, workspace_root: &str) -> serde_js .to_owned(); let mut json_value = serde_json::to_value(value).unwrap(); - // On Windows, paths might use either backslashes or forward slashes - // Try both variants for workspace_root, manifest_dir, and tools_dir + // On Windows, paths might use either backslashes or forward slashes. let workspace_root_forward = workspace_root.cow_replace('\\', "/"); let manifest_dir_forward = manifest_dir.as_str().cow_replace('\\', "/"); let tools_dir_forward = tools_dir_str.as_str().cow_replace('\\', "/");