@ultimat3/cli 20.1.2 → 20.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -40,6 +40,7 @@ import { execOutput } from './exec';
40
40
  import { msg } from './messages';
41
41
  import type { CommandResult, Finding, JsonValue, StepResult } from './output';
42
42
  import { quoteArg } from './shell-quote';
43
+ import { testEnvOverrides } from './test-dotenv';
43
44
  import { testPasses } from './test-passes';
44
45
  import type { TestFile } from './test-select';
45
46
  import type { TestType } from './verify-tests';
@@ -165,6 +166,13 @@ export interface RunShardsOptions {
165
166
  readonly affected?: AffectedSelection;
166
167
  /** Everything after the caller's `--`, forwarded to every pass and printed in the reproduce. */
167
168
  readonly passthrough?: readonly string[];
169
+ /**
170
+ * This process's own environment, as `exec.ts` would otherwise hand it whole to the spawned
171
+ * child. Optional and defaulted to `Bun.env`: every real caller's is `Bun.env` already (`x
172
+ * test`/`x verify` read `CommandContext.env`, itself `Bun.env`), so the default is not a
173
+ * fallback so much as a seam this file's own tests use to hand it a fixture instead.
174
+ */
175
+ readonly env?: Readonly<Record<string, string | undefined>>;
168
176
  }
169
177
 
170
178
  /**
@@ -219,6 +227,11 @@ export const failureOf = (code: number, files: number, plan: ReproduceOptions):
219
227
  */
220
228
  export async function runShards(options: RunShardsOptions): Promise<CommandResult> {
221
229
  const only = options.only;
230
+ // Computed ONCE per invocation, never per pass: every pass spawns from the same `root` and the
231
+ // same parent env, so the leaked-key set cannot differ pass to pass.
232
+ const envOverrides: Record<string, string | undefined> = {
233
+ ...testEnvOverrides(options.root, options.env ?? Bun.env),
234
+ };
222
235
  const passes = testPasses({
223
236
  files: options.files,
224
237
  workers: options.workers,
@@ -241,7 +254,14 @@ export async function runShards(options: RunShardsOptions): Promise<CommandResul
241
254
  }),
242
255
  {
243
256
  cwd: options.root,
244
- ...(only === undefined ? {} : { env: { ULTIMATE_TEST_WORKER: String(only) } }),
257
+ ...(Object.keys(envOverrides).length === 0 && only === undefined
258
+ ? {}
259
+ : {
260
+ env: {
261
+ ...envOverrides,
262
+ ...(only === undefined ? {} : { ULTIMATE_TEST_WORKER: String(only) }),
263
+ },
264
+ }),
245
265
  },
246
266
  );
247
267
  const plan = planOf(options, pass);
@@ -65,6 +65,13 @@ export type HostCheck = (root: string) => Promise<readonly Finding[]>;
65
65
  export interface VerifyContext {
66
66
  readonly root: string;
67
67
  readonly runner: Runner;
68
+ /**
69
+ * This process's own environment. Optional and defaulted to `Bun.env` at every reader
70
+ * (`verify-tests.ts`'s `runSerial`/`runType`): every real caller's IS `Bun.env` already
71
+ * (`cmd-verify.ts` passes `ctx.env`, itself `Bun.env`), so the default only matters to a test
72
+ * that constructs a `VerifyContext` fixture and never mentions `env`.
73
+ */
74
+ readonly env?: Readonly<Record<string, string | undefined>>;
68
75
  readonly hostChecks?: Partial<Record<VerifyStepName, HostCheck>>;
69
76
  /**
70
77
  * How wide the parallel test steps go. Absent means `defaultWorkers()` — a knob, never a
@@ -6,6 +6,7 @@ import type { Runner } from './exec';
6
6
  import { execOutput } from './exec';
7
7
  import type { Finding } from './output';
8
8
  import { countsOf } from './test-counts';
9
+ import { testEnvOverrides } from './test-dotenv';
9
10
  import type { TestFile } from './test-select';
10
11
  import { failureOf, testArgs } from './test-shards';
11
12
  import type { StepOutcome } from './verify-step';
@@ -20,6 +21,8 @@ export interface ParallelRunOptions {
20
21
  readonly workers: number;
21
22
  /** Carried into the `fix:` so a failure reproduces as `x test <type> --workers N`. */
22
23
  readonly type: TestType;
24
+ /** This process's own environment. Optional and defaulted to `Bun.env` — see `VerifyContext.env`. */
25
+ readonly env?: Readonly<Record<string, string | undefined>>;
23
26
  }
24
27
 
25
28
  /**
@@ -38,7 +41,11 @@ export interface ParallelRunOptions {
38
41
  export async function runParallel(options: ParallelRunOptions): Promise<StepOutcome> {
39
42
  const files = options.files.map((file) => file.path);
40
43
  const workers = Math.max(1, Math.min(Math.trunc(options.workers), files.length || 1));
41
- const result = await options.runner(testArgs({ files, workers }), { cwd: options.root });
44
+ const envOverrides = testEnvOverrides(options.root, options.env ?? Bun.env);
45
+ const result = await options.runner(testArgs({ files, workers }), {
46
+ cwd: options.root,
47
+ ...(Object.keys(envOverrides).length === 0 ? {} : { env: envOverrides }),
48
+ });
42
49
  // `failureOf` is `x test`'s own, imported rather than restated: the two paths report the SAME
43
50
  // failed `bun test`, so a second literal here is two `cause:` strings and two `fix:` lines free
44
51
  // to drift — and the one that drifts is the gate's, which is the one an agent reads first.
@@ -15,6 +15,7 @@ import { TEST_TYPES } from '@ultimat3/testing';
15
15
  import { checkEvalBaselines, checkEvalCoverage, checkEvalRecording } from './app-evals';
16
16
  import { APP_CONFIG_FILE } from './app-root';
17
17
  import { countsOf } from './test-counts';
18
+ import { testEnvOverrides } from './test-dotenv';
18
19
  import type { TestFile } from './test-select';
19
20
  import { discoverTests } from './test-select';
20
21
  import { defaultWorkers } from './test-workers';
@@ -201,7 +202,11 @@ export const resetTestDiscovery = (): void => discovered.clear();
201
202
 
202
203
  const runSerial = async (ctx: VerifyContext, type: TestType): Promise<StepOutcome> => {
203
204
  const command = testStepCommand(type);
204
- const result = await ctx.runner(command, { cwd: ctx.root });
205
+ const envOverrides = testEnvOverrides(ctx.root, ctx.env ?? Bun.env);
206
+ const result = await ctx.runner(command, {
207
+ cwd: ctx.root,
208
+ ...(Object.keys(envOverrides).length === 0 ? {} : { env: envOverrides }),
209
+ });
205
210
  return {
206
211
  ...fromExec(result, {
207
212
  code: 'X_TEST_FAILED',
@@ -223,6 +228,7 @@ const runType = async (ctx: VerifyContext, type: TestType): Promise<StepOutcome>
223
228
  files,
224
229
  workers: ctx.workers ?? defaultWorkers(),
225
230
  type,
231
+ ...(ctx.env === undefined ? {} : { env: ctx.env }),
226
232
  });
227
233
  };
228
234