@hubspot/cli 5.2.1-beta.8 → 5.3.0
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/auth.js +2 -4
- package/commands/functions/deploy.js +2 -2
- package/commands/init.js +2 -4
- package/commands/module/marketplace-validate.js +1 -1
- package/commands/project/__tests__/deploy.test.js +432 -0
- package/commands/project/cloneApp.js +208 -0
- package/commands/project/deploy.js +82 -27
- package/commands/project/listBuilds.js +1 -1
- package/commands/project/logs.js +1 -1
- package/commands/project/migrateApp.js +85 -30
- package/commands/project/upload.js +1 -1
- package/commands/project.js +15 -12
- package/commands/sandbox/create.js +17 -48
- package/commands/sandbox/delete.js +5 -2
- package/commands/sandbox/sync.js +12 -2
- package/commands/sandbox.js +2 -1
- package/commands/theme/marketplace-validate.js +1 -1
- package/lang/en.lyaml +77 -76
- package/lib/LocalDevManager.js +59 -11
- package/lib/buildAccount.js +3 -3
- package/lib/constants.js +3 -1
- package/lib/interpolationHelpers.js +3 -0
- package/lib/localDev.js +21 -11
- package/lib/marketplace-validate.js +11 -3
- package/lib/polling.js +16 -10
- package/lib/projects.js +143 -100
- package/lib/prompts/accountNamePrompt.js +78 -0
- package/lib/prompts/activeInstallConfirmationPrompt.js +20 -0
- package/lib/prompts/createProjectPrompt.js +12 -2
- package/lib/prompts/deployBuildIdPrompt.js +22 -0
- package/lib/prompts/installPublicAppPrompt.js +13 -4
- package/lib/prompts/personalAccessKeyPrompt.js +2 -2
- package/lib/prompts/sandboxesPrompt.js +12 -41
- package/lib/prompts/selectPublicAppPrompt.js +41 -22
- package/lib/sandboxSync.js +49 -68
- package/lib/sandboxes.js +8 -149
- package/lib/serverlessLogs.js +2 -2
- package/lib/ui/index.js +74 -0
- package/package.json +5 -4
- package/lib/prompts/buildIdPrompt.js +0 -35
- package/lib/prompts/developerTestAccountNamePrompt.js +0 -29
- package/lib/prompts/enterAccountNamePrompt.js +0 -33
- package/lib/ui/CliProgressMultibarManager.js +0 -66
|
@@ -9,7 +9,7 @@ const { loadAndValidateOptions } = require('../../lib/validation');
|
|
|
9
9
|
const { i18n } = require('../../lib/lang');
|
|
10
10
|
const { EXIT_CODES } = require('../../lib/enums/exitCodes');
|
|
11
11
|
const { getAccountConfig, getEnv } = require('@hubspot/local-dev-lib/config');
|
|
12
|
-
const { uiFeatureHighlight,
|
|
12
|
+
const { uiFeatureHighlight, uiBetaTag } = require('../../lib/ui');
|
|
13
13
|
const {
|
|
14
14
|
sandboxTypeMap,
|
|
15
15
|
getAvailableSyncTypes,
|
|
@@ -18,14 +18,8 @@ const {
|
|
|
18
18
|
} = require('../../lib/sandboxes');
|
|
19
19
|
const { getValidEnv } = require('@hubspot/local-dev-lib/environment');
|
|
20
20
|
const { logger } = require('@hubspot/local-dev-lib/logger');
|
|
21
|
-
const {
|
|
22
|
-
|
|
23
|
-
trackCommandMetadataUsage,
|
|
24
|
-
} = require('../../lib/usageTracking');
|
|
25
|
-
const {
|
|
26
|
-
sandboxTypePrompt,
|
|
27
|
-
sandboxNamePrompt,
|
|
28
|
-
} = require('../../lib/prompts/sandboxesPrompt');
|
|
21
|
+
const { trackCommandUsage } = require('../../lib/usageTracking');
|
|
22
|
+
const { sandboxTypePrompt } = require('../../lib/prompts/sandboxesPrompt');
|
|
29
23
|
const { promptUser } = require('../../lib/prompts/promptUtils');
|
|
30
24
|
const { syncSandbox } = require('../../lib/sandboxSync');
|
|
31
25
|
const { logErrorInstance } = require('../../lib/errorHandlers/standardErrors');
|
|
@@ -38,11 +32,14 @@ const {
|
|
|
38
32
|
HUBSPOT_ACCOUNT_TYPE_STRINGS,
|
|
39
33
|
} = require('@hubspot/local-dev-lib/constants/config');
|
|
40
34
|
const { buildNewAccount } = require('../../lib/buildAccount');
|
|
35
|
+
const {
|
|
36
|
+
hubspotAccountNamePrompt,
|
|
37
|
+
} = require('../../lib/prompts/accountNamePrompt');
|
|
41
38
|
|
|
42
39
|
const i18nKey = 'commands.sandbox.subcommands.create';
|
|
43
40
|
|
|
44
41
|
exports.command = 'create [--name] [--type]';
|
|
45
|
-
exports.describe = i18n(`${i18nKey}.describe`);
|
|
42
|
+
exports.describe = uiBetaTag(i18n(`${i18nKey}.describe`), false);
|
|
46
43
|
|
|
47
44
|
exports.handler = async options => {
|
|
48
45
|
await loadAndValidateOptions(options);
|
|
@@ -112,7 +109,7 @@ exports.handler = async options => {
|
|
|
112
109
|
|
|
113
110
|
if (!name) {
|
|
114
111
|
if (!force) {
|
|
115
|
-
namePrompt = await
|
|
112
|
+
namePrompt = await hubspotAccountNamePrompt({ accountType: sandboxType });
|
|
116
113
|
} else {
|
|
117
114
|
logger.error(i18n(`${i18nKey}.failure.optionMissing.name`));
|
|
118
115
|
process.exit(EXIT_CODES.ERROR);
|
|
@@ -120,34 +117,18 @@ exports.handler = async options => {
|
|
|
120
117
|
}
|
|
121
118
|
const sandboxName = name || namePrompt.name;
|
|
122
119
|
|
|
123
|
-
let
|
|
124
|
-
let contactRecordsSyncPromptResult = true;
|
|
120
|
+
let contactRecordsSyncPromptResult = false;
|
|
125
121
|
if (!force) {
|
|
126
|
-
const
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
const { sandboxSyncPrompt } = await promptUser([
|
|
132
|
-
{
|
|
133
|
-
name: 'sandboxSyncPrompt',
|
|
134
|
-
type: 'confirm',
|
|
135
|
-
message: i18n(`${syncI18nKey}.confirm.createFlow.${sandboxLangKey}`, {
|
|
136
|
-
parentAccountName: uiAccountDescription(accountId),
|
|
137
|
-
sandboxName,
|
|
138
|
-
}),
|
|
139
|
-
},
|
|
140
|
-
]);
|
|
141
|
-
sandboxSyncPromptResult = sandboxSyncPrompt;
|
|
142
|
-
// We can prompt for contact records before fetching types since we're starting with a fresh sandbox in create
|
|
143
|
-
if (sandboxSyncPrompt) {
|
|
122
|
+
const isStandardSandbox =
|
|
123
|
+
sandboxType === HUBSPOT_ACCOUNT_TYPES.STANDARD_SANDBOX;
|
|
124
|
+
|
|
125
|
+
// Prompt to sync contact records for standard sandboxes only
|
|
126
|
+
if (isStandardSandbox) {
|
|
144
127
|
const { contactRecordsSyncPrompt } = await promptUser([
|
|
145
128
|
{
|
|
146
129
|
name: 'contactRecordsSyncPrompt',
|
|
147
130
|
type: 'confirm',
|
|
148
|
-
message: i18n(
|
|
149
|
-
`${syncI18nKey}.confirm.syncContactRecords.${sandboxLangKey}`
|
|
150
|
-
),
|
|
131
|
+
message: i18n('lib.sandbox.sync.confirm.syncContactRecords.standard'),
|
|
151
132
|
},
|
|
152
133
|
]);
|
|
153
134
|
contactRecordsSyncPromptResult = contactRecordsSyncPrompt;
|
|
@@ -163,15 +144,8 @@ exports.handler = async options => {
|
|
|
163
144
|
force,
|
|
164
145
|
});
|
|
165
146
|
|
|
166
|
-
// Prompt user to sync assets after sandbox creation
|
|
167
147
|
const sandboxAccountConfig = getAccountConfig(result.sandbox.sandboxHubId);
|
|
168
148
|
const handleSyncSandbox = async syncTasks => {
|
|
169
|
-
// Send tracking event for secondary action, in this case a sandbox sync within the sandbox create flow
|
|
170
|
-
trackCommandMetadataUsage(
|
|
171
|
-
'sandbox-sync',
|
|
172
|
-
{ step: 'sandbox-create' },
|
|
173
|
-
result.sandbox.sandboxHubId
|
|
174
|
-
);
|
|
175
149
|
await syncSandbox({
|
|
176
150
|
accountConfig: sandboxAccountConfig,
|
|
177
151
|
parentAccountConfig: accountConfig,
|
|
@@ -184,18 +158,13 @@ exports.handler = async options => {
|
|
|
184
158
|
accountConfig,
|
|
185
159
|
sandboxAccountConfig
|
|
186
160
|
);
|
|
161
|
+
|
|
187
162
|
if (!contactRecordsSyncPromptResult) {
|
|
188
163
|
availableSyncTasks = availableSyncTasks.filter(
|
|
189
164
|
t => t.type !== syncTypes.OBJECT_RECORDS
|
|
190
165
|
);
|
|
191
166
|
}
|
|
192
|
-
|
|
193
|
-
if (sandboxSyncPromptResult) {
|
|
194
|
-
await handleSyncSandbox(availableSyncTasks);
|
|
195
|
-
}
|
|
196
|
-
} else {
|
|
197
|
-
await handleSyncSandbox(availableSyncTasks);
|
|
198
|
-
}
|
|
167
|
+
await handleSyncSandbox(availableSyncTasks);
|
|
199
168
|
} catch (err) {
|
|
200
169
|
logErrorInstance(err);
|
|
201
170
|
throw err;
|
|
@@ -33,12 +33,15 @@ const { promptUser } = require('../../lib/prompts/promptUtils');
|
|
|
33
33
|
const { getHubSpotWebsiteOrigin } = require('@hubspot/local-dev-lib/urls');
|
|
34
34
|
|
|
35
35
|
const { getValidEnv } = require('@hubspot/local-dev-lib/environment');
|
|
36
|
-
const { uiAccountDescription } = require('../../lib/ui');
|
|
36
|
+
const { uiAccountDescription, uiBetaTag } = require('../../lib/ui');
|
|
37
37
|
|
|
38
38
|
const i18nKey = 'commands.sandbox.subcommands.delete';
|
|
39
39
|
|
|
40
40
|
exports.command = 'delete [--account]';
|
|
41
|
-
exports.describe =
|
|
41
|
+
exports.describe = exports.describe = uiBetaTag(
|
|
42
|
+
i18n(`${i18nKey}.describe`),
|
|
43
|
+
false
|
|
44
|
+
);
|
|
42
45
|
|
|
43
46
|
exports.handler = async options => {
|
|
44
47
|
await loadAndValidateOptions(options, false);
|
package/commands/sandbox/sync.js
CHANGED
|
@@ -13,7 +13,12 @@ const { EXIT_CODES } = require('../../lib/enums/exitCodes');
|
|
|
13
13
|
const { getAccountConfig, getEnv } = require('@hubspot/local-dev-lib/config');
|
|
14
14
|
const { getHubSpotWebsiteOrigin } = require('@hubspot/local-dev-lib/urls');
|
|
15
15
|
const { promptUser } = require('../../lib/prompts/promptUtils');
|
|
16
|
-
const {
|
|
16
|
+
const {
|
|
17
|
+
uiLine,
|
|
18
|
+
uiAccountDescription,
|
|
19
|
+
uiDeprecatedMessage,
|
|
20
|
+
uiDeprecatedDescription,
|
|
21
|
+
} = require('../../lib/ui');
|
|
17
22
|
const {
|
|
18
23
|
isSandbox,
|
|
19
24
|
isStandardSandbox,
|
|
@@ -35,11 +40,16 @@ const {
|
|
|
35
40
|
const i18nKey = 'commands.sandbox.subcommands.sync';
|
|
36
41
|
|
|
37
42
|
exports.command = 'sync';
|
|
38
|
-
exports.describe =
|
|
43
|
+
exports.describe = uiDeprecatedDescription(
|
|
44
|
+
i18n(`${i18nKey}.describe`),
|
|
45
|
+
'hs sandbox sync'
|
|
46
|
+
);
|
|
39
47
|
|
|
40
48
|
exports.handler = async options => {
|
|
41
49
|
await loadAndValidateOptions(options);
|
|
42
50
|
|
|
51
|
+
uiDeprecatedMessage('hs sandbox sync');
|
|
52
|
+
|
|
43
53
|
const { force } = options; // For scripting purposes
|
|
44
54
|
const accountId = getAccountId(options);
|
|
45
55
|
const accountConfig = getAccountConfig(accountId);
|
package/commands/sandbox.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const { addConfigOptions, addAccountOptions } = require('../lib/commonOpts');
|
|
2
2
|
const { i18n } = require('../lib/lang');
|
|
3
|
+
const { uiBetaTag } = require('../lib/ui');
|
|
3
4
|
const create = require('./sandbox/create');
|
|
4
5
|
const del = require('./sandbox/delete');
|
|
5
6
|
const sync = require('./sandbox/sync');
|
|
@@ -7,7 +8,7 @@ const sync = require('./sandbox/sync');
|
|
|
7
8
|
const i18nKey = 'commands.sandbox';
|
|
8
9
|
|
|
9
10
|
exports.command = 'sandbox';
|
|
10
|
-
exports.describe = i18n(`${i18nKey}.describe`);
|
|
11
|
+
exports.describe = uiBetaTag(i18n(`${i18nKey}.describe`), false);
|
|
11
12
|
|
|
12
13
|
exports.builder = yargs => {
|
|
13
14
|
addConfigOptions(yargs);
|
package/lang/en.lyaml
CHANGED
|
@@ -514,20 +514,38 @@ en:
|
|
|
514
514
|
done: "Converting app configuration to public-app.json component definition ... DONE"
|
|
515
515
|
failure: "Converting app configuration to public-app.json component definition ... FAILED"
|
|
516
516
|
warning:
|
|
517
|
-
title: "{{#bold}}Migrate
|
|
518
|
-
projectConversion: "{{#bold}}The selected app will be
|
|
517
|
+
title: "{{#bold}}Migrate {{appName}} to the projects framework?{{/bold}}"
|
|
518
|
+
projectConversion: "{{#bold}}The selected app will be converted to a project component.{{/bold}}"
|
|
519
519
|
appConfig: "All supported app configuration will be moved to the {{#bold}}public-app.json{{/bold}} component definition file. Future updates to those features must be made through the project build and deploy pipeline, not the developer account UI."
|
|
520
520
|
buildAndDeploy: "This will create a new project with a single app component and immediately build and deploy it to your developer account (build #1)."
|
|
521
521
|
existingApps: "{{#bold}}This will not affect existing app users or installs.{{/bold}}"
|
|
522
522
|
copyApp: "We strongly recommend making a copy of your app to test this process in a development app before replacing production."
|
|
523
|
-
|
|
523
|
+
migrationInterrupted: "\nThe command is terminated, but app migration is still in progress. Please check your account to ensure that the project and associated app have been created successfully."
|
|
524
|
+
createAppPrompt: "Proceed with migrating this app to a project component (this process can't be aborted)?"
|
|
524
525
|
projectDetailsLink: "View project details in your developer account"
|
|
525
526
|
errors:
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
\n- Run {{ authCommand }} to connect an app developer account to the HubSpot CLI.\n"
|
|
527
|
+
invalidAccountTypeTitle: "{{#bold}}Developer account not targeted{{/bold}}"
|
|
528
|
+
invalidAccountTypeDescription: "Only public apps created in a developer account can be converted to a project component. Select a connected developer account with {{useCommand}} or {{authCommand}} and try again."
|
|
529
529
|
projectAlreadyExists: "A project with name {{ projectName }} already exists. Please choose another name."
|
|
530
|
-
|
|
530
|
+
invalidApp: "Could not migrate appId {{ appId }}. This app cannot be migrated at this time. Please choose another public app."
|
|
531
|
+
cloneApp:
|
|
532
|
+
describe: "Clone a public app using the projects framework"
|
|
533
|
+
examples:
|
|
534
|
+
default: "Clone a public app using the projects framework"
|
|
535
|
+
options:
|
|
536
|
+
appId:
|
|
537
|
+
describe: "The ID for the public app being cloned"
|
|
538
|
+
location:
|
|
539
|
+
describe: "Directory where project should be created"
|
|
540
|
+
cloneStatus:
|
|
541
|
+
inProgress: "Cloning app configuration to {{#bold}}public-app.json{{/bold}} component definition ..."
|
|
542
|
+
done: "Cloning app configuration to public-app.json component definition ... DONE"
|
|
543
|
+
success: "Your cloned project was created in {{ location }}"
|
|
544
|
+
failure: "Cloning app configuration to public-app.json component definition ... FAILED"
|
|
545
|
+
errors:
|
|
546
|
+
invalidAccountTypeTitle: "{{#bold}}Developer account not targeted{{/bold}}"
|
|
547
|
+
invalidAccountTypeDescription: "Only public apps created in a developer account can be converted to a project component. Select a connected developer account with {{useCommand}} or {{authCommand}} and try again."
|
|
548
|
+
couldNotWriteConfigPath: "Failed to write project config at {{ configPath }}"
|
|
531
549
|
add:
|
|
532
550
|
describe: "Create a new component within a project"
|
|
533
551
|
options:
|
|
@@ -551,12 +569,15 @@ en:
|
|
|
551
569
|
deploy: "Deploy error: {{ details }}"
|
|
552
570
|
noBuilds: "Deploy error: no builds for this project were found."
|
|
553
571
|
noBuildId: "You must specify a build to deploy"
|
|
554
|
-
projectNotFound: "{{ projectName }} does not exist in account {{ accountIdentifier }}. Run {{ command }} to upload your project files to HubSpot."
|
|
572
|
+
projectNotFound: "The project {{ projectName }} does not exist in account {{ accountIdentifier }}. Run {{ command }} to upload your project files to HubSpot."
|
|
573
|
+
buildIdDoesNotExist: "Build {{ buildId }} does not exist for project {{ projectName }}. {{ linkToProject }}"
|
|
574
|
+
buildAlreadyDeployed: "Build {{ buildId }} is already deployed. {{ linkToProject}}"
|
|
575
|
+
viewProjectsBuilds: 'View project builds in HubSpot'
|
|
555
576
|
examples:
|
|
556
577
|
default: "Deploy the latest build of the current project"
|
|
557
578
|
withOptions: "Deploy build 5 of the project my-project"
|
|
558
579
|
options:
|
|
559
|
-
|
|
580
|
+
build:
|
|
560
581
|
describe: "Project build ID to be deployed"
|
|
561
582
|
project:
|
|
562
583
|
describe: "Project name"
|
|
@@ -959,7 +980,8 @@ en:
|
|
|
959
980
|
learnMoreLocalDevServer: "Learn more about the projects local dev server"
|
|
960
981
|
running: "Running {{#bold}}{{ projectName }}{{/bold}} locally on {{ accountIdentifier }}, waiting for changes ..."
|
|
961
982
|
quitHelper: "Press {{#bold}}'q'{{/bold}} to stop the local dev server"
|
|
962
|
-
|
|
983
|
+
viewProjectLink: "View project in HubSpot"
|
|
984
|
+
viewTestAccountLink: "View developer test account in HubSpot"
|
|
963
985
|
exitingStart: "Stopping local dev server ..."
|
|
964
986
|
exitingSucceed: "Successfully exited"
|
|
965
987
|
exitingFail: "Failed to cleanup before exiting"
|
|
@@ -968,17 +990,15 @@ en:
|
|
|
968
990
|
appLabel: "[App]"
|
|
969
991
|
uiExtensionLabel: "[UI Extension]"
|
|
970
992
|
missingComponents: "Couldn't find the following components in the deployed build for this project: {{#bold}}'{{ missingComponents }}'{{/bold}}. This may cause issues in local development."
|
|
971
|
-
defaultWarning: "Changing project configuration requires a new project build."
|
|
972
|
-
defaultPublicAppWarning: "Changing project configuration requires a new project build.
|
|
993
|
+
defaultWarning: "{{#bold}}Changing project configuration requires a new project build.{{/bold}}"
|
|
994
|
+
defaultPublicAppWarning: "{{#bold}}Changing project configuration requires a new project build.{{/bold}}\n\nThis will affect your public app's {{#bold}}{{ installCount }} existing {{ installText }}{{/bold}}. If your app has users in production, we strongly recommend creating a copy of this app to test your changes before proceding."
|
|
973
995
|
header: "{{ warning }} To reflect these changes and continue testing:"
|
|
974
996
|
stopDev: " * Stop {{ command }}"
|
|
975
997
|
runUpload: " * Run {{ command }}"
|
|
976
998
|
restartDev: " * Re-run {{ command }}"
|
|
977
999
|
pushToGithub: " * Commit and push your changes to GitHub"
|
|
978
1000
|
activeInstallWarning:
|
|
979
|
-
installCount: "{{#bold}}The app {{ appName }} has {{ installCount }} production
|
|
980
|
-
genericHeader: "{{#bold}}Local development can affect existing installs of your public app.{{/bold}}"
|
|
981
|
-
genericExplanation: "Some changes made during local development may need to be synced to HubSpot, which will impact users with existing installs. You will always be asked to confirm these changes before uploading them. If your app has any production installs, we strongly recommend creating a copy of this app to develop on instead."
|
|
1001
|
+
installCount: "{{#bold}}The app {{ appName }} has {{ installCount }} production {{ installText }}{{/bold}}"
|
|
982
1002
|
explanation: "Some changes made during local development may need to be synced to HubSpot, which will impact those existing installs. We strongly recommend creating a copy of this app to use instead."
|
|
983
1003
|
confirmation: "You will always be asked to confirm any permanent changes to your app’s configuration before uploading them."
|
|
984
1004
|
devServer:
|
|
@@ -1032,9 +1052,12 @@ en:
|
|
|
1032
1052
|
successStatusText: "DONE"
|
|
1033
1053
|
failedStatusText: "FAILED"
|
|
1034
1054
|
errorFetchingTaskStatus: "Error fetching {{ taskType }} status"
|
|
1055
|
+
pollBuildAutodeployStatusError: "Error fetching autodeploy status for build #{{ buildId }}"
|
|
1035
1056
|
pollProjectBuildAndDeploy:
|
|
1036
1057
|
buildSucceededAutomaticallyDeploying: "Build #{{ buildId }} succeeded. {{#bold}}Automatically deploying{{/bold}} to {{ accountIdentifier }}\n"
|
|
1037
1058
|
cleanedUpTempFile: "Cleaned up temporary file {{ path }}"
|
|
1059
|
+
viewDeploys: "View all deploys for this project in HubSpot"
|
|
1060
|
+
unableToFindAutodeployStatus: "Unable to find the auto deploy for build #{{ buildId }}. This deploy may have been skipped. {{ viewDeploysLink }}."
|
|
1038
1061
|
logFeedbackMessage:
|
|
1039
1062
|
feedbackHeader: "We'd love to hear your feedback!"
|
|
1040
1063
|
feedbackMessage: "How are you liking the new projects and developer tools? \n > Run `{{#yellow}}hs feedback{{/yellow}}` to let us know what you think!\n"
|
|
@@ -1043,6 +1066,14 @@ en:
|
|
|
1043
1066
|
betaWarning:
|
|
1044
1067
|
header: "{{#yellow}}***************************** WARNING ****************************{{/yellow}}"
|
|
1045
1068
|
footer: "{{#yellow}}******************************************************************{{/yellow}}"
|
|
1069
|
+
infoTag: "{{#bold}}[INFO]{{/bold}}"
|
|
1070
|
+
deprecatedTag: "{{#bold}}[DEPRECATED]{{/bold}}"
|
|
1071
|
+
errorTag: "{{#bold}}[ERROR]{{/bold}}"
|
|
1072
|
+
deprecatedMessage: "The {{ command }} command is deprecated and will be disabled soon. {{ url }}"
|
|
1073
|
+
deprecatedDescription: "{{ message }}. The {{ command }} command is deprecated and will be disabled soon. {{ url }}"
|
|
1074
|
+
deprecatedUrlText: 'Learn more.'
|
|
1075
|
+
disabledMessage: "The {{ command }} command is disabled. Run {{ npmCommand }} to update to the latest HubSpot CLI version. {{ url }}"
|
|
1076
|
+
disabledUrlText: "See all HubSpot CLI commands here."
|
|
1046
1077
|
featureHighlight:
|
|
1047
1078
|
defaultTitle: "What's next?"
|
|
1048
1079
|
commandKeys:
|
|
@@ -1143,8 +1174,13 @@ en:
|
|
|
1143
1174
|
setAsDefaultAccountMessage: "Set this account as the default?"
|
|
1144
1175
|
setAsDefaultAccount: "Account \"{{ accountName }}\" set as the default account"
|
|
1145
1176
|
keepingCurrentDefault: "Account \"{{ accountName }}\" will continue to be the default account"
|
|
1146
|
-
|
|
1177
|
+
accountNamePrompt:
|
|
1147
1178
|
enterAccountName: "Enter a unique name to reference this account in the CLI:"
|
|
1179
|
+
enterDeveloperTestAccountName: "Name your developer test account:"
|
|
1180
|
+
enterStandardSandboxName: "Name your standard sandbox:"
|
|
1181
|
+
enterDevelopmentSandboxName: "Name your development sandbox:"
|
|
1182
|
+
sandboxDefaultName: "New {{ sandboxType }} sandbox"
|
|
1183
|
+
developerTestAccountDefaultName: "Developer test account {{ count }}"
|
|
1148
1184
|
errors:
|
|
1149
1185
|
invalidName: "You entered an invalid name. Please try again."
|
|
1150
1186
|
nameRequired: "The name may not be blank. Please try again."
|
|
@@ -1206,6 +1242,7 @@ en:
|
|
|
1206
1242
|
nameRequired: "A project name is required"
|
|
1207
1243
|
locationRequired: "A project location is required"
|
|
1208
1244
|
invalidLocation: "The selected destination already exists. Please provide a new path for this project."
|
|
1245
|
+
invalidCharacters: "The selected destination contains invalid characters. Please provide a new path and try again."
|
|
1209
1246
|
invalidTemplate: "[--template] Could not find template {{ template }}. Please choose an available template."
|
|
1210
1247
|
noProjectsInConfig: "Please ensure that there is a config.json file that contains a \"projects\" field."
|
|
1211
1248
|
missingPropertiesInConfig: "Please ensure that each of the projects in your config.json file contain the following properties: [\"name\", \"label\", \"path\", \"insertPath\"]."
|
|
@@ -1213,17 +1250,12 @@ en:
|
|
|
1213
1250
|
selectAppIdMigrate: "[--appId] Choose an app under {{ accountName }} to migrate:"
|
|
1214
1251
|
selectAppIdClone: "[--appId] Choose an app under {{ accountName }} to clone:"
|
|
1215
1252
|
errors:
|
|
1216
|
-
|
|
1217
|
-
|
|
1253
|
+
noAppsMigration: "{{#bold}}No apps to migrate{{/bold}}"
|
|
1254
|
+
noAppsClone: "{{#bold}}No apps to clone{{/bold}}"
|
|
1255
|
+
noAppsMigrationMessage: "The selected developer account {{#bold}}{{ accountName }}{{/bold}} doesn't have any apps that can be migrated to the projects framework."
|
|
1256
|
+
noAppsCloneMessage: "The selected developer account {{#bold}}{{ accountName }}{{/bold}} doesn't have any apps that can be cloned to the projects framework."
|
|
1218
1257
|
errorFetchingApps: "There was an error fetching public apps."
|
|
1219
|
-
|
|
1220
|
-
developerTestAccountPrompt:
|
|
1221
|
-
name:
|
|
1222
|
-
message: "Name your developer test account"
|
|
1223
|
-
errors:
|
|
1224
|
-
invalidName: "You entered an invalid name. Please try again."
|
|
1225
|
-
nameRequired: "The name may not be blank. Please try again."
|
|
1226
|
-
accountNameExists: "Account with name \"{{ name }}\" already exists in the CLI config, please enter a different name."
|
|
1258
|
+
cannotBeMigrated: "Cannot be migrated"
|
|
1227
1259
|
downloadProjectPrompt:
|
|
1228
1260
|
selectProject: "Select a project to download:"
|
|
1229
1261
|
errors:
|
|
@@ -1239,19 +1271,12 @@ en:
|
|
|
1239
1271
|
errors:
|
|
1240
1272
|
invalidValue: "You entered an invalid value. Please try again."
|
|
1241
1273
|
sandboxesPrompt:
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
developmentSandboxMessage: "Name your development sandbox"
|
|
1245
|
-
errors:
|
|
1246
|
-
invalidName: "You entered an invalid name. Please try again."
|
|
1247
|
-
nameRequired: "The name may not be blank. Please try again."
|
|
1248
|
-
accountNameExists: "Account with name \"{{ name }}\" already exists in the CLI config, please enter a different name."
|
|
1249
|
-
selectAccountName: "Select the sandbox account you want to delete"
|
|
1250
|
-
selectParentAccountName: "Select the account that the sandbox belongs to"
|
|
1274
|
+
selectAccountName: "Select the sandbox account you want to delete"
|
|
1275
|
+
selectParentAccountName: "Select the account that the sandbox belongs to"
|
|
1251
1276
|
type:
|
|
1252
|
-
message: "
|
|
1253
|
-
developer: "Development sandbox (
|
|
1254
|
-
standard: "Standard sandbox (
|
|
1277
|
+
message: "Choose the type of sandbox you want to create"
|
|
1278
|
+
developer: "Development sandbox (Includes production's object definitions)"
|
|
1279
|
+
standard: "Standard sandbox (Includes partial copy of production's assets)"
|
|
1255
1280
|
uploadPrompt:
|
|
1256
1281
|
enterDest: "[--dest] Enter the destination path: "
|
|
1257
1282
|
enterSrc: "[--src] Enter the source path: "
|
|
@@ -1271,11 +1296,8 @@ en:
|
|
|
1271
1296
|
general: "[--general] Tell us about your experience with HubSpot's developer tools"
|
|
1272
1297
|
bugPrompt: "Create an issue on Github in your browser?"
|
|
1273
1298
|
generalPrompt: "Create an issue on Github in your browser?"
|
|
1274
|
-
|
|
1299
|
+
deployBuildIdPrompt:
|
|
1275
1300
|
enterBuildId: "[--build] Deploy which build?"
|
|
1276
|
-
errors:
|
|
1277
|
-
buildIdDoesNotExist: "Build {{ buildId }} does not exist for project {{ projectName }}."
|
|
1278
|
-
buildAlreadyDeployed: "Build {{ buildId }} is already deployed."
|
|
1279
1301
|
previewPrompt:
|
|
1280
1302
|
enterSrc: "[--src] Enter a local theme directory to preview."
|
|
1281
1303
|
enterDest: "[--dest] Enter the destination path for the src theme in HubSpot Design Tools."
|
|
@@ -1287,8 +1309,12 @@ en:
|
|
|
1287
1309
|
message: "You are about to remove any remote files in \"{{ filePath }}\" on HubSpot account {{ accountId }} that don't exist locally. Are you sure you want to do this?"
|
|
1288
1310
|
installPublicAppPrompt:
|
|
1289
1311
|
explanation: "Local development requires this app to be installed in the target test account"
|
|
1312
|
+
reinstallExplanation: "This app's required scopes have been updated since it was last installed on the target test account. To avoid issues with local development, we recommend reinstalling the app with the updated scopes."
|
|
1290
1313
|
prompt: "Open hubspot.com to install this app?"
|
|
1314
|
+
reinstallPrompt: "Open hubspot.com to reinstall this app?"
|
|
1291
1315
|
decline: "To continue local development of this app, install it in your target test account and re-run {{#bold}}`hs project dev`{{/bold}}"
|
|
1316
|
+
activeInstallConfirmationPrompt:
|
|
1317
|
+
message: "Proceed with local development of this {{#bold}}production{{/bold}} app?"
|
|
1292
1318
|
convertFields:
|
|
1293
1319
|
positionals:
|
|
1294
1320
|
src:
|
|
@@ -1321,11 +1347,11 @@ en:
|
|
|
1321
1347
|
developer:
|
|
1322
1348
|
add: "Creating development sandbox {{#bold}}{{ accountName }}{{/bold}}"
|
|
1323
1349
|
fail: "Failed to create a development sandbox {{#bold}}{{ accountName }}{{/bold}}."
|
|
1324
|
-
succeed: "
|
|
1350
|
+
succeed: "Created {{#bold}}{{ accountName }} [dev sandbox] ({{ accountId }}){{/bold}}."
|
|
1325
1351
|
standard:
|
|
1326
1352
|
add: "Creating standard sandbox {{#bold}}{{ accountName }}{{/bold}}"
|
|
1327
1353
|
fail: "Failed to create a standard sandbox {{#bold}}{{ accountName }}{{/bold}}."
|
|
1328
|
-
succeed: "
|
|
1354
|
+
succeed: "Created {{#bold}}{{ accountName }} [standard sandbox] ({{ accountId }}){{/bold}}."
|
|
1329
1355
|
failure:
|
|
1330
1356
|
invalidUser: "Couldn't create {{#bold}}{{ accountName }}{{/bold}} because your account has been removed from {{#bold}}{{ parentAccountName }}{{/bold}} or your permission set doesn't allow you to create the sandbox. To update your permissions, contact a super admin in {{#bold}}{{ parentAccountName }}{{/bold}}."
|
|
1331
1357
|
403Gating: "Couldn't create {{#bold}}{{ accountName }}{{/bold}} because {{#bold}}{{ parentAccountName }}{{/bold}} does not have access to development sandboxes. To opt in to the CRM Development Beta and use development sandboxes, visit https://app.hubspot.com/l/product-updates/in-beta?update=13899236."
|
|
@@ -1367,53 +1393,28 @@ en:
|
|
|
1367
1393
|
sync:
|
|
1368
1394
|
info:
|
|
1369
1395
|
syncStatus: "View the sync status details at: {{#bold}}{{ url }}{{/bold}}"
|
|
1370
|
-
|
|
1396
|
+
syncMessage: "Asset sync from production to the sandbox is in progress and is running in the background. It may take some time. {{ url }}"
|
|
1397
|
+
syncMessageDevSb: "Sync of object definitions from production to the sandbox is in progress and is running in the background. It may take some time. {{ url }}"
|
|
1398
|
+
syncStatusDetailsLinkText: "View sync status details here"
|
|
1371
1399
|
confirm:
|
|
1372
1400
|
createFlow:
|
|
1373
1401
|
standard: "Sync all supported assets to {{#cyan}}{{#bold}}{{ sandboxName }}{{/bold}}{{/cyan}} from {{#bold}}{{ parentAccountName }}{{/bold}}?"
|
|
1374
1402
|
developer: "Sync CRM object definitions to {{#cyan}}{{#bold}}{{ sandboxName }}{{/bold}}{{/cyan}} from {{#bold}}{{ parentAccountName }}{{/bold}}?"
|
|
1375
1403
|
syncContactRecords:
|
|
1376
|
-
standard: "
|
|
1404
|
+
standard: "Copy up to 5000 most recently updated contacts? This includes up to 100 of each of the following: associated deals, tickets, and companies."
|
|
1377
1405
|
developer: "Include up to 100 most recently updated contacts? This includes up to 100 of each of the following: associated deals, tickets, and companies. This can be done once per sandbox."
|
|
1378
1406
|
loading:
|
|
1379
1407
|
startSync: "Initiating sync..."
|
|
1380
1408
|
fail: "Failed to sync sandbox."
|
|
1381
|
-
succeed: "
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
polling:
|
|
1385
|
-
syncing: "Syncing sandbox..."
|
|
1386
|
-
fail: "Failed to fetch sync updates. View the sync status at: {{ url }}"
|
|
1387
|
-
succeed: "Sandbox sync complete."
|
|
1409
|
+
succeed: "Initiated asset sync from production to {{ accountName }}"
|
|
1410
|
+
succeedDevSb: "Initiated sync of object definitions from production to {{ accountName }}"
|
|
1411
|
+
successDevSbInfo: "Initiated sync of object definitions from production to {{ accountName }}. It may take some time. {{ url }}"
|
|
1388
1412
|
failure:
|
|
1389
1413
|
invalidUser: "Couldn't sync {{ accountName }} because your account has been removed from {{ parentAccountName }} or your permission set doesn't allow you to sync the sandbox. To update your permissions, contact a super admin in {{ parentAccountName }}."
|
|
1390
1414
|
missingScopes: "Couldn’t run the sync because there are scopes missing in your production account. To update scopes, deactivate your current personal access key for {{#bold}}{{ accountName }}{{/bold}}, and generate a new one. Then run `hs auth` to update the CLI with the new key."
|
|
1391
1415
|
syncInProgress: "Couldn’t run the sync because there’s another sync in progress. Wait for the current sync to finish and then try again. To check the sync status, visit the sync activity log: {{ url }}."
|
|
1392
1416
|
notSuperAdmin: "Couldn't run the sync because you are not a super admin in {{ account }}. Ask the account owner for super admin access to the sandbox."
|
|
1393
1417
|
objectNotFound: "Couldn't sync the sandbox because {{#bold}}{{ account }}{{/bold}} may have been deleted through the UI. Run {{#bold}}hs sandbox delete{{/bold}} to remove this account from the config. "
|
|
1394
|
-
types:
|
|
1395
|
-
parcels:
|
|
1396
|
-
label: "Account tools and features"
|
|
1397
|
-
super-admins:
|
|
1398
|
-
label: "Super Admins"
|
|
1399
|
-
object-schemas:
|
|
1400
|
-
label: "Object definitions"
|
|
1401
|
-
object-records:
|
|
1402
|
-
label: "Contacts and associated records"
|
|
1403
|
-
cms-developer-assets:
|
|
1404
|
-
label: "Themes, templates, and modules"
|
|
1405
|
-
object-pipelines:
|
|
1406
|
-
label: "Pipelines"
|
|
1407
|
-
object-lists:
|
|
1408
|
-
label: "Lists"
|
|
1409
|
-
workflows:
|
|
1410
|
-
label: "Workflows"
|
|
1411
|
-
forms:
|
|
1412
|
-
label: "Forms"
|
|
1413
|
-
lead-flows:
|
|
1414
|
-
label: "Lead Flows"
|
|
1415
|
-
marketing-email:
|
|
1416
|
-
label: "Marketing emails"
|
|
1417
1418
|
errorHandlers:
|
|
1418
1419
|
standardErrors:
|
|
1419
1420
|
errorOccurred: "Error: {{ error }}"
|
package/lib/LocalDevManager.js
CHANGED
|
@@ -9,6 +9,7 @@ const {
|
|
|
9
9
|
} = require('@hubspot/local-dev-lib/api/localDevAuth');
|
|
10
10
|
const {
|
|
11
11
|
fetchPublicAppsForPortal,
|
|
12
|
+
fetchPublicAppProductionInstallCounts,
|
|
12
13
|
} = require('@hubspot/local-dev-lib/api/appsDev');
|
|
13
14
|
const {
|
|
14
15
|
getAccountId,
|
|
@@ -19,6 +20,7 @@ const SpinniesManager = require('./ui/SpinniesManager');
|
|
|
19
20
|
const DevServerManager = require('./DevServerManager');
|
|
20
21
|
const { EXIT_CODES } = require('./enums/exitCodes');
|
|
21
22
|
const { getProjectDetailUrl } = require('./projects');
|
|
23
|
+
const { getAccountHomeUrl } = require('./localDev');
|
|
22
24
|
const {
|
|
23
25
|
CONFIG_FILES,
|
|
24
26
|
COMPONENT_TYPES,
|
|
@@ -34,6 +36,9 @@ const {
|
|
|
34
36
|
} = require('./ui');
|
|
35
37
|
const { logErrorInstance } = require('./errorHandlers/standardErrors');
|
|
36
38
|
const { installPublicAppPrompt } = require('./prompts/installPublicAppPrompt');
|
|
39
|
+
const {
|
|
40
|
+
activeInstallConfirmationPrompt,
|
|
41
|
+
} = require('./prompts/activeInstallConfirmationPrompt');
|
|
37
42
|
|
|
38
43
|
const WATCH_EVENTS = {
|
|
39
44
|
add: 'add',
|
|
@@ -62,6 +67,7 @@ class LocalDevManager {
|
|
|
62
67
|
this.activeApp = null;
|
|
63
68
|
this.activePublicAppData = null;
|
|
64
69
|
this.env = options.env;
|
|
70
|
+
this.publicAppActiveInstalls = null;
|
|
65
71
|
|
|
66
72
|
this.projectSourceDir = path.join(
|
|
67
73
|
this.projectDir,
|
|
@@ -132,20 +138,43 @@ class LocalDevManager {
|
|
|
132
138
|
({ sourceId }) => sourceId === this.activeApp.config.uid
|
|
133
139
|
);
|
|
134
140
|
|
|
141
|
+
// TODO: Update to account for new API with { data }
|
|
142
|
+
const {
|
|
143
|
+
uniquePortalInstallCount,
|
|
144
|
+
} = await fetchPublicAppProductionInstallCounts(
|
|
145
|
+
activePublicAppData.id,
|
|
146
|
+
this.targetProjectAccountId
|
|
147
|
+
);
|
|
148
|
+
|
|
135
149
|
this.activePublicAppData = activePublicAppData;
|
|
150
|
+
this.publicAppActiveInstalls = uniquePortalInstallCount;
|
|
136
151
|
}
|
|
137
152
|
|
|
138
153
|
async checkActivePublicAppInstalls() {
|
|
139
|
-
|
|
140
|
-
|
|
154
|
+
if (
|
|
155
|
+
!this.activePublicAppData ||
|
|
156
|
+
!this.publicAppActiveInstalls ||
|
|
157
|
+
this.publicAppActiveInstalls < 1
|
|
158
|
+
) {
|
|
141
159
|
return;
|
|
142
160
|
}
|
|
143
161
|
uiLine();
|
|
144
|
-
// TODO: Replace with final copy
|
|
145
162
|
|
|
146
|
-
logger.warn(
|
|
147
|
-
|
|
163
|
+
logger.warn(
|
|
164
|
+
i18n(`${i18nKey}.activeInstallWarning.installCount`, {
|
|
165
|
+
appName: this.activePublicAppData.name,
|
|
166
|
+
installCount: this.publicAppActiveInstalls,
|
|
167
|
+
installText:
|
|
168
|
+
this.publicAppActiveInstalls === 1 ? 'install' : 'installs',
|
|
169
|
+
})
|
|
170
|
+
);
|
|
171
|
+
logger.log(i18n(`${i18nKey}.activeInstallWarning.explanation`));
|
|
148
172
|
uiLine();
|
|
173
|
+
const proceed = await activeInstallConfirmationPrompt();
|
|
174
|
+
|
|
175
|
+
if (!proceed) {
|
|
176
|
+
process.exit(EXIT_CODES.SUCCESS);
|
|
177
|
+
}
|
|
149
178
|
}
|
|
150
179
|
|
|
151
180
|
async start() {
|
|
@@ -193,13 +222,23 @@ class LocalDevManager {
|
|
|
193
222
|
);
|
|
194
223
|
logger.log(
|
|
195
224
|
uiLink(
|
|
196
|
-
i18n(`${i18nKey}.
|
|
225
|
+
i18n(`${i18nKey}.viewProjectLink`),
|
|
197
226
|
getProjectDetailUrl(
|
|
198
227
|
this.projectConfig.name,
|
|
199
228
|
this.targetProjectAccountId
|
|
200
229
|
)
|
|
201
230
|
)
|
|
202
231
|
);
|
|
232
|
+
|
|
233
|
+
if (this.activeApp.type === COMPONENT_TYPES.publicApp) {
|
|
234
|
+
logger.log(
|
|
235
|
+
uiLink(
|
|
236
|
+
i18n(`${i18nKey}.viewTestAccountLink`),
|
|
237
|
+
getAccountHomeUrl(this.targetAccountId)
|
|
238
|
+
)
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
|
|
203
242
|
logger.log();
|
|
204
243
|
logger.log(i18n(`${i18nKey}.quitHelper`));
|
|
205
244
|
uiLine();
|
|
@@ -258,16 +297,20 @@ class LocalDevManager {
|
|
|
258
297
|
|
|
259
298
|
async checkPublicAppInstallation() {
|
|
260
299
|
const {
|
|
261
|
-
isInstalledWithScopeGroups
|
|
300
|
+
isInstalledWithScopeGroups,
|
|
301
|
+
previouslyAuthorizedScopeGroups,
|
|
262
302
|
} = await this.getActiveAppInstallationData();
|
|
263
303
|
|
|
264
|
-
|
|
304
|
+
const isReinstall = previouslyAuthorizedScopeGroups.length > 0;
|
|
305
|
+
|
|
306
|
+
if (!isInstalledWithScopeGroups) {
|
|
265
307
|
await installPublicAppPrompt(
|
|
266
308
|
this.env,
|
|
267
309
|
this.targetAccountId,
|
|
268
310
|
this.activePublicAppData.clientId,
|
|
269
311
|
this.activeApp.config.auth.requiredScopes,
|
|
270
|
-
this.activeApp.config.auth.redirectUrls
|
|
312
|
+
this.activeApp.config.auth.redirectUrls,
|
|
313
|
+
isReinstall
|
|
271
314
|
);
|
|
272
315
|
}
|
|
273
316
|
}
|
|
@@ -294,8 +337,13 @@ class LocalDevManager {
|
|
|
294
337
|
let warning = reason;
|
|
295
338
|
if (!reason) {
|
|
296
339
|
warning =
|
|
297
|
-
this.activeApp.type === COMPONENT_TYPES.publicApp
|
|
298
|
-
|
|
340
|
+
this.activeApp.type === COMPONENT_TYPES.publicApp &&
|
|
341
|
+
this.publicAppActiveInstalls > 0
|
|
342
|
+
? i18n(`${i18nKey}.uploadWarning.defaultPublicAppWarning`, {
|
|
343
|
+
installCount: this.publicAppActiveInstalls,
|
|
344
|
+
installText:
|
|
345
|
+
this.publicAppActiveInstalls === 1 ? 'install' : 'installs',
|
|
346
|
+
})
|
|
299
347
|
: i18n(`${i18nKey}.uploadWarning.defaultWarning`);
|
|
300
348
|
}
|
|
301
349
|
|