Skip to content

Commit 77b57b7

Browse files
committed
feat(misc): a/b different messages during migration to next major
1 parent 4678f3a commit 77b57b7

File tree

6 files changed

+192
-73
lines changed

6 files changed

+192
-73
lines changed
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import axios from 'axios';
2+
import { isCI } from './output';
3+
4+
export class PromptMessages {
5+
private messages = {
6+
nxCloudCreation: [
7+
{
8+
code: 'set-up-distributed-caching-ci',
9+
message: `Enable distributed caching to make your CI faster`,
10+
},
11+
],
12+
nxCloudMigration: [
13+
{
14+
code: 'we-noticed',
15+
message: `We noticed you are migrating to a new major version, but are not taking advantage of Nx Cloud. Nx Cloud can make your CI up to 10 times faster. Learn more about it here: nx.app. Would you like to add it?`,
16+
},
17+
{
18+
code: 'not-leveraging-caching',
19+
message: `You're not leveraging distributed caching yet. Do you want to enable it and speed up your CI?`,
20+
},
21+
{
22+
code: 'make-ci-faster',
23+
message: `Enable distributed caching to make your CI faster?`,
24+
},
25+
],
26+
};
27+
28+
private selectedMessages = {};
29+
30+
getPromptMessage(key: string): string {
31+
if (this.selectedMessages[key] === undefined) {
32+
if (process.env.NX_GENERATE_DOCS_PROCESS === 'true') {
33+
this.selectedMessages[key] = 0;
34+
} else {
35+
this.selectedMessages[key] = Math.floor(
36+
Math.random() * this.messages[key].length
37+
);
38+
}
39+
}
40+
return this.messages[key][this.selectedMessages[key]].message;
41+
}
42+
43+
codeOfSelectedPromptMessage(key: string): string {
44+
if (this.selectedMessages[key] === undefined) return null;
45+
return this.messages[key][this.selectedMessages[key]].code;
46+
}
47+
}
48+
49+
export const messages = new PromptMessages();
50+
51+
/**
52+
* We are incrementing a counter to track how often create-nx-workspace is used in CI
53+
* vs dev environments. No personal information is collected.
54+
*/
55+
export async function recordStat(opts: {
56+
command: string;
57+
nxVersion: string;
58+
useCloud: boolean;
59+
meta: string;
60+
}) {
61+
try {
62+
const major = Number(opts.nxVersion.split('.')[0]);
63+
if (process.env.NX_VERBOSE_LOGGING === 'true') {
64+
console.log(`Record stat. Major: ${major}`);
65+
}
66+
if (major < 10 || major > 14) return; // test version, skip it
67+
await axios
68+
.create({
69+
baseURL: 'https://cloud.nx.app',
70+
timeout: 400,
71+
})
72+
.post('/nx-cloud/stats', {
73+
command: opts.command,
74+
isCI: isCI(),
75+
useCloud: opts.useCloud,
76+
meta: opts.meta,
77+
});
78+
} catch (e) {
79+
if (process.env.NX_VERBOSE_LOGGING === 'true') {
80+
console.error(e);
81+
}
82+
}
83+
}

packages/create-nx-workspace/bin/create-nx-workspace.ts

