Skip to content
Merged
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
10 changes: 10 additions & 0 deletions packages/create-nx-workspace/bin/create-nx-workspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,16 @@ async function normalizeArgsMiddleware(
if (!templateProvided && !presetProvided) {
const workspaceName = (argv.name as string) || (argv._[0] as string);
writeAiOutput(buildTemplateRequiredResult(workspaceName));
await recordStat({
nxVersion,
command: 'create-nx-workspace',
useCloud: false,
meta: {
type: 'cancel',
flowVariant: getFlowVariant(),
aiAgent: true,
},
});
process.exit(0); // Exit 0 - JSON output has success: false, AI parses that
}

Expand Down
21 changes: 20 additions & 1 deletion packages/create-nx-workspace/src/create-sandbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,29 @@ export async function createSandbox(packageManager: PackageManager) {
installSpinner.succeed();
} catch (e) {
installSpinner.fail();
const logFile = e instanceof CnwError ? e.logFile : undefined;
const exitCode = e instanceof CnwError ? e.exitCode : undefined;
const message = e instanceof Error ? e.message : String(e);

const lines = [`Failed to install dependencies`];
if (message?.trim()) {
lines.push(message.trim());
}
if (exitCode != null) {
lines.push(`Exit code: ${exitCode}`);
}
if (logFile) {
lines.push(`Log file: ${logFile}`);
}
lines.push(
`\nPlease verify that "${install}" runs successfully in a temporary directory.`
);

throw new CnwError(
'SANDBOX_FAILED',
`Failed to install dependencies: ${message}`
lines.join('\n'),
logFile,
exitCode ?? undefined
);
} finally {
installSpinner.stop();
Expand Down
20 changes: 16 additions & 4 deletions packages/create-nx-workspace/src/utils/child-process-utils.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { spawn, exec } from 'child_process';
import { writeFileSync } from 'fs';
import { join } from 'path';
import { CreateNxWorkspaceError } from './error-utils';
import { CnwError } from './error-utils';

/**
* Use spawn only for interactive shells
Expand Down Expand Up @@ -47,16 +47,28 @@ export function execAndWait(
return new Promise<{ code: number; stdout: string }>((res, rej) => {
exec(
command,
{ cwd, env: { ...process.env, NX_DAEMON: 'false' }, windowsHide: false },
{
cwd,
env: { ...process.env, NX_DAEMON: 'false' },
windowsHide: false,
maxBuffer: 1024 * 1024 * 10, // 10MB — default 1MB can be exceeded by verbose PM output
},
(error, stdout, stderr) => {
if (error) {
if (silenceErrors) {
rej();
} else {
const logFile = join(cwd, 'error.log');
writeFileSync(logFile, `${stdout}\n${stderr}`);
const message = stderr && stderr.trim().length ? stderr : stdout;
rej(new CreateNxWorkspaceError(message, error.code, logFile));
const message =
stderr && stderr.trim().length
? stderr
: stdout && stdout.trim().length
? stdout
: `Command failed with exit code ${error.code ?? 'unknown'}. See ${logFile} for details.`;
rej(
new CnwError('UNKNOWN', message, logFile, error.code ?? undefined)
);
}
} else {
res({ code: 0, stdout });
Expand Down
11 changes: 7 additions & 4 deletions packages/create-nx-workspace/src/utils/package-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,10 @@ export function getPackageManagerCommand(
switch (packageManager) {
case 'yarn':
const useBerry = +pmMajor >= 2;
const installCommand = 'yarn install --silent';
// Don't use --silent so that error output is captured on failure.
// Since install is run via exec() (not spawn), output is captured
// in memory and never shown to the terminal.
const installCommand = 'yarn install';
return {
preInstall: `yarn set version ${pmVersion}`,
install: useBerry
Expand All @@ -69,23 +72,23 @@ export function getPackageManagerCommand(
useExec = true;
}
return {
install: 'pnpm install --no-frozen-lockfile --silent --ignore-scripts',
install: 'pnpm install --no-frozen-lockfile --ignore-scripts',
exec: useExec ? 'pnpm exec' : 'pnpx',
globalAdd: 'pnpm add -g',
getRegistryUrl: 'pnpm config get registry',
};

case 'npm':
return {
install: 'npm install --silent --ignore-scripts',
install: 'npm install --ignore-scripts',
exec: 'npx',
globalAdd: 'npm i -g',
getRegistryUrl: 'npm config get registry',
};
case 'bun':
// bun doesn't current support programmatically reading config https://github.com/oven-sh/bun/issues/7140
return {
install: 'bun install --silent --ignore-scripts',
install: 'bun install --ignore-scripts',
exec: 'bunx',
globalAdd: 'bun install -g',
};
Expand Down
Loading