create-nx-workspace 22.2.0-beta.2 → 22.2.0-beta.3
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.
- package/bin/create-nx-workspace.d.ts.map +1 -1
- package/bin/create-nx-workspace.js +70 -39
- package/package.json +1 -1
- package/src/create-workspace-options.d.ts +3 -0
- package/src/create-workspace-options.d.ts.map +1 -1
- package/src/create-workspace.d.ts.map +1 -1
- package/src/create-workspace.js +58 -14
- package/src/internal-utils/prompts.d.ts +9 -0
- package/src/internal-utils/prompts.d.ts.map +1 -1
- package/src/internal-utils/prompts.js +73 -0
- package/src/utils/child-process-utils.d.ts.map +1 -1
- package/src/utils/child-process-utils.js +6 -1
- package/src/utils/git/git.d.ts.map +1 -1
- package/src/utils/git/git.js +27 -10
- package/src/utils/nx/ab-testing.d.ts +16 -0
- package/src/utils/nx/ab-testing.d.ts.map +1 -1
- package/src/utils/nx/ab-testing.js +145 -10
- package/src/utils/nx/messages.d.ts +21 -31
- package/src/utils/nx/messages.d.ts.map +1 -1
- package/src/utils/nx/messages.js +32 -44
- package/src/utils/nx/nx-cloud.d.ts +5 -2
- package/src/utils/nx/nx-cloud.d.ts.map +1 -1
- package/src/utils/nx/nx-cloud.js +45 -14
- package/src/utils/template/clone-template.d.ts +2 -0
- package/src/utils/template/clone-template.d.ts.map +1 -0
- package/src/utils/template/clone-template.js +34 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-nx-workspace.d.ts","sourceRoot":"","sources":["../../../../packages/create-nx-workspace/bin/create-nx-workspace.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,OAAO,EACL,sBAAsB,EAEvB,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EAAiB,MAAM,EAAE,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"create-nx-workspace.d.ts","sourceRoot":"","sources":["../../../../packages/create-nx-workspace/bin/create-nx-workspace.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,OAAO,EACL,sBAAsB,EAEvB,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EAAiB,MAAM,EAAE,MAAM,4BAA4B,CAAC;AAgCnE,UAAU,aAAc,SAAQ,sBAAsB;IACpD,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,GAAG,UAAU,CAAC;IAChC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,UAAU,aAAc,SAAQ,aAAa;IAC3C,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,eAAe,GAAG,YAAY,GAAG,YAAY,CAAC;IAC9D,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC9B;AAED,UAAU,cAAe,SAAQ,aAAa;IAC5C,KAAK,EAAE,OAAO,CAAC;IACf,aAAa,EAAE,YAAY,GAAG,YAAY,CAAC;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,SAAS,GAAG,MAAM,GAAG,QAAQ,CAAC;IACvC,UAAU,EAAE,OAAO,CAAC;IACpB,UAAU,EAAE,OAAO,CAAC;IACpB,cAAc,EAAE,OAAO,CAAC;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,cAAc,EAAE,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAC;IAC3C,aAAa,EAAE,MAAM,GAAG,SAAS,GAAG,YAAY,CAAC;CAClD;AAED,UAAU,gBAAiB,SAAQ,aAAa;IAC9C,KAAK,EAAE,SAAS,CAAC;IACjB,aAAa,EAAE,YAAY,GAAG,YAAY,CAAC;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,OAAO,CAAC;IACvB,cAAc,EAAE,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAC;IAC3C,aAAa,EAAE,MAAM,GAAG,SAAS,GAAG,YAAY,CAAC;IACjD,OAAO,EAAE,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC;IAC1C,GAAG,EAAE,OAAO,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,YAAa,SAAQ,aAAa;IAC1C,KAAK,EAAE,KAAK,CAAC;IACb,aAAa,EAAE,YAAY,GAAG,YAAY,CAAC;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,MAAM,GAAG,QAAQ,CAAC;IAClC,aAAa,EAAE,MAAM,GAAG,SAAS,GAAG,YAAY,CAAC;CAClD;AAED,UAAU,aAAc,SAAQ,aAAa;IAC3C,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,YAAY,GAAG,YAAY,CAAC;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,KAAK,GAAG,MAAM,CAAC;IAC3D,MAAM,EAAE,OAAO,CAAC;IAChB,cAAc,EAAE,MAAM,GAAG,MAAM,CAAC;CACjC;AAED,UAAU,qBAAsB,SAAQ,aAAa;IACnD,KAAK,EAAE,SAAS,CAAC;CAClB;AAED,KAAK,SAAS,GACV,aAAa,GACb,cAAc,GACd,gBAAgB,GAChB,YAAY,GACZ,aAAa,GACb,qBAAqB,CAAC;AAE1B,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,IAAI,CAAC,SAAS,CA8IrB,CAAC;AAuK7B,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAaxD"}
|
|
@@ -130,9 +130,10 @@ exports.commandsObject = yargs
|
|
|
130
130
|
await main(argv).catch((error) => {
|
|
131
131
|
const { version } = require('../package.json');
|
|
132
132
|
output_1.output.error({
|
|
133
|
-
title: `
|
|
133
|
+
title: `Failed to create workspace (v${version})`,
|
|
134
|
+
bodyLines: (0, error_utils_1.mapErrorToBodyLines)(error),
|
|
134
135
|
});
|
|
135
|
-
|
|
136
|
+
process.exit(1);
|
|
136
137
|
});
|
|
137
138
|
}, [normalizeArgsMiddleware])
|
|
138
139
|
.help('help', chalk.dim `Show help`)
|
|
@@ -159,12 +160,17 @@ async function main(parsedArgs) {
|
|
|
159
160
|
command: 'create-nx-workspace',
|
|
160
161
|
useCloud: parsedArgs.nxCloud !== 'skip',
|
|
161
162
|
meta: [
|
|
163
|
+
// User sees one of: setupCI (preset flow) or setupNxCloudV2 (template flow)
|
|
162
164
|
ab_testing_1.messages.codeOfSelectedPromptMessage('setupCI'),
|
|
163
|
-
|
|
165
|
+
// User sees one of: setupNxCloud (preset flow) or setupNxCloudV2 (template flow)
|
|
166
|
+
ab_testing_1.messages.codeOfSelectedPromptMessage('setupNxCloudV2') ||
|
|
167
|
+
ab_testing_1.messages.codeOfSelectedPromptMessage('setupNxCloud'),
|
|
164
168
|
parsedArgs.nxCloud,
|
|
165
169
|
rawArgs.nxCloud,
|
|
166
170
|
workspaceInfo.pushedToVcs,
|
|
171
|
+
`flow-variant-${(0, ab_testing_1.getFlowVariant)()}`,
|
|
167
172
|
],
|
|
173
|
+
directory: workspaceInfo.directory,
|
|
168
174
|
});
|
|
169
175
|
if (parsedArgs.nxCloud && workspaceInfo.nxCloudInfo) {
|
|
170
176
|
process.stdout.write(workspaceInfo.nxCloudInfo);
|
|
@@ -188,53 +194,78 @@ async function normalizeArgsMiddleware(argv) {
|
|
|
188
194
|
output_1.output.log({
|
|
189
195
|
title: "Let's create a new workspace [https://nx.dev/getting-started/intro]",
|
|
190
196
|
});
|
|
191
|
-
// Record stat for initial invocation before any prompts
|
|
192
|
-
await (0, ab_testing_1.recordStat)({
|
|
193
|
-
nxVersion: nx_version_1.nxVersion,
|
|
194
|
-
command: 'create-nx-workspace',
|
|
195
|
-
meta: ['start'],
|
|
196
|
-
useCloud: argv.nxCloud !== 'skip',
|
|
197
|
-
});
|
|
198
197
|
argv.workspaces ??= true;
|
|
199
198
|
argv.useProjectJson ??= !argv.workspaces;
|
|
200
199
|
try {
|
|
201
200
|
argv.name = await determineFolder(argv);
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
201
|
+
const workingDir = process.cwd().replace(/\\/g, '/');
|
|
202
|
+
const directory = require('path').join(workingDir, argv.name);
|
|
203
|
+
const template = await (0, prompts_1.determineTemplate)(argv);
|
|
204
|
+
// Old (start) vs new (start-v2) flows
|
|
205
|
+
const startPrefix = (0, ab_testing_1.getFlowVariant)() === '1' ? 'start-v2' : 'start';
|
|
206
|
+
await (0, ab_testing_1.recordStat)({
|
|
207
|
+
nxVersion: nx_version_1.nxVersion,
|
|
208
|
+
command: 'create-nx-workspace',
|
|
209
|
+
meta: [startPrefix],
|
|
210
|
+
useCloud: argv.nxCloud !== 'skip',
|
|
211
|
+
directory,
|
|
212
|
+
});
|
|
213
|
+
if (template !== 'custom') {
|
|
214
|
+
// Template flow - uses npm and 'main' branch by default
|
|
215
|
+
argv.template = template;
|
|
216
|
+
const aiAgents = await (0, prompts_1.determineAiAgents)(argv);
|
|
217
|
+
const nxCloud = argv.skipGit === true ? 'skip' : await (0, prompts_1.determineNxCloudV2)(argv);
|
|
218
|
+
const completionMessageKey = nxCloud === 'skip'
|
|
219
|
+
? undefined
|
|
220
|
+
: ab_testing_1.messages.completionMessageOfSelectedPrompt('setupNxCloudV2');
|
|
221
|
+
Object.assign(argv, {
|
|
222
|
+
nxCloud,
|
|
223
|
+
useGitHub: nxCloud !== 'skip',
|
|
224
|
+
completionMessageKey,
|
|
225
|
+
packageManager: 'npm',
|
|
226
|
+
defaultBase: 'main',
|
|
227
|
+
aiAgents,
|
|
228
|
+
});
|
|
206
229
|
}
|
|
207
230
|
else {
|
|
208
|
-
|
|
209
|
-
|
|
231
|
+
// Preset flow - existing behavior
|
|
232
|
+
if (!argv.preset || (0, preset_1.isKnownPreset)(argv.preset)) {
|
|
233
|
+
argv.stack = await determineStack(argv);
|
|
234
|
+
const presetOptions = await determinePresetOptions(argv);
|
|
235
|
+
Object.assign(argv, presetOptions);
|
|
210
236
|
}
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
title: `Could not find preset "${argv.preset}"`,
|
|
215
|
-
bodyLines: (0, error_utils_1.mapErrorToBodyLines)(e),
|
|
216
|
-
});
|
|
237
|
+
else {
|
|
238
|
+
try {
|
|
239
|
+
(0, get_third_party_preset_1.getPackageNameFromThirdPartyPreset)(argv.preset);
|
|
217
240
|
}
|
|
218
|
-
|
|
219
|
-
|
|
241
|
+
catch (e) {
|
|
242
|
+
if (e instanceof Error) {
|
|
243
|
+
output_1.output.error({
|
|
244
|
+
title: `Could not find preset "${argv.preset}"`,
|
|
245
|
+
bodyLines: (0, error_utils_1.mapErrorToBodyLines)(e),
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
249
|
+
console.error(e);
|
|
250
|
+
}
|
|
251
|
+
process.exit(1);
|
|
220
252
|
}
|
|
221
|
-
process.exit(1);
|
|
222
253
|
}
|
|
254
|
+
const packageManager = await (0, prompts_1.determinePackageManager)(argv);
|
|
255
|
+
const aiAgents = await (0, prompts_1.determineAiAgents)(argv);
|
|
256
|
+
const defaultBase = await (0, prompts_1.determineDefaultBase)(argv);
|
|
257
|
+
const nxCloud = argv.skipGit === true ? 'skip' : await (0, prompts_1.determineNxCloud)(argv);
|
|
258
|
+
const useGitHub = nxCloud === 'skip'
|
|
259
|
+
? undefined
|
|
260
|
+
: nxCloud === 'github' || (await (0, prompts_1.determineIfGitHubWillBeUsed)(argv));
|
|
261
|
+
Object.assign(argv, {
|
|
262
|
+
nxCloud,
|
|
263
|
+
useGitHub,
|
|
264
|
+
packageManager,
|
|
265
|
+
defaultBase,
|
|
266
|
+
aiAgents,
|
|
267
|
+
});
|
|
223
268
|
}
|
|
224
|
-
const packageManager = await (0, prompts_1.determinePackageManager)(argv);
|
|
225
|
-
const aiAgents = await (0, prompts_1.determineAiAgents)(argv);
|
|
226
|
-
const defaultBase = await (0, prompts_1.determineDefaultBase)(argv);
|
|
227
|
-
const nxCloud = argv.skipGit === true ? 'skip' : await (0, prompts_1.determineNxCloud)(argv);
|
|
228
|
-
const useGitHub = nxCloud === 'skip'
|
|
229
|
-
? undefined
|
|
230
|
-
: nxCloud === 'github' || (await (0, prompts_1.determineIfGitHubWillBeUsed)(argv));
|
|
231
|
-
Object.assign(argv, {
|
|
232
|
-
nxCloud,
|
|
233
|
-
useGitHub,
|
|
234
|
-
packageManager,
|
|
235
|
-
defaultBase,
|
|
236
|
-
aiAgents,
|
|
237
|
-
});
|
|
238
269
|
}
|
|
239
270
|
catch (e) {
|
|
240
271
|
console.error(e);
|
package/package.json
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { NxCloud } from './utils/nx/nx-cloud';
|
|
2
|
+
import type { CompletionMessageKey } from './utils/nx/messages';
|
|
2
3
|
import { PackageManager } from './utils/package-manager';
|
|
3
4
|
export interface CreateWorkspaceOptions {
|
|
4
5
|
name: string;
|
|
5
6
|
packageManager: PackageManager;
|
|
6
7
|
nxCloud: NxCloud;
|
|
7
8
|
useGitHub?: boolean;
|
|
9
|
+
template?: string;
|
|
10
|
+
completionMessageKey?: CompletionMessageKey;
|
|
8
11
|
/**
|
|
9
12
|
* @description Enable interactive mode with presets
|
|
10
13
|
* @default true
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-workspace-options.d.ts","sourceRoot":"","sources":["../../../../packages/create-nx-workspace/src/create-workspace-options.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAEzD,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,cAAc,CAAC;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE;QACP,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,KAAK,EAAE,CAAC;CACpB;AAED,eAAO,MAAM,eAAe,6DAMlB,CAAC;AACX,MAAM,MAAM,KAAK,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC;AACrD,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,KAAK,EAAE,MAAM,CAMjD,CAAC"}
|
|
1
|
+
{"version":3,"file":"create-workspace-options.d.ts","sourceRoot":"","sources":["../../../../packages/create-nx-workspace/src/create-workspace-options.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAC9C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAChE,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAEzD,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,cAAc,CAAC;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oBAAoB,CAAC,EAAE,oBAAoB,CAAC;IAC5C;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE;QACP,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,KAAK,EAAE,CAAC;CACpB;AAED,eAAO,MAAM,eAAe,6DAMlB,CAAC;AACX,MAAM,MAAM,KAAK,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC;AACrD,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,KAAK,EAAE,MAAM,CAMjD,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-workspace.d.ts","sourceRoot":"","sources":["../../../../packages/create-nx-workspace/src/create-workspace.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"create-workspace.d.ts","sourceRoot":"","sources":["../../../../packages/create-nx-workspace/src/create-workspace.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AAGpE,OAAO,EAGL,aAAa,EACd,MAAM,iBAAiB,CAAC;AAczB,wBAAsB,eAAe,CAAC,CAAC,SAAS,sBAAsB,EACpE,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,CAAC,EACV,OAAO,CAAC,EAAE,CAAC;;;;GAwJZ;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAI7D"}
|
package/src/create-workspace.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createWorkspace = createWorkspace;
|
|
4
4
|
exports.extractConnectUrl = extractConnectUrl;
|
|
5
|
+
const path_1 = require("path");
|
|
5
6
|
const create_empty_workspace_1 = require("./create-empty-workspace");
|
|
6
7
|
const create_preset_1 = require("./create-preset");
|
|
7
8
|
const create_sandbox_1 = require("./create-sandbox");
|
|
@@ -12,27 +13,62 @@ const nx_cloud_1 = require("./utils/nx/nx-cloud");
|
|
|
12
13
|
const output_1 = require("./utils/output");
|
|
13
14
|
const get_third_party_preset_1 = require("./utils/preset/get-third-party-preset");
|
|
14
15
|
const preset_1 = require("./utils/preset/preset");
|
|
16
|
+
const clone_template_1 = require("./utils/template/clone-template");
|
|
17
|
+
const child_process_utils_1 = require("./utils/child-process-utils");
|
|
15
18
|
async function createWorkspace(preset, options, rawArgs) {
|
|
16
19
|
const { packageManager, name, nxCloud, skipGit = false, defaultBase = 'main', commit, cliName, useGitHub, skipGitHubPush = false, verbose = false, } = options;
|
|
17
20
|
if (cliName) {
|
|
18
21
|
output_1.output.setCliName(cliName ?? 'NX');
|
|
19
22
|
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
23
|
+
let directory;
|
|
24
|
+
if (options.template) {
|
|
25
|
+
if (!options.template.startsWith('nrwl/'))
|
|
26
|
+
throw new Error(`Invalid template. Only templates from the 'nrwl' GitHub org are supported.`);
|
|
27
|
+
const templateUrl = `https://github.com/${options.template}`;
|
|
28
|
+
const workingDir = process.cwd().replace(/\\/g, '/');
|
|
29
|
+
directory = (0, path_1.join)(workingDir, name);
|
|
30
|
+
const ora = require('ora');
|
|
31
|
+
const workspaceSetupSpinner = ora(`Creating workspace from template`).start();
|
|
32
|
+
try {
|
|
33
|
+
await (0, clone_template_1.cloneTemplate)(templateUrl, name);
|
|
34
|
+
// Install dependencies (template flow always uses npm)
|
|
35
|
+
await (0, child_process_utils_1.execAndWait)('npm install --silent --ignore-scripts', directory);
|
|
36
|
+
workspaceSetupSpinner.succeed(`Successfully created the workspace: ${directory}`);
|
|
37
|
+
}
|
|
38
|
+
catch (e) {
|
|
39
|
+
workspaceSetupSpinner.fail();
|
|
40
|
+
throw e;
|
|
41
|
+
}
|
|
42
|
+
// Connect to Nx Cloud for template flow
|
|
43
|
+
if (nxCloud !== 'skip') {
|
|
44
|
+
await (0, nx_cloud_1.connectToNxCloudForTemplate)(directory, 'create-nx-workspace', useGitHub);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
// Preset flow - existing behavior
|
|
49
|
+
const tmpDir = await (0, create_sandbox_1.createSandbox)(packageManager);
|
|
50
|
+
const workspaceGlobs = getWorkspaceGlobsFromPreset(preset);
|
|
51
|
+
// nx new requires a preset currently. We should probably make it optional.
|
|
52
|
+
directory = await (0, create_empty_workspace_1.createEmptyWorkspace)(tmpDir, name, packageManager, {
|
|
53
|
+
...options,
|
|
54
|
+
preset,
|
|
55
|
+
workspaceGlobs,
|
|
56
|
+
});
|
|
57
|
+
// If the preset is a third-party preset, we need to call createPreset to install it
|
|
58
|
+
// For first-party presets, it will be created by createEmptyWorkspace instead.
|
|
59
|
+
// In createEmptyWorkspace, it will call `nx new` -> `@nx/workspace newGenerator` -> `@nx/workspace generatePreset`.
|
|
60
|
+
const thirdPartyPackageName = (0, get_third_party_preset_1.getPackageNameFromThirdPartyPreset)(preset);
|
|
61
|
+
if (thirdPartyPackageName) {
|
|
62
|
+
await (0, create_preset_1.createPreset)(thirdPartyPackageName, options, packageManager, directory);
|
|
63
|
+
}
|
|
30
64
|
}
|
|
65
|
+
const isTemplate = !!options.template;
|
|
31
66
|
let connectUrl;
|
|
32
67
|
let nxCloudInfo;
|
|
33
68
|
if (nxCloud !== 'skip') {
|
|
34
69
|
const token = (0, nx_cloud_1.readNxCloudToken)(directory);
|
|
35
|
-
|
|
70
|
+
// Only generate CI for preset flow (not template)
|
|
71
|
+
if (!isTemplate && nxCloud !== 'yes') {
|
|
36
72
|
await (0, setup_ci_1.setupCI)(directory, nxCloud, packageManager);
|
|
37
73
|
}
|
|
38
74
|
connectUrl = await (0, nx_cloud_1.createNxCloudOnboardingUrl)(nxCloud, token, directory, useGitHub);
|
|
@@ -41,8 +77,12 @@ async function createWorkspace(preset, options, rawArgs) {
|
|
|
41
77
|
if (!skipGit) {
|
|
42
78
|
try {
|
|
43
79
|
await (0, git_1.initializeGitRepo)(directory, { defaultBase, commit, connectUrl });
|
|
44
|
-
// Push to GitHub if commit was made, GitHub push is not skipped, and
|
|
45
|
-
|
|
80
|
+
// Push to GitHub if commit was made, GitHub push is not skipped, and:
|
|
81
|
+
// - CI provider is GitHub (preset flow), OR
|
|
82
|
+
// - Using template flow with Nx Cloud enabled (yes)
|
|
83
|
+
if (commit &&
|
|
84
|
+
!skipGitHubPush &&
|
|
85
|
+
(nxCloud === 'github' || (isTemplate && nxCloud === 'yes'))) {
|
|
46
86
|
pushedToVcs = await (0, git_1.pushToGitHub)(directory, {
|
|
47
87
|
skipGitHubPush,
|
|
48
88
|
name,
|
|
@@ -64,7 +104,11 @@ async function createWorkspace(preset, options, rawArgs) {
|
|
|
64
104
|
}
|
|
65
105
|
}
|
|
66
106
|
if (connectUrl) {
|
|
67
|
-
nxCloudInfo = await (0, nx_cloud_1.getNxCloudInfo)(
|
|
107
|
+
nxCloudInfo = await (0, nx_cloud_1.getNxCloudInfo)(connectUrl, pushedToVcs, options.completionMessageKey);
|
|
108
|
+
}
|
|
109
|
+
else if (isTemplate && nxCloud === 'skip') {
|
|
110
|
+
// Show nx connect message when user skips cloud in template flow
|
|
111
|
+
nxCloudInfo = (0, nx_cloud_1.getSkippedNxCloudInfo)();
|
|
68
112
|
}
|
|
69
113
|
return {
|
|
70
114
|
nxCloudInfo,
|
|
@@ -5,10 +5,19 @@ import { Agent } from '../create-workspace-options';
|
|
|
5
5
|
export declare function determineNxCloud(parsedArgs: yargs.Arguments<{
|
|
6
6
|
nxCloud: NxCloud;
|
|
7
7
|
}>): Promise<NxCloud>;
|
|
8
|
+
export declare function determineNxCloudV2(parsedArgs: yargs.Arguments<{
|
|
9
|
+
nxCloud?: string;
|
|
10
|
+
interactive?: boolean;
|
|
11
|
+
}>): Promise<'github' | 'skip'>;
|
|
8
12
|
export declare function determineIfGitHubWillBeUsed(parsedArgs: yargs.Arguments<{
|
|
9
13
|
nxCloud: NxCloud;
|
|
10
14
|
useGitHub?: boolean;
|
|
11
15
|
}>): Promise<boolean>;
|
|
16
|
+
export declare function determineTemplate(parsedArgs: yargs.Arguments<{
|
|
17
|
+
template?: string;
|
|
18
|
+
preset?: string;
|
|
19
|
+
interactive?: boolean;
|
|
20
|
+
}>): Promise<string | 'custom'>;
|
|
12
21
|
export declare function determineAiAgents(parsedArgs: yargs.Arguments<{
|
|
13
22
|
aiAgents?: Agent[];
|
|
14
23
|
interactive?: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../../../../packages/create-nx-workspace/src/internal-utils/prompts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../../../../packages/create-nx-workspace/src/internal-utils/prompts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAW/B,OAAO,EAEL,cAAc,EAEf,MAAM,0BAA0B,CAAC;AAElC,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAE/C,OAAO,EACL,KAAK,EAGN,MAAM,6BAA6B,CAAC;AAErC,wBAAsB,gBAAgB,CACpC,UAAU,EAAE,KAAK,CAAC,SAAS,CAAC;IAAE,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC,GAChD,OAAO,CAAC,OAAO,CAAC,CAQlB;AAED,wBAAsB,kBAAkB,CACtC,UAAU,EAAE,KAAK,CAAC,SAAS,CAAC;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,GACvE,OAAO,CAAC,QAAQ,GAAG,MAAM,CAAC,CAiC5B;AAED,wBAAsB,2BAA2B,CAC/C,UAAU,EAAE,KAAK,CAAC,SAAS,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,GACrE,OAAO,CAAC,OAAO,CAAC,CAelB;AA4BD,wBAAsB,iBAAiB,CACrC,UAAU,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC,GACD,OAAO,CAAC,MAAM,GAAG,QAAQ,CAAC,CA2C5B;AAED,wBAAsB,iBAAiB,CACrC,UAAU,EAAE,KAAK,CAAC,SAAS,CAAC;IAAE,QAAQ,CAAC,EAAE,KAAK,EAAE,CAAC;IAAC,WAAW,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,GACzE,OAAO,CAAC,KAAK,EAAE,CAAC,CAElB;AAqBD,wBAAsB,oBAAoB,CACxC,UAAU,EAAE,KAAK,CAAC,SAAS,CAAC;IAAE,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,GACpD,OAAO,CAAC,MAAM,CAAC,CAyBjB;AAED,wBAAsB,uBAAuB,CAC3C,UAAU,EAAE,KAAK,CAAC,SAAS,CAAC;IAAE,cAAc,EAAE,MAAM,CAAA;CAAE,CAAC,GACtD,OAAO,CAAC,cAAc,CAAC,CAoCzB"}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.determineNxCloud = determineNxCloud;
|
|
4
|
+
exports.determineNxCloudV2 = determineNxCloudV2;
|
|
4
5
|
exports.determineIfGitHubWillBeUsed = determineIfGitHubWillBeUsed;
|
|
6
|
+
exports.determineTemplate = determineTemplate;
|
|
5
7
|
exports.determineAiAgents = determineAiAgents;
|
|
6
8
|
exports.determineDefaultBase = determineDefaultBase;
|
|
7
9
|
exports.determinePackageManager = determinePackageManager;
|
|
@@ -25,6 +27,35 @@ async function determineNxCloud(parsedArgs) {
|
|
|
25
27
|
return nxCloudPrompt('setupCI');
|
|
26
28
|
}
|
|
27
29
|
}
|
|
30
|
+
async function determineNxCloudV2(parsedArgs) {
|
|
31
|
+
// Provided via flag
|
|
32
|
+
if (parsedArgs.nxCloud) {
|
|
33
|
+
return parsedArgs.nxCloud === 'skip' ? 'skip' : 'github';
|
|
34
|
+
}
|
|
35
|
+
// Non-interactive mode
|
|
36
|
+
if (!parsedArgs.interactive || (0, is_ci_1.isCI)()) {
|
|
37
|
+
return 'skip';
|
|
38
|
+
}
|
|
39
|
+
// Show simplified prompt
|
|
40
|
+
const { message, choices, initial, footer, hint } = ab_testing_1.messages.getPrompt('setupNxCloudV2');
|
|
41
|
+
const promptConfig = {
|
|
42
|
+
name: 'nxCloud',
|
|
43
|
+
message,
|
|
44
|
+
type: 'autocomplete',
|
|
45
|
+
choices,
|
|
46
|
+
initial,
|
|
47
|
+
}; // types in enquirer are not up to date
|
|
48
|
+
if (footer) {
|
|
49
|
+
promptConfig.footer = () => footer;
|
|
50
|
+
}
|
|
51
|
+
if (hint) {
|
|
52
|
+
promptConfig.hint = () => hint;
|
|
53
|
+
}
|
|
54
|
+
const result = await enquirer.prompt([
|
|
55
|
+
promptConfig,
|
|
56
|
+
]);
|
|
57
|
+
return result.nxCloud;
|
|
58
|
+
}
|
|
28
59
|
async function determineIfGitHubWillBeUsed(parsedArgs) {
|
|
29
60
|
if (parsedArgs.nxCloud === 'yes' || parsedArgs.nxCloud === 'circleci') {
|
|
30
61
|
if (parsedArgs?.useGitHub)
|
|
@@ -64,6 +95,48 @@ async function nxCloudPrompt(key) {
|
|
|
64
95
|
return a.NxCloud;
|
|
65
96
|
});
|
|
66
97
|
}
|
|
98
|
+
async function determineTemplate(parsedArgs) {
|
|
99
|
+
if (parsedArgs.template)
|
|
100
|
+
return parsedArgs.template;
|
|
101
|
+
if (parsedArgs.preset)
|
|
102
|
+
return 'custom';
|
|
103
|
+
if (!parsedArgs.interactive || (0, is_ci_1.isCI)())
|
|
104
|
+
return 'custom';
|
|
105
|
+
// A/B test: shouldUseTemplateFlow() determines if user sees template or preset flow
|
|
106
|
+
if (!(0, ab_testing_1.shouldUseTemplateFlow)())
|
|
107
|
+
return 'custom';
|
|
108
|
+
const { template } = await enquirer.prompt([
|
|
109
|
+
{
|
|
110
|
+
name: 'template',
|
|
111
|
+
message: 'Which starter do you want to use?',
|
|
112
|
+
type: 'autocomplete',
|
|
113
|
+
choices: [
|
|
114
|
+
{
|
|
115
|
+
name: 'nrwl/empty-template',
|
|
116
|
+
message: 'TypeScript (minimal TypeScript monorepo without projects)',
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
name: 'nrwl/typescript-template',
|
|
120
|
+
message: 'NPM Packages (monorepo with TypeScript packages ready to publish)',
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
name: 'nrwl/react-template',
|
|
124
|
+
message: 'React (fullstack monorepo with React and Express)',
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
name: 'nrwl/angular-template',
|
|
128
|
+
message: 'Angular (fullstack monorepo with Angular and Express)',
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
name: 'custom',
|
|
132
|
+
message: 'Custom (more options for frameworks, test runners, etc.)',
|
|
133
|
+
},
|
|
134
|
+
],
|
|
135
|
+
initial: 0,
|
|
136
|
+
},
|
|
137
|
+
]);
|
|
138
|
+
return template;
|
|
139
|
+
}
|
|
67
140
|
async function determineAiAgents(parsedArgs) {
|
|
68
141
|
return parsedArgs.aiAgents ?? [];
|
|
69
142
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"child-process-utils.d.ts","sourceRoot":"","sources":["../../../../../packages/create-nx-workspace/src/utils/child-process-utils.ts"],"names":[],"mappings":"AAKA;;GAEG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"child-process-utils.d.ts","sourceRoot":"","sources":["../../../../../packages/create-nx-workspace/src/utils/child-process-utils.ts"],"names":[],"mappings":"AAKA;;GAEG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,oBA+BxE;AAED,wBAAgB,WAAW,CACzB,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,EACX,aAAa,UAAQ;UAEM,MAAM;YAAU,MAAM;GAoBlD"}
|
|
@@ -11,7 +11,12 @@ const error_utils_1 = require("./error-utils");
|
|
|
11
11
|
*/
|
|
12
12
|
function spawnAndWait(command, args, cwd) {
|
|
13
13
|
return new Promise((res, rej) => {
|
|
14
|
-
|
|
14
|
+
// Combine command and args into a single string to avoid DEP0190 warning
|
|
15
|
+
// (passing args with shell: true is deprecated)
|
|
16
|
+
const fullCommand = [command, ...args]
|
|
17
|
+
.map((arg) => (arg.includes(' ') ? `"${arg}"` : arg))
|
|
18
|
+
.join(' ');
|
|
19
|
+
const childProcess = (0, child_process_1.spawn)(fullCommand, {
|
|
15
20
|
cwd,
|
|
16
21
|
stdio: 'inherit',
|
|
17
22
|
env: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../../../../../packages/create-nx-workspace/src/utils/git/git.ts"],"names":[],"mappings":"AAMA,oBAAY,aAAa;IACvB,WAAW,gBAAgB;IAC3B,sBAAsB,2BAA2B;IACjD,iBAAiB,sBAAsB;IACvC,UAAU,eAAe;CAC1B;AAED,qBAAa,sBAAuB,SAAQ,KAAK;IAC/C,SAAgB,KAAK,yBAAyB;gBAElC,OAAO,EAAE,MAAM;CAI5B;AAED,wBAAsB,eAAe,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAQ1E;
|
|
1
|
+
{"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../../../../../packages/create-nx-workspace/src/utils/git/git.ts"],"names":[],"mappings":"AAMA,oBAAY,aAAa;IACvB,WAAW,gBAAgB;IAC3B,sBAAsB,2BAA2B;IACjD,iBAAiB,sBAAsB;IACvC,UAAU,eAAe;CAC1B;AAED,qBAAa,sBAAuB,SAAQ,KAAK;IAC/C,SAAgB,KAAK,yBAAyB;gBAElC,OAAO,EAAE,MAAM;CAI5B;AAED,wBAAsB,eAAe,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAQ1E;AA0ED,wBAAsB,iBAAiB,CACrC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE;IACP,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1D,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B,iBAsDF;AAED,wBAAsB,YAAY,CAChC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE;IACP,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,GACA,OAAO,CAAC,aAAa,CAAC,CAuHxB"}
|
package/src/utils/git/git.js
CHANGED
|
@@ -41,12 +41,18 @@ async function getGitHubUsername(directory) {
|
|
|
41
41
|
}
|
|
42
42
|
return username;
|
|
43
43
|
}
|
|
44
|
+
// Module-level promise for background repo fetching
|
|
45
|
+
let existingReposPromise;
|
|
46
|
+
function populateExistingRepos(directory) {
|
|
47
|
+
existingReposPromise ??= getUserRepositories(directory);
|
|
48
|
+
}
|
|
44
49
|
async function getUserRepositories(directory) {
|
|
45
50
|
try {
|
|
46
51
|
const allRepos = new Set();
|
|
47
52
|
// Get user's personal repos and organizations concurrently
|
|
53
|
+
// Limit to 100 repos for faster response (covers most use cases)
|
|
48
54
|
const [userRepos, orgsResult] = await Promise.all([
|
|
49
|
-
(0, child_process_utils_1.execAndWait)('gh repo list --limit
|
|
55
|
+
(0, child_process_utils_1.execAndWait)('gh repo list --limit 100 --json nameWithOwner --jq ".[].nameWithOwner"', directory),
|
|
50
56
|
(0, child_process_utils_1.execAndWait)('gh api user/orgs --jq ".[].login"', directory),
|
|
51
57
|
]);
|
|
52
58
|
// Add user's personal repos
|
|
@@ -63,7 +69,7 @@ async function getUserRepositories(directory) {
|
|
|
63
69
|
// Get repos from all organizations concurrently
|
|
64
70
|
const orgRepoPromises = orgs.map(async (org) => {
|
|
65
71
|
try {
|
|
66
|
-
const orgRepos = await (0, child_process_utils_1.execAndWait)(`gh repo list ${org} --limit
|
|
72
|
+
const orgRepos = await (0, child_process_utils_1.execAndWait)(`gh repo list ${org} --limit 100 --json nameWithOwner --jq ".[].nameWithOwner"`, directory);
|
|
67
73
|
return orgRepos.stdout
|
|
68
74
|
.trim()
|
|
69
75
|
.split('\n')
|
|
@@ -134,12 +140,18 @@ async function pushToGitHub(directory, options) {
|
|
|
134
140
|
if (process.env['NX_SKIP_GH_PUSH'] === 'true') {
|
|
135
141
|
throw new GitHubPushSkippedError('NX_SKIP_GH_PUSH is true so skipping GitHub push.');
|
|
136
142
|
}
|
|
143
|
+
// Note: This call can throw an error even if user hasn't opted in to push yet,
|
|
144
|
+
// which could be confusing as they haven't been asked about GitHub push at this point.
|
|
145
|
+
// We check gh authentication early to provide a better error message.
|
|
137
146
|
const username = await getGitHubUsername(directory);
|
|
147
|
+
// Start fetching existing repositories in the background immediately
|
|
148
|
+
// This runs while user is answering prompts, so validation is usually instant
|
|
149
|
+
populateExistingRepos(directory);
|
|
138
150
|
// First prompt: Ask if they want to push to GitHub
|
|
139
151
|
const { push } = await enquirer.prompt([
|
|
140
152
|
{
|
|
141
153
|
name: 'push',
|
|
142
|
-
message: 'Would you like to push this workspace to
|
|
154
|
+
message: 'Would you like to push this workspace to GitHub?',
|
|
143
155
|
type: 'autocomplete',
|
|
144
156
|
choices: [{ name: 'Yes' }, { name: 'No' }],
|
|
145
157
|
initial: 0,
|
|
@@ -148,10 +160,9 @@ async function pushToGitHub(directory, options) {
|
|
|
148
160
|
if (push !== 'Yes') {
|
|
149
161
|
return VcsPushStatus.OptedOutOfPushingToVcs;
|
|
150
162
|
}
|
|
151
|
-
// Preload existing repositories for validation
|
|
152
|
-
const existingRepos = await getUserRepositories(directory);
|
|
153
163
|
// Create default repository name using the username we already have
|
|
154
164
|
const defaultRepo = `${username}/${options.name}`;
|
|
165
|
+
const createRepoUrl = `https://github.com/new?name=${encodeURIComponent(options.name)}`;
|
|
155
166
|
// Second prompt: Ask where to create the repository with validation
|
|
156
167
|
const { repoName } = await enquirer.prompt([
|
|
157
168
|
{
|
|
@@ -163,8 +174,10 @@ async function pushToGitHub(directory, options) {
|
|
|
163
174
|
if (!value.includes('/')) {
|
|
164
175
|
return 'Repository name must be in format: username/repo-name';
|
|
165
176
|
}
|
|
166
|
-
|
|
167
|
-
|
|
177
|
+
// Wait for background fetch to complete before validating
|
|
178
|
+
const existingRepos = await existingReposPromise;
|
|
179
|
+
if (existingRepos?.has(value)) {
|
|
180
|
+
return `Repository '${value}' already exists. Choose a different name or create manually: ${createRepoUrl}`;
|
|
168
181
|
}
|
|
169
182
|
return true;
|
|
170
183
|
},
|
|
@@ -172,6 +185,9 @@ async function pushToGitHub(directory, options) {
|
|
|
172
185
|
]);
|
|
173
186
|
// Create GitHub repository using gh CLI from the workspace directory
|
|
174
187
|
// This will automatically add remote origin and push the current branch
|
|
188
|
+
output_1.output.log({
|
|
189
|
+
title: 'Creating GitHub repository and pushing (this may take a moment)...',
|
|
190
|
+
});
|
|
175
191
|
await (0, child_process_utils_1.spawnAndWait)('gh', [
|
|
176
192
|
'repo',
|
|
177
193
|
'create',
|
|
@@ -193,19 +209,20 @@ async function pushToGitHub(directory, options) {
|
|
|
193
209
|
const isVerbose = options.verbose || process.env.NX_VERBOSE_LOGGING === 'true';
|
|
194
210
|
const errorMessage = e instanceof Error ? e.message : String(e);
|
|
195
211
|
// Error code 127 means gh wasn't installed
|
|
212
|
+
// GitHubPushSkippedError means user hasn't opted in or we couldn't authenticate
|
|
196
213
|
const title = e instanceof GitHubPushSkippedError || e?.code === 127
|
|
197
214
|
? 'Push your workspace to GitHub.'
|
|
198
|
-
: '
|
|
215
|
+
: 'Could not push. Push repo to complete setup.';
|
|
199
216
|
const createRepoUrl = `https://github.com/new?name=${encodeURIComponent(options.name)}`;
|
|
200
217
|
output_1.output.log({
|
|
201
218
|
title,
|
|
202
219
|
bodyLines: isVerbose
|
|
203
220
|
? [
|
|
204
|
-
`
|
|
221
|
+
`Go to ${createRepoUrl} and push this workspace.`,
|
|
205
222
|
'Error details:',
|
|
206
223
|
errorMessage,
|
|
207
224
|
]
|
|
208
|
-
: [`
|
|
225
|
+
: [`Go to ${createRepoUrl} and push this workspace.`],
|
|
209
226
|
});
|
|
210
227
|
return VcsPushStatus.FailedToPushToVcs;
|
|
211
228
|
}
|
|
@@ -1,3 +1,16 @@
|
|
|
1
|
+
import type { CompletionMessageKey } from './messages';
|
|
2
|
+
/**
|
|
3
|
+
* Determines whether to use the new template flow (1) or old preset flow (0).
|
|
4
|
+
* - NX_CNW_FLOW_VARIANT=0 forces preset flow
|
|
5
|
+
* - NX_CNW_FLOW_VARIANT=1 forces template flow
|
|
6
|
+
* - NX_GENERATE_DOCS_PROCESS=true forces preset flow (for docs generation)
|
|
7
|
+
* - Otherwise, uses cached value (7 days) or randomly assigns
|
|
8
|
+
*/
|
|
9
|
+
export declare function shouldUseTemplateFlow(): boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Returns the flow variant for tracking (0 = preset, 1 = template).
|
|
12
|
+
*/
|
|
13
|
+
export declare function getFlowVariant(): string;
|
|
1
14
|
export declare const NxCloudChoices: string[];
|
|
2
15
|
declare const messageOptions: Record<string, MessageData[]>;
|
|
3
16
|
export type MessageKey = keyof typeof messageOptions;
|
|
@@ -15,11 +28,13 @@ interface MessageData {
|
|
|
15
28
|
value: string;
|
|
16
29
|
key: MessageKey;
|
|
17
30
|
};
|
|
31
|
+
completionMessage: CompletionMessageKey;
|
|
18
32
|
}
|
|
19
33
|
export declare class PromptMessages {
|
|
20
34
|
private selectedMessages;
|
|
21
35
|
getPrompt(key: MessageKey): MessageData;
|
|
22
36
|
codeOfSelectedPromptMessage(key: MessageKey): string;
|
|
37
|
+
completionMessageOfSelectedPrompt(key: MessageKey): CompletionMessageKey;
|
|
23
38
|
}
|
|
24
39
|
export declare const messages: PromptMessages;
|
|
25
40
|
/**
|
|
@@ -31,6 +46,7 @@ export declare function recordStat(opts: {
|
|
|
31
46
|
nxVersion: string;
|
|
32
47
|
useCloud: boolean;
|
|
33
48
|
meta: string[];
|
|
49
|
+
directory: string;
|
|
34
50
|
}): Promise<void>;
|
|
35
51
|
export {};
|
|
36
52
|
//# sourceMappingURL=ab-testing.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ab-testing.d.ts","sourceRoot":"","sources":["../../../../../../packages/create-nx-workspace/src/utils/nx/ab-testing.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ab-testing.d.ts","sourceRoot":"","sources":["../../../../../../packages/create-nx-workspace/src/utils/nx/ab-testing.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAsDvD;;;;;;GAMG;AACH,wBAAgB,qBAAqB,IAAI,OAAO,CAO/C;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAKvC;AAED,eAAO,MAAM,cAAc,UAQ1B,CAAC;AAEF,QAAA,MAAM,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,EAAE,CAsGjD,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,MAAM,OAAO,cAAc,CAAC;AACrD,UAAU,WAAW;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAChD,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,UAAU,CAAA;KAAE,CAAC;IAC9C,iBAAiB,EAAE,oBAAoB,CAAC;CACzC;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,gBAAgB,CAAwC;IAEhE,SAAS,CAAC,GAAG,EAAE,UAAU,GAAG,WAAW;IAavC,2BAA2B,CAAC,GAAG,EAAE,UAAU,GAAG,MAAM;IAQpD,iCAAiC,CAAC,GAAG,EAAE,UAAU,GAAG,oBAAoB;CAQzE;AAED,eAAO,MAAM,QAAQ,gBAAuB,CAAC;AAS7C;;;GAGG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB,iBAgCA"}
|
|
@@ -1,10 +1,82 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.messages = exports.PromptMessages = exports.NxCloudChoices = void 0;
|
|
4
|
+
exports.shouldUseTemplateFlow = shouldUseTemplateFlow;
|
|
5
|
+
exports.getFlowVariant = getFlowVariant;
|
|
4
6
|
exports.recordStat = recordStat;
|
|
5
7
|
const node_child_process_1 = require("node:child_process");
|
|
8
|
+
const node_fs_1 = require("node:fs");
|
|
9
|
+
const node_path_1 = require("node:path");
|
|
10
|
+
const node_os_1 = require("node:os");
|
|
6
11
|
const is_ci_1 = require("../ci/is-ci");
|
|
7
|
-
|
|
12
|
+
// TODO(jack): Remove flow variant logic after A/B testing is complete
|
|
13
|
+
const FLOW_VARIANT_CACHE_FILE = (0, node_path_1.join)((0, node_os_1.tmpdir)(), 'nx-cnw-flow-variant');
|
|
14
|
+
const FLOW_VARIANT_EXPIRY_MS = 7 * 24 * 60 * 60 * 1000; // 1 week
|
|
15
|
+
// In-memory cache to ensure consistency within a single run
|
|
16
|
+
let flowVariantCache = null;
|
|
17
|
+
function readCachedFlowVariant() {
|
|
18
|
+
try {
|
|
19
|
+
if (!(0, node_fs_1.existsSync)(FLOW_VARIANT_CACHE_FILE))
|
|
20
|
+
return null;
|
|
21
|
+
const stats = (0, node_fs_1.statSync)(FLOW_VARIANT_CACHE_FILE);
|
|
22
|
+
if (Date.now() - stats.mtimeMs > FLOW_VARIANT_EXPIRY_MS)
|
|
23
|
+
return null;
|
|
24
|
+
const value = (0, node_fs_1.readFileSync)(FLOW_VARIANT_CACHE_FILE, 'utf-8').trim();
|
|
25
|
+
return value === '0' || value === '1' ? value : null;
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function writeCachedFlowVariant(variant) {
|
|
32
|
+
try {
|
|
33
|
+
(0, node_fs_1.writeFileSync)(FLOW_VARIANT_CACHE_FILE, variant, 'utf-8');
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
// Ignore write errors
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Internal function to determine and cache the flow variant.
|
|
41
|
+
*/
|
|
42
|
+
function getFlowVariantInternal() {
|
|
43
|
+
if (flowVariantCache)
|
|
44
|
+
return flowVariantCache;
|
|
45
|
+
const variant = process.env.NX_CNW_FLOW_VARIANT ??
|
|
46
|
+
readCachedFlowVariant() ??
|
|
47
|
+
(Math.random() < 0.5 ? '0' : '1');
|
|
48
|
+
flowVariantCache = variant;
|
|
49
|
+
// Only write to cache if we randomly assigned a variant and no cache exists yet
|
|
50
|
+
// This ensures the cache expiry is based on original creation time, not last access
|
|
51
|
+
if (!process.env.NX_CNW_FLOW_VARIANT &&
|
|
52
|
+
!(0, node_fs_1.existsSync)(FLOW_VARIANT_CACHE_FILE)) {
|
|
53
|
+
writeCachedFlowVariant(variant);
|
|
54
|
+
}
|
|
55
|
+
return variant;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Determines whether to use the new template flow (1) or old preset flow (0).
|
|
59
|
+
* - NX_CNW_FLOW_VARIANT=0 forces preset flow
|
|
60
|
+
* - NX_CNW_FLOW_VARIANT=1 forces template flow
|
|
61
|
+
* - NX_GENERATE_DOCS_PROCESS=true forces preset flow (for docs generation)
|
|
62
|
+
* - Otherwise, uses cached value (7 days) or randomly assigns
|
|
63
|
+
*/
|
|
64
|
+
function shouldUseTemplateFlow() {
|
|
65
|
+
if (process.env.NX_GENERATE_DOCS_PROCESS === 'true') {
|
|
66
|
+
flowVariantCache = '0';
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
return getFlowVariantInternal() === '1';
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Returns the flow variant for tracking (0 = preset, 1 = template).
|
|
73
|
+
*/
|
|
74
|
+
function getFlowVariant() {
|
|
75
|
+
if (process.env.NX_GENERATE_DOCS_PROCESS === 'true') {
|
|
76
|
+
return '0';
|
|
77
|
+
}
|
|
78
|
+
return flowVariantCache ?? getFlowVariantInternal();
|
|
79
|
+
}
|
|
8
80
|
exports.NxCloudChoices = [
|
|
9
81
|
'github',
|
|
10
82
|
'gitlab',
|
|
@@ -33,6 +105,7 @@ const messageOptions = {
|
|
|
33
105
|
],
|
|
34
106
|
footer: '\nSelf-healing CI, remote caching, and task distribution are provided by Nx Cloud: https://nx.dev/nx-cloud',
|
|
35
107
|
fallback: { value: 'skip', key: 'setupNxCloud' },
|
|
108
|
+
completionMessage: 'ci-setup',
|
|
36
109
|
},
|
|
37
110
|
],
|
|
38
111
|
/**
|
|
@@ -51,8 +124,62 @@ const messageOptions = {
|
|
|
51
124
|
},
|
|
52
125
|
],
|
|
53
126
|
footer: '\nRead more about remote caching at https://nx.dev/ci/features/remote-cache',
|
|
54
|
-
hint: `\n(can be disabled any time)
|
|
127
|
+
hint: `\n(can be disabled any time).`,
|
|
128
|
+
fallback: undefined,
|
|
129
|
+
completionMessage: 'cache-setup',
|
|
130
|
+
},
|
|
131
|
+
],
|
|
132
|
+
/**
|
|
133
|
+
* Simplified Cloud prompt for template flow
|
|
134
|
+
*/
|
|
135
|
+
setupNxCloudV2: [
|
|
136
|
+
{
|
|
137
|
+
code: 'cloud-v2-remote-cache-visit',
|
|
138
|
+
message: 'Enable remote caching with Nx Cloud?',
|
|
139
|
+
initial: 0,
|
|
140
|
+
choices: [
|
|
141
|
+
{ value: 'yes', name: 'Yes' },
|
|
142
|
+
{ value: 'skip', name: 'Skip' },
|
|
143
|
+
],
|
|
144
|
+
footer: '\nRemote caching makes your builds faster for development and in CI: https://nx.dev/ci/features/remote-cache',
|
|
145
|
+
fallback: undefined,
|
|
146
|
+
completionMessage: 'cache-setup',
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
code: 'cloud-v2-fast-ci-visit',
|
|
150
|
+
message: 'Speed up CI and reduce compute costs with Nx Cloud?',
|
|
151
|
+
initial: 0,
|
|
152
|
+
choices: [
|
|
153
|
+
{ value: 'yes', name: 'Yes' },
|
|
154
|
+
{ value: 'skip', name: 'Skip' },
|
|
155
|
+
],
|
|
156
|
+
footer: '\n70% faster CI, 60% less compute, Automatically fix broken PRs: https://nx.dev/nx-cloud',
|
|
157
|
+
fallback: undefined,
|
|
158
|
+
completionMessage: 'ci-setup',
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
code: 'cloud-v2-green-prs-visit',
|
|
162
|
+
message: 'Get to green PRs faster with Nx Cloud?',
|
|
163
|
+
initial: 0,
|
|
164
|
+
choices: [
|
|
165
|
+
{ value: 'yes', name: 'Yes' },
|
|
166
|
+
{ value: 'skip', name: 'Skip' },
|
|
167
|
+
],
|
|
168
|
+
footer: '\nAutomatically fix broken PRs, 70% faster CI: https://nx.dev/nx-cloud',
|
|
169
|
+
fallback: undefined,
|
|
170
|
+
completionMessage: 'ci-setup',
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
code: 'cloud-v2-full-platform-visit',
|
|
174
|
+
message: 'Try the full Nx platform?',
|
|
175
|
+
initial: 0,
|
|
176
|
+
choices: [
|
|
177
|
+
{ value: 'yes', name: 'Yes' },
|
|
178
|
+
{ value: 'skip', name: 'Skip' },
|
|
179
|
+
],
|
|
180
|
+
footer: '\nAutomatically fix broken PRs, 70% faster CI: https://nx.dev/nx-cloud',
|
|
55
181
|
fallback: undefined,
|
|
182
|
+
completionMessage: 'platform-setup',
|
|
56
183
|
},
|
|
57
184
|
],
|
|
58
185
|
};
|
|
@@ -76,8 +203,15 @@ class PromptMessages {
|
|
|
76
203
|
if (selected === undefined) {
|
|
77
204
|
return '';
|
|
78
205
|
}
|
|
206
|
+
return messageOptions[key][selected].code;
|
|
207
|
+
}
|
|
208
|
+
completionMessageOfSelectedPrompt(key) {
|
|
209
|
+
const selected = this.selectedMessages[key];
|
|
210
|
+
if (selected === undefined) {
|
|
211
|
+
return 'ci-setup';
|
|
212
|
+
}
|
|
79
213
|
else {
|
|
80
|
-
return messageOptions[key][selected].
|
|
214
|
+
return messageOptions[key][selected].completionMessage;
|
|
81
215
|
}
|
|
82
216
|
}
|
|
83
217
|
}
|
|
@@ -97,6 +231,12 @@ async function recordStat(opts) {
|
|
|
97
231
|
if (!shouldRecordStats()) {
|
|
98
232
|
return;
|
|
99
233
|
}
|
|
234
|
+
// nx-ignore-next-line
|
|
235
|
+
const { getCloudUrl } = require(require.resolve('nx/src/nx-cloud/utilities/get-cloud-options', {
|
|
236
|
+
paths: [opts.directory],
|
|
237
|
+
}
|
|
238
|
+
// nx-ignore-next-line
|
|
239
|
+
));
|
|
100
240
|
const axios = require('axios');
|
|
101
241
|
await (axios['default'] ?? axios)
|
|
102
242
|
.create({
|
|
@@ -117,14 +257,9 @@ async function recordStat(opts) {
|
|
|
117
257
|
}
|
|
118
258
|
}
|
|
119
259
|
function shouldRecordStats() {
|
|
120
|
-
const pmc = (0, package_manager_1.getPackageManagerCommand)();
|
|
121
|
-
if (!pmc.getRegistryUrl) {
|
|
122
|
-
// Fallback on true as Package management doesn't support reading config for registry.
|
|
123
|
-
// currently Bun doesn't support fetching config settings https://github.com/oven-sh/bun/issues/7140
|
|
124
|
-
return true;
|
|
125
|
-
}
|
|
126
260
|
try {
|
|
127
|
-
|
|
261
|
+
// Use npm to check registry - this works regardless of which package manager invoked us
|
|
262
|
+
const stdout = (0, node_child_process_1.execSync)('npm config get registry', {
|
|
128
263
|
encoding: 'utf-8',
|
|
129
264
|
windowsHide: false,
|
|
130
265
|
});
|
|
@@ -1,37 +1,27 @@
|
|
|
1
1
|
import { VcsPushStatus } from '../git/git';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
readonly code: "remote-cache-visit";
|
|
13
|
-
readonly createMessage: (url: string | null, pushedToVcs: VcsPushStatus) => {
|
|
14
|
-
title: string;
|
|
15
|
-
type: string;
|
|
16
|
-
bodyLines: string[];
|
|
17
|
-
};
|
|
18
|
-
}];
|
|
19
|
-
};
|
|
20
|
-
type OutputMessageKey = keyof typeof outputMessages;
|
|
21
|
-
export declare function getMessageFactory(key: OutputMessageKey): {
|
|
22
|
-
readonly code: "ci-setup-visit";
|
|
23
|
-
readonly createMessage: (url: string | null, pushedToVcs: VcsPushStatus) => {
|
|
24
|
-
title: string;
|
|
25
|
-
type: string;
|
|
26
|
-
bodyLines: string[];
|
|
2
|
+
/**
|
|
3
|
+
* Completion messages shown after workspace creation.
|
|
4
|
+
* Keys are referenced by ab-testing.ts prompts via completionMessage field.
|
|
5
|
+
*/
|
|
6
|
+
declare const completionMessages: {
|
|
7
|
+
readonly 'ci-setup': {
|
|
8
|
+
readonly title: "Your CI setup is almost complete.";
|
|
9
|
+
};
|
|
10
|
+
readonly 'cache-setup': {
|
|
11
|
+
readonly title: "Your remote cache setup is almost complete.";
|
|
27
12
|
};
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
readonly createMessage: (url: string | null, pushedToVcs: VcsPushStatus) => {
|
|
31
|
-
title: string;
|
|
32
|
-
type: string;
|
|
33
|
-
bodyLines: string[];
|
|
13
|
+
readonly 'platform-setup': {
|
|
14
|
+
readonly title: "Your platform setup is almost complete.";
|
|
34
15
|
};
|
|
35
16
|
};
|
|
17
|
+
export type CompletionMessageKey = keyof typeof completionMessages;
|
|
18
|
+
export declare function getCompletionMessage(completionMessageKey: CompletionMessageKey | undefined, url: string | null, pushedToVcs: VcsPushStatus): {
|
|
19
|
+
title: string;
|
|
20
|
+
bodyLines: string[];
|
|
21
|
+
};
|
|
22
|
+
export declare function getSkippedCloudMessage(): {
|
|
23
|
+
title: string;
|
|
24
|
+
bodyLines: string[];
|
|
25
|
+
};
|
|
36
26
|
export {};
|
|
37
27
|
//# sourceMappingURL=messages.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../../../../../packages/create-nx-workspace/src/utils/nx/messages.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAkB3C,QAAA,MAAM,
|
|
1
|
+
{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../../../../../packages/create-nx-workspace/src/utils/nx/messages.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAkB3C;;;GAGG;AACH,QAAA,MAAM,kBAAkB;;;;;;;;;;CAUd,CAAC;AAEX,MAAM,MAAM,oBAAoB,GAAG,MAAM,OAAO,kBAAkB,CAAC;AAEnE,wBAAgB,oBAAoB,CAClC,oBAAoB,EAAE,oBAAoB,GAAG,SAAS,EACtD,GAAG,EAAE,MAAM,GAAG,IAAI,EAClB,WAAW,EAAE,aAAa,GACzB;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,EAAE,CAAA;CAAE,CAOxC;AAED,wBAAgB,sBAAsB,IAAI;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB,CAUA"}
|
package/src/utils/nx/messages.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.getCompletionMessage = getCompletionMessage;
|
|
4
|
+
exports.getSkippedCloudMessage = getSkippedCloudMessage;
|
|
4
5
|
const git_1 = require("../git/git");
|
|
5
6
|
function getSetupMessage(url, pushedToVcs) {
|
|
6
7
|
if (pushedToVcs === git_1.VcsPushStatus.PushedToVcs) {
|
|
@@ -13,49 +14,36 @@ function getSetupMessage(url, pushedToVcs) {
|
|
|
13
14
|
const urlSuffix = url ? `: ${url}` : '.';
|
|
14
15
|
return `Push your repo, then ${action} to Nx Cloud and finish the setup${urlSuffix}`;
|
|
15
16
|
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
{
|
|
31
|
-
code: 'remote-cache-visit',
|
|
32
|
-
createMessage: (url, pushedToVcs) => {
|
|
33
|
-
return {
|
|
34
|
-
title: `Your remote cache is almost complete.`,
|
|
35
|
-
type: 'success',
|
|
36
|
-
bodyLines: [getSetupMessage(url, pushedToVcs)],
|
|
37
|
-
};
|
|
38
|
-
},
|
|
39
|
-
},
|
|
40
|
-
],
|
|
17
|
+
/**
|
|
18
|
+
* Completion messages shown after workspace creation.
|
|
19
|
+
* Keys are referenced by ab-testing.ts prompts via completionMessage field.
|
|
20
|
+
*/
|
|
21
|
+
const completionMessages = {
|
|
22
|
+
'ci-setup': {
|
|
23
|
+
title: 'Your CI setup is almost complete.',
|
|
24
|
+
},
|
|
25
|
+
'cache-setup': {
|
|
26
|
+
title: 'Your remote cache setup is almost complete.',
|
|
27
|
+
},
|
|
28
|
+
'platform-setup': {
|
|
29
|
+
title: 'Your platform setup is almost complete.',
|
|
30
|
+
},
|
|
41
31
|
};
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
if (process.env.NX_GENERATE_DOCS_PROCESS === 'true') {
|
|
49
|
-
this.selectedMessages[key] = 0;
|
|
50
|
-
}
|
|
51
|
-
else {
|
|
52
|
-
this.selectedMessages[key] = Math.floor(Math.random() * outputMessages[key].length);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
return outputMessages[key][this.selectedMessages[key]];
|
|
56
|
-
}
|
|
32
|
+
function getCompletionMessage(completionMessageKey, url, pushedToVcs) {
|
|
33
|
+
const key = completionMessageKey ?? 'ci-setup';
|
|
34
|
+
return {
|
|
35
|
+
title: completionMessages[key].title,
|
|
36
|
+
bodyLines: [getSetupMessage(url, pushedToVcs)],
|
|
37
|
+
};
|
|
57
38
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
39
|
+
function getSkippedCloudMessage() {
|
|
40
|
+
return {
|
|
41
|
+
title: 'Next steps',
|
|
42
|
+
bodyLines: [
|
|
43
|
+
'Run "nx connect" to enable remote caching and speed up your CI.',
|
|
44
|
+
'',
|
|
45
|
+
'70% faster CI, 60% less compute, automatically fix broken PRs.',
|
|
46
|
+
'Learn more at https://nx.dev/nx-cloud',
|
|
47
|
+
],
|
|
48
|
+
};
|
|
61
49
|
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { VcsPushStatus } from '../git/git';
|
|
2
|
+
import { CompletionMessageKey } from './messages';
|
|
2
3
|
export type NxCloud = 'yes' | 'github' | 'gitlab' | 'azure' | 'bitbucket-pipelines' | 'circleci' | 'skip';
|
|
4
|
+
export declare function connectToNxCloudForTemplate(directory: string, installationSource: string, useGitHub?: boolean): Promise<string | null>;
|
|
3
5
|
export declare function readNxCloudToken(directory: string): string;
|
|
4
|
-
export declare function createNxCloudOnboardingUrl(nxCloud: NxCloud, token: string, directory: string, useGitHub?: boolean): Promise<
|
|
5
|
-
export declare function getNxCloudInfo(
|
|
6
|
+
export declare function createNxCloudOnboardingUrl(nxCloud: NxCloud, token: string, directory: string, useGitHub?: boolean): Promise<string>;
|
|
7
|
+
export declare function getNxCloudInfo(connectCloudUrl: string, pushedToVcs: VcsPushStatus, completionMessageKey?: CompletionMessageKey): Promise<string>;
|
|
8
|
+
export declare function getSkippedNxCloudInfo(): string;
|
|
6
9
|
//# sourceMappingURL=nx-cloud.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nx-cloud.d.ts","sourceRoot":"","sources":["../../../../../../packages/create-nx-workspace/src/utils/nx/nx-cloud.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"nx-cloud.d.ts","sourceRoot":"","sources":["../../../../../../packages/create-nx-workspace/src/utils/nx/nx-cloud.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3C,OAAO,EAGL,oBAAoB,EACrB,MAAM,YAAY,CAAC;AAIpB,MAAM,MAAM,OAAO,GACf,KAAK,GACL,QAAQ,GACR,QAAQ,GACR,OAAO,GACP,qBAAqB,GACrB,UAAU,GACV,MAAM,CAAC;AAEX,wBAAsB,2BAA2B,CAC/C,SAAS,EAAE,MAAM,EACjB,kBAAkB,EAAE,MAAM,EAC1B,SAAS,CAAC,EAAE,OAAO,GAClB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA8BxB;AAED,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,UAcjD;AAED,wBAAsB,0BAA0B,CAC9C,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,EACjB,SAAS,CAAC,EAAE,OAAO,GAClB,OAAO,CAAC,MAAM,CAAC,CAqCjB;AAED,wBAAsB,cAAc,CAClC,eAAe,EAAE,MAAM,EACvB,WAAW,EAAE,aAAa,EAC1B,oBAAoB,CAAC,EAAE,oBAAoB,mBAU5C;AAED,wBAAgB,qBAAqB,WAIpC"}
|
package/src/utils/nx/nx-cloud.js
CHANGED
|
@@ -1,11 +1,36 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.connectToNxCloudForTemplate = connectToNxCloudForTemplate;
|
|
3
4
|
exports.readNxCloudToken = readNxCloudToken;
|
|
4
5
|
exports.createNxCloudOnboardingUrl = createNxCloudOnboardingUrl;
|
|
5
6
|
exports.getNxCloudInfo = getNxCloudInfo;
|
|
7
|
+
exports.getSkippedNxCloudInfo = getSkippedNxCloudInfo;
|
|
6
8
|
const output_1 = require("../output");
|
|
7
9
|
const messages_1 = require("./messages");
|
|
10
|
+
const ab_testing_1 = require("./ab-testing");
|
|
8
11
|
const ora = require("ora");
|
|
12
|
+
async function connectToNxCloudForTemplate(directory, installationSource, useGitHub) {
|
|
13
|
+
// nx-ignore-next-line
|
|
14
|
+
const { connectToNxCloud } = require(require.resolve('nx/src/nx-cloud/generators/connect-to-nx-cloud/connect-to-nx-cloud', {
|
|
15
|
+
paths: [directory],
|
|
16
|
+
}
|
|
17
|
+
// nx-ignore-next-line
|
|
18
|
+
));
|
|
19
|
+
// nx-ignore-next-line
|
|
20
|
+
const { FsTree, flushChanges } = require(require.resolve('nx/src/generators/tree', {
|
|
21
|
+
paths: [directory],
|
|
22
|
+
// nx-ignore-next-line
|
|
23
|
+
}));
|
|
24
|
+
const tree = new FsTree(directory, false);
|
|
25
|
+
const result = await connectToNxCloud(tree, {
|
|
26
|
+
installationSource,
|
|
27
|
+
directory: '',
|
|
28
|
+
github: useGitHub,
|
|
29
|
+
});
|
|
30
|
+
// Flush the tree changes to disk
|
|
31
|
+
flushChanges(directory, tree.listChanges());
|
|
32
|
+
return result;
|
|
33
|
+
}
|
|
9
34
|
function readNxCloudToken(directory) {
|
|
10
35
|
const nxCloudSpinner = ora(`Checking Nx Cloud setup`).start();
|
|
11
36
|
// nx-ignore-next-line
|
|
@@ -25,25 +50,31 @@ async function createNxCloudOnboardingUrl(nxCloud, token, directory, useGitHub)
|
|
|
25
50
|
}
|
|
26
51
|
// nx-ignore-next-line
|
|
27
52
|
));
|
|
53
|
+
// Source determines the onboarding flow type
|
|
28
54
|
const source = nxCloud === 'yes'
|
|
29
55
|
? 'create-nx-workspace-success-cache-setup'
|
|
30
56
|
: 'create-nx-workspace-success-ci-setup';
|
|
31
|
-
|
|
32
|
-
|
|
57
|
+
// Meta: "start" or "start-v2" prefix, with prompt code
|
|
58
|
+
// For template flow (variant 1): use specific prompt code from setupNxCloudV2
|
|
59
|
+
// For preset flow (variant 0): use visit codes based on nxCloud value
|
|
60
|
+
const flowVariant = (0, ab_testing_1.getFlowVariant)();
|
|
61
|
+
const prefix = flowVariant === '1' ? 'start-v2' : 'start';
|
|
62
|
+
const promptCode = flowVariant === '1'
|
|
63
|
+
? ab_testing_1.messages.codeOfSelectedPromptMessage('setupNxCloudV2')
|
|
64
|
+
: '';
|
|
65
|
+
const code = promptCode || (nxCloud === 'yes' ? 'remote-cache-visit' : 'ci-setup-visit');
|
|
66
|
+
const meta = `${prefix}-${code}`;
|
|
67
|
+
return createNxCloudOnboardingURL(source, token, meta, false, useGitHub ??
|
|
33
68
|
(nxCloud === 'yes' || nxCloud === 'github' || nxCloud === 'circleci'));
|
|
34
69
|
}
|
|
35
|
-
async function getNxCloudInfo(
|
|
36
|
-
const source = nxCloud === 'yes'
|
|
37
|
-
? 'create-nx-workspace-success-cache-setup'
|
|
38
|
-
: 'create-nx-workspace-success-ci-setup';
|
|
39
|
-
const { createMessage } = (0, messages_1.getMessageFactory)(source);
|
|
70
|
+
async function getNxCloudInfo(connectCloudUrl, pushedToVcs, completionMessageKey) {
|
|
40
71
|
const out = new output_1.CLIOutput(false);
|
|
41
|
-
const message =
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
72
|
+
const message = (0, messages_1.getCompletionMessage)(completionMessageKey, connectCloudUrl, pushedToVcs);
|
|
73
|
+
out.success(message);
|
|
74
|
+
return out.getOutput();
|
|
75
|
+
}
|
|
76
|
+
function getSkippedNxCloudInfo() {
|
|
77
|
+
const out = new output_1.CLIOutput(false);
|
|
78
|
+
out.success((0, messages_1.getSkippedCloudMessage)());
|
|
48
79
|
return out.getOutput();
|
|
49
80
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clone-template.d.ts","sourceRoot":"","sources":["../../../../../../packages/create-nx-workspace/src/utils/template/clone-template.ts"],"names":[],"mappings":"AAOA,wBAAsB,aAAa,CACjC,WAAW,EAAE,MAAM,EACnB,eAAe,EAAE,MAAM,GACtB,OAAO,CAAC,IAAI,CAAC,CA6Bf"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.cloneTemplate = cloneTemplate;
|
|
4
|
+
const child_process_utils_1 = require("../child-process-utils");
|
|
5
|
+
const fs_1 = require("fs");
|
|
6
|
+
const promises_1 = require("fs/promises");
|
|
7
|
+
const path_1 = require("path");
|
|
8
|
+
const output_1 = require("../output");
|
|
9
|
+
const error_utils_1 = require("../error-utils");
|
|
10
|
+
async function cloneTemplate(templateUrl, targetDirectory) {
|
|
11
|
+
if ((0, fs_1.existsSync)(targetDirectory)) {
|
|
12
|
+
throw new Error(`The directory '${targetDirectory}' already exists and is not empty. Choose a different name or remove the existing directory.`);
|
|
13
|
+
}
|
|
14
|
+
try {
|
|
15
|
+
await (0, child_process_utils_1.execAndWait)(`git clone --depth 1 "${templateUrl}" "${targetDirectory}"`, process.cwd());
|
|
16
|
+
// Ensure clean history
|
|
17
|
+
const gitDir = (0, path_1.join)(targetDirectory, '.git');
|
|
18
|
+
if ((0, fs_1.existsSync)(gitDir)) {
|
|
19
|
+
await (0, promises_1.rm)(gitDir, { recursive: true, force: true });
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
catch (e) {
|
|
23
|
+
if (e instanceof Error) {
|
|
24
|
+
output_1.output.error({
|
|
25
|
+
title: 'Failed to create starter workspace',
|
|
26
|
+
bodyLines: (0, error_utils_1.mapErrorToBodyLines)(e),
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
console.error(e);
|
|
31
|
+
}
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
}
|