Lines changed: 10 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import * as path from 'path';
55
import { dirSync } from 'tmp';
66
import * as yargs from 'yargs';
77
import { showNxWarning, unparse } from './shared';
8-
import { isCI, output } from './output';
8+
import { output } from './output';
99
import * as ora from 'ora';
1010
import {
1111
detectInvokedPackageManager,
@@ -23,7 +23,7 @@ import chalk = require('chalk');
2323
import { ciList } from './ci';
2424
import { join } from 'path';
2525
import { initializeGitRepo } from './git';
26-
import axios from 'axios';
26+
import { messages, recordStat } from './ab-testing';
2727

2828
type Arguments = {
2929
name: string;
@@ -62,37 +62,6 @@ enum Preset {
6262
Express = 'express',
6363
}
6464

65-
class PromptMessages {
66-
private messages = {
67-
nxCloud: [
68-
{
69-
code: 'set-up-distributed-caching-ci',
70-
message: `Enable distributed caching to make your CI faster`,
71-
},
72-
],
73-
};
74-
75-
private selectedMessages = {};
76-
77-
getPromptMessage(key: string): string {
78-
if (this.selectedMessages[key] === undefined) {
79-
if (process.env.NX_GENERATE_DOCS_PROCESS === 'true') {
80-
this.selectedMessages[key] = 0;
81-
} else {
82-
this.selectedMessages[key] = Math.floor(
83-
Math.random() * this.messages[key].length
84-
);
85-
}
86-
}
87-
return this.messages[key][this.selectedMessages[key]].message;
88-
}
89-
90-
codeOfSelectedPromptMessage(key: string): string {
91-
if (this.selectedMessages[key] === undefined) return null;
92-
return this.messages[key][this.selectedMessages[key]].code;
93-
}
94-
}
95-
9665
const presetOptions: { name: Preset; message: string }[] = [
9766
{
9867
name: Preset.Apps,
@@ -162,8 +131,6 @@ const nxVersion = require('../package.json').version;
162131
const tsVersion = 'TYPESCRIPT_VERSION'; // This gets replaced with the typescript version in the root package.json during build
163132
const prettierVersion = 'PRETTIER_VERSION'; // This gets replaced with the prettier version in the root package.json during build
164133

165-
const messages = new PromptMessages();
166-
167134
export const commandsObject: yargs.Argv<Arguments> = yargs
168135
.wrap(yargs.terminalWidth())
169136
.parserConfiguration({
@@ -208,7 +175,7 @@ export const commandsObject: yargs.Argv<Arguments> = yargs
208175
type: 'string',
209176
})
210177
.option('nxCloud', {
211-
describe: chalk.dim(messages.getPromptMessage('nxCloud')),
178+
describe: chalk.dim(messages.getPromptMessage('nxCloudCreation')),
212179
type: 'boolean',
213180
})
214181
.option('ci', {
@@ -346,7 +313,12 @@ async function main(parsedArgs: yargs.Arguments<Arguments>) {
346313
printNxCloudSuccessMessage(nxCloudInstallRes.stdout);
347314
}
348315

349-
await recordWorkspaceCreationStats(nxCloud);
316+
await recordStat({
317+
nxVersion,
318+
command: 'create-nx-workspace',
319+
useCloud: nxCloud,
320+
meta: messages.codeOfSelectedPromptMessage('nxCloudCreation'),
321+
});
350322
}
351323

352324
async function getConfiguration(
@@ -718,7 +690,7 @@ async function determineNxCloud(
718690
.prompt([
719691
{
720692
name: 'NxCloud',
721-
message: messages.getPromptMessage('nxCloud'),
693+
message: messages.getPromptMessage('nxCloudCreation'),
722694
type: 'autocomplete',
723695
choices: [
724696
{
@@ -1039,32 +1011,3 @@ function pointToTutorialAndCourse(preset: Preset) {
10391011
break;
10401012
}
10411013
}
1042-
1043-
/**
1044-
* We are incrementing a counter to track how often create-nx-workspace is used in CI
1045-
* vs dev environments. No personal information is collected.
1046-
*/
1047-
async function recordWorkspaceCreationStats(useCloud: boolean) {
1048-
try {
1049-
const major = Number(nxVersion.split('.')[0]);
1050-
if (process.env.NX_VERBOSE_LOGGING === 'true') {
1051-
console.log(`Record stat. Major: ${major}`);
1052-
}
1053-
if (major < 10 || major > 14) return; // test version, skip it
1054-
await axios
1055-
.create({
1056-
baseURL: 'https://cloud.nx.app',
1057-
timeout: 400,
1058-
})
1059-
.post('/nx-cloud/stats', {
1060-
command: 'create-nx-workspace',
1061-
isCI: isCI(),
1062-
useCloud,
1063-
meta: messages.codeOfSelectedPromptMessage('nxCloud'),
1064-
});
1065-
} catch (e) {
1066-
if (process.env.NX_VERBOSE_LOGGING === 'true') {
1067-
console.error(e);
1068-
}
1069-
}
1070-
}

packages/nx/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,8 @@
6363
"v8-compile-cache": "2.3.0",
6464
"yargs": "^17.4.0",
6565
"yargs-parser": "21.0.1",
66-
"js-yaml": "4.1.0"
66+
"js-yaml": "4.1.0",
67+
"axios": "0.21.1"
6768
},
6869
"peerDependencies": {
6970
"@swc-node/register": "^1.4.2",

packages/nx/src/command-line/connect-to-nx-cloud.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export async function connectToNxCloudIfExplicitlyAsked(opts: {
2929

3030
export async function connectToNxCloudCommand(
3131
promptOverride?: string
32-
): Promise<void> {
32+
): Promise<boolean> {
3333
const nxJson = readNxJson();
3434
const nxCloudUsed = Object.values(nxJson.tasksRunnerOptions).find(
3535
(r) => r.runner == '@nrwl/nx-cloud'
@@ -38,16 +38,17 @@ export async function connectToNxCloudCommand(
3838
output.log({
3939
title: 'This workspace is already connected to Nx Cloud.',
4040
});
41-
return;
41+
return false;
4242
}
4343

4444
const res = await connectToNxCloudPrompt(promptOverride);
45-
if (!res) return;
45+
if (!res) return false;
4646
const pmc = getPackageManagerCommand();
4747
execSync(`${pmc.addDev} @nrwl/nx-cloud@latest`);
4848
execSync(`${pmc.exec} nx g @nrwl/nx-cloud:init`, {
4949
stdio: [0, 1, 2],
5050
});
51+
return true;
5152
}
5253

5354
async function connectToNxCloudPrompt(prompt?: string) {

packages/nx/src/command-line/migrate.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ import {
3434
import { handleErrors } from '../utils/params';
3535
import { connectToNxCloudCommand } from './connect-to-nx-cloud';
3636
import { output } from '../utils/output';
37+
import { messages, recordStat } from 'nx/src/utils/ab-testing';
38+
import { nxVersion } from '../utils/versions';
3739

3840
export interface ResolvedMigrationConfiguration extends MigrationsJson {
3941
packageGroup?: NxMigrationsConfiguration['packageGroup'];
@@ -815,9 +817,15 @@ async function generateMigrationsJsonAndUpdatePackageJson(
815817
opts.targetVersion
816818
))
817819
) {
818-
await connectToNxCloudCommand(
819-
'We noticed you are migrating to a new major version, but are not taking advantage of Nx Cloud. Nx Cloud can make your CI up to 10 times faster. Learn more about it here: nx.app. Would you like to add it?'
820+
const useCloud = await connectToNxCloudCommand(
821+
messages.getPromptMessage('nxCloudMigration')
820822
);
823+
await recordStat({
824+
command: 'migrate',
825+
nxVersion,
826+
useCloud,
827+
meta: messages.codeOfSelectedPromptMessage('nxCloudMigration'),
828+
});
821829
originalPackageJson = readJsonFile<PackageJson>(
822830
join(root, 'package.json')
823831
);

packages/nx/src/utils/ab-testing.ts

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import axios from 'axios';
2+
import { isCI } from './is-ci';
3+
4+
export class PromptMessages {
5+
private messages = {
6+
nxCloudCreation: [
7+
{
8+
code: 'set-up-distributed-caching-ci',
9+
message: `Enable distributed caching to make your CI faster`,
10+
},
11+
],
12+
nxCloudMigration: [
13+
{
14+
code: 'we-noticed',
15+
message: `We noticed you are migrating to a new major version, but are not taking advantage of Nx Cloud. Nx Cloud can make your CI up to 10 times faster. Learn more about it here: nx.app. Would you like to add it?`,
16+
},
17+
{
18+
code: 'not-leveraging-caching',
19+
message: `You're not leveraging distributed caching yet. Do you want to enable it and speed up your CI?`,
20+
},
21+
{
22+
code: 'make-ci-faster',
23+
message: `Enable distributed caching to make your CI faster?`,
24+
},
25+
],
26+
};
27+
28+
private selectedMessages = {};
29+
30+
getPromptMessage(key: string): string {
31+
if (this.selectedMessages[key] === undefined) {
32+
if (process.env.NX_GENERATE_DOCS_PROCESS === 'true') {
33+
this.selectedMessages[key] = 0;
34+
} else {
35+
this.selectedMessages[key] = Math.floor(
36+
Math.random() * this.messages[key].length
37+
);
38+
}
39+
}
40+
return this.messages[key][this.selectedMessages[key]].message;
41+
}
42+
43+
codeOfSelectedPromptMessage(key: string): string {
44+
if (this.selectedMessages[key] === undefined) return null;
45+
return this.messages[key][this.selectedMessages[key]].code;
46+
}
47+
}
48+
49+
export const messages = new PromptMessages();
50+
51+
/**
52+
* We are incrementing a counter to track how often create-nx-workspace is used in CI
53+
* vs dev environments. No personal information is collected.
54+
*/
55+
export async function recordStat(opts: {
56+
command: string;
57+
nxVersion: string;
58+
useCloud: boolean;
59+
meta: string;
60+
}) {
61+
try {
62+
const major = Number(opts.nxVersion.split('.')[0]);
63+
if (process.env.NX_VERBOSE_LOGGING === 'true') {
64+
console.log(`Record stat. Major: ${major}`);
65+
}
66+
if (major < 10 || major > 14) return; // test version, skip it
67+
await axios
68+
.create({
69+
baseURL: 'https://cloud.nx.app',
70+
timeout: 400,
71+
})
72+
.post('/nx-cloud/stats', {
73+
command: opts.command,
74+
isCI: isCI(),
75+
useCloud: opts.useCloud,
76+
meta: opts.meta,
77+
});
78+
} catch (e) {
79+
if (process.env.NX_VERBOSE_LOGGING === 'true') {
80+
console.error(e);
81+
}
82+
}
83+
}

0 commit comments

Comments
 (0)