Skip to content

Commit 75993eb

Browse files
committed
fix(utils): add silent flag to executeProcess
1 parent c90eea2 commit 75993eb

File tree

3 files changed

+79
-53
lines changed

3 files changed

+79
-53
lines changed

packages/plugin-axe/src/lib/runner/run-axe.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ async function ensureBrowserInstalled(): Promise<void> {
8181
await executeProcess({
8282
command: 'npx',
8383
args: ['playwright-core', 'install', 'chromium'],
84+
silent: true,
8485
});
8586

8687
browserChecked = true;

packages/utils/src/lib/execute-process.int.test.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,4 +136,15 @@ process:complete
136136
{ force: true },
137137
);
138138
});
139+
140+
it('should successfully execute process with silent flag without spinner', async () => {
141+
const result = await executeProcess({
142+
command: 'node',
143+
args: ['-v'],
144+
silent: true,
145+
});
146+
expect(result.code).toBe(0);
147+
expect(result.stdout).toMatch(/v\d{1,2}(\.\d{1,2}){0,2}/);
148+
expect(logger.command).not.toHaveBeenCalled();
149+
});
139150
});

packages/utils/src/lib/execute-process.ts

Lines changed: 67 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ export type ProcessConfig = Omit<
103103
args?: string[];
104104
observer?: ProcessObserver;
105105
ignoreExitCode?: boolean;
106+
silent?: boolean;
106107
};
107108

108109
/**
@@ -127,6 +128,9 @@ export type ProcessObserver = {
127128
/**
128129
* Executes a process and returns a promise with the result as `ProcessResult`.
129130
*
131+
* By default, displays a spinner via `logger.command()`. Use `silent: true` to bypass
132+
* the spinner for commands that may run concurrently (e.g., plugin setup steps).
133+
*
130134
* @example
131135
*
132136
* // sync process execution
@@ -153,62 +157,72 @@ export type ProcessObserver = {
153157
* @param cfg - see {@link ProcessConfig}
154158
*/
155159
export function executeProcess(cfg: ProcessConfig): Promise<ProcessResult> {
156-
const { command, args, observer, ignoreExitCode = false, ...options } = cfg;
160+
const {
161+
command,
162+
args,
163+
observer,
164+
ignoreExitCode = false,
165+
silent = false,
166+
...options
167+
} = cfg;
157168
const { onStdout, onStderr, onError, onComplete } = observer ?? {};
158169

159170
const bin = [command, ...(args ?? [])].join(' ');
160171

161-
return logger.command(
162-
bin,
163-
() =>
164-
new Promise((resolve, reject) => {
165-
const spawnedProcess = spawn(command, args ?? [], {
166-
// shell:true tells Windows to use shell command for spawning a child process
167-
// https://stackoverflow.com/questions/60386867/node-spawn-child-process-not-working-in-windows
168-
shell: true,
169-
windowsHide: true,
170-
...options,
171-
}) as ChildProcessByStdio<Writable, Readable, Readable>;
172-
173-
// eslint-disable-next-line functional/no-let
174-
let stdout = '';
175-
// eslint-disable-next-line functional/no-let
176-
let stderr = '';
177-
// eslint-disable-next-line functional/no-let
178-
let output = ''; // interleaved stdout and stderr
179-
180-
spawnedProcess.stdout.on('data', (data: unknown) => {
181-
const message = String(data);
182-
stdout += message;
183-
output += message;
184-
onStdout?.(message, spawnedProcess);
185-
});
186-
187-
spawnedProcess.stderr.on('data', (data: unknown) => {
188-
const message = String(data);
189-
stderr += message;
190-
output += message;
191-
onStderr?.(message, spawnedProcess);
192-
});
193-
194-
spawnedProcess.on('error', error => {
172+
const worker = () =>
173+
new Promise<ProcessResult>((resolve, reject) => {
174+
const spawnedProcess = spawn(command, args ?? [], {
175+
// shell:true tells Windows to use shell command for spawning a child process
176+
// https://stackoverflow.com/questions/60386867/node-spawn-child-process-not-working-in-windows
177+
shell: true,
178+
windowsHide: true,
179+
...options,
180+
}) as ChildProcessByStdio<Writable, Readable, Readable>;
181+
182+
// eslint-disable-next-line functional/no-let
183+
let stdout = '';
184+
// eslint-disable-next-line functional/no-let
185+
let stderr = '';
186+
// eslint-disable-next-line functional/no-let
187+
let output = ''; // interleaved stdout and stderr
188+
189+
spawnedProcess.stdout.on('data', (data: unknown) => {
190+
const message = String(data);
191+
stdout += message;
192+
output += message;
193+
onStdout?.(message, spawnedProcess);
194+
});
195+
196+
spawnedProcess.stderr.on('data', (data: unknown) => {
197+
const message = String(data);
198+
stderr += message;
199+
output += message;
200+
onStderr?.(message, spawnedProcess);
201+
});
202+
203+
spawnedProcess.on('error', error => {
204+
reject(error);
205+
});
206+
207+
spawnedProcess.on('close', (code, signal) => {
208+
const result: ProcessResult = { bin, code, signal, stdout, stderr };
209+
if (code === 0 || ignoreExitCode) {
210+
logger.debug(output);
211+
onComplete?.();
212+
resolve(result);
213+
} else {
214+
// ensure stdout and stderr are logged to help debug failure
215+
logger.debug(output, { force: true });
216+
const error = new ProcessError(result);
217+
onError?.(error);
195218
reject(error);
196-
});
197-
198-
spawnedProcess.on('close', (code, signal) => {
199-
const result: ProcessResult = { bin, code, signal, stdout, stderr };
200-
if (code === 0 || ignoreExitCode) {
201-
logger.debug(output);
202-
onComplete?.();
203-
resolve(result);
204-
} else {
205-
// ensure stdout and stderr are logged to help debug failure
206-
logger.debug(output, { force: true });
207-
const error = new ProcessError(result);
208-
onError?.(error);
209-
reject(error);
210-
}
211-
});
212-
}),
213-
);
219+
}
220+
});
221+
});
222+
223+
if (silent) {
224+
return worker();
225+
}
226+
227+
return logger.command(bin, worker);
214228
}

0 commit comments

Comments
 (0)