Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Changelog

- **Fixed** `vp run` now preserves pathname expansion from Unix package-script shells, so unquoted patterns such as `packages/*/src` expand before they are passed to the underlying command ([#573](https://github.com/voidzero-dev/vite-task/issues/573)).
- **Fixed** An invalid glob in `--filter` no longer shows its error message twice ([#763](https://github.com/voidzero-dev/vite-task/pull/763)).
- **Changed** The detailed summary from `vp run --verbose` and `vp run --last-details` now shows each underlying cause of an error on its own line ([#761](https://github.com/voidzero-dev/vite-task/pull/761)).
- **Added** Remote caching. Configure an endpoint with the workspace's `cache: { remote: { url } }` or `VP_REMOTE_CACHE_URL`, and choose access with `--remote-cache=off|read|read-write` or `VP_REMOTE_CACHE`. The default is `read` with an endpoint and `off` without one. After a local cache miss, `vp run` looks the task up in the remote cache and, on a hit, restores its outputs and caches it locally. The task output and the run summary show which hits came from the remote cache. A failed read is just a cache miss, with the failure as its reason. In `read-write` mode, `vp run` also uploads the results of successful, cacheable tasks after caching them locally. A failed upload doesn't fail the task; the run summary shows a warning instead. Ctrl-C, or a failing task, stops remote cache requests right away, and a task still being looked up doesn't start. Tasks can opt out with `cache: { remote: false }`. Requests use the proxy environment variables or, on macOS and Windows, the system proxy settings ([#727](https://github.com/voidzero-dev/vite-task/pull/727), [#755](https://github.com/voidzero-dev/vite-task/pull/755), [#756](https://github.com/voidzero-dev/vite-task/pull/756), [#757](https://github.com/voidzero-dev/vite-task/pull/757), [#764](https://github.com/voidzero-dev/vite-task/pull/764), [#771](https://github.com/voidzero-dev/vite-task/pull/771), [#772](https://github.com/voidzero-dev/vite-task/pull/772)).
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"name": "package-script-glob",
"private": true,
"scripts": {
"unquoted-glob": "vtt print packages/*/src",
"and-glob": "vtt print before && vtt print packages/*/src",
"quoted-glob": "vtt print \"packages/*/src\"",
"nested-vt-glob": "vt run print-paths prefix packages/*/src",
"nested-vt-quoted-glob": "vt run print-paths prefix \"packages/*/src\"",
"nested-vt-glob-fails": "vt run fail-with-code packages/*/src",
"print-paths": "vtt print",
"fail-with-code": "vtt exit 23"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
a
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
b
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
[[e2e]]
name = "unquoted_glob_expands_on_unix"
cfg = "unix"
comment = """
Unquoted pathname patterns in package scripts are executed by the platform shell, matching package-manager script semantics on Unix.
"""
steps = [["vt", "run", "unquoted-glob"]]

[[e2e]]
name = "unquoted_glob_stays_static_on_windows"
cfg = "windows"
comment = """
Because `cmd.exe` does not perform pathname expansion, an unquoted pattern stays on the static execution path and is passed to the program literally.
"""
steps = [["vt", "run", "unquoted-glob"]]

[[e2e]]
name = "unquoted_glob_preserves_extra_args_on_unix"
cfg = "unix"
comment = """
Extra arguments passed to `vt run` are shell-escaped and appended after the package script. Shell operators inside one argument must remain literal after Unix shell expansion.
"""
steps = [["vt", "run", "unquoted-glob", "tail && vtt exit 31"]]

[[e2e]]
name = "unquoted_glob_preserves_extra_args_on_windows"
cfg = "windows"
comment = """
The static Windows execution path preserves extra argument boundaries without routing them through `cmd.exe`. Shell operators inside one argument must remain literal.
"""
steps = [["vt", "run", "unquoted-glob", "tail && vtt exit 31"]]

[[e2e]]
name = "and_list_with_glob_uses_one_shell_on_unix"
cfg = "unix"
comment = """
If any command in an `&&` list needs pathname expansion, the complete list is kept intact for the Unix shell so ordering and short-circuit semantics are preserved.
"""
steps = [["vt", "run", "and-glob"]]

[[e2e]]
name = "and_list_with_glob_stays_static_on_windows"
cfg = "windows"
comment = """
Since the pathname pattern has no special meaning to `cmd.exe`, the existing static `&&` planning remains available on Windows while preserving ordering and literal arguments.
"""
steps = [["vt", "run", "and-glob"]]

[[e2e]]
name = "quoted_glob_stays_literal"
comment = """
Quoted pathname patterns remain literal for the child command to interpret on every platform.
"""
steps = [["vt", "run", "quoted-glob"]]

[[e2e]]
name = "nested_vt_quoted_glob_stays_command_owned"
comment = """
A quoted pathname pattern remains one literal argument when passed to a nested Vite+ command, so the command can implement portable glob semantics itself.
"""
steps = [["vt", "run", "nested-vt-quoted-glob"]]

[[e2e]]
name = "nested_vt_receives_expanded_glob_on_unix"
cfg = "unix"
comment = """
An unquoted pathname pattern in a package script that invokes nested `vt run` is expanded by the shell before the new `vt` process starts. This verifies PATH lookup and preserves both preceding extra arguments and expanded paths.
"""
steps = [["vt", "run", "nested-vt-glob"]]

[[e2e]]
name = "nested_vt_receives_literal_glob_on_windows"
cfg = "windows"
comment = """
On Windows, the static planner keeps nested `vt run` in process and forwards the pattern literally while preserving the preceding extra argument.
"""
steps = [["vt", "run", "nested-vt-glob"]]

[[e2e]]
name = "nested_vt_propagates_exit_code_on_unix"
cfg = "unix"
comment = """
The shell fallback used for an unquoted pathname pattern preserves a nested `vt run` failure exit code after Unix shell expansion.
"""
steps = [["vt", "run", "nested-vt-glob-fails"]]

[[e2e]]
name = "nested_vt_propagates_exit_code_on_windows"
cfg = "windows"
comment = """
The static Windows path for an unquoted pathname pattern preserves a nested `vt run` failure exit code.
"""
steps = [["vt", "run", "nested-vt-glob-fails"]]
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# and_list_with_glob_stays_static_on_windows

Since the pathname pattern has no special meaning to `cmd.exe`, the existing static `&&` planning remains available on Windows while preserving ordering and literal arguments.

## `vt run and-glob`

```
$ vtt print before && vtt print packages/*/src ⊘ cache disabled
before
packages/*/src
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# and_list_with_glob_uses_one_shell_on_unix

If any command in an `&&` list needs pathname expansion, the complete list is kept intact for the Unix shell so ordering and short-circuit semantics are preserved.

## `vt run and-glob`

```
$ vtt print before && vtt print packages/*/src ⊘ cache disabled
before
packages/a/src packages/b/src
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# nested_vt_propagates_exit_code_on_unix

The shell fallback used for an unquoted pathname pattern preserves a nested `vt run` failure exit code after Unix shell expansion.

## `vt run nested-vt-glob-fails`

**Exit code:** 23

```
$ vt run fail-with-code packages/*/src ⊘ cache disabled
$ vtt exit 23 packages/a/src packages/b/src ⊘ cache disabled
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# nested_vt_propagates_exit_code_on_windows

The static Windows path for an unquoted pathname pattern preserves a nested `vt run` failure exit code.

## `vt run nested-vt-glob-fails`

**Exit code:** 23

```
$ vt run fail-with-code packages/*/src ⊘ cache disabled
$ vtt exit 23 packages/*/src ⊘ cache disabled
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# nested_vt_quoted_glob_stays_command_owned

A quoted pathname pattern remains one literal argument when passed to a nested Vite+ command, so the command can implement portable glob semantics itself.

## `vt run nested-vt-quoted-glob`

```
$ vtt print prefix 'packages/*/src' ⊘ cache disabled
prefix packages/*/src
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# nested_vt_receives_expanded_glob_on_unix

An unquoted pathname pattern in a package script that invokes nested `vt run` is expanded by the shell before the new `vt` process starts. This verifies PATH lookup and preserves both preceding extra arguments and expanded paths.

## `vt run nested-vt-glob`

```
$ vt run print-paths prefix packages/*/src ⊘ cache disabled
$ vtt print prefix packages/a/src packages/b/src ⊘ cache disabled
prefix packages/a/src packages/b/src
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# nested_vt_receives_literal_glob_on_windows

On Windows, the static planner keeps nested `vt run` in process and forwards the pattern literally while preserving the preceding extra argument.

## `vt run nested-vt-glob`

```
$ vt run print-paths prefix packages/*/src ⊘ cache disabled
$ vtt print prefix packages/*/src ⊘ cache disabled
prefix packages/*/src
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# quoted_glob_stays_literal

Quoted pathname patterns remain literal for the child command to interpret on every platform.

## `vt run quoted-glob`

```
$ vtt print "packages/*/src" ⊘ cache disabled
packages/*/src
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# unquoted_glob_expands_on_unix

Unquoted pathname patterns in package scripts are executed by the platform shell, matching package-manager script semantics on Unix.

## `vt run unquoted-glob`

```
$ vtt print packages/*/src ⊘ cache disabled
packages/a/src packages/b/src
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# unquoted_glob_preserves_extra_args_on_unix

Extra arguments passed to `vt run` are shell-escaped and appended after the package script. Shell operators inside one argument must remain literal after Unix shell expansion.

## `vt run unquoted-glob 'tail && vtt exit 31'`

```
$ vtt print packages/*/src ⊘ cache disabled
packages/a/src packages/b/src tail && vtt exit 31
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# unquoted_glob_preserves_extra_args_on_windows

The static Windows execution path preserves extra argument boundaries without routing them through `cmd.exe`. Shell operators inside one argument must remain literal.

## `vt run unquoted-glob "tail && vtt exit 31"`

```
$ vtt print packages/*/src ⊘ cache disabled
packages/*/src tail && vtt exit 31
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# unquoted_glob_stays_static_on_windows

Because `cmd.exe` does not perform pathname expansion, an unquoted pattern stays on the static execution path and is passed to the program literally.

## `vt run unquoted-glob`

```
$ vtt print packages/*/src ⊘ cache disabled
packages/*/src
```
4 changes: 3 additions & 1 deletion crates/vt_plan/src/plan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,9 @@ async fn plan_task_as_execution_node(
let command_str = command.as_str();
let is_last_command = command_item_index + 1 == commands.len();
// Try to parse the command string as a list of subcommands separated by `&&`
if let Some(parsed_subcommands) = try_parse_as_and_list(command_str) {
// `cmd.exe` passes wildcard characters through literally. Only shells with
// POSIX pathname expansion need to preserve unquoted patterns for shell execution.
if let Some(parsed_subcommands) = try_parse_as_and_list(command_str, cfg!(unix)) {
let and_item_count = parsed_subcommands.len();
for (and_item_index, (and_item, add_item_span)) in
parsed_subcommands.into_iter().enumerate()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
{
"scripts": {
"pipe-test": "echo hello | node -e \"process.stdin.pipe(process.stdout)\""
"pipe-test": "echo hello | node -e \"process.stdin.pipe(process.stdout)\"",
"unquoted-glob": "vtt print packages/*/src",
"quoted-glob": "vtt print \"packages/*/src\""
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,12 @@
[[plan]]
name = "shell_fallback_for_pipe_command"
args = ["run", "pipe-test"]

[[plan]]
name = "shell_fallback_for_unquoted_glob"
args = ["run", "unquoted-glob"]
platform = "unix"

[[plan]]
name = "direct_spawn_for_quoted_glob"
args = ["run", "quoted-glob"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// run quoted-glob
{
"graph": [
{
"key": [
"<workspace>/",
"quoted-glob"
],
"node": {
"task_display": {
"package_name": "",
"task_name": "quoted-glob",
"package_path": "<workspace>/"
},
"items": [
{
"execution_item_display": {
"task_display": {
"package_name": "",
"task_name": "quoted-glob",
"package_path": "<workspace>/"
},
"command": "vtt print \"packages/*/src\"",
"cwd": "<workspace>/"
},
"kind": {
"Leaf": {
"Spawn": {
"cache_metadata": {
"spawn_fingerprint": {
"cwd": "",
"program_fingerprint": {
"OutsideWorkspace": {
"program_name": "vtt"
}
},
"args": [
"print",
"packages/*/src"
],
"env_fingerprints": {
"fingerprinted_envs": {},
"untracked_env_config": [
"<default untracked envs>"
]
}
},
"execution_cache_key": {
"UserTask": {
"task_name": "quoted-glob",
"command_item_index": 0,
"and_item_index": 0,
"extra_args": [],
"package_path": ""
}
},
"input_config": {
"includes_auto": true,
"positive_globs": [],
"negative_globs": []
},
"output_config": {
"includes_auto": true,
"positive_globs": [],
"negative_globs": []
},
"remote_cache": null
},
"spawn_command": {
"program_path": "<tools>/vtt",
"args": [
"print",
"packages/*/src"
],
"spawn_envs": {
"FORCE_COLOR": "1",
"PATH": "<workspace>/node_modules/.bin:<tools>",
"VP_RUN": "1"
},
"cwd": "<workspace>/"
}
}
}
}
}
]
},
"neighbors": []
}
],
"concurrency_limit": 4
}
Loading