@hubspot/cli 7.7.16-experimental.3 → 7.7.16-experimental.4
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/commands/app/install.d.ts +8 -0
- package/commands/app/install.js +91 -0
- package/commands/app.js +6 -1
- package/commands/getStarted.js +2 -2
- package/commands/project/cloneApp.js +4 -4
- package/commands/project/create.js +9 -9
- package/commands/project/dev/unifiedFlow.js +1 -0
- package/commands/testAccount/create.js +8 -4
- package/lang/en.d.ts +29 -3
- package/lang/en.js +29 -3
- package/lib/app/migrate_legacy.js +2 -3
- package/lib/polling.d.ts +1 -1
- package/lib/polling.js +11 -1
- package/lib/projects/add/v3AddComponent.js +4 -0
- package/lib/projects/create/index.d.ts +3 -2
- package/lib/projects/create/index.js +11 -5
- package/lib/projects/create/v3.d.ts +3 -3
- package/lib/projects/create/v3.js +2 -2
- package/lib/projects/localDev/LocalDevProcess.d.ts +3 -2
- package/lib/projects/localDev/LocalDevProcess.js +16 -12
- package/lib/projects/localDev/LocalDevState.d.ts +10 -5
- package/lib/projects/localDev/LocalDevState.js +18 -20
- package/lib/projects/localDev/LocalDevWatcher.js +1 -1
- package/lib/prompts/projectNameAndDestPrompt.d.ts +3 -0
- package/lib/prompts/projectNameAndDestPrompt.js +60 -0
- package/lib/prompts/selectProjectTemplatePrompt.d.ts +26 -0
- package/lib/prompts/{createProjectPrompt.js → selectProjectTemplatePrompt.js} +6 -55
- package/package.json +2 -2
- package/types/LocalDev.d.ts +1 -0
- package/lib/prompts/createProjectPrompt.d.ts +0 -28
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { CommonArgs, ConfigArgs, AccountArgs, EnvironmentArgs, YargsCommandModule, JSONOutputArgs } from '../../types/Yargs';
|
|
2
|
+
type InstallAppArgs = CommonArgs & ConfigArgs & AccountArgs & EnvironmentArgs & JSONOutputArgs & {
|
|
3
|
+
appUid?: string;
|
|
4
|
+
projectName?: string;
|
|
5
|
+
testAccountId?: number;
|
|
6
|
+
};
|
|
7
|
+
declare const installAppCommand: YargsCommandModule<unknown, InstallAppArgs>;
|
|
8
|
+
export default installAppCommand;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const developerTestAccounts_1 = require("@hubspot/local-dev-lib/api/developerTestAccounts");
|
|
7
|
+
const usageTracking_1 = require("../../lib/usageTracking");
|
|
8
|
+
const en_1 = require("../../lang/en");
|
|
9
|
+
const exitCodes_1 = require("../../lib/enums/exitCodes");
|
|
10
|
+
const yargsUtils_1 = require("../../lib/yargsUtils");
|
|
11
|
+
const logger_1 = require("../../lib/ui/logger");
|
|
12
|
+
const SpinniesManager_1 = __importDefault(require("../../lib/ui/SpinniesManager"));
|
|
13
|
+
const errorHandlers_1 = require("../../lib/errorHandlers");
|
|
14
|
+
const polling_1 = require("../../lib/polling");
|
|
15
|
+
const command = 'install';
|
|
16
|
+
const describe = undefined; // commands.app.subcommands.install.describe;
|
|
17
|
+
async function handler(args) {
|
|
18
|
+
const { derivedAccountId, appUid, projectName, testAccountId, formatOutputAsJson, } = args;
|
|
19
|
+
(0, usageTracking_1.trackCommandUsage)('app-install', {}, derivedAccountId);
|
|
20
|
+
const jsonOutput = {};
|
|
21
|
+
try {
|
|
22
|
+
const { data } = await (0, developerTestAccounts_1.installOauthAppIntoDeveloperTestAccount)(derivedAccountId, testAccountId, projectName, appUid);
|
|
23
|
+
if (data?.authCodes.length > 0) {
|
|
24
|
+
jsonOutput.authCode = data.authCodes[0].authCode;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
catch (err) {
|
|
28
|
+
(0, errorHandlers_1.logError)(err);
|
|
29
|
+
process.exit(exitCodes_1.EXIT_CODES.ERROR);
|
|
30
|
+
}
|
|
31
|
+
SpinniesManager_1.default.init({
|
|
32
|
+
succeedColor: 'white',
|
|
33
|
+
});
|
|
34
|
+
SpinniesManager_1.default.add('installApp', {
|
|
35
|
+
text: en_1.commands.app.subcommands.install.polling.start,
|
|
36
|
+
});
|
|
37
|
+
let appInstallSucceeded = false;
|
|
38
|
+
try {
|
|
39
|
+
await (0, polling_1.poll)(() => (0, developerTestAccounts_1.fetchDeveloperTestAccountOauthAppInstallStatus)(derivedAccountId, projectName, appUid), {
|
|
40
|
+
successStates: ['SUCCESS'],
|
|
41
|
+
errorStates: [],
|
|
42
|
+
});
|
|
43
|
+
appInstallSucceeded = true;
|
|
44
|
+
}
|
|
45
|
+
catch (err) {
|
|
46
|
+
SpinniesManager_1.default.fail('installApp');
|
|
47
|
+
(0, errorHandlers_1.logError)(err);
|
|
48
|
+
process.exit(exitCodes_1.EXIT_CODES.ERROR);
|
|
49
|
+
}
|
|
50
|
+
if (!appInstallSucceeded) {
|
|
51
|
+
SpinniesManager_1.default.fail('installApp');
|
|
52
|
+
process.exit(exitCodes_1.EXIT_CODES.ERROR);
|
|
53
|
+
}
|
|
54
|
+
SpinniesManager_1.default.succeed('installApp', {
|
|
55
|
+
text: en_1.commands.app.subcommands.install.polling.success,
|
|
56
|
+
});
|
|
57
|
+
if (formatOutputAsJson) {
|
|
58
|
+
logger_1.uiLogger.json(jsonOutput);
|
|
59
|
+
}
|
|
60
|
+
process.exit(exitCodes_1.EXIT_CODES.SUCCESS);
|
|
61
|
+
}
|
|
62
|
+
function installAppBuilder(yargs) {
|
|
63
|
+
yargs.option('test-account-id', {
|
|
64
|
+
describe: en_1.commands.app.subcommands.install.options.testAccountId,
|
|
65
|
+
type: 'number',
|
|
66
|
+
});
|
|
67
|
+
yargs.positional('app-uid', {
|
|
68
|
+
describe: en_1.commands.app.subcommands.install.options.appUid,
|
|
69
|
+
type: 'string',
|
|
70
|
+
});
|
|
71
|
+
yargs.option('project-name', {
|
|
72
|
+
describe: en_1.commands.app.subcommands.install.options.projectName,
|
|
73
|
+
type: 'string',
|
|
74
|
+
});
|
|
75
|
+
yargs.example('install --app-uid=1234567890 --project-name=my-project', en_1.commands.app.subcommands.install.example);
|
|
76
|
+
return yargs;
|
|
77
|
+
}
|
|
78
|
+
const builder = (0, yargsUtils_1.makeYargsBuilder)(installAppBuilder, command, en_1.commands.app.subcommands.install.describe, {
|
|
79
|
+
useGlobalOptions: true,
|
|
80
|
+
useAccountOptions: true,
|
|
81
|
+
useConfigOptions: true,
|
|
82
|
+
useEnvironmentOptions: true,
|
|
83
|
+
useJSONOutputOptions: true,
|
|
84
|
+
});
|
|
85
|
+
const installAppCommand = {
|
|
86
|
+
command,
|
|
87
|
+
describe,
|
|
88
|
+
handler,
|
|
89
|
+
builder,
|
|
90
|
+
};
|
|
91
|
+
exports.default = installAppCommand;
|
package/commands/app.js
CHANGED
|
@@ -5,12 +5,17 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const migrate_1 = __importDefault(require("./app/migrate"));
|
|
7
7
|
const secret_1 = __importDefault(require("./app/secret"));
|
|
8
|
+
const install_1 = __importDefault(require("./app/install"));
|
|
8
9
|
const yargsUtils_1 = require("../lib/yargsUtils");
|
|
9
10
|
const command = ['app', 'apps'];
|
|
10
11
|
// Keep the command hidden for now
|
|
11
12
|
const describe = undefined;
|
|
12
13
|
function appBuilder(yargs) {
|
|
13
|
-
yargs
|
|
14
|
+
yargs
|
|
15
|
+
.command(migrate_1.default)
|
|
16
|
+
.command(secret_1.default)
|
|
17
|
+
.command(install_1.default)
|
|
18
|
+
.demandCommand(1, '');
|
|
14
19
|
return yargs;
|
|
15
20
|
}
|
|
16
21
|
const builder = (0, yargsUtils_1.makeYargsBuilder)(appBuilder, command, describe);
|
package/commands/getStarted.js
CHANGED
|
@@ -14,7 +14,7 @@ const usageTracking_1 = require("../lib/usageTracking");
|
|
|
14
14
|
const exitCodes_1 = require("../lib/enums/exitCodes");
|
|
15
15
|
const yargsUtils_1 = require("../lib/yargsUtils");
|
|
16
16
|
const promptUtils_1 = require("../lib/prompts/promptUtils");
|
|
17
|
-
const
|
|
17
|
+
const projectNameAndDestPrompt_1 = require("../lib/prompts/projectNameAndDestPrompt");
|
|
18
18
|
const ui_1 = require("../lib/ui");
|
|
19
19
|
const logger_1 = require("../lib/ui/logger");
|
|
20
20
|
const errorHandlers_1 = require("../lib/errorHandlers");
|
|
@@ -76,7 +76,7 @@ async function handler(args) {
|
|
|
76
76
|
logger_1.uiLogger.log(en_1.commands.getStarted.prompts.appSelected);
|
|
77
77
|
// 1. Fetch project templates
|
|
78
78
|
let latestRepoReleaseTag;
|
|
79
|
-
const { dest, name } = await (0,
|
|
79
|
+
const { dest, name } = await (0, projectNameAndDestPrompt_1.projectNameAndDestPrompt)(args);
|
|
80
80
|
// Specific template for get-started command
|
|
81
81
|
const projectTemplate = {
|
|
82
82
|
name: 'private-app-get-started-template',
|
|
@@ -8,7 +8,7 @@ const fs_1 = __importDefault(require("fs"));
|
|
|
8
8
|
const usageTracking_1 = require("../../lib/usageTracking");
|
|
9
9
|
const lang_1 = require("../../lib/lang");
|
|
10
10
|
const selectPublicAppForMigrationPrompt_1 = require("../../lib/prompts/selectPublicAppForMigrationPrompt");
|
|
11
|
-
const
|
|
11
|
+
const projectNameAndDestPrompt_1 = require("../../lib/prompts/projectNameAndDestPrompt");
|
|
12
12
|
const polling_1 = require("../../lib/polling");
|
|
13
13
|
const errorHandlers_1 = require("../../lib/errorHandlers");
|
|
14
14
|
const exitCodes_1 = require("../../lib/enums/exitCodes");
|
|
@@ -53,9 +53,9 @@ async function handler(args) {
|
|
|
53
53
|
});
|
|
54
54
|
appId = appIdResponse.appId;
|
|
55
55
|
}
|
|
56
|
-
const
|
|
57
|
-
projectName =
|
|
58
|
-
projectDest =
|
|
56
|
+
const projectNameAndDestPromptResponse = await (0, projectNameAndDestPrompt_1.projectNameAndDestPrompt)(args);
|
|
57
|
+
projectName = projectNameAndDestPromptResponse.name;
|
|
58
|
+
projectDest = projectNameAndDestPromptResponse.dest;
|
|
59
59
|
}
|
|
60
60
|
catch (error) {
|
|
61
61
|
(0, errorHandlers_1.logError)(error, new errorHandlers_1.ApiErrorContext({ accountId: derivedAccountId }));
|
|
@@ -39,15 +39,15 @@ async function handler(args) {
|
|
|
39
39
|
(0, errorHandlers_1.logError)(error);
|
|
40
40
|
process.exit(exitCodes_1.EXIT_CODES.ERROR);
|
|
41
41
|
}
|
|
42
|
-
const { authType, distribution, repoConfig, projectContents,
|
|
42
|
+
const { authType, distribution, repoConfig, projectContents, selectProjectTemplatePromptResponse, projectNameAndDestPromptResponse, } = handleResult;
|
|
43
43
|
(0, usageTracking_1.trackCommandUsage)('project-create', {
|
|
44
|
-
type:
|
|
45
|
-
(
|
|
44
|
+
type: selectProjectTemplatePromptResponse.projectTemplate?.name ||
|
|
45
|
+
(selectProjectTemplatePromptResponse.componentTemplates || [])
|
|
46
46
|
// @ts-expect-error
|
|
47
47
|
.map((item) => item.label)
|
|
48
48
|
.join(','),
|
|
49
49
|
}, derivedAccountId);
|
|
50
|
-
const projectDest = path_1.default.resolve((0, path_2.getCwd)(),
|
|
50
|
+
const projectDest = path_1.default.resolve((0, path_2.getCwd)(), projectNameAndDestPromptResponse.dest);
|
|
51
51
|
const { projectConfig: existingProjectConfig, projectDir: existingProjectDir, } = await (0, config_1.getProjectConfig)(projectDest);
|
|
52
52
|
// Exit if the target destination is within an existing project
|
|
53
53
|
if (existingProjectConfig &&
|
|
@@ -57,7 +57,7 @@ async function handler(args) {
|
|
|
57
57
|
process.exit(exitCodes_1.EXIT_CODES.ERROR);
|
|
58
58
|
}
|
|
59
59
|
const components = (0, v3_2.generateComponentPaths)({
|
|
60
|
-
|
|
60
|
+
selectProjectTemplatePromptResponse,
|
|
61
61
|
platformVersion,
|
|
62
62
|
repoConfig,
|
|
63
63
|
projectContents,
|
|
@@ -66,7 +66,7 @@ async function handler(args) {
|
|
|
66
66
|
});
|
|
67
67
|
try {
|
|
68
68
|
await (0, github_1.cloneGithubRepo)(repo, projectDest, {
|
|
69
|
-
sourceDir:
|
|
69
|
+
sourceDir: selectProjectTemplatePromptResponse.projectTemplate?.path || components,
|
|
70
70
|
hideLogs: true,
|
|
71
71
|
branch: 'main',
|
|
72
72
|
});
|
|
@@ -80,15 +80,15 @@ async function handler(args) {
|
|
|
80
80
|
const parsedConfigFile = JSON.parse(fs_extra_1.default.readFileSync(projectConfigPath).toString());
|
|
81
81
|
(0, config_1.writeProjectConfig)(projectConfigPath, {
|
|
82
82
|
...parsedConfigFile,
|
|
83
|
-
name:
|
|
83
|
+
name: projectNameAndDestPromptResponse.name,
|
|
84
84
|
});
|
|
85
85
|
// If the template is 'no-template', we need to manually create a src directory
|
|
86
|
-
if (
|
|
86
|
+
if (selectProjectTemplatePromptResponse.projectTemplate?.name ===
|
|
87
87
|
legacy_1.EMPTY_PROJECT_TEMPLATE_NAME ||
|
|
88
88
|
projectContents === v3_1.EMPTY_PROJECT) {
|
|
89
89
|
fs_extra_1.default.ensureDirSync(path_1.default.join(projectDest, 'src'));
|
|
90
90
|
}
|
|
91
|
-
logger_1.uiLogger.success(en_1.commands.project.create.logs.success(
|
|
91
|
+
logger_1.uiLogger.success(en_1.commands.project.create.logs.success(projectNameAndDestPromptResponse.name, projectDest));
|
|
92
92
|
logger_1.uiLogger.log(en_1.commands.project.create.logs.welcomeMessage);
|
|
93
93
|
(0, ui_1.uiFeatureHighlight)([
|
|
94
94
|
'projectCommandTip',
|
|
@@ -121,6 +121,7 @@ async function unifiedProjectDevFlow({ args, targetProjectAccountId, providedTar
|
|
|
121
121
|
debug: args.debug,
|
|
122
122
|
deployedBuild,
|
|
123
123
|
isGithubLinked,
|
|
124
|
+
profile: args.profile,
|
|
124
125
|
targetProjectAccountId,
|
|
125
126
|
targetTestingAccountId: targetTestingAccountId,
|
|
126
127
|
projectConfig,
|
|
@@ -92,14 +92,18 @@ async function handler(args) {
|
|
|
92
92
|
await (0, polling_1.poll)(() => (0, developerTestAccounts_1.fetchDeveloperTestAccountGateSyncStatus)(derivedAccountId, testAccountId), {
|
|
93
93
|
successStates: ['SUCCESS'],
|
|
94
94
|
errorStates: [],
|
|
95
|
+
}, 5000 // 5 seconds
|
|
96
|
+
);
|
|
97
|
+
SpinniesManager_1.default.succeed('createTestAccount', {
|
|
98
|
+
text: en_1.commands.testAccount.create.polling.success(testAccountConfig.accountName, testAccountId),
|
|
95
99
|
});
|
|
96
100
|
}
|
|
97
101
|
catch (err) {
|
|
98
|
-
(0, errorHandlers_1.
|
|
102
|
+
(0, errorHandlers_1.debugError)(err);
|
|
103
|
+
SpinniesManager_1.default.fail('createTestAccount', {
|
|
104
|
+
text: en_1.commands.testAccount.create.polling.failure,
|
|
105
|
+
});
|
|
99
106
|
}
|
|
100
|
-
SpinniesManager_1.default.succeed('createTestAccount', {
|
|
101
|
-
text: en_1.commands.testAccount.create.polling.success(testAccountConfig.accountName, testAccountId),
|
|
102
|
-
});
|
|
103
107
|
if (formatOutputAsJson) {
|
|
104
108
|
logger_1.uiLogger.json(jsonOutput);
|
|
105
109
|
}
|
package/lang/en.d.ts
CHANGED
|
@@ -1498,6 +1498,21 @@ ${string}`;
|
|
|
1498
1498
|
readonly app: {
|
|
1499
1499
|
readonly describe: "Commands for managing apps.";
|
|
1500
1500
|
readonly subcommands: {
|
|
1501
|
+
readonly install: {
|
|
1502
|
+
readonly describe: "Install an app.";
|
|
1503
|
+
readonly options: {
|
|
1504
|
+
readonly appUid: "The uid of the app to install";
|
|
1505
|
+
readonly projectName: "The name of the project to install the app to";
|
|
1506
|
+
readonly testAccountId: "The id of the test account to install the app into";
|
|
1507
|
+
};
|
|
1508
|
+
readonly polling: {
|
|
1509
|
+
readonly start: "Installing app...";
|
|
1510
|
+
readonly success: "App installed successfully";
|
|
1511
|
+
readonly failure: "App installation failed";
|
|
1512
|
+
readonly error: "Error installing app";
|
|
1513
|
+
};
|
|
1514
|
+
readonly example: "Install the app with uid 1234567890 from the project named \"my-project\" into the target account";
|
|
1515
|
+
};
|
|
1501
1516
|
readonly secret: {
|
|
1502
1517
|
readonly describe: "Commands for managing secrets.";
|
|
1503
1518
|
readonly subcommands: {
|
|
@@ -1807,6 +1822,7 @@ ${string}`;
|
|
|
1807
1822
|
readonly start: (testAccountName: string) => string;
|
|
1808
1823
|
readonly syncing: "Test account created! Syncing account data... (may take a few minutes - you can exit and the sync will continue)";
|
|
1809
1824
|
readonly success: (testAccountName: string, testAccountId: number) => string;
|
|
1825
|
+
readonly failure: "Failed to sync data into test account. The account may not be ready to use.";
|
|
1810
1826
|
};
|
|
1811
1827
|
readonly options: {
|
|
1812
1828
|
readonly configPath: "The path to the test account config";
|
|
@@ -2608,6 +2624,9 @@ Run ${string} to upgrade to version ${string}`;
|
|
|
2608
2624
|
readonly invalidAuthDistCombo: (authType: string, distribution: string) => string;
|
|
2609
2625
|
};
|
|
2610
2626
|
};
|
|
2627
|
+
readonly add: {
|
|
2628
|
+
readonly nothingAdded: "No features added.";
|
|
2629
|
+
};
|
|
2611
2630
|
readonly validateProjectConfig: {
|
|
2612
2631
|
readonly configNotFound: `Unable to locate a project configuration file. Try running again from a project directory, or run ${string} to create a new project.`;
|
|
2613
2632
|
readonly configMissingFields: "The project configuration file is missing required fields.";
|
|
@@ -2918,16 +2937,20 @@ Run ${string} to upgrade to version ${string}`;
|
|
|
2918
2937
|
readonly languageRequired: "Please select API sample app's language";
|
|
2919
2938
|
};
|
|
2920
2939
|
};
|
|
2921
|
-
readonly
|
|
2940
|
+
readonly projectNameAndDestPrompt: {
|
|
2922
2941
|
readonly enterName: "[--name] Give your project a name: ";
|
|
2923
2942
|
readonly enterDest: "[--dest] Enter the folder to create the project in:";
|
|
2924
|
-
readonly selectTemplate: "[--template] Choose a project template: ";
|
|
2925
|
-
readonly features: "[--features] Which features would you like your app to include?";
|
|
2926
2943
|
readonly errors: {
|
|
2927
2944
|
readonly nameRequired: "A project name is required";
|
|
2928
2945
|
readonly destRequired: "A project dest is required";
|
|
2929
2946
|
readonly invalidDest: "There is an existing project at this destination. Please provide a new path for this project.";
|
|
2930
2947
|
readonly invalidCharacters: "The selected destination contains invalid characters. Please provide a new path and try again.";
|
|
2948
|
+
};
|
|
2949
|
+
};
|
|
2950
|
+
readonly selectProjectTemplatePrompt: {
|
|
2951
|
+
readonly selectTemplate: "[--template] Choose a project template: ";
|
|
2952
|
+
readonly features: "[--features] Which features would you like your app to include?";
|
|
2953
|
+
readonly errors: {
|
|
2931
2954
|
readonly invalidTemplate: (template: string) => string;
|
|
2932
2955
|
readonly projectTemplateRequired: "Project template is required when projectTemplates is provided";
|
|
2933
2956
|
};
|
|
@@ -3032,6 +3055,9 @@ Run ${string} to upgrade to version ${string}`;
|
|
|
3032
3055
|
};
|
|
3033
3056
|
};
|
|
3034
3057
|
};
|
|
3058
|
+
readonly polling: {
|
|
3059
|
+
readonly timeoutError: (timeoutMs: number) => string;
|
|
3060
|
+
};
|
|
3035
3061
|
readonly convertFields: {
|
|
3036
3062
|
readonly positionals: {
|
|
3037
3063
|
readonly src: {
|
package/lang/en.js
CHANGED
|
@@ -1496,6 +1496,21 @@ exports.commands = {
|
|
|
1496
1496
|
app: {
|
|
1497
1497
|
describe: 'Commands for managing apps.',
|
|
1498
1498
|
subcommands: {
|
|
1499
|
+
install: {
|
|
1500
|
+
describe: 'Install an app.',
|
|
1501
|
+
options: {
|
|
1502
|
+
appUid: 'The uid of the app to install',
|
|
1503
|
+
projectName: 'The name of the project to install the app to',
|
|
1504
|
+
testAccountId: 'The id of the test account to install the app into',
|
|
1505
|
+
},
|
|
1506
|
+
polling: {
|
|
1507
|
+
start: 'Installing app...',
|
|
1508
|
+
success: 'App installed successfully',
|
|
1509
|
+
failure: 'App installation failed',
|
|
1510
|
+
error: 'Error installing app',
|
|
1511
|
+
},
|
|
1512
|
+
example: 'Install the app with uid 1234567890 from the project named "my-project" into the target account',
|
|
1513
|
+
},
|
|
1499
1514
|
secret: {
|
|
1500
1515
|
describe: 'Commands for managing secrets.',
|
|
1501
1516
|
subcommands: {
|
|
@@ -1805,6 +1820,7 @@ exports.commands = {
|
|
|
1805
1820
|
start: (testAccountName) => `Creating test account "${chalk_1.default.bold(testAccountName)}"...`,
|
|
1806
1821
|
syncing: 'Test account created! Syncing account data... (may take a few minutes - you can exit and the sync will continue)',
|
|
1807
1822
|
success: (testAccountName, testAccountId) => `Test account "${chalk_1.default.bold(testAccountName)}" successfully created with id: ${chalk_1.default.bold(testAccountId)}`,
|
|
1823
|
+
failure: 'Failed to sync data into test account. The account may not be ready to use.',
|
|
1808
1824
|
},
|
|
1809
1825
|
options: {
|
|
1810
1826
|
configPath: 'The path to the test account config',
|
|
@@ -2605,6 +2621,9 @@ exports.lib = {
|
|
|
2605
2621
|
invalidAuthDistCombo: (authType, distribution) => `Invalid distribution and auth combination. Apps with distribution '${distribution}' must have auth '${authType}'`,
|
|
2606
2622
|
},
|
|
2607
2623
|
},
|
|
2624
|
+
add: {
|
|
2625
|
+
nothingAdded: 'No features added.',
|
|
2626
|
+
},
|
|
2608
2627
|
validateProjectConfig: {
|
|
2609
2628
|
configNotFound: `Unable to locate a project configuration file. Try running again from a project directory, or run ${(0, ui_1.uiCommandReference)('hs project create')} to create a new project.`,
|
|
2610
2629
|
configMissingFields: 'The project configuration file is missing required fields.',
|
|
@@ -2913,16 +2932,20 @@ exports.lib = {
|
|
|
2913
2932
|
languageRequired: "Please select API sample app's language",
|
|
2914
2933
|
},
|
|
2915
2934
|
},
|
|
2916
|
-
|
|
2935
|
+
projectNameAndDestPrompt: {
|
|
2917
2936
|
enterName: '[--name] Give your project a name: ',
|
|
2918
2937
|
enterDest: '[--dest] Enter the folder to create the project in:',
|
|
2919
|
-
selectTemplate: '[--template] Choose a project template: ',
|
|
2920
|
-
features: '[--features] Which features would you like your app to include?',
|
|
2921
2938
|
errors: {
|
|
2922
2939
|
nameRequired: 'A project name is required',
|
|
2923
2940
|
destRequired: 'A project dest is required',
|
|
2924
2941
|
invalidDest: 'There is an existing project at this destination. Please provide a new path for this project.',
|
|
2925
2942
|
invalidCharacters: 'The selected destination contains invalid characters. Please provide a new path and try again.',
|
|
2943
|
+
},
|
|
2944
|
+
},
|
|
2945
|
+
selectProjectTemplatePrompt: {
|
|
2946
|
+
selectTemplate: '[--template] Choose a project template: ',
|
|
2947
|
+
features: '[--features] Which features would you like your app to include?',
|
|
2948
|
+
errors: {
|
|
2926
2949
|
invalidTemplate: (template) => `[--template] Could not find template "${template}". Please choose an available template:`,
|
|
2927
2950
|
projectTemplateRequired: 'Project template is required when projectTemplates is provided',
|
|
2928
2951
|
},
|
|
@@ -3027,6 +3050,9 @@ exports.lib = {
|
|
|
3027
3050
|
},
|
|
3028
3051
|
},
|
|
3029
3052
|
},
|
|
3053
|
+
polling: {
|
|
3054
|
+
timeoutError: (timeoutMs) => `Polling timed out after ${timeoutMs}ms.`,
|
|
3055
|
+
},
|
|
3030
3056
|
convertFields: {
|
|
3031
3057
|
positionals: {
|
|
3032
3058
|
src: {
|
|
@@ -18,7 +18,7 @@ const ui_1 = require("../ui");
|
|
|
18
18
|
const lang_1 = require("../lang");
|
|
19
19
|
const accountTypes_1 = require("../accountTypes");
|
|
20
20
|
const selectPublicAppForMigrationPrompt_1 = require("../prompts/selectPublicAppForMigrationPrompt");
|
|
21
|
-
const
|
|
21
|
+
const projectNameAndDestPrompt_1 = require("../prompts/projectNameAndDestPrompt");
|
|
22
22
|
const ensureProjectExists_1 = require("../projects/ensureProjectExists");
|
|
23
23
|
const usageTracking_1 = require("../usageTracking");
|
|
24
24
|
const SpinniesManager_1 = __importDefault(require("../ui/SpinniesManager"));
|
|
@@ -58,8 +58,7 @@ async function migrateApp2023_2(derivedAccountId, options, accountConfig) {
|
|
|
58
58
|
(0, errorHandlers_1.logError)(error, new errorHandlers_1.ApiErrorContext({ accountId: derivedAccountId }));
|
|
59
59
|
return process.exit(exitCodes_1.EXIT_CODES.ERROR);
|
|
60
60
|
}
|
|
61
|
-
const
|
|
62
|
-
const { name: projectName, dest: projectDest } = createProjectPromptResponse;
|
|
61
|
+
const { name: projectName, dest: projectDest } = await (0, projectNameAndDestPrompt_1.projectNameAndDestPrompt)(options);
|
|
63
62
|
const { projectExists } = await (0, ensureProjectExists_1.ensureProjectExists)(derivedAccountId, projectName, {
|
|
64
63
|
allowCreate: false,
|
|
65
64
|
noLogs: true,
|
package/lib/polling.d.ts
CHANGED
|
@@ -17,5 +17,5 @@ type PollingCallback<T extends GenericPollingResponse> = () => HubSpotPromise<T>
|
|
|
17
17
|
export declare function poll<T extends GenericPollingResponse>(callback: PollingCallback<T>, statusLookup?: {
|
|
18
18
|
successStates: string[];
|
|
19
19
|
errorStates: string[];
|
|
20
|
-
}): Promise<T>;
|
|
20
|
+
}, timeoutMs?: number): Promise<T>;
|
|
21
21
|
export {};
|
package/lib/polling.js
CHANGED
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.DEFAULT_POLLING_STATUS_LOOKUP = exports.DEFAULT_POLLING_STATES = void 0;
|
|
4
4
|
exports.poll = poll;
|
|
5
5
|
const constants_1 = require("./constants");
|
|
6
|
+
const en_1 = require("../lang/en");
|
|
6
7
|
exports.DEFAULT_POLLING_STATES = {
|
|
7
8
|
STARTED: 'STARTED',
|
|
8
9
|
SUCCESS: 'SUCCESS',
|
|
@@ -18,7 +19,8 @@ exports.DEFAULT_POLLING_STATUS_LOOKUP = {
|
|
|
18
19
|
exports.DEFAULT_POLLING_STATES.FAILURE,
|
|
19
20
|
],
|
|
20
21
|
};
|
|
21
|
-
function poll(callback, statusLookup = exports.DEFAULT_POLLING_STATUS_LOOKUP
|
|
22
|
+
function poll(callback, statusLookup = exports.DEFAULT_POLLING_STATUS_LOOKUP, timeoutMs = 60000 // Default 60 second timeout
|
|
23
|
+
) {
|
|
22
24
|
return new Promise((resolve, reject) => {
|
|
23
25
|
const pollInterval = setInterval(async () => {
|
|
24
26
|
try {
|
|
@@ -26,17 +28,25 @@ function poll(callback, statusLookup = exports.DEFAULT_POLLING_STATUS_LOOKUP) {
|
|
|
26
28
|
const { status } = pollResp;
|
|
27
29
|
if (statusLookup.successStates.includes(status)) {
|
|
28
30
|
clearInterval(pollInterval);
|
|
31
|
+
clearTimeout(timeoutId);
|
|
29
32
|
resolve(pollResp);
|
|
30
33
|
}
|
|
31
34
|
else if (statusLookup.errorStates.includes(status)) {
|
|
32
35
|
clearInterval(pollInterval);
|
|
36
|
+
clearTimeout(timeoutId);
|
|
33
37
|
reject(pollResp);
|
|
34
38
|
}
|
|
35
39
|
}
|
|
36
40
|
catch (error) {
|
|
37
41
|
clearInterval(pollInterval);
|
|
42
|
+
clearTimeout(timeoutId);
|
|
38
43
|
reject(error);
|
|
39
44
|
}
|
|
40
45
|
}, constants_1.DEFAULT_POLLING_DELAY);
|
|
46
|
+
// Set a timeout to stop polling after specified duration
|
|
47
|
+
const timeoutId = setTimeout(() => {
|
|
48
|
+
clearInterval(pollInterval);
|
|
49
|
+
reject(new Error(en_1.lib.polling.timeoutError(timeoutMs)));
|
|
50
|
+
}, timeoutMs);
|
|
41
51
|
});
|
|
42
52
|
}
|
|
@@ -66,6 +66,10 @@ async function v3AddComponent(args, projectDir, projectConfig) {
|
|
|
66
66
|
components.push(path_1.default.join(projectConfig.platformVersion, parentComponent.path));
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
|
+
if (components.length === 0) {
|
|
70
|
+
logger_1.uiLogger.log(en_1.lib.projects.add.nothingAdded);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
69
73
|
await (0, github_1.cloneGithubRepo)(constants_1.HUBSPOT_PROJECT_COMPONENTS_GITHUB_PATH, projectDir, {
|
|
70
74
|
sourceDir: components,
|
|
71
75
|
hideLogs: true,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ArgumentsCamelCase } from 'yargs';
|
|
2
2
|
import { ProjectTemplateRepoConfig } from '../../../types/Projects';
|
|
3
|
-
import {
|
|
3
|
+
import { SelectProjectTemplatePromptResponse, ProjectNameAndDestPromptResponse } from '../../prompts/selectProjectTemplatePrompt';
|
|
4
4
|
import { AccountArgs, CommonArgs, ConfigArgs, EnvironmentArgs } from '../../../types/Yargs';
|
|
5
5
|
import { RepoPath } from '@hubspot/local-dev-lib/types/Github';
|
|
6
6
|
export type ProjectCreateArgs = CommonArgs & ConfigArgs & AccountArgs & EnvironmentArgs & {
|
|
@@ -19,5 +19,6 @@ export declare function handleProjectCreationFlow(args: ArgumentsCamelCase<Proje
|
|
|
19
19
|
distribution?: string;
|
|
20
20
|
repoConfig?: ProjectTemplateRepoConfig;
|
|
21
21
|
projectContents?: string;
|
|
22
|
-
|
|
22
|
+
selectProjectTemplatePromptResponse: SelectProjectTemplatePromptResponse;
|
|
23
|
+
projectNameAndDestPromptResponse: ProjectNameAndDestPromptResponse;
|
|
23
24
|
}>;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.handleProjectCreationFlow = handleProjectCreationFlow;
|
|
4
|
-
const
|
|
4
|
+
const selectProjectTemplatePrompt_1 = require("../../prompts/selectProjectTemplatePrompt");
|
|
5
|
+
const projectNameAndDestPrompt_1 = require("../../prompts/projectNameAndDestPrompt");
|
|
5
6
|
const constants_1 = require("../../constants");
|
|
6
7
|
const buildAndDeploy_1 = require("../buildAndDeploy");
|
|
7
8
|
const v3_1 = require("./v3");
|
|
@@ -12,15 +13,17 @@ const exitCodes_1 = require("../../enums/exitCodes");
|
|
|
12
13
|
async function handleProjectCreationFlow(args) {
|
|
13
14
|
const { platformVersion, templateSource, projectBase, auth: providedAuth, distribution: providedDistribution, } = args;
|
|
14
15
|
const repo = templateSource || constants_1.HUBSPOT_PROJECT_COMPONENTS_GITHUB_PATH;
|
|
16
|
+
const projectNameAndDestPromptResponse = await (0, projectNameAndDestPrompt_1.projectNameAndDestPrompt)(args);
|
|
15
17
|
if ((0, buildAndDeploy_1.useV3Api)(platformVersion)) {
|
|
16
18
|
const { componentTemplateChoices, authType, distribution, repoConfig, projectContents, } = await (0, v3_1.v3ComponentFlow)(platformVersion, projectBase, providedAuth, providedDistribution);
|
|
17
|
-
const
|
|
19
|
+
const selectProjectTemplatePromptResponse = await (0, selectProjectTemplatePrompt_1.selectProjectTemplatePrompt)(args, undefined, projectContents !== v3_1.EMPTY_PROJECT ? componentTemplateChoices : undefined);
|
|
18
20
|
return {
|
|
19
21
|
authType,
|
|
20
22
|
distribution,
|
|
21
23
|
repoConfig,
|
|
22
24
|
projectContents,
|
|
23
|
-
|
|
25
|
+
selectProjectTemplatePromptResponse,
|
|
26
|
+
projectNameAndDestPromptResponse,
|
|
24
27
|
};
|
|
25
28
|
}
|
|
26
29
|
const projectTemplates = await (0, legacy_1.getProjectTemplateListFromRepo)(repo, 'main');
|
|
@@ -28,6 +31,9 @@ async function handleProjectCreationFlow(args) {
|
|
|
28
31
|
logger_1.uiLogger.error(en_1.commands.project.create.errors.failedToFetchProjectList);
|
|
29
32
|
process.exit(exitCodes_1.EXIT_CODES.ERROR);
|
|
30
33
|
}
|
|
31
|
-
const
|
|
32
|
-
return {
|
|
34
|
+
const selectProjectTemplatePromptResponse = await (0, selectProjectTemplatePrompt_1.selectProjectTemplatePrompt)(args, projectTemplates);
|
|
35
|
+
return {
|
|
36
|
+
selectProjectTemplatePromptResponse,
|
|
37
|
+
projectNameAndDestPromptResponse,
|
|
38
|
+
};
|
|
33
39
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ComponentTemplate, ComponentTemplateChoice, ProjectTemplateRepoConfig } from '../../../types/Projects';
|
|
2
2
|
import { ProjectMetadata } from '@hubspot/project-parsing-lib/src/lib/project';
|
|
3
|
-
import {
|
|
3
|
+
import { SelectProjectTemplatePromptResponse } from '../../prompts/selectProjectTemplatePrompt';
|
|
4
4
|
export declare const EMPTY_PROJECT = "empty";
|
|
5
5
|
export declare const PROJECT_WITH_APP = "app";
|
|
6
6
|
export declare function createV3App(providedAuth: string | undefined, providedDistribution: string | undefined): Promise<{
|
|
@@ -16,8 +16,8 @@ type V3ComponentInfo = {
|
|
|
16
16
|
componentTemplateChoices?: ComponentTemplateChoice[];
|
|
17
17
|
};
|
|
18
18
|
export declare function v3ComponentFlow(platformVersion: string, projectBase: string | undefined, providedAuth: string | undefined, providedDistribution: string | undefined): Promise<V3ComponentInfo>;
|
|
19
|
-
export declare function generateComponentPaths({
|
|
20
|
-
|
|
19
|
+
export declare function generateComponentPaths({ selectProjectTemplatePromptResponse, platformVersion, repoConfig, projectContents, authType, distribution, }: {
|
|
20
|
+
selectProjectTemplatePromptResponse: SelectProjectTemplatePromptResponse;
|
|
21
21
|
platformVersion: string;
|
|
22
22
|
repoConfig?: ProjectTemplateRepoConfig;
|
|
23
23
|
projectContents?: string;
|
|
@@ -134,11 +134,11 @@ async function v3ComponentFlow(platformVersion, projectBase, providedAuth, provi
|
|
|
134
134
|
repoConfig,
|
|
135
135
|
};
|
|
136
136
|
}
|
|
137
|
-
function generateComponentPaths({
|
|
137
|
+
function generateComponentPaths({ selectProjectTemplatePromptResponse, platformVersion, repoConfig, projectContents, authType, distribution, }) {
|
|
138
138
|
if (!(0, buildAndDeploy_1.useV3Api)(platformVersion)) {
|
|
139
139
|
return [];
|
|
140
140
|
}
|
|
141
|
-
const components =
|
|
141
|
+
const components = selectProjectTemplatePromptResponse.componentTemplates?.map((componentTemplate) => {
|
|
142
142
|
return path_1.default.join(platformVersion, componentTemplate.path);
|
|
143
143
|
}) || [];
|
|
144
144
|
if (projectContents && projectContents !== exports.EMPTY_PROJECT) {
|
|
@@ -16,15 +16,16 @@ declare class LocalDevProcess {
|
|
|
16
16
|
[key: string]: IntermediateRepresentationNodeLocalDev;
|
|
17
17
|
};
|
|
18
18
|
get logger(): LocalDevLogger;
|
|
19
|
-
get configFilesUpdatedSinceLastUpload(): Set<string>;
|
|
20
19
|
private setupDevServers;
|
|
21
20
|
private startDevServers;
|
|
22
21
|
private cleanupDevServers;
|
|
23
22
|
private compareLocalProjectToDeployed;
|
|
24
23
|
private projectConfigValidForUpload;
|
|
24
|
+
private getIntermediateRepresentation;
|
|
25
25
|
private updateProjectNodes;
|
|
26
|
+
private updateProjectNodesAfterUpload;
|
|
26
27
|
handleFileChange(filePath: string, event: string): Promise<void>;
|
|
27
|
-
handleConfigFileChange(
|
|
28
|
+
handleConfigFileChange(): Promise<void>;
|
|
28
29
|
start(): Promise<void>;
|
|
29
30
|
stop(showProgress?: boolean): Promise<void>;
|
|
30
31
|
uploadProject(): Promise<boolean>;
|
|
@@ -46,9 +46,6 @@ class LocalDevProcess {
|
|
|
46
46
|
get logger() {
|
|
47
47
|
return this._logger;
|
|
48
48
|
}
|
|
49
|
-
get configFilesUpdatedSinceLastUpload() {
|
|
50
|
-
return this.state.configFilesUpdatedSinceLastUpload;
|
|
51
|
-
}
|
|
52
49
|
async setupDevServers() {
|
|
53
50
|
try {
|
|
54
51
|
await this.devServerManager.setup();
|
|
@@ -105,17 +102,28 @@ class LocalDevProcess {
|
|
|
105
102
|
});
|
|
106
103
|
return true;
|
|
107
104
|
}
|
|
108
|
-
|
|
109
|
-
|
|
105
|
+
getIntermediateRepresentation(projectNodesAtLastUpload) {
|
|
106
|
+
return (0, project_parsing_lib_1.translateForLocalDev)({
|
|
110
107
|
projectSourceDir: path_1.default.join(this.state.projectDir, this.state.projectConfig.srcDir),
|
|
111
108
|
platformVersion: this.state.projectConfig.platformVersion,
|
|
112
109
|
accountId: this.state.targetProjectAccountId,
|
|
113
110
|
}, {
|
|
114
|
-
|
|
111
|
+
projectNodesAtLastUpload,
|
|
112
|
+
profile: this.state.profile,
|
|
115
113
|
});
|
|
114
|
+
}
|
|
115
|
+
async updateProjectNodes() {
|
|
116
|
+
const intermediateRepresentation = await this.getIntermediateRepresentation(this.state.projectNodesAtLastUpload);
|
|
116
117
|
this.state.projectNodes =
|
|
117
118
|
intermediateRepresentation.intermediateNodesIndexedByUid;
|
|
118
119
|
}
|
|
120
|
+
async updateProjectNodesAfterUpload() {
|
|
121
|
+
const intermediateRepresentation = await this.getIntermediateRepresentation();
|
|
122
|
+
this.state.projectNodes =
|
|
123
|
+
intermediateRepresentation.intermediateNodesIndexedByUid;
|
|
124
|
+
this.state.projectNodesAtLastUpload =
|
|
125
|
+
intermediateRepresentation.intermediateNodesIndexedByUid;
|
|
126
|
+
}
|
|
119
127
|
async handleFileChange(filePath, event) {
|
|
120
128
|
await this.updateProjectNodes();
|
|
121
129
|
try {
|
|
@@ -125,10 +133,7 @@ class LocalDevProcess {
|
|
|
125
133
|
this.logger.fileChangeError(e);
|
|
126
134
|
}
|
|
127
135
|
}
|
|
128
|
-
async handleConfigFileChange(
|
|
129
|
-
if (event === 'add' || event === 'change') {
|
|
130
|
-
this.state.addUpdatedConfigFileUpdatedSinceLastUpload(filePath);
|
|
131
|
-
}
|
|
136
|
+
async handleConfigFileChange() {
|
|
132
137
|
await this.updateProjectNodes();
|
|
133
138
|
this.logger.uploadWarning();
|
|
134
139
|
}
|
|
@@ -185,8 +190,7 @@ class LocalDevProcess {
|
|
|
185
190
|
this.logger.uploadError(uploadError);
|
|
186
191
|
return false;
|
|
187
192
|
}
|
|
188
|
-
this.
|
|
189
|
-
this.updateProjectNodes();
|
|
193
|
+
await this.updateProjectNodesAfterUpload();
|
|
190
194
|
this.logger.uploadSuccess();
|
|
191
195
|
this.logger.clearUploadWarnings();
|
|
192
196
|
return true;
|
|
@@ -6,6 +6,7 @@ import { LocalDevStateConstructorOptions, LocalDevStateListener, AppLocalDevData
|
|
|
6
6
|
declare class LocalDevState {
|
|
7
7
|
private _targetProjectAccountId;
|
|
8
8
|
private _targetTestingAccountId;
|
|
9
|
+
private _profile?;
|
|
9
10
|
private _projectConfig;
|
|
10
11
|
private _projectDir;
|
|
11
12
|
private _projectId;
|
|
@@ -14,15 +15,16 @@ declare class LocalDevState {
|
|
|
14
15
|
private _deployedBuild?;
|
|
15
16
|
private _isGithubLinked;
|
|
16
17
|
private _projectNodes;
|
|
18
|
+
private _projectNodesAtLastUpload;
|
|
17
19
|
private _env;
|
|
18
20
|
private _listeners;
|
|
19
|
-
private _configFilesUpdatedSinceLastUpload;
|
|
20
21
|
private _appData;
|
|
21
22
|
private _devServerMessage;
|
|
22
|
-
constructor({ targetProjectAccountId, targetTestingAccountId, projectConfig, projectDir, projectId, projectName, debug, deployedBuild, isGithubLinked, initialProjectNodes, env, }: LocalDevStateConstructorOptions);
|
|
23
|
+
constructor({ targetProjectAccountId, targetTestingAccountId, projectConfig, projectDir, projectId, projectName, debug, deployedBuild, isGithubLinked, initialProjectNodes, profile, env, }: LocalDevStateConstructorOptions);
|
|
23
24
|
private runListeners;
|
|
24
25
|
get targetProjectAccountId(): number;
|
|
25
26
|
get targetTestingAccountId(): number;
|
|
27
|
+
get profile(): string | undefined;
|
|
26
28
|
get projectConfig(): ProjectConfig;
|
|
27
29
|
get projectDir(): string;
|
|
28
30
|
get projectId(): number;
|
|
@@ -36,10 +38,13 @@ declare class LocalDevState {
|
|
|
36
38
|
set projectNodes(nodes: {
|
|
37
39
|
[key: string]: IntermediateRepresentationNodeLocalDev;
|
|
38
40
|
});
|
|
41
|
+
get projectNodesAtLastUpload(): {
|
|
42
|
+
[key: string]: IntermediateRepresentationNodeLocalDev;
|
|
43
|
+
};
|
|
44
|
+
set projectNodesAtLastUpload(nodes: {
|
|
45
|
+
[key: string]: IntermediateRepresentationNodeLocalDev;
|
|
46
|
+
});
|
|
39
47
|
get env(): Environment;
|
|
40
|
-
get configFilesUpdatedSinceLastUpload(): Set<string>;
|
|
41
|
-
addUpdatedConfigFileUpdatedSinceLastUpload(filePath: string): void;
|
|
42
|
-
resetConfigFilesUpdatedSinceLastUpload(): void;
|
|
43
48
|
get appData(): Record<string, AppLocalDevData>;
|
|
44
49
|
getAppDataByUid(uid: string): AppLocalDevData | undefined;
|
|
45
50
|
setAppDataForUid(uid: string, appData: AppLocalDevData): void;
|
|
@@ -4,6 +4,7 @@ const constants_1 = require("../../constants");
|
|
|
4
4
|
class LocalDevState {
|
|
5
5
|
_targetProjectAccountId;
|
|
6
6
|
_targetTestingAccountId;
|
|
7
|
+
_profile;
|
|
7
8
|
_projectConfig;
|
|
8
9
|
_projectDir;
|
|
9
10
|
_projectId;
|
|
@@ -12,14 +13,15 @@ class LocalDevState {
|
|
|
12
13
|
_deployedBuild;
|
|
13
14
|
_isGithubLinked;
|
|
14
15
|
_projectNodes;
|
|
16
|
+
_projectNodesAtLastUpload;
|
|
15
17
|
_env;
|
|
16
18
|
_listeners;
|
|
17
|
-
_configFilesUpdatedSinceLastUpload;
|
|
18
19
|
_appData;
|
|
19
20
|
_devServerMessage;
|
|
20
|
-
constructor({ targetProjectAccountId, targetTestingAccountId, projectConfig, projectDir, projectId, projectName, debug, deployedBuild, isGithubLinked, initialProjectNodes, env, }) {
|
|
21
|
+
constructor({ targetProjectAccountId, targetTestingAccountId, projectConfig, projectDir, projectId, projectName, debug, deployedBuild, isGithubLinked, initialProjectNodes, profile, env, }) {
|
|
21
22
|
this._targetProjectAccountId = targetProjectAccountId;
|
|
22
23
|
this._targetTestingAccountId = targetTestingAccountId;
|
|
24
|
+
this._profile = profile;
|
|
23
25
|
this._projectConfig = projectConfig;
|
|
24
26
|
this._projectDir = projectDir;
|
|
25
27
|
this._projectId = projectId;
|
|
@@ -28,8 +30,8 @@ class LocalDevState {
|
|
|
28
30
|
this._deployedBuild = deployedBuild;
|
|
29
31
|
this._isGithubLinked = isGithubLinked;
|
|
30
32
|
this._projectNodes = initialProjectNodes;
|
|
33
|
+
this._projectNodesAtLastUpload = initialProjectNodes;
|
|
31
34
|
this._env = env;
|
|
32
|
-
this._configFilesUpdatedSinceLastUpload = new Set();
|
|
33
35
|
this._appData = {};
|
|
34
36
|
this._devServerMessage = constants_1.LOCAL_DEV_SERVER_MESSAGE_TYPES.INITIAL;
|
|
35
37
|
this._listeners = {};
|
|
@@ -45,10 +47,11 @@ class LocalDevState {
|
|
|
45
47
|
get targetTestingAccountId() {
|
|
46
48
|
return this._targetTestingAccountId;
|
|
47
49
|
}
|
|
50
|
+
get profile() {
|
|
51
|
+
return this._profile;
|
|
52
|
+
}
|
|
48
53
|
get projectConfig() {
|
|
49
|
-
return
|
|
50
|
-
...this._projectConfig,
|
|
51
|
-
};
|
|
54
|
+
return structuredClone(this._projectConfig);
|
|
52
55
|
}
|
|
53
56
|
get projectDir() {
|
|
54
57
|
return this._projectDir;
|
|
@@ -63,34 +66,29 @@ class LocalDevState {
|
|
|
63
66
|
return this._debug;
|
|
64
67
|
}
|
|
65
68
|
get deployedBuild() {
|
|
66
|
-
return
|
|
67
|
-
...this._deployedBuild,
|
|
68
|
-
});
|
|
69
|
+
return this._deployedBuild && structuredClone(this._deployedBuild);
|
|
69
70
|
}
|
|
70
71
|
get isGithubLinked() {
|
|
71
72
|
return this._isGithubLinked;
|
|
72
73
|
}
|
|
73
74
|
get projectNodes() {
|
|
74
|
-
return
|
|
75
|
+
return structuredClone(this._projectNodes);
|
|
75
76
|
}
|
|
76
77
|
set projectNodes(nodes) {
|
|
77
78
|
this._projectNodes = nodes;
|
|
78
79
|
this.runListeners('projectNodes');
|
|
79
80
|
}
|
|
80
|
-
get
|
|
81
|
-
return this.
|
|
82
|
-
}
|
|
83
|
-
get configFilesUpdatedSinceLastUpload() {
|
|
84
|
-
return this._configFilesUpdatedSinceLastUpload;
|
|
81
|
+
get projectNodesAtLastUpload() {
|
|
82
|
+
return structuredClone(this._projectNodesAtLastUpload);
|
|
85
83
|
}
|
|
86
|
-
|
|
87
|
-
this.
|
|
84
|
+
set projectNodesAtLastUpload(nodes) {
|
|
85
|
+
this._projectNodesAtLastUpload = nodes;
|
|
88
86
|
}
|
|
89
|
-
|
|
90
|
-
this.
|
|
87
|
+
get env() {
|
|
88
|
+
return this._env;
|
|
91
89
|
}
|
|
92
90
|
get appData() {
|
|
93
|
-
return
|
|
91
|
+
return structuredClone(this._appData);
|
|
94
92
|
}
|
|
95
93
|
getAppDataByUid(uid) {
|
|
96
94
|
return { ...this._appData[uid] };
|
|
@@ -21,7 +21,7 @@ class LocalDevWatcher {
|
|
|
21
21
|
}
|
|
22
22
|
handleWatchEvent(filePath, event, configPaths) {
|
|
23
23
|
if (configPaths.includes(filePath)) {
|
|
24
|
-
return this.localDevProcess.handleConfigFileChange(
|
|
24
|
+
return this.localDevProcess.handleConfigFileChange();
|
|
25
25
|
}
|
|
26
26
|
return this.localDevProcess.handleFileChange(filePath, event);
|
|
27
27
|
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { PromptOptionsArg, ProjectNameAndDestPromptResponse } from './selectProjectTemplatePrompt';
|
|
2
|
+
export declare function projectNameAndDestPrompt(promptOptions: PromptOptionsArg): Promise<ProjectNameAndDestPromptResponse>;
|
|
3
|
+
export declare function validateProjectDirectory(input?: string): string | boolean;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.projectNameAndDestPrompt = projectNameAndDestPrompt;
|
|
7
|
+
exports.validateProjectDirectory = validateProjectDirectory;
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
const path_2 = require("@hubspot/local-dev-lib/path");
|
|
11
|
+
const en_1 = require("../../lang/en");
|
|
12
|
+
const promptUtils_1 = require("./promptUtils");
|
|
13
|
+
const constants_1 = require("../constants");
|
|
14
|
+
async function projectNameAndDestPrompt(promptOptions) {
|
|
15
|
+
const result = await (0, promptUtils_1.promptUser)([
|
|
16
|
+
{
|
|
17
|
+
name: 'name',
|
|
18
|
+
message: en_1.lib.prompts.projectNameAndDestPrompt.enterName,
|
|
19
|
+
when: !promptOptions.name,
|
|
20
|
+
validate: (input) => {
|
|
21
|
+
if (!input) {
|
|
22
|
+
return en_1.lib.prompts.projectNameAndDestPrompt.errors.nameRequired;
|
|
23
|
+
}
|
|
24
|
+
return true;
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
name: 'dest',
|
|
29
|
+
message: en_1.lib.prompts.projectNameAndDestPrompt.enterDest,
|
|
30
|
+
when: !promptOptions.dest,
|
|
31
|
+
default: answers => {
|
|
32
|
+
const projectName = (0, path_2.sanitizeFileName)(promptOptions.name || answers.name);
|
|
33
|
+
return path_1.default.resolve((0, path_2.getCwd)(), projectName);
|
|
34
|
+
},
|
|
35
|
+
validate: validateProjectDirectory,
|
|
36
|
+
filter: input => {
|
|
37
|
+
return (0, path_2.untildify)(input);
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
]);
|
|
41
|
+
if (!result.name) {
|
|
42
|
+
result.name = promptOptions.name;
|
|
43
|
+
}
|
|
44
|
+
if (!result.dest) {
|
|
45
|
+
result.dest = promptOptions.dest;
|
|
46
|
+
}
|
|
47
|
+
return result;
|
|
48
|
+
}
|
|
49
|
+
function validateProjectDirectory(input) {
|
|
50
|
+
if (!input) {
|
|
51
|
+
return en_1.lib.prompts.projectNameAndDestPrompt.errors.destRequired;
|
|
52
|
+
}
|
|
53
|
+
if (fs_1.default.existsSync(path_1.default.resolve((0, path_2.getCwd)(), path_1.default.join(input, constants_1.PROJECT_CONFIG_FILE)))) {
|
|
54
|
+
return en_1.lib.prompts.projectNameAndDestPrompt.errors.invalidDest;
|
|
55
|
+
}
|
|
56
|
+
if (!(0, path_2.isValidPath)(input)) {
|
|
57
|
+
return en_1.lib.prompts.projectNameAndDestPrompt.errors.invalidCharacters;
|
|
58
|
+
}
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { ComponentTemplate, ComponentTemplateChoice, ProjectTemplate } from '../../types/Projects';
|
|
2
|
+
export type SelectProjectTemplatePromptResponse = {
|
|
3
|
+
projectTemplate?: ProjectTemplate;
|
|
4
|
+
componentTemplates?: ComponentTemplate[];
|
|
5
|
+
};
|
|
6
|
+
type SelectProjectTemplatePromptResponseProjectTemplate = {
|
|
7
|
+
projectTemplate: ProjectTemplate;
|
|
8
|
+
componentTemplates: undefined;
|
|
9
|
+
};
|
|
10
|
+
type SelectProjectTemplatePromptResponseComponentTemplates = {
|
|
11
|
+
projectTemplate?: undefined;
|
|
12
|
+
componentTemplates?: ComponentTemplate[];
|
|
13
|
+
};
|
|
14
|
+
export type ProjectNameAndDestPromptResponse = {
|
|
15
|
+
name: string;
|
|
16
|
+
dest: string;
|
|
17
|
+
};
|
|
18
|
+
export type PromptOptionsArg = {
|
|
19
|
+
name?: string;
|
|
20
|
+
dest?: string;
|
|
21
|
+
template?: string;
|
|
22
|
+
features?: string[];
|
|
23
|
+
};
|
|
24
|
+
export declare function selectProjectTemplatePrompt(promptOptions: PromptOptionsArg, projectTemplates?: ProjectTemplate[], componentTemplates?: undefined): Promise<SelectProjectTemplatePromptResponseProjectTemplate>;
|
|
25
|
+
export declare function selectProjectTemplatePrompt(promptOptions: PromptOptionsArg, projectTemplates?: undefined, componentTemplates?: ComponentTemplateChoice[]): Promise<SelectProjectTemplatePromptResponseComponentTemplates>;
|
|
26
|
+
export {};
|
|
@@ -1,31 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.
|
|
7
|
-
const fs_1 = __importDefault(require("fs"));
|
|
8
|
-
const path_1 = __importDefault(require("path"));
|
|
9
|
-
const path_2 = require("@hubspot/local-dev-lib/path");
|
|
3
|
+
exports.selectProjectTemplatePrompt = selectProjectTemplatePrompt;
|
|
10
4
|
const promptUtils_1 = require("./promptUtils");
|
|
11
|
-
const constants_1 = require("../constants");
|
|
12
5
|
const en_1 = require("../../lang/en");
|
|
13
|
-
function validateProjectDirectory(input) {
|
|
14
|
-
if (!input) {
|
|
15
|
-
return en_1.lib.prompts.createProjectPrompt.errors.destRequired;
|
|
16
|
-
}
|
|
17
|
-
if (fs_1.default.existsSync(path_1.default.resolve((0, path_2.getCwd)(), path_1.default.join(input, constants_1.PROJECT_CONFIG_FILE)))) {
|
|
18
|
-
return en_1.lib.prompts.createProjectPrompt.errors.invalidDest;
|
|
19
|
-
}
|
|
20
|
-
if (!(0, path_2.isValidPath)(input)) {
|
|
21
|
-
return en_1.lib.prompts.createProjectPrompt.errors.invalidCharacters;
|
|
22
|
-
}
|
|
23
|
-
return true;
|
|
24
|
-
}
|
|
25
6
|
function findTemplateByNameOrLabel(projectTemplates, templateNameOrLabel) {
|
|
26
7
|
return projectTemplates.find(t => t.name === templateNameOrLabel || t.label === templateNameOrLabel);
|
|
27
8
|
}
|
|
28
|
-
async function
|
|
9
|
+
async function selectProjectTemplatePrompt(promptOptions, projectTemplates, componentTemplates) {
|
|
29
10
|
const createProjectFromTemplate = !!projectTemplates && projectTemplates.length > 0;
|
|
30
11
|
const createProjectFromComponents = Array.isArray(componentTemplates) && componentTemplates?.length > 0;
|
|
31
12
|
const selectedComponents = [];
|
|
@@ -46,36 +27,12 @@ async function createProjectPrompt(promptOptions, projectTemplates, componentTem
|
|
|
46
27
|
!!promptOptions.template &&
|
|
47
28
|
!!findTemplateByNameOrLabel(projectTemplates, promptOptions.template);
|
|
48
29
|
const result = await (0, promptUtils_1.promptUser)([
|
|
49
|
-
{
|
|
50
|
-
name: 'name',
|
|
51
|
-
message: en_1.lib.prompts.createProjectPrompt.enterName,
|
|
52
|
-
when: !promptOptions.name,
|
|
53
|
-
validate: (input) => {
|
|
54
|
-
if (!input) {
|
|
55
|
-
return en_1.lib.prompts.createProjectPrompt.errors.nameRequired;
|
|
56
|
-
}
|
|
57
|
-
return true;
|
|
58
|
-
},
|
|
59
|
-
},
|
|
60
|
-
{
|
|
61
|
-
name: 'dest',
|
|
62
|
-
message: en_1.lib.prompts.createProjectPrompt.enterDest,
|
|
63
|
-
when: !promptOptions.dest,
|
|
64
|
-
default: answers => {
|
|
65
|
-
const projectName = (0, path_2.sanitizeFileName)(promptOptions.name || answers.name);
|
|
66
|
-
return path_1.default.resolve((0, path_2.getCwd)(), projectName);
|
|
67
|
-
},
|
|
68
|
-
validate: validateProjectDirectory,
|
|
69
|
-
filter: input => {
|
|
70
|
-
return (0, path_2.untildify)(input);
|
|
71
|
-
},
|
|
72
|
-
},
|
|
73
30
|
{
|
|
74
31
|
name: 'projectTemplate',
|
|
75
32
|
message: () => {
|
|
76
33
|
return promptOptions.template && !providedTemplateIsValid
|
|
77
|
-
? en_1.lib.prompts.
|
|
78
|
-
: en_1.lib.prompts.
|
|
34
|
+
? en_1.lib.prompts.selectProjectTemplatePrompt.errors.invalidTemplate(promptOptions.template)
|
|
35
|
+
: en_1.lib.prompts.selectProjectTemplatePrompt.selectTemplate;
|
|
79
36
|
},
|
|
80
37
|
when: createProjectFromTemplate && !providedTemplateIsValid,
|
|
81
38
|
type: 'list',
|
|
@@ -90,7 +47,7 @@ async function createProjectPrompt(promptOptions, projectTemplates, componentTem
|
|
|
90
47
|
},
|
|
91
48
|
{
|
|
92
49
|
name: 'componentTemplates',
|
|
93
|
-
message: en_1.lib.prompts.
|
|
50
|
+
message: en_1.lib.prompts.selectProjectTemplatePrompt.features,
|
|
94
51
|
when: !promptOptions.features &&
|
|
95
52
|
createProjectFromComponents &&
|
|
96
53
|
selectedComponents.length === 0,
|
|
@@ -98,12 +55,6 @@ async function createProjectPrompt(promptOptions, projectTemplates, componentTem
|
|
|
98
55
|
choices: componentTemplates,
|
|
99
56
|
},
|
|
100
57
|
]);
|
|
101
|
-
if (!result.name) {
|
|
102
|
-
result.name = promptOptions.name;
|
|
103
|
-
}
|
|
104
|
-
if (!result.dest) {
|
|
105
|
-
result.dest = promptOptions.dest;
|
|
106
|
-
}
|
|
107
58
|
if (!result.componentTemplates) {
|
|
108
59
|
result.componentTemplates = selectedComponents;
|
|
109
60
|
}
|
|
@@ -112,7 +63,7 @@ async function createProjectPrompt(promptOptions, projectTemplates, componentTem
|
|
|
112
63
|
}
|
|
113
64
|
if (projectTemplates && projectTemplates.length > 0) {
|
|
114
65
|
if (!result.projectTemplate) {
|
|
115
|
-
throw new Error(en_1.lib.prompts.
|
|
66
|
+
throw new Error(en_1.lib.prompts.selectProjectTemplatePrompt.errors.projectTemplateRequired);
|
|
116
67
|
}
|
|
117
68
|
return result;
|
|
118
69
|
}
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hubspot/cli",
|
|
3
|
-
"version": "7.7.16-experimental.
|
|
3
|
+
"version": "7.7.16-experimental.4",
|
|
4
4
|
"description": "The official CLI for developing on HubSpot",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": "https://github.com/HubSpot/hubspot-cli",
|
|
7
7
|
"dependencies": {
|
|
8
8
|
"@hubspot/local-dev-lib": "3.11.0",
|
|
9
|
-
"@hubspot/project-parsing-lib": "0.
|
|
9
|
+
"@hubspot/project-parsing-lib": "0.5.0",
|
|
10
10
|
"@hubspot/serverless-dev-runtime": "7.0.6",
|
|
11
11
|
"@hubspot/theme-preview-dev-server": "0.0.10",
|
|
12
12
|
"@hubspot/ui-extensions-dev-server": "0.9.2",
|
package/types/LocalDev.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ import { APP_INSTALLATION_STATES, LOCAL_DEV_SERVER_MESSAGE_TYPES } from '../lib/
|
|
|
8
8
|
export type LocalDevStateConstructorOptions = {
|
|
9
9
|
targetProjectAccountId: number;
|
|
10
10
|
targetTestingAccountId: number;
|
|
11
|
+
profile?: string;
|
|
11
12
|
projectConfig: ProjectConfig;
|
|
12
13
|
projectDir: string;
|
|
13
14
|
projectId: number;
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { ComponentTemplate, ComponentTemplateChoice, ProjectTemplate } from '../../types/Projects';
|
|
2
|
-
export type CreateProjectPromptResponse = {
|
|
3
|
-
name: string;
|
|
4
|
-
dest: string;
|
|
5
|
-
projectTemplate?: ProjectTemplate;
|
|
6
|
-
componentTemplates?: ComponentTemplate[];
|
|
7
|
-
};
|
|
8
|
-
type CreateProjectPromptResponseProjectTemplate = {
|
|
9
|
-
name: string;
|
|
10
|
-
dest: string;
|
|
11
|
-
projectTemplate: ProjectTemplate;
|
|
12
|
-
componentTemplates: undefined;
|
|
13
|
-
};
|
|
14
|
-
type CreateProjectPromptResponseComponentTemplates = {
|
|
15
|
-
name: string;
|
|
16
|
-
dest: string;
|
|
17
|
-
projectTemplate?: undefined;
|
|
18
|
-
componentTemplates?: ComponentTemplate[];
|
|
19
|
-
};
|
|
20
|
-
type PromptOptionsArg = {
|
|
21
|
-
name?: string;
|
|
22
|
-
dest?: string;
|
|
23
|
-
template?: string;
|
|
24
|
-
features?: string[];
|
|
25
|
-
};
|
|
26
|
-
export declare function createProjectPrompt(promptOptions: PromptOptionsArg, projectTemplates?: ProjectTemplate[], componentTemplates?: undefined): Promise<CreateProjectPromptResponseProjectTemplate>;
|
|
27
|
-
export declare function createProjectPrompt(promptOptions: PromptOptionsArg, projectTemplates?: undefined, componentTemplates?: ComponentTemplateChoice[]): Promise<CreateProjectPromptResponseComponentTemplates>;
|
|
28
|
-
export {};
|