feat(misc): add onboarding a/b testing (#27217)

<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->

The onboarding message during `create-nx-workspace` is not ideal.

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

We are A/b testing some options for the `create-nx-workspace` onboarding
message.

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #
This commit is contained in:
Jason Jean 2024-07-30 18:33:38 -05:00 committed by GitHub
parent 66a8c75f87
commit 341f2951a8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 380 additions and 187 deletions

View File

@ -20,7 +20,6 @@ import { output } from 'create-nx-workspace/src/utils/output';
import { NxCloud } from 'create-nx-workspace/src/utils/nx/nx-cloud';
import type { PackageManager } from 'create-nx-workspace/src/utils/package-manager';
import { showNxWarning } from 'create-nx-workspace/src/utils/nx/show-nx-warning';
import { printNxCloudSuccessMessage } from 'create-nx-workspace/src/utils/nx/nx-cloud';
import {
messages,
recordStat,
@ -164,7 +163,7 @@ async function main(parsedArgs: yargs.Arguments<CreateNxPluginArguments>) {
});
if (parsedArgs.nxCloud && workspaceInfo.nxCloudInfo) {
printNxCloudSuccessMessage(workspaceInfo.nxCloudInfo);
console.log(workspaceInfo.nxCloudInfo);
}
}

View File

