create-nx-workspace
Version:
171 lines (170 loc) • 7.92 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.getInterruptedWorkspaceState = getInterruptedWorkspaceState;
exports.createWorkspace = createWorkspace;
exports.extractConnectUrl = extractConnectUrl;
const node_fs_1 = require("node:fs");
const path_1 = require("path");
const create_empty_workspace_1 = require("./create-empty-workspace");
const create_preset_1 = require("./create-preset");
const create_sandbox_1 = require("./create-sandbox");
const setup_ci_1 = require("./utils/ci/setup-ci");
const error_utils_1 = require("./utils/error-utils");
const git_1 = require("./utils/git/git");
const nx_cloud_1 = require("./utils/nx/nx-cloud");
const output_1 = require("./utils/output");
const get_third_party_preset_1 = require("./utils/preset/get-third-party-preset");
const preset_1 = require("./utils/preset/preset");
const clone_template_1 = require("./utils/template/clone-template");
const child_process_utils_1 = require("./utils/child-process-utils");
const package_manager_1 = require("./utils/package-manager");
// State for SIGINT handler - only set after workspace is fully installed
let workspaceDirectory;
let cloudConnectUrl;
function getInterruptedWorkspaceState() {
return { directory: workspaceDirectory, connectUrl: cloudConnectUrl };
}
async function createWorkspace(preset, options, rawArgs) {
const { packageManager, name, nxCloud, skipGit = false, defaultBase = 'main', commit, cliName, useGitHub, skipGitHubPush = false, verbose = false, } = options;
if (cliName) {
output_1.output.setCliName(cliName ?? 'NX');
}
let directory;
if (options.template) {
if (!options.template.startsWith('nrwl/'))
throw new Error(`Invalid template. Only templates from the 'nrwl' GitHub org are supported.`);
const templateUrl = `https://github.com/${options.template}`;
const workingDir = process.cwd().replace(/\\/g, '/');
directory = (0, path_1.join)(workingDir, name);
const ora = require('ora');
const workspaceSetupSpinner = ora(`Creating workspace from template`).start();
try {
await (0, clone_template_1.cloneTemplate)(templateUrl, name);
// Remove npm lockfile from template since we'll generate the correct one
const npmLockPath = (0, path_1.join)(directory, 'package-lock.json');
if ((0, node_fs_1.existsSync)(npmLockPath)) {
(0, node_fs_1.unlinkSync)(npmLockPath);
}
// Generate package manager specific files (e.g., .yarnrc.yml for Yarn Berry)
(0, package_manager_1.generatePackageManagerFiles)(directory, packageManager);
// Install dependencies with the user's package manager
const pmc = (0, package_manager_1.getPackageManagerCommand)(packageManager);
if (pmc.preInstall) {
await (0, child_process_utils_1.execAndWait)(pmc.preInstall, directory);
}
await (0, child_process_utils_1.execAndWait)(pmc.install, directory);
// Mark workspace as ready for SIGINT handler
workspaceDirectory = directory;
workspaceSetupSpinner.succeed(`Successfully created the workspace: ${directory}`);
}
catch (e) {
workspaceSetupSpinner.fail();
throw e;
}
// Connect to Nx Cloud for template flow
if (nxCloud !== 'skip') {
await (0, nx_cloud_1.connectToNxCloudForTemplate)(directory, 'create-nx-workspace', useGitHub);
}
}
else {
// Preset flow - existing behavior
const tmpDir = await (0, create_sandbox_1.createSandbox)(packageManager);
const workspaceGlobs = getWorkspaceGlobsFromPreset(preset);
// nx new requires a preset currently. We should probably make it optional.
directory = await (0, create_empty_workspace_1.createEmptyWorkspace)(tmpDir, name, packageManager, {
...options,
preset,
workspaceGlobs,
});
// Mark workspace as ready for SIGINT handler
workspaceDirectory = directory;
// If the preset is a third-party preset, we need to call createPreset to install it
// For first-party presets, it will be created by createEmptyWorkspace instead.
// In createEmptyWorkspace, it will call `nx new` -> `@nx/workspace newGenerator` -> `@nx/workspace generatePreset`.
const thirdPartyPackageName = (0, get_third_party_preset_1.getPackageNameFromThirdPartyPreset)(preset);
if (thirdPartyPackageName) {
await (0, create_preset_1.createPreset)(thirdPartyPackageName, options, packageManager, directory);
}
}
const isTemplate = !!options.template;
// Generate CI for preset flow (not template)
// When nxCloud === 'yes' (from simplified prompt), use GitHub as the CI provider
if (nxCloud !== 'skip' && !isTemplate) {
const ciProvider = nxCloud === 'yes' ? 'github' : nxCloud;
await (0, setup_ci_1.setupCI)(directory, ciProvider, packageManager);
}
let pushedToVcs = git_1.VcsPushStatus.SkippedGit;
if (!skipGit) {
try {
await (0, git_1.initializeGitRepo)(directory, { defaultBase, commit });
// Push to GitHub if commit was made, GitHub push is not skipped, and:
// - CI provider is GitHub (preset flow with CLI arg), OR
// - Nx Cloud enabled via simplified prompt (nxCloud === 'yes')
if (commit &&
!skipGitHubPush &&
(nxCloud === 'github' || nxCloud === 'yes')) {
pushedToVcs = await (0, git_1.pushToGitHub)(directory, {
skipGitHubPush,
name,
defaultBase,
verbose,
});
}
}
catch (e) {
if (e instanceof Error) {
output_1.output.error({
title: 'Could not initialize git repository',
bodyLines: (0, error_utils_1.mapErrorToBodyLines)(e),
});
}
else {
console.error(e);
}
}
}
// Create onboarding URL AFTER git operations so getVcsRemoteInfo() can detect the repo
let connectUrl;
let nxCloudInfo;
if (nxCloud !== 'skip') {
const token = (0, nx_cloud_1.readNxCloudToken)(directory);
connectUrl = await (0, nx_cloud_1.createNxCloudOnboardingUrl)(nxCloud, token, directory, useGitHub);
// Store for SIGINT handler
cloudConnectUrl = connectUrl;
nxCloudInfo = await (0, nx_cloud_1.getNxCloudInfo)(connectUrl, pushedToVcs, options.completionMessageKey);
}
else if (isTemplate && nxCloud === 'skip') {
// Show nx connect message when user skips cloud in template flow
nxCloudInfo = (0, nx_cloud_1.getSkippedNxCloudInfo)();
}
return {
nxCloudInfo,
directory,
pushedToVcs,
connectUrl,
};
}
function extractConnectUrl(text) {
const urlPattern = /(https:\/\/[^\s]+\/connect\/[^\s]+)/g;
const match = text.match(urlPattern);
return match ? match[0] : null;
}
function getWorkspaceGlobsFromPreset(preset) {
// Should match how apps are created in `packages/workspace/src/generators/preset/preset.ts`.
switch (preset) {
case preset_1.Preset.AngularMonorepo:
case preset_1.Preset.Expo:
case preset_1.Preset.Express:
case preset_1.Preset.Nest:
case preset_1.Preset.NextJs:
case preset_1.Preset.NodeMonorepo:
case preset_1.Preset.Nuxt:
case preset_1.Preset.ReactNative:
case preset_1.Preset.ReactMonorepo:
case preset_1.Preset.VueMonorepo:
case preset_1.Preset.WebComponents:
return ['apps/*'];
default:
return ['packages/*'];
}
}