feat(misc): a/b different messages during migration to next major
This commit is contained in:
parent
4678f3a83b
commit
77b57b78e8
83
packages/create-nx-workspace/bin/ab-testing.ts
Normal file
83
packages/create-nx-workspace/bin/ab-testing.ts
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
import axios from 'axios';
|
||||||
|
import { isCI } from './output';
|
||||||
|
|
||||||
|
export class PromptMessages {
|
||||||
|
private messages = {
|
||||||
|
nxCloudCreation: [
|
||||||
|
{
|
||||||
|
code: 'set-up-distributed-caching-ci',
|
||||||
|
message: `Enable distributed caching to make your CI faster`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
nxCloudMigration: [
|
||||||
|
{
|
||||||
|
code: 'we-noticed',
|
||||||
|
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?`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: 'not-leveraging-caching',
|
||||||
|
message: `You're not leveraging distributed caching yet. Do you want to enable it and speed up your CI?`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: 'make-ci-faster',
|
||||||
|
message: `Enable distributed caching to make your CI faster?`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
private selectedMessages = {};
|
||||||
|
|
||||||
|
getPromptMessage(key: string): string {
|
||||||
|
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() * this.messages[key].length
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.messages[key][this.selectedMessages[key]].message;
|
||||||
|
}
|
||||||
|
|
||||||
|
codeOfSelectedPromptMessage(key: string): string {
|
||||||
|
if (this.selectedMessages[key] === undefined) return null;
|
||||||
|
return this.messages[key][this.selectedMessages[key]].code;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const messages = new PromptMessages();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We are incrementing a counter to track how often create-nx-workspace is used in CI
|
||||||
|
* vs dev environments. No personal information is collected.
|
||||||
|
*/
|
||||||
|
export async function recordStat(opts: {
|
||||||
|
command: string;
|
||||||
|
nxVersion: string;
|
||||||
|
useCloud: boolean;
|
||||||
|
meta: string;
|
||||||
|
}) {
|
||||||
|
try {
|
||||||
|
const major = Number(opts.nxVersion.split('.')[0]);
|
||||||
|
if (process.env.NX_VERBOSE_LOGGING === 'true') {
|
||||||
|
console.log(`Record stat. Major: ${major}`);
|
||||||
|
}
|
||||||
|
if (major < 10 || major > 14) return; // test version, skip it
|
||||||
|
await axios
|
||||||
|
.create({
|
||||||
|
baseURL: 'https://cloud.nx.app',
|
||||||
|
timeout: 400,
|
||||||
|
})
|
||||||
|
.post('/nx-cloud/stats', {
|
||||||
|
command: opts.command,
|
||||||
|
isCI: isCI(),
|
||||||
|
useCloud: opts.useCloud,
|
||||||
|
meta: opts.meta,
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
if (process.env.NX_VERBOSE_LOGGING === 'true') {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -5,7 +5,7 @@ import * as path from 'path';
|
|||||||
import { dirSync } from 'tmp';
|
import { dirSync } from 'tmp';
|
||||||
import * as yargs from 'yargs';
|
import * as yargs from 'yargs';
|
||||||
import { showNxWarning, unparse } from './shared';
|
import { showNxWarning, unparse } from './shared';
|
||||||
import { isCI, output } from './output';
|
import { output } from './output';
|
||||||
import * as ora from 'ora';
|
import * as ora from 'ora';
|
||||||
import {
|
import {
|
||||||
detectInvokedPackageManager,
|
detectInvokedPackageManager,
|
||||||
@ -23,7 +23,7 @@ import chalk = require('chalk');
|
|||||||
import { ciList } from './ci';
|
import { ciList } from './ci';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
import { initializeGitRepo } from './git';
|
import { initializeGitRepo } from './git';
|
||||||
import axios from 'axios';
|
import { messages, recordStat } from './ab-testing';
|
||||||
|
|
||||||
type Arguments = {
|
type Arguments = {
|
||||||
name: string;
|
name: string;
|
||||||
@ -62,37 +62,6 @@ enum Preset {
|
|||||||
Express = 'express',
|
Express = 'express',
|
||||||
}
|
}
|
||||||
|
|
||||||
class PromptMessages {
|
|
||||||
private messages = {
|
|
||||||
nxCloud: [
|
|
||||||
{
|
|
||||||
code: 'set-up-distributed-caching-ci',
|
|
||||||
message: `Enable distributed caching to make your CI faster`,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
private selectedMessages = {};
|
|
||||||
|
|
||||||
getPromptMessage(key: string): string {
|
|
||||||
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() * this.messages[key].length
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return this.messages[key][this.selectedMessages[key]].message;
|
|
||||||
}
|
|
||||||
|
|
||||||
codeOfSelectedPromptMessage(key: string): string {
|
|
||||||
if (this.selectedMessages[key] === undefined) return null;
|
|
||||||
return this.messages[key][this.selectedMessages[key]].code;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const presetOptions: { name: Preset; message: string }[] = [
|
const presetOptions: { name: Preset; message: string }[] = [
|
||||||
{
|
{
|
||||||
name: Preset.Apps,
|
name: Preset.Apps,
|
||||||
@ -162,8 +131,6 @@ const nxVersion = require('../package.json').version;
|
|||||||
const tsVersion = 'TYPESCRIPT_VERSION'; // This gets replaced with the typescript version in the root package.json during build
|
const tsVersion = 'TYPESCRIPT_VERSION'; // This gets replaced with the typescript version in the root package.json during build
|
||||||
const prettierVersion = 'PRETTIER_VERSION'; // This gets replaced with the prettier version in the root package.json during build
|
const prettierVersion = 'PRETTIER_VERSION'; // This gets replaced with the prettier version in the root package.json during build
|
||||||
|
|
||||||
const messages = new PromptMessages();
|
|
||||||
|
|
||||||
export const commandsObject: yargs.Argv<Arguments> = yargs
|
export const commandsObject: yargs.Argv<Arguments> = yargs
|
||||||
.wrap(yargs.terminalWidth())
|
.wrap(yargs.terminalWidth())
|
||||||
.parserConfiguration({
|
.parserConfiguration({
|
||||||
@ -208,7 +175,7 @@ export const commandsObject: yargs.Argv<Arguments> = yargs
|
|||||||
type: 'string',
|
type: 'string',
|
||||||
})
|
})
|
||||||
.option('nxCloud', {
|
.option('nxCloud', {
|
||||||
describe: chalk.dim(messages.getPromptMessage('nxCloud')),
|
describe: chalk.dim(messages.getPromptMessage('nxCloudCreation')),
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
})
|
})
|
||||||
.option('ci', {
|
.option('ci', {
|
||||||
@ -346,7 +313,12 @@ async function main(parsedArgs: yargs.Arguments<Arguments>) {
|
|||||||
printNxCloudSuccessMessage(nxCloudInstallRes.stdout);
|
printNxCloudSuccessMessage(nxCloudInstallRes.stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
await recordWorkspaceCreationStats(nxCloud);
|
await recordStat({
|
||||||
|
nxVersion,
|
||||||
|
command: 'create-nx-workspace',
|
||||||
|
useCloud: nxCloud,
|
||||||
|
meta: messages.codeOfSelectedPromptMessage('nxCloudCreation'),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getConfiguration(
|
async function getConfiguration(
|
||||||
@ -718,7 +690,7 @@ async function determineNxCloud(
|
|||||||
.prompt([
|
.prompt([
|
||||||
{
|
{
|
||||||
name: 'NxCloud',
|
name: 'NxCloud',
|
||||||
message: messages.getPromptMessage('nxCloud'),
|
message: messages.getPromptMessage('nxCloudCreation'),
|
||||||
type: 'autocomplete',
|
type: 'autocomplete',
|
||||||
choices: [
|
choices: [
|
||||||
{
|
{
|
||||||
@ -1039,32 +1011,3 @@ function pointToTutorialAndCourse(preset: Preset) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* We are incrementing a counter to track how often create-nx-workspace is used in CI
|
|
||||||
* vs dev environments. No personal information is collected.
|
|
||||||
*/
|
|
||||||
async function recordWorkspaceCreationStats(useCloud: boolean) {
|
|
||||||
try {
|
|
||||||
const major = Number(nxVersion.split('.')[0]);
|
|
||||||
if (process.env.NX_VERBOSE_LOGGING === 'true') {
|
|
||||||
console.log(`Record stat. Major: ${major}`);
|
|
||||||
}
|
|
||||||
if (major < 10 || major > 14) return; // test version, skip it
|
|
||||||
await axios
|
|
||||||
.create({
|
|
||||||
baseURL: 'https://cloud.nx.app',
|
|
||||||
timeout: 400,
|
|
||||||
})
|
|
||||||
.post('/nx-cloud/stats', {
|
|
||||||
command: 'create-nx-workspace',
|
|
||||||
isCI: isCI(),
|
|
||||||
useCloud,
|
|
||||||
meta: messages.codeOfSelectedPromptMessage('nxCloud'),
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
if (process.env.NX_VERBOSE_LOGGING === 'true') {
|
|
||||||
console.error(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -63,7 +63,8 @@
|
|||||||
"v8-compile-cache": "2.3.0",
|
"v8-compile-cache": "2.3.0",
|
||||||
"yargs": "^17.4.0",
|
"yargs": "^17.4.0",
|
||||||
"yargs-parser": "21.0.1",
|
"yargs-parser": "21.0.1",
|
||||||
"js-yaml": "4.1.0"
|
"js-yaml": "4.1.0",
|
||||||
|
"axios": "0.21.1"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@swc-node/register": "^1.4.2",
|
"@swc-node/register": "^1.4.2",
|
||||||
|
|||||||
@ -29,7 +29,7 @@ export async function connectToNxCloudIfExplicitlyAsked(opts: {
|
|||||||
|
|
||||||
export async function connectToNxCloudCommand(
|
export async function connectToNxCloudCommand(
|
||||||
promptOverride?: string
|
promptOverride?: string
|
||||||
): Promise<void> {
|
): Promise<boolean> {
|
||||||
const nxJson = readNxJson();
|
const nxJson = readNxJson();
|
||||||
const nxCloudUsed = Object.values(nxJson.tasksRunnerOptions).find(
|
const nxCloudUsed = Object.values(nxJson.tasksRunnerOptions).find(
|
||||||
(r) => r.runner == '@nrwl/nx-cloud'
|
(r) => r.runner == '@nrwl/nx-cloud'
|
||||||
@ -38,16 +38,17 @@ export async function connectToNxCloudCommand(
|
|||||||
output.log({
|
output.log({
|
||||||
title: 'This workspace is already connected to Nx Cloud.',
|
title: 'This workspace is already connected to Nx Cloud.',
|
||||||
});
|
});
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await connectToNxCloudPrompt(promptOverride);
|
const res = await connectToNxCloudPrompt(promptOverride);
|
||||||
if (!res) return;
|
if (!res) return false;
|
||||||
const pmc = getPackageManagerCommand();
|
const pmc = getPackageManagerCommand();
|
||||||
execSync(`${pmc.addDev} @nrwl/nx-cloud@latest`);
|
execSync(`${pmc.addDev} @nrwl/nx-cloud@latest`);
|
||||||
execSync(`${pmc.exec} nx g @nrwl/nx-cloud:init`, {
|
execSync(`${pmc.exec} nx g @nrwl/nx-cloud:init`, {
|
||||||
stdio: [0, 1, 2],
|
stdio: [0, 1, 2],
|
||||||
});
|
});
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function connectToNxCloudPrompt(prompt?: string) {
|
async function connectToNxCloudPrompt(prompt?: string) {
|
||||||
|
|||||||
@ -34,6 +34,8 @@ import {
|
|||||||
import { handleErrors } from '../utils/params';
|
import { handleErrors } from '../utils/params';
|
||||||
import { connectToNxCloudCommand } from './connect-to-nx-cloud';
|
import { connectToNxCloudCommand } from './connect-to-nx-cloud';
|
||||||
import { output } from '../utils/output';
|
import { output } from '../utils/output';
|
||||||
|
import { messages, recordStat } from 'nx/src/utils/ab-testing';
|
||||||
|
import { nxVersion } from '../utils/versions';
|
||||||
|
|
||||||
export interface ResolvedMigrationConfiguration extends MigrationsJson {
|
export interface ResolvedMigrationConfiguration extends MigrationsJson {
|
||||||
packageGroup?: NxMigrationsConfiguration['packageGroup'];
|
packageGroup?: NxMigrationsConfiguration['packageGroup'];
|
||||||
@ -815,9 +817,15 @@ async function generateMigrationsJsonAndUpdatePackageJson(
|
|||||||
opts.targetVersion
|
opts.targetVersion
|
||||||
))
|
))
|
||||||
) {
|
) {
|
||||||
await connectToNxCloudCommand(
|
const useCloud = await connectToNxCloudCommand(
|
||||||
'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?'
|
messages.getPromptMessage('nxCloudMigration')
|
||||||
);
|
);
|
||||||
|
await recordStat({
|
||||||
|
command: 'migrate',
|
||||||
|
nxVersion,
|
||||||
|
useCloud,
|
||||||
|
meta: messages.codeOfSelectedPromptMessage('nxCloudMigration'),
|
||||||
|
});
|
||||||
originalPackageJson = readJsonFile<PackageJson>(
|
originalPackageJson = readJsonFile<PackageJson>(
|
||||||
join(root, 'package.json')
|
join(root, 'package.json')
|
||||||
);
|
);
|
||||||
|
|||||||
83
packages/nx/src/utils/ab-testing.ts
Normal file
83
packages/nx/src/utils/ab-testing.ts
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
import axios from 'axios';
|
||||||
|
import { isCI } from './is-ci';
|
||||||
|
|
||||||
|
export class PromptMessages {
|
||||||
|
private messages = {
|
||||||
|
nxCloudCreation: [
|
||||||
|
{
|
||||||
|
code: 'set-up-distributed-caching-ci',
|
||||||
|
message: `Enable distributed caching to make your CI faster`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
nxCloudMigration: [
|
||||||
|
{
|
||||||
|
code: 'we-noticed',
|
||||||
|
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?`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: 'not-leveraging-caching',
|
||||||
|
message: `You're not leveraging distributed caching yet. Do you want to enable it and speed up your CI?`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: 'make-ci-faster',
|
||||||
|
message: `Enable distributed caching to make your CI faster?`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
private selectedMessages = {};
|
||||||
|
|
||||||
|
getPromptMessage(key: string): string {
|
||||||
|
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() * this.messages[key].length
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.messages[key][this.selectedMessages[key]].message;
|
||||||
|
}
|
||||||
|
|
||||||
|
codeOfSelectedPromptMessage(key: string): string {
|
||||||
|
if (this.selectedMessages[key] === undefined) return null;
|
||||||
|
return this.messages[key][this.selectedMessages[key]].code;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const messages = new PromptMessages();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We are incrementing a counter to track how often create-nx-workspace is used in CI
|
||||||
|
* vs dev environments. No personal information is collected.
|
||||||
|
*/
|
||||||
|
export async function recordStat(opts: {
|
||||||
|
command: string;
|
||||||
|
nxVersion: string;
|
||||||
|
useCloud: boolean;
|
||||||
|
meta: string;
|
||||||
|
}) {
|
||||||
|
try {
|
||||||
|
const major = Number(opts.nxVersion.split('.')[0]);
|
||||||
|
if (process.env.NX_VERBOSE_LOGGING === 'true') {
|
||||||
|
console.log(`Record stat. Major: ${major}`);
|
||||||
|
}
|
||||||
|
if (major < 10 || major > 14) return; // test version, skip it
|
||||||
|
await axios
|
||||||
|
.create({
|
||||||
|
baseURL: 'https://cloud.nx.app',
|
||||||
|
timeout: 400,
|
||||||
|
})
|
||||||
|
.post('/nx-cloud/stats', {
|
||||||
|
command: opts.command,
|
||||||
|
isCI: isCI(),
|
||||||
|
useCloud: opts.useCloud,
|
||||||
|
meta: opts.meta,
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
if (process.env.NX_VERBOSE_LOGGING === 'true') {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user