diff --git a/CHANGELOG.md b/CHANGELOG.md index 65f3c73a2..601ba9eb9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ # Changelog +- **Changed** In `@voidzero-dev/vite-task-client`, a `getEnvs` query that matches every env name, `{ prefix: '' }` or `*`, now returns nothing instead of every environment variable, and no longer adds them to the cache key ([#976](https://github.com/voidzero-dev/vite-task/pull/976)). - **Added** `vp run --json` prints every package and task in the workspace, with each task's `dependsOn` resolved to task IDs, as one JSON document for scripts, editors and coding agents. It runs nothing and, like `vp run` without a task, loads every package's config. It prints the same document from any directory in the workspace: indented in a terminal, on one line when captured. Its `$schema` field points to a JSON Schema that describes each field, which `vp run` writes to the system temp directory ([#948](https://github.com/voidzero-dev/vite-task/pull/948)). - **Fixed** On Linux, where every user shares the temp folder `/tmp`, the helper files `vp run` writes there, such as the library that tracks file accesses, now go in a folder only the current user can write to, like `/tmp/fspy-1000`. Before, they went in a folder such as `/tmp/fspy` that belonged to whoever ran `vp run` first: running a different version as another user failed, and the same version used files that user could replace ([#947](https://github.com/voidzero-dev/vite-task/pull/947)). - **Fixed** On macOS, task commands that use `sh` or `bash` now behave as they do on Linux in four cases. A `while read` loop with a redirect under `set -e` no longer exits the script. An `EXIT` trap now sees the exit status in `$?`, and a bare `exit` in the trap keeps that status, so a failed task is no longer reported as successful. `$BASH` is now set when the command runs as `bash`. The bundled shell is updated to an Oils build from master that has these fixes ([#939](https://github.com/voidzero-dev/vite-task/pull/939)). diff --git a/crates/vt_bin/tests/e2e_snapshots/fixtures/vite_build_cache/snapshots.toml b/crates/vt_bin/tests/e2e_snapshots/fixtures/vite_build_cache/snapshots.toml index 4248aa961..a510d240d 100644 --- a/crates/vt_bin/tests/e2e_snapshots/fixtures/vite_build_cache/snapshots.toml +++ b/crates/vt_bin/tests/e2e_snapshots/fixtures/vite_build_cache/snapshots.toml @@ -179,3 +179,57 @@ steps = [ ], ], comment = "cache miss: envs changed (NODE_ENV changed)" }, ] + +[[e2e]] +name = "vite_load_env_without_prefix_ignores_unrelated_env" +comment = """ +A config calling `loadEnv(mode, dir, '')` makes Vite send `getEnvs({ prefix: '' })`, a query that matches every env name. The runner answers it with nothing and records nothing, so `loadEnv` returns the task's own env from `process.env`: `APP_LABEL`, which the task declares, but not `UNRELATED`. A change to `UNRELATED` doesn't make the next run miss. +""" +ignore = true +steps = [ + { argv = [ + "vt", + "run", + "--cache", + "build-load-all-env", + ], envs = [ + [ + "APP_LABEL", + "alpha", + ], + [ + "UNRELATED", + "one", + ], + ], comment = "first run: loadEnv sees the declared APP_LABEL only" }, + { argv = [ + "vt", + "run", + "--cache", + "build-load-all-env", + ], envs = [ + [ + "APP_LABEL", + "alpha", + ], + [ + "UNRELATED", + "two", + ], + ], comment = "cache hit: UNRELATED changed, but it isn't in the cache key" }, + { argv = [ + "vt", + "run", + "--cache", + "build-load-all-env", + ], envs = [ + [ + "APP_LABEL", + "bravo", + ], + [ + "UNRELATED", + "two", + ], + ], comment = "cache miss: the declared APP_LABEL changed" }, +] diff --git a/crates/vt_bin/tests/e2e_snapshots/fixtures/vite_build_cache/snapshots/vite_load_env_without_prefix_ignores_unrelated_env.md b/crates/vt_bin/tests/e2e_snapshots/fixtures/vite_build_cache/snapshots/vite_load_env_without_prefix_ignores_unrelated_env.md new file mode 100644 index 000000000..e4875cd1c --- /dev/null +++ b/crates/vt_bin/tests/e2e_snapshots/fixtures/vite_build_cache/snapshots/vite_load_env_without_prefix_ignores_unrelated_env.md @@ -0,0 +1,33 @@ +# vite_load_env_without_prefix_ignores_unrelated_env + +A config calling `loadEnv(mode, dir, '')` makes Vite send `getEnvs({ prefix: '' })`, a query that matches every env name. The runner answers it with nothing and records nothing, so `loadEnv` returns the task's own env from `process.env`: `APP_LABEL`, which the task declares, but not `UNRELATED`. A change to `UNRELATED` doesn't make the next run miss. + +## `APP_LABEL=alpha UNRELATED=one vt run --cache build-load-all-env` + +first run: loadEnv sees the declared APP_LABEL only + +``` +$ vite build --config vite.load-all-env.config.js +APP_LABEL=alpha UNRELATED=(unset) +``` + +## `APP_LABEL=alpha UNRELATED=two vt run --cache build-load-all-env` + +cache hit: UNRELATED changed, but it isn't in the cache key + +``` +$ vite build --config vite.load-all-env.config.js ◉ cache hit, replaying +APP_LABEL=alpha UNRELATED=(unset) + +--- +vt run: cache hit. +``` + +## `APP_LABEL=bravo UNRELATED=two vt run --cache build-load-all-env` + +cache miss: the declared APP_LABEL changed + +``` +$ vite build --config vite.load-all-env.config.js ○ cache miss: env 'APP_LABEL' changed, executing +APP_LABEL=bravo UNRELATED=(unset) +``` diff --git a/crates/vt_bin/tests/e2e_snapshots/fixtures/vite_build_cache/vite-task.json b/crates/vt_bin/tests/e2e_snapshots/fixtures/vite_build_cache/vite-task.json index 44a96b59b..985080a4b 100644 --- a/crates/vt_bin/tests/e2e_snapshots/fixtures/vite_build_cache/vite-task.json +++ b/crates/vt_bin/tests/e2e_snapshots/fixtures/vite_build_cache/vite-task.json @@ -6,6 +6,10 @@ // every `VITE_*` env via `getEnvs`, so the glob + match-set are // fingerprinted automatically. "cache": true + }, + "build-load-all-env": { + "command": "vite build --config vite.load-all-env.config.js", + "cache": { "env": ["APP_LABEL"] } } } } diff --git a/crates/vt_bin/tests/e2e_snapshots/fixtures/vite_build_cache/vite.load-all-env.config.js b/crates/vt_bin/tests/e2e_snapshots/fixtures/vite_build_cache/vite.load-all-env.config.js new file mode 100644 index 000000000..d0fc00639 --- /dev/null +++ b/crates/vt_bin/tests/e2e_snapshots/fixtures/vite_build_cache/vite.load-all-env.config.js @@ -0,0 +1,9 @@ +import { defineConfig, loadEnv } from 'vite'; + +// Reads the whole env the way frameworks such as SvelteKit do, with +// `loadEnv(mode, dir, '')`, and prints what it got for two variables. +export default defineConfig(({ mode }) => { + const env = loadEnv(mode, process.cwd(), ''); + console.log(`APP_LABEL=${env.APP_LABEL ?? '(unset)'} UNRELATED=${env.UNRELATED ?? '(unset)'}`); + return { logLevel: 'silent' }; +}); diff --git a/crates/vt_server/src/lib.rs b/crates/vt_server/src/lib.rs index dd079d172..cf031600a 100644 --- a/crates/vt_server/src/lib.rs +++ b/crates/vt_server/src/lib.rs @@ -157,6 +157,13 @@ impl Handler for Recorder { query: &IpcEnvQuery<'_>, tracked: bool, ) -> Result>, Arc>, vt_glob::env::EnvGlobError> { + // A query that matches every name, like the one Vite's + // `loadEnv(mode, dir, '')` sends, gets nothing and records nothing. + // Recording it would put every variable of the parent env in the cache + // key, so per-run ones, such as a CI run ID, would make every run miss. + if matches!(query, IpcEnvQuery::Prefix("") | IpcEnvQuery::Glob("*")) { + return Ok(FxHashMap::default()); + } let key = match query { IpcEnvQuery::Glob(pattern) => EnvQuery::Glob(Arc::from(*pattern)), IpcEnvQuery::Prefix(prefix) => EnvQuery::Prefix(Arc::from(*prefix)), diff --git a/packages/vite-task-client/src/index.d.ts b/packages/vite-task-client/src/index.d.ts index f61f2882a..92e16fcbd 100644 --- a/packages/vite-task-client/src/index.d.ts +++ b/packages/vite-task-client/src/index.d.ts @@ -51,6 +51,10 @@ export function getEnv(name: string, options?: { * dependency, so adding, removing, or changing a matching env invalidates * this run's cache entry. * + * A query that matches every env name, `{ prefix: '' }` or `*`, returns an + * empty object and records nothing: read the task's own env from + * `process.env` instead. + * * Has no effect on `process.env`; the caller decides what to do with the * returned values. Returns an empty object when not running inside a runner. * diff --git a/packages/vite-task-client/src/index.js b/packages/vite-task-client/src/index.js index 7a135f65d..c1e69ccf4 100644 --- a/packages/vite-task-client/src/index.js +++ b/packages/vite-task-client/src/index.js @@ -116,6 +116,10 @@ export function getEnv(name, options) { * dependency, so adding, removing, or changing a matching env invalidates * this run's cache entry. * + * A query that matches every env name, `{ prefix: '' }` or `*`, returns an + * empty object and records nothing: read the task's own env from + * `process.env` instead. + * * Has no effect on `process.env`; the caller decides what to do with the * returned values. Returns an empty object when not running inside a runner. *