@ -26,7 +26,6 @@ import {
withPackageManager,
} from '../src/internal-utils/yargs-options';
import { showNxWarning } from '../src/utils/nx/show-nx-warning';
import { printNxCloudSuccessMessage } from '../src/utils/nx/nx-cloud';
import { messages, recordStat } from '../src/utils/nx/ab-testing';
import { mapErrorToBodyLines } from '../src/utils/error-utils';
import { existsSync } from 'fs';
@ -233,7 +232,7 @@ async function main(parsedArgs: yargs.Arguments<Arguments>) {
});
if (parsedArgs.nxCloud && workspaceInfo.nxCloudInfo) {
printNxCloudSuccessMessage(workspaceInfo.nxCloudInfo);
console.log(workspaceInfo.nxCloudInfo);
}
if (isKnownPreset(parsedArgs.preset)) {

View File

@ -1,6 +1,6 @@
import { CreateWorkspaceOptions } from './create-workspace-options';
import { output } from './utils/output';
import { setupNxCloud } from './utils/nx/nx-cloud';
import { getOnboardingInfo, setupNxCloud } from './utils/nx/nx-cloud';
import { createSandbox } from './create-sandbox';
import { createEmptyWorkspace } from './create-empty-workspace';
import { createPreset } from './create-preset';
@ -51,31 +51,27 @@ export async function createWorkspace<T extends CreateWorkspaceOptions>(
);
}
let nxCloudInstallRes;
let connectUrl: string | undefined;
let nxCloudInfo: string | undefined;
if (nxCloud !== 'skip') {
nxCloudInstallRes = await setupNxCloud(
directory,
packageManager,
nxCloud,
useGitHub
);
const token = await setupNxCloud(directory, nxCloud, useGitHub);
if (nxCloud !== 'yes') {
await setupCI(
directory,
nxCloud,
packageManager,
nxCloudInstallRes?.code === 0
);
await setupCI(directory, nxCloud, packageManager);
}
const { connectCloudUrl, output } = await getOnboardingInfo(
nxCloud,
token,
directory,
useGitHub
);
connectUrl = connectCloudUrl;
nxCloudInfo = output;
}
if (!skipGit) {
try {
let connectUrl;
if (nxCloudInstallRes?.code === 0) {
connectUrl = extractConnectUrl(nxCloudInstallRes?.stdout);
}
await initializeGitRepo(directory, { defaultBase, commit, connectUrl });
} catch (e) {
if (e instanceof Error) {
@ -90,7 +86,7 @@ export async function createWorkspace<T extends CreateWorkspaceOptions>(
}
return {
nxCloudInfo: nxCloudInstallRes?.stdout,
nxCloudInfo,
directory,
};
}

View File

@ -8,18 +8,8 @@ import { getPackageManagerCommand, PackageManager } from '../package-manager';
export async function setupCI(
directory: string,
ci: string,
packageManager: PackageManager,
nxCloudSuccessfullyInstalled: boolean
packageManager: PackageManager
) {
if (!nxCloudSuccessfullyInstalled) {
output.error({
title: `CI workflow generation skipped`,
bodyLines: [
`Nx Cloud was not installed`,
`The autogenerated CI workflow requires Nx Cloud to be set-up.`,
],
});
}
const ciSpinner = ora(`Generating CI workflow`).start();
try {
const pmc = getPackageManagerCommand(packageManager);

View File

@ -0,0 +1,185 @@
const outputMessages = {
'create-nx-workspace-success-ci-setup': [
{
code: 'nx-cloud-workspace-push-goto',
createMessage: (url: string) => ({
title: `Your Nx Cloud workspace is ready.`,
type: 'success',
bodyLines: [
`To claim it, connect it to your Nx Cloud account:`,
`- Push your repository to your git hosting provider.`,
`- Go to the following URL to connect your workspace to Nx Cloud:`,
'',
`${url}`,
],
}),
},
{
code: 'nx-cloud-powered-ci-setup-visit',
createMessage: (url: string) => ({
title: `Your CI setup powered by Nx Cloud is almost complete.`,
type: 'success',
bodyLines: [`Finish it by visiting: ${url}`],
}),
},
{
code: 'nx-cloud-powered-ci-setup-connect',
createMessage: (url: string) => ({
title: `Your CI setup powered by Nx Cloud is almost complete.`,
type: 'success',
bodyLines: [`Connect your repository: ${url}`],
}),
},
{
code: 'ci-setup-visit',
createMessage: (url: string) => ({
title: `Your CI setup is almost complete.`,
type: 'success',
bodyLines: [`Finish it by visiting: ${url}`],
}),
},
{
code: 'ci-setup-connect',
createMessage: (url: string) => ({
title: `Your CI setup is almost complete.`,
type: 'success',
bodyLines: [`Connect your repository: ${url}`],
}),
},
{
code: 'nx-cloud-powered-ci-setup-visit-warn',
createMessage: (url: string) => ({
title: `Your CI setup powered by Nx Cloud is almost complete.`,
type: 'warning',
bodyLines: [`Finish it by visiting: ${url}`],
}),
},
{
code: 'nx-cloud-powered-ci-setup-connect-warn',
createMessage: (url: string) => ({
title: `Your CI setup powered by Nx Cloud is almost complete.`,
type: 'warning',
bodyLines: [`Connect your repository: ${url}`],
}),
},
{
code: 'ci-setup-visit-warn',
createMessage: (url: string) => ({
title: `Your CI setup is almost complete.`,
type: 'warning',
bodyLines: [`Finish it by visiting: ${url}`],
}),
},
{
code: 'ci-setup-connect-warn',
createMessage: (url: string) => ({
title: `Your CI setup is almost complete.`,
type: 'warning',
bodyLines: [`Connect your repository: ${url}`],
}),
},
],
'create-nx-workspace-success-cache-setup': [
{
code: 'nx-cloud-workspace-push-goto',
createMessage: (url: string) => ({
title: `Your Nx Cloud workspace is ready.`,
type: 'success',
bodyLines: [
`To claim it, connect it to your Nx Cloud account:`,
`- Push your repository to your git hosting provider.`,
`- Go to the following URL to connect your workspace to Nx Cloud:`,
'',
`${url}`,
],
}),
},
{
code: 'nx-cloud-remote-cache-setup-finish',
createMessage: (url: string) => ({
title: `Your Nx Cloud remote cache setup is almost complete.`,
type: 'success',
bodyLines: [`Finish it by visiting: ${url}`],
}),
},
{
code: 'nx-cloud-remote-cache-setup-connect',
createMessage: (url: string) => ({
title: `Your Nx Cloud remote cache setup is almost complete.`,
type: 'success',
bodyLines: [`Connect your repository: ${url}`],
}),
},
{
code: 'remote-cache-visit',
createMessage: (url: string) => ({
title: `Your remote cache setup is almost complete.`,
type: 'success',
bodyLines: [`Finish it by visiting: ${url}`],
}),
},
{
code: 'remote-cache-connect',
createMessage: (url: string) => ({
title: `Your remote cache setup is almost complete.`,
type: 'success',
bodyLines: [`Connect your repository: ${url}`],
}),
},
{
code: 'nx-cloud-remote-cache-setup-visit-warn',
createMessage: (url: string) => ({
title: `Your Nx Cloud remote cache setup is almost complete.`,
type: 'warning',
bodyLines: [`Finish it by visiting: ${url}`],
}),
},
{
code: 'nx-cloud-remote-cache-setup-connect-warn',
createMessage: (url: string) => ({
title: `Your Nx Cloud remote cache setup is almost complete.`,
type: 'warning',
bodyLines: [`Connect your repository: ${url}`],
}),
},
{
code: 'remote-cache-visit-warn',
createMessage: (url: string) => ({
title: `Your remote cache setup is almost complete.`,
type: 'warning',
bodyLines: [`Finish it by visiting: ${url}`],
}),
},
{
code: 'remote-cache-connect-warn',
createMessage: (url: string) => ({
title: `Your remote cache setup is almost complete.`,
type: 'warning',
bodyLines: [`Connect your repository: ${url}`],
}),
},
],
} as const;
type OutputMessageKey = keyof typeof outputMessages;
class ABTestingMessages {
private selectedMessages: Record<string, number> = {};
getMessageFactory(key: OutputMessageKey) {
if (this.selectedMessages[key] === undefined) {
if (process.env.NX_GENERATE_DOCS_PROCESS === 'true') {
this.selectedMessages[key] = 0;
} else {
this.selectedMessages[key] = Math.floor(
Math.random() * outputMessages[key].length
);
}
}
return outputMessages[key][this.selectedMessages[key]!];
}
}
const messages = new ABTestingMessages();
export function getMessageFactory(key: OutputMessageKey) {
return messages.getMessageFactory(key);
}

View File

@ -1,37 +1,34 @@
import * as ora from 'ora';
import { execAndWait } from '../child-process-utils';
import { output } from '../output';
import { getPackageManagerCommand, PackageManager } from '../package-manager';
import { CLIOutput, output } from '../output';
import { mapErrorToBodyLines } from '../error-utils';
import { getMessageFactory } from './messages';
export type NxCloud = 'yes' | 'github' | 'circleci' | 'skip';
export async function setupNxCloud(
directory: string,
packageManager: PackageManager,
nxCloud: NxCloud,
useGitHub?: boolean
) {
const nxCloudSpinner = ora(`Setting up Nx Cloud`).start();
try {
const pmc = getPackageManagerCommand(packageManager);
const res = await execAndWait(
`${
pmc.exec
} nx g nx:connect-to-nx-cloud --installationSource=create-nx-workspace --directory=${directory} ${
useGitHub ? '--github' : ''
} --no-interactive`,
directory
);
// nx-ignore-next-line
const { connectWorkspaceToCloud } = require(require.resolve(
'nx/src/command-line/connect/connect-to-nx-cloud',
{
paths: [directory],
}
// nx-ignore-next-line
)) as typeof import('nx/src/command-line/connect/connect-to-nx-cloud');
if (nxCloud !== 'yes') {
nxCloudSpinner.succeed(
'CI workflow with Nx Cloud has been generated successfully'
);
} else {
nxCloudSpinner.succeed('Nx Cloud has been set up successfully');
}
return res;
const accessToken = await connectWorkspaceToCloud({
installationSource: 'create-nx-workspace',
directory,
github: useGitHub,
});
nxCloudSpinner.succeed('Nx Cloud has been set up successfully');
return accessToken;
} catch (e) {
nxCloudSpinner.fail();
@ -50,19 +47,39 @@ export async function setupNxCloud(
}
}
export function printNxCloudSuccessMessage(nxCloudOut: string) {
// remove leading Nx carret and any new lines
const logContent = nxCloudOut.split('NX ')[1];
const indexOfTitleEnd = logContent.indexOf('\n');
const title = logContent.slice(0, logContent.indexOf('\n')).trim();
const bodyLines = logContent
.slice(indexOfTitleEnd)
.replace(/^\n*/, '') // remove leading new lines
.replace(/\n*$/, '') // remove trailing new lines
.split('\n')
.map((r) => r.trim());
output.warn({
title,
bodyLines,
});
export async function getOnboardingInfo(
nxCloud: NxCloud,
token: string,
directory: string,
useGithub?: boolean
) {
// nx-ignore-next-line
const { createNxCloudOnboardingURL } = require(require.resolve(
'nx/src/nx-cloud/utilities/url-shorten',
{
paths: [directory],
}
// nx-ignore-next-line
)) as typeof import('nx/src/nx-cloud/utilities/url-shorten');
const source =
nxCloud === 'yes'
? 'create-nx-workspace-success-cache-setup'
: 'create-nx-workspace-success-ci-setup';
const { code, createMessage } = getMessageFactory(source);
const connectCloudUrl = await createNxCloudOnboardingURL(
source,
token,
useGithub ??
(nxCloud === 'yes' || nxCloud === 'github' || nxCloud === 'circleci'),
code
);
const out = new CLIOutput(false);
const message = createMessage(connectCloudUrl);
if (message.type === 'success') {
out.success(message);
} else {
out.warn(message);
}
return { output: out.getOutput(), connectCloudUrl };
}

View File

@ -34,7 +34,9 @@ if (isCI()) {
(chalk as any).level = 0;
}
class CLIOutput {
export class CLIOutput {
private outstream = this.real ? process.stdout : new FakeStdout();
constructor(private real = true) {}
/**
* Longer dash character which forms more of a continuous line when place side to side
* with itself, unlike the standard dash character
@ -64,7 +66,7 @@ class CLIOutput {
dim = chalk.dim;
private writeToStdOut(str: string) {
process.stdout.write(str);
this.outstream.write(str);
}
private writeOutputTitle({
@ -192,6 +194,21 @@ class CLIOutput {
this.addNewline();
}
getOutput() {
return this.outstream.toString();
}
}
export const output = new CLIOutput();
class FakeStdout {
private content = '';
write(str: string) {
this.content += str;
}
toString() {
return this.content;
}
}

View File

@ -1,8 +1,11 @@
import { output } from '../../utils/output';
import { readNxJson } from '../../config/configuration';
import { FsTree, flushChanges } from '../../generators/tree';
import { connectToNxCloud } from '../../nx-cloud/generators/connect-to-nx-cloud/connect-to-nx-cloud';
import { shortenedCloudUrl } from '../../nx-cloud/utilities/url-shorten';
import {
connectToNxCloud,
ConnectToNxCloudOptions,
} from '../../nx-cloud/generators/connect-to-nx-cloud/connect-to-nx-cloud';
import { createNxCloudOnboardingURL } from '../../nx-cloud/utilities/url-shorten';
import { isNxCloudUsed } from '../../utils/nx-cloud-utils';
import { runNxSync } from '../../utils/child-process';
import { NxJsonConfiguration } from '../../config/nx-json';
@ -16,6 +19,8 @@ import {
import { nxVersion } from '../../utils/versions';
import { workspaceRoot } from '../../utils/workspace-root';
import chalk = require('chalk');
import * as ora from 'ora';
import * as open from 'open';
export function onlyDefaultRunnerIsUsed(nxJson: NxJsonConfiguration) {
const defaultRunner = nxJson.tasksRunnerOptions?.default?.runner;
@ -50,6 +55,16 @@ export async function connectToNxCloudIfExplicitlyAsked(
}
}
export async function connectWorkspaceToCloud(
options: ConnectToNxCloudOptions
) {
const tree = new FsTree(workspaceRoot, false, 'connect-to-nx-cloud');
const accessToken = await connectToNxCloud(tree, options);
tree.lock();
flushChanges(workspaceRoot, tree.listChanges());
return accessToken;
}
export async function connectToNxCloudCommand(
command?: string
): Promise<boolean> {
@ -63,7 +78,10 @@ export async function connectToNxCloudCommand(
`Unable to authenticate. Either define accessToken in nx.json or set the NX_CLOUD_ACCESS_TOKEN env variable.`
);
}
const connectCloudUrl = await shortenedCloudUrl('nx-connect', token);
const connectCloudUrl = await createNxCloudOnboardingURL(
'nx-connect',
token
);
output.log({
title: '✔ This workspace already has Nx Cloud set up',
bodyLines: [
@ -76,18 +94,37 @@ export async function connectToNxCloudCommand(
return false;
}
const tree = new FsTree(workspaceRoot, false, 'connect-to-nx-cloud');
const callback = await connectToNxCloud(tree, {
const token = await connectWorkspaceToCloud({
installationSource: command ?? 'nx-connect',
});
tree.lock();
flushChanges(workspaceRoot, tree.listChanges());
await callback();
const connectCloudUrl = await createNxCloudOnboardingURL('nx-connect', token);
try {
const cloudConnectSpinner = ora(
`Opening Nx Cloud ${connectCloudUrl} in your browser to connect your workspace.`
).start();
await sleep(2000);
await open(connectCloudUrl);
cloudConnectSpinner.succeed();
} catch (e) {
output.note({
title: `Your Nx Cloud workspace is ready.`,
bodyLines: [
`To claim it, connect it to your Nx Cloud account:`,
`- Go to the following URL to connect your workspace to Nx Cloud:`,
'',
`${connectCloudUrl}`,
],
});
}
return true;
}
function sleep(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
export async function connectExistingRepoToNxCloudPrompt(
command = 'init',
key: MessageKey = 'setupNxCloud'

View File

@ -2,9 +2,13 @@ import { getPackageManagerCommand } from '../../utils/package-manager';
import { execSync } from 'child_process';
import { isNxCloudUsed } from '../../utils/nx-cloud-utils';
import { output } from '../../utils/output';
import { runNxSync } from '../../utils/child-process';
import { readNxJson } from '../../config/nx-json';
import { connectExistingRepoToNxCloudPrompt } from './connect-to-nx-cloud';
import {
connectExistingRepoToNxCloudPrompt,
connectWorkspaceToCloud,
} from './connect-to-nx-cloud';
import { printSuccessMessage } from '../../nx-cloud/generators/connect-to-nx-cloud/connect-to-nx-cloud';
import { repoUsesGithub } from '../../nx-cloud/utilities/url-shorten';
export async function viewLogs(): Promise<number> {
const cloudUsed = isNxCloudUsed(readNxJson());
@ -30,12 +34,11 @@ export async function viewLogs(): Promise<number> {
output.log({
title: 'Connecting to Nx Cloud',
});
runNxSync(
`g nx:connect-to-nx-cloud --installation-source=view-logs --quiet --no-interactive`,
{
stdio: 'ignore',
}
);
const token = await connectWorkspaceToCloud({
installationSource: 'view-logs',
});
await printSuccessMessage(token, 'view-logs', await repoUsesGithub());
} catch (e) {
output.log({
title: 'Failed to connect to Nx Cloud',

View File

@ -108,7 +108,7 @@ export async function addNxToMonorepo(options: Options) {
if (useNxCloud) {
output.log({ title: '🛠️ Setting up Nx Cloud' });
initCloud(repoRoot, 'nx-init-monorepo');
await initCloud('nx-init-monorepo');
}
}

View File

@ -140,7 +140,7 @@ export async function addNxToNest(options: Options, packageJson: PackageJson) {
if (useNxCloud) {
output.log({ title: '🛠️ Setting up Nx Cloud' });
initCloud(repoRoot, 'nx-init-nest');
await initCloud('nx-init-nest');
}
}

View File

@ -97,6 +97,6 @@ export async function addNxToNpmRepo(options: Options) {
if (useNxCloud) {
output.log({ title: '🛠️ Setting up Nx Cloud' });
initCloud(repoRoot, 'nx-init-npm-repo');
await initCloud('nx-init-npm-repo');
}
}

View File

@ -62,7 +62,7 @@ export async function addNxToAngularCliRepo(options: Options) {
if (useNxCloud) {
output.log({ title: '🛠️ Setting up Nx Cloud' });
initCloud(repoRoot, 'nx-init-angular');
await initCloud('nx-init-angular');
}
}

View File

@ -110,7 +110,7 @@ export async function getLegacyMigrationFunctionIfApplicable(
if (useNxCloud) {
output.log({ title: '🛠️ Setting up Nx Cloud' });
initCloud(repoRoot, 'nx-init-angular');
await initCloud('nx-init-angular');
}
};
}

View File

@ -2,7 +2,6 @@ import { execSync } from 'child_process';
import { join } from 'path';
import { NxJsonConfiguration } from '../../../config/nx-json';
import { runNxSync } from '../../../utils/child-process';
import {
fileExists,
readJsonFile,
@ -17,6 +16,9 @@ import {
import { joinPathFragments } from '../../../utils/path';
import { nxVersion } from '../../../utils/versions';
import { existsSync, readFileSync, writeFileSync } from 'fs';
import { printSuccessMessage } from '../../../nx-cloud/generators/connect-to-nx-cloud/connect-to-nx-cloud';
import { repoUsesGithub } from '../../../nx-cloud/utilities/url-shorten';
import { connectWorkspaceToCloud } from '../../connect/connect-to-nx-cloud';
export function createNxJsonFile(
repoRoot: string,
@ -141,22 +143,19 @@ export function runInstall(
execSync(pmc.install, { stdio: [0, 1, 2], cwd: repoRoot });
}
export function initCloud(
repoRoot: string,
export async function initCloud(
installationSource:
| 'nx-init'
| 'nx-init-angular'
| 'nx-init-cra'
| 'nx-init-monorepo'
| 'nx-init-nest'
| 'nx-init-npm-repo'
) {
runNxSync(
`g nx:connect-to-nx-cloud --installationSource=${installationSource} --quiet --no-interactive`,
{
stdio: [0, 1, 2],
cwd: repoRoot,
}
);
const token = await connectWorkspaceToCloud({
installationSource,
});
await printSuccessMessage(token, installationSource, await repoUsesGithub());
}
export function addVsCodeRecommendedExtensions(

View File

@ -10,6 +10,7 @@ import { nxVersion } from '../../utils/versions';
import {
addDepsToPackageJson,
createNxJsonFile,
initCloud,
isMonorepo,
printFinalMessage,
runInstall,
@ -126,13 +127,7 @@ export async function initHandler(options: InitArgs): Promise<void> {
if (useNxCloud) {
output.log({ title: '🛠️ Setting up Nx Cloud' });
execSync(
`${pmc.exec} nx g nx:connect-to-nx-cloud --installationSource=nx-init --quiet --hideFormatLogs --no-interactive`,
{
stdio: [0, 1, 2],
cwd: repoRoot,
}
);
await initCloud('nx-init');
}
printFinalMessage({

View File

@ -5,10 +5,11 @@ import { readJson } from '../../../generators/utils/json';
import { NxJsonConfiguration } from '../../../config/nx-json';
import { readNxJson, updateNxJson } from '../../../generators/utils/nx-json';
import { formatChangedFilesWithPrettierIfAvailable } from '../../../generators/internal-utils/format-changed-files-with-prettier-if-available';
import { repoUsesGithub, shortenedCloudUrl } from '../../utilities/url-shorten';
import {
repoUsesGithub,
createNxCloudOnboardingURL,
} from '../../utilities/url-shorten';
import { getCloudUrl } from '../../utilities/get-cloud-options';
import * as ora from 'ora';
import * as open from 'open';
function printCloudConnectionDisabledMessage() {
output.error({
@ -68,65 +69,31 @@ async function createNxCloudWorkspace(
return response.data;
}
async function printSuccessMessage(
export async function printSuccessMessage(
token: string | undefined,
installationSource: string,
usesGithub: boolean
) {
const connectCloudUrl = await shortenedCloudUrl(
const connectCloudUrl = await createNxCloudOnboardingURL(
installationSource,
token,
usesGithub
);
if (installationSource === 'nx-connect' && usesGithub) {
try {
const cloudConnectSpinner = ora(
`Opening Nx Cloud ${connectCloudUrl} in your browser to connect your workspace.`
).start();
await sleep(2000);
open(connectCloudUrl);
cloudConnectSpinner.succeed();
} catch (e) {
output.note({
title: `Your Nx Cloud workspace is ready.`,
bodyLines: [
`To claim it, connect it to your Nx Cloud account:`,
`- Go to the following URL to connect your workspace to Nx Cloud:`,
'',
`${connectCloudUrl}`,
],
});
}
} else {
if (installationSource === 'create-nx-workspace') {
output.note({
title: `Your Nx Cloud workspace is ready.`,
bodyLines: [
`To claim it, connect it to your Nx Cloud account:`,
`- Push your repository to your git hosting provider.`,
`- Go to the following URL to connect your workspace to Nx Cloud:`,
'',
`${connectCloudUrl}`,
],
});
} else {
output.note({
title: `Your Nx Cloud workspace is ready.`,
bodyLines: [
`To claim it, connect it to your Nx Cloud account:`,
`- Commit and push your changes.`,
`- Create a pull request for the changes.`,
`- Go to the following URL to connect your workspace to Nx Cloud:`,
'',
`${connectCloudUrl}`,
],
});
}
}
output.note({
title: `Your Nx Cloud workspace is ready.`,
bodyLines: [
`To claim it, connect it to your Nx Cloud account:`,
`- Commit and push your changes.`,
`- Create a pull request for the changes.`,
`- Go to the following URL to connect your workspace to Nx Cloud:`,
'',
`${connectCloudUrl}`,
],
});
return connectCloudUrl;
}
interface ConnectToNxCloudOptions {
export interface ConnectToNxCloudOptions {
analytics?: boolean;
installationSource?: string;
hideFormatLogs?: boolean;
@ -153,7 +120,7 @@ function addNxCloudOptionsToNxJson(
export async function connectToNxCloud(
tree: Tree,
schema: ConnectToNxCloudOptions
) {
): Promise<string> {
schema.installationSource ??= 'user';
const nxJson = readNxJson(tree) as
@ -161,16 +128,14 @@ export async function connectToNxCloud(
| (NxJsonConfiguration & { neverConnectToCloud: boolean });
if (nxJson?.neverConnectToCloud) {
return () => {
printCloudConnectionDisabledMessage();
};
printCloudConnectionDisabledMessage();
return null;
} else {
const usesGithub = await repoUsesGithub(schema.github);
const usesGithub = schema.github ?? (await repoUsesGithub(schema.github));
let responseFromCreateNxCloudWorkspace:
| {
token: string;
url: string;
}
| undefined;
@ -192,18 +157,9 @@ export async function connectToNxCloud(
await formatChangedFilesWithPrettierIfAvailable(tree, {
silent: schema.hideFormatLogs,
});
return responseFromCreateNxCloudWorkspace.token;
}
return async () =>
await printSuccessMessage(
responseFromCreateNxCloudWorkspace?.token,
schema.installationSource,
usesGithub
);
}
}
function sleep(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
export default connectToNxCloud;

View File

@ -2,10 +2,11 @@ import { logger } from '../../devkit-exports';
import { getGithubSlugOrNull } from '../../utils/git-utils';
import { getCloudUrl } from './get-cloud-options';
export async function shortenedCloudUrl(
installationSource: string,
export async function createNxCloudOnboardingURL(
onboardingSource: string,
accessToken?: string,
usesGithub?: boolean
usesGithub?: boolean,
meta?: string
) {
const githubSlug = getGithubSlugOrNull();
@ -29,7 +30,7 @@ export async function shortenedCloudUrl(
return apiUrl;
}
const source = getSource(installationSource);
const source = getSource(onboardingSource);
try {
const response = await require('axios').post(
@ -39,6 +40,7 @@ export async function shortenedCloudUrl(
source,
accessToken: usesGithub ? null : accessToken,
selectedRepositoryName: githubSlug === 'github' ? null : githubSlug,
meta,
}
);
@ -87,15 +89,13 @@ export async function repoUsesGithub(
function getSource(
installationSource: string
): 'nx-init' | 'nx-connect' | 'create-nx-workspace' | 'other' {
): 'nx-init' | 'nx-connect' | string {
if (installationSource.includes('nx-init')) {
return 'nx-init';
} else if (installationSource.includes('nx-connect')) {
return 'nx-connect';
} else if (installationSource.includes('create-nx-workspace')) {
return 'create-nx-workspace';
} else {
return 'other';
return installationSource;
}
}