From 7b7e0fd5a27dc181dfe21a9258453098cb87031a Mon Sep 17 00:00:00 2001 From: Charles Lyding <19598772+clydin@users.noreply.github.com> Date: Thu, 4 Dec 2025 21:21:40 -0500 Subject: [PATCH] fix(@angular/cli): correctly spawn package managers on Windows in new abstraction When running E2E tests on Windows, `spawn` was failing to find package manager executables like `npm` because it does not automatically resolve `.cmd` or `.bat` extensions when `shell: false` is used. --- packages/angular/cli/src/package-managers/host.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/angular/cli/src/package-managers/host.ts b/packages/angular/cli/src/package-managers/host.ts index 1d4b441bdc37..82d61031d147 100644 --- a/packages/angular/cli/src/package-managers/host.ts +++ b/packages/angular/cli/src/package-managers/host.ts @@ -13,10 +13,10 @@ * enabling the injection of mock or test-specific implementations. */ -import { spawn } from 'node:child_process'; +import { type SpawnOptions, spawn } from 'node:child_process'; import { Stats } from 'node:fs'; import { mkdtemp, readFile, readdir, rm, stat, writeFile } from 'node:fs/promises'; -import { tmpdir } from 'node:os'; +import { platform, tmpdir } from 'node:os'; import { join } from 'node:path'; import { PackageManagerError } from './error'; @@ -107,10 +107,11 @@ export const NodeJS_HOST: Host = { } = {}, ): Promise<{ stdout: string; stderr: string }> => { const signal = options.timeout ? AbortSignal.timeout(options.timeout) : undefined; + const isWin32 = platform() === 'win32'; return new Promise((resolve, reject) => { - const childProcess = spawn(command, args, { - shell: false, + const spawnOptions = { + shell: isWin32, stdio: options.stdio ?? 'pipe', signal, cwd: options.cwd, @@ -118,7 +119,10 @@ export const NodeJS_HOST: Host = { ...process.env, ...options.env, }, - }); + } satisfies SpawnOptions; + const childProcess = isWin32 + ? spawn(`${command} ${args.join(' ')}`, spawnOptions) + : spawn(command, args, spawnOptions); let stdout = ''; childProcess.stdout?.on('data', (data) => (stdout += data.toString()));