@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
package/lib/buildAccount.js
CHANGED
|
@@ -13,7 +13,7 @@ const {
|
|
|
13
13
|
} = require('@hubspot/local-dev-lib/config');
|
|
14
14
|
const { logger } = require('@hubspot/local-dev-lib/logger');
|
|
15
15
|
const { i18n } = require('./lang');
|
|
16
|
-
const {
|
|
16
|
+
const { cliAccountNamePrompt } = require('./prompts/accountNamePrompt');
|
|
17
17
|
const SpinniesManager = require('./ui/SpinniesManager');
|
|
18
18
|
const {
|
|
19
19
|
debugErrorAndContext,
|
|
@@ -65,11 +65,11 @@ async function saveAccountToConfig({
|
|
|
65
65
|
if (!force) {
|
|
66
66
|
logger.log('');
|
|
67
67
|
logger.warn(
|
|
68
|
-
i18n(`lib.prompts.
|
|
68
|
+
i18n(`lib.prompts.accountNamePrompt.errors.accountNameExists`, {
|
|
69
69
|
name: nameForConfig,
|
|
70
70
|
})
|
|
71
71
|
);
|
|
72
|
-
const { name: promptName } = await
|
|
72
|
+
const { name: promptName } = await cliAccountNamePrompt(
|
|
73
73
|
nameForConfig + `_${accountId}`
|
|
74
74
|
);
|
|
75
75
|
validName = promptName;
|
package/lib/constants.js
CHANGED
|
@@ -25,6 +25,7 @@ const POLLING_DELAY = 2000;
|
|
|
25
25
|
const POLLING_STATUS = {
|
|
26
26
|
SUCCESS: 'SUCCESS',
|
|
27
27
|
ERROR: 'ERROR',
|
|
28
|
+
REVERTED: 'REVERTED',
|
|
28
29
|
FAILURE: 'FAILURE',
|
|
29
30
|
};
|
|
30
31
|
|
|
@@ -65,8 +66,9 @@ const PROJECT_ERROR_TYPES = {
|
|
|
65
66
|
};
|
|
66
67
|
const PROJECT_TASK_TYPES = {
|
|
67
68
|
PRIVATE_APP: 'private app',
|
|
69
|
+
PUBLIC_APP: 'public app',
|
|
68
70
|
APP_FUNCTION: 'function',
|
|
69
|
-
CRM_CARD_V2: '
|
|
71
|
+
CRM_CARD_V2: 'card',
|
|
70
72
|
};
|
|
71
73
|
const PROJECT_COMPONENT_TYPES = {
|
|
72
74
|
PROJECTS: 'projects',
|
package/lib/localDev.js
CHANGED
|
@@ -8,18 +8,17 @@ const {
|
|
|
8
8
|
isSpecifiedError,
|
|
9
9
|
} = require('@hubspot/local-dev-lib/errors/apiErrors');
|
|
10
10
|
const { getHubSpotWebsiteOrigin } = require('@hubspot/local-dev-lib/urls');
|
|
11
|
-
const { getAccountConfig } = require('@hubspot/local-dev-lib/config');
|
|
11
|
+
const { getAccountConfig, getEnv } = require('@hubspot/local-dev-lib/config');
|
|
12
12
|
const { createProject } = require('@hubspot/local-dev-lib/api/projects');
|
|
13
|
+
const {
|
|
14
|
+
ENVIRONMENTS,
|
|
15
|
+
} = require('@hubspot/local-dev-lib/constants/environments');
|
|
13
16
|
const {
|
|
14
17
|
confirmDefaultAccountPrompt,
|
|
15
18
|
selectSandboxTargetAccountPrompt,
|
|
16
19
|
selectDeveloperTestTargetAccountPrompt,
|
|
17
20
|
confirmUseExistingDeveloperTestAccountPrompt,
|
|
18
21
|
} = require('./prompts/projectDevTargetAccountPrompt');
|
|
19
|
-
const { sandboxNamePrompt } = require('./prompts/sandboxesPrompt');
|
|
20
|
-
const {
|
|
21
|
-
developerTestAccountNamePrompt,
|
|
22
|
-
} = require('./prompts/developerTestAccountNamePrompt');
|
|
23
22
|
const { confirmPrompt } = require('./prompts/promptUtils');
|
|
24
23
|
const {
|
|
25
24
|
validateSandboxUsageLimits,
|
|
@@ -56,6 +55,7 @@ const {
|
|
|
56
55
|
PERSONAL_ACCESS_KEY_AUTH_METHOD,
|
|
57
56
|
} = require('@hubspot/local-dev-lib/constants/auth');
|
|
58
57
|
const { buildNewAccount, saveAccountToConfig } = require('./buildAccount');
|
|
58
|
+
const { hubspotAccountNamePrompt } = require('./prompts/accountNamePrompt');
|
|
59
59
|
|
|
60
60
|
const i18nKey = 'lib.localDev';
|
|
61
61
|
|
|
@@ -163,9 +163,9 @@ const createSandboxForLocalDev = async (accountId, accountConfig, env) => {
|
|
|
163
163
|
process.exit(EXIT_CODES.ERROR);
|
|
164
164
|
}
|
|
165
165
|
try {
|
|
166
|
-
const { name } = await
|
|
167
|
-
HUBSPOT_ACCOUNT_TYPES.DEVELOPMENT_SANDBOX
|
|
168
|
-
);
|
|
166
|
+
const { name } = await hubspotAccountNamePrompt({
|
|
167
|
+
accountType: HUBSPOT_ACCOUNT_TYPES.DEVELOPMENT_SANDBOX,
|
|
168
|
+
});
|
|
169
169
|
|
|
170
170
|
trackCommandMetadataUsage(
|
|
171
171
|
'sandbox-create',
|
|
@@ -192,8 +192,7 @@ const createSandboxForLocalDev = async (accountId, accountConfig, env) => {
|
|
|
192
192
|
parentAccountConfig: accountConfig,
|
|
193
193
|
env,
|
|
194
194
|
syncTasks,
|
|
195
|
-
|
|
196
|
-
skipPolling: true, // Skip polling, sync will run and complete in the background
|
|
195
|
+
slimInfoMessage: true,
|
|
197
196
|
});
|
|
198
197
|
return targetAccountId;
|
|
199
198
|
} catch (err) {
|
|
@@ -242,7 +241,10 @@ const createDeveloperTestAccountForLocalDev = async (
|
|
|
242
241
|
}
|
|
243
242
|
|
|
244
243
|
try {
|
|
245
|
-
const { name } = await
|
|
244
|
+
const { name } = await hubspotAccountNamePrompt({
|
|
245
|
+
currentPortalCount,
|
|
246
|
+
accountType: HUBSPOT_ACCOUNT_TYPES.DEVELOPER_TEST,
|
|
247
|
+
});
|
|
246
248
|
trackCommandMetadataUsage(
|
|
247
249
|
'developer-test-account-create',
|
|
248
250
|
{ step: 'project-dev' },
|
|
@@ -427,6 +429,13 @@ const createInitialBuildForNewProject = async (
|
|
|
427
429
|
return initialUploadResult.buildResult;
|
|
428
430
|
};
|
|
429
431
|
|
|
432
|
+
const getAccountHomeUrl = accountId => {
|
|
433
|
+
const baseUrl = getHubSpotWebsiteOrigin(
|
|
434
|
+
getEnv(accountId) === 'qa' ? ENVIRONMENTS.QA : ENVIRONMENTS.PROD
|
|
435
|
+
);
|
|
436
|
+
return `${baseUrl}/home?portalId=${accountId}`;
|
|
437
|
+
};
|
|
438
|
+
|
|
430
439
|
module.exports = {
|
|
431
440
|
confirmDefaultAccountIsTarget,
|
|
432
441
|
checkIfAppDeveloperAccount,
|
|
@@ -437,4 +446,5 @@ module.exports = {
|
|
|
437
446
|
useExistingDevTestAccount,
|
|
438
447
|
createNewProjectForLocalDev,
|
|
439
448
|
createInitialBuildForNewProject,
|
|
449
|
+
getAccountHomeUrl,
|
|
440
450
|
};
|
|
@@ -57,12 +57,20 @@ const fetchValidationResults = async (accountId, validationId) => {
|
|
|
57
57
|
}
|
|
58
58
|
};
|
|
59
59
|
|
|
60
|
-
const processValidationErrors = validationResults => {
|
|
60
|
+
const processValidationErrors = (i18nKey, validationResults) => {
|
|
61
61
|
if (validationResults.errors.length) {
|
|
62
|
-
const { errors } = validationResults;
|
|
62
|
+
const { assetPath, errors } = validationResults;
|
|
63
63
|
|
|
64
64
|
errors.forEach(err => {
|
|
65
|
-
|
|
65
|
+
if (err.failureReasonType === 'DOWNLOAD_EMPTY') {
|
|
66
|
+
logger.error(
|
|
67
|
+
i18n(`${i18nKey}.errors.invalidPath`, {
|
|
68
|
+
path: assetPath,
|
|
69
|
+
})
|
|
70
|
+
);
|
|
71
|
+
} else {
|
|
72
|
+
logger.error(`${err.context}`);
|
|
73
|
+
}
|
|
66
74
|
});
|
|
67
75
|
process.exit(EXIT_CODES.ERROR);
|
|
68
76
|
}
|
package/lib/polling.js
CHANGED
|
@@ -3,18 +3,24 @@ const { POLLING_DELAY, POLLING_STATUS } = require('./constants');
|
|
|
3
3
|
const poll = (callback, accountId, taskId) => {
|
|
4
4
|
return new Promise((resolve, reject) => {
|
|
5
5
|
const pollInterval = setInterval(async () => {
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
try {
|
|
7
|
+
const pollResp = await callback(accountId, taskId);
|
|
8
|
+
const { status } = pollResp;
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
if (status === POLLING_STATUS.SUCCESS) {
|
|
11
|
+
clearInterval(pollInterval);
|
|
12
|
+
resolve(pollResp);
|
|
13
|
+
} else if (
|
|
14
|
+
status === POLLING_STATUS.ERROR ||
|
|
15
|
+
status === POLLING_STATUS.REVERTED ||
|
|
16
|
+
status === POLLING_STATUS.FAILURE
|
|
17
|
+
) {
|
|
18
|
+
clearInterval(pollInterval);
|
|
19
|
+
reject(pollResp);
|
|
20
|
+
}
|
|
21
|
+
} catch (error) {
|
|
10
22
|
clearInterval(pollInterval);
|
|
11
|
-
|
|
12
|
-
} else if (
|
|
13
|
-
status === POLLING_STATUS.ERROR ||
|
|
14
|
-
status === POLLING_STATUS.FAILURE
|
|
15
|
-
) {
|
|
16
|
-
clearInterval(pollInterval);
|
|
17
|
-
reject(pollResp);
|
|
23
|
+
reject(error);
|
|
18
24
|
}
|
|
19
25
|
}, POLLING_DELAY);
|
|
20
26
|
});
|
package/lib/projects.js
CHANGED
|
@@ -60,8 +60,10 @@ const writeProjectConfig = (configPath, config) => {
|
|
|
60
60
|
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
61
61
|
logger.debug(`Wrote project config at ${configPath}`);
|
|
62
62
|
} catch (e) {
|
|
63
|
-
logger.
|
|
63
|
+
logger.debug(e);
|
|
64
|
+
return false;
|
|
64
65
|
}
|
|
66
|
+
return true;
|
|
65
67
|
};
|
|
66
68
|
|
|
67
69
|
const getIsInProject = _dir => {
|
|
@@ -326,17 +328,19 @@ const getProjectDetailUrl = (projectName, accountId) => {
|
|
|
326
328
|
return `${getProjectHomeUrl(accountId)}/project/${projectName}`;
|
|
327
329
|
};
|
|
328
330
|
|
|
331
|
+
const getProjectActivityUrl = (projectName, accountId) => {
|
|
332
|
+
if (!projectName) return;
|
|
333
|
+
return `${getProjectDetailUrl(projectName, accountId)}/activity`;
|
|
334
|
+
};
|
|
335
|
+
|
|
329
336
|
const getProjectBuildDetailUrl = (projectName, buildId, accountId) => {
|
|
330
337
|
if (!projectName || !buildId || !accountId) return;
|
|
331
|
-
return `${
|
|
338
|
+
return `${getProjectActivityUrl(projectName, accountId)}/build/${buildId}`;
|
|
332
339
|
};
|
|
333
340
|
|
|
334
341
|
const getProjectDeployDetailUrl = (projectName, deployId, accountId) => {
|
|
335
342
|
if (!projectName || !deployId || !accountId) return;
|
|
336
|
-
return `${
|
|
337
|
-
projectName,
|
|
338
|
-
accountId
|
|
339
|
-
)}/activity/deploy/${deployId}`;
|
|
343
|
+
return `${getProjectActivityUrl(projectName, accountId)}/deploy/${deployId}`;
|
|
340
344
|
};
|
|
341
345
|
|
|
342
346
|
const uploadProjectFiles = async (
|
|
@@ -405,7 +409,7 @@ const pollProjectBuildAndDeploy = async (
|
|
|
405
409
|
buildId,
|
|
406
410
|
silenceLogs = false
|
|
407
411
|
) => {
|
|
408
|
-
|
|
412
|
+
let buildStatus = await pollBuildStatus(
|
|
409
413
|
accountId,
|
|
410
414
|
projectConfig.name,
|
|
411
415
|
buildId,
|
|
@@ -413,16 +417,6 @@ const pollProjectBuildAndDeploy = async (
|
|
|
413
417
|
silenceLogs
|
|
414
418
|
);
|
|
415
419
|
|
|
416
|
-
const {
|
|
417
|
-
autoDeployId,
|
|
418
|
-
isAutoDeployEnabled,
|
|
419
|
-
deployStatusTaskLocator,
|
|
420
|
-
} = buildStatus;
|
|
421
|
-
|
|
422
|
-
// autoDeployId of 0 indicates a skipped deploy
|
|
423
|
-
const isDeploying =
|
|
424
|
-
isAutoDeployEnabled && autoDeployId > 0 && deployStatusTaskLocator;
|
|
425
|
-
|
|
426
420
|
if (!silenceLogs) {
|
|
427
421
|
uiLine();
|
|
428
422
|
}
|
|
@@ -437,7 +431,7 @@ const pollProjectBuildAndDeploy = async (
|
|
|
437
431
|
if (buildStatus.status === 'FAILURE') {
|
|
438
432
|
result.succeeded = false;
|
|
439
433
|
return result;
|
|
440
|
-
} else if (
|
|
434
|
+
} else if (buildStatus.isAutoDeployEnabled) {
|
|
441
435
|
if (!silenceLogs) {
|
|
442
436
|
logger.log(
|
|
443
437
|
i18n(
|
|
@@ -452,17 +446,45 @@ const pollProjectBuildAndDeploy = async (
|
|
|
452
446
|
displayWarnLogs(accountId, projectConfig.name, buildId);
|
|
453
447
|
}
|
|
454
448
|
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
449
|
+
// autoDeployId of 0 indicates a skipped deploy
|
|
450
|
+
const getIsDeploying = () =>
|
|
451
|
+
buildStatus.autoDeployId > 0 && buildStatus.deployStatusTaskLocator;
|
|
452
|
+
|
|
453
|
+
// Sometimes the deploys do not immediately initiate, give them a chance to kick off
|
|
454
|
+
if (!getIsDeploying()) {
|
|
455
|
+
buildStatus = await pollBuildAutodeployStatus(
|
|
456
|
+
accountId,
|
|
457
|
+
projectConfig.name,
|
|
458
|
+
buildId
|
|
459
|
+
);
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
if (getIsDeploying()) {
|
|
463
|
+
const deployStatus = await pollDeployStatus(
|
|
464
|
+
accountId,
|
|
465
|
+
projectConfig.name,
|
|
466
|
+
buildStatus.deployStatusTaskLocator.id,
|
|
467
|
+
buildId,
|
|
468
|
+
silenceLogs
|
|
469
|
+
);
|
|
470
|
+
result.deployResult = deployStatus;
|
|
463
471
|
|
|
464
|
-
|
|
465
|
-
|
|
472
|
+
if (deployStatus.status === 'FAILURE') {
|
|
473
|
+
result.succeeded = false;
|
|
474
|
+
}
|
|
475
|
+
} else if (!silenceLogs) {
|
|
476
|
+
logger.log(
|
|
477
|
+
i18n(
|
|
478
|
+
`${i18nKey}.pollProjectBuildAndDeploy.unableToFindAutodeployStatus`,
|
|
479
|
+
{
|
|
480
|
+
buildId,
|
|
481
|
+
viewDeploysLink: uiLink(
|
|
482
|
+
i18n(`${i18nKey}.pollProjectBuildAndDeploy.viewDeploys`),
|
|
483
|
+
getProjectActivityUrl(projectConfig.name, accountId)
|
|
484
|
+
),
|
|
485
|
+
}
|
|
486
|
+
)
|
|
487
|
+
);
|
|
466
488
|
}
|
|
467
489
|
}
|
|
468
490
|
|
|
@@ -588,17 +610,6 @@ const makePollTaskStatusFunc = ({
|
|
|
588
610
|
statusStrings,
|
|
589
611
|
linkToHubSpot,
|
|
590
612
|
}) => {
|
|
591
|
-
const isTaskComplete = task => {
|
|
592
|
-
if (
|
|
593
|
-
!task[statusText.SUBTASK_KEY].length ||
|
|
594
|
-
task.status === statusText.STATES.FAILURE
|
|
595
|
-
) {
|
|
596
|
-
return true;
|
|
597
|
-
} else if (task.status === statusText.STATES.SUCCESS) {
|
|
598
|
-
return task.isAutoDeployEnabled ? !!task.deployStatusTaskLocator : true;
|
|
599
|
-
}
|
|
600
|
-
};
|
|
601
|
-
|
|
602
613
|
return async (
|
|
603
614
|
accountId,
|
|
604
615
|
taskName,
|
|
@@ -635,9 +646,9 @@ const makePollTaskStatusFunc = ({
|
|
|
635
646
|
|
|
636
647
|
const tasksById = initialTaskStatus[statusText.SUBTASK_KEY].reduce(
|
|
637
648
|
(acc, task) => {
|
|
638
|
-
const
|
|
639
|
-
if (
|
|
640
|
-
acc[
|
|
649
|
+
const { id, visible } = task;
|
|
650
|
+
if (visible) {
|
|
651
|
+
acc[id] = task;
|
|
641
652
|
}
|
|
642
653
|
return acc;
|
|
643
654
|
},
|
|
@@ -677,7 +688,7 @@ const makePollTaskStatusFunc = ({
|
|
|
677
688
|
const formattedTaskType = PROJECT_TASK_TYPES[taskType]
|
|
678
689
|
? `[${PROJECT_TASK_TYPES[taskType]}]`
|
|
679
690
|
: '';
|
|
680
|
-
const text = `${statusText.STATUS_TEXT} ${chalk.bold(
|
|
691
|
+
const text = `${indent <= 2 ? statusText.STATUS_TEXT : ''} ${chalk.bold(
|
|
681
692
|
taskName
|
|
682
693
|
)} ${formattedTaskType} ...${newline ? '\n' : ''}`;
|
|
683
694
|
|
|
@@ -703,13 +714,7 @@ const makePollTaskStatusFunc = ({
|
|
|
703
714
|
try {
|
|
704
715
|
taskStatus = await statusFn(accountId, taskName, taskId);
|
|
705
716
|
} catch (e) {
|
|
706
|
-
|
|
707
|
-
e,
|
|
708
|
-
new ApiErrorContext({
|
|
709
|
-
accountId,
|
|
710
|
-
projectName: taskName,
|
|
711
|
-
})
|
|
712
|
-
);
|
|
717
|
+
logger.debug(e);
|
|
713
718
|
return reject(
|
|
714
719
|
new Error(
|
|
715
720
|
i18n(
|
|
@@ -785,61 +790,64 @@ const makePollTaskStatusFunc = ({
|
|
|
785
790
|
}
|
|
786
791
|
});
|
|
787
792
|
|
|
788
|
-
if (
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
793
|
+
if (status === statusText.STATES.SUCCESS) {
|
|
794
|
+
SpinniesManager.succeed(overallTaskSpinniesKey, {
|
|
795
|
+
text: statusStrings.SUCCESS(taskName, displayId),
|
|
796
|
+
});
|
|
797
|
+
clearInterval(pollInterval);
|
|
798
|
+
resolve(taskStatus);
|
|
799
|
+
} else if (status === statusText.STATES.FAILURE) {
|
|
800
|
+
SpinniesManager.fail(overallTaskSpinniesKey, {
|
|
801
|
+
text: statusStrings.FAIL(taskName, displayId),
|
|
802
|
+
});
|
|
803
|
+
|
|
804
|
+
if (!silenceLogs) {
|
|
805
|
+
const failedSubtasks = subTaskStatus.filter(
|
|
806
|
+
subtask => subtask.status === 'FAILURE'
|
|
807
|
+
);
|
|
808
|
+
|
|
809
|
+
uiLine();
|
|
810
|
+
logger.log(
|
|
811
|
+
`${statusStrings.SUBTASK_FAIL(
|
|
812
|
+
displayId,
|
|
813
|
+
failedSubtasks.length === 1
|
|
814
|
+
? failedSubtasks[0][statusText.SUBTASK_NAME_KEY]
|
|
815
|
+
: failedSubtasks.length + ' components'
|
|
816
|
+
)}\n`
|
|
817
|
+
);
|
|
818
|
+
logger.log('See below for a summary of errors.');
|
|
819
|
+
uiLine();
|
|
820
|
+
|
|
821
|
+
const displayErrors = failedSubtasks.filter(
|
|
822
|
+
subtask =>
|
|
823
|
+
subtask.standardError.subCategory !==
|
|
824
|
+
PROJECT_ERROR_TYPES.SUBBUILD_FAILED &&
|
|
825
|
+
subtask.standardError.subCategory !==
|
|
826
|
+
PROJECT_ERROR_TYPES.SUBDEPLOY_FAILED
|
|
827
|
+
);
|
|
828
|
+
|
|
829
|
+
displayErrors.forEach(subTask => {
|
|
804
830
|
logger.log(
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
? failedSubtasks[0][statusText.SUBTASK_NAME_KEY]
|
|
809
|
-
: failedSubtasks.length + ' components'
|
|
810
|
-
)}\n`
|
|
811
|
-
);
|
|
812
|
-
logger.log('See below for a summary of errors.');
|
|
813
|
-
uiLine();
|
|
814
|
-
|
|
815
|
-
const displayErrors = failedSubtasks.filter(
|
|
816
|
-
subtask =>
|
|
817
|
-
subtask.standardError.subCategory !==
|
|
818
|
-
PROJECT_ERROR_TYPES.SUBBUILD_FAILED &&
|
|
819
|
-
subtask.standardError.subCategory !==
|
|
820
|
-
PROJECT_ERROR_TYPES.SUBDEPLOY_FAILED
|
|
831
|
+
`\n--- ${chalk.bold(
|
|
832
|
+
subTask[statusText.SUBTASK_NAME_KEY]
|
|
833
|
+
)} failed with the following error ---`
|
|
821
834
|
);
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
if (subTask.standardError && subTask.standardError.errors) {
|
|
833
|
-
logger.log();
|
|
834
|
-
subTask.standardError.errors.forEach(error => {
|
|
835
|
-
logger.log(error.message);
|
|
836
|
-
});
|
|
837
|
-
}
|
|
838
|
-
});
|
|
839
|
-
}
|
|
835
|
+
logger.error(subTask.errorMessage);
|
|
836
|
+
|
|
837
|
+
// Log nested errors
|
|
838
|
+
if (subTask.standardError && subTask.standardError.errors) {
|
|
839
|
+
logger.log();
|
|
840
|
+
subTask.standardError.errors.forEach(error => {
|
|
841
|
+
logger.log(error.message);
|
|
842
|
+
});
|
|
843
|
+
}
|
|
844
|
+
});
|
|
840
845
|
}
|
|
841
846
|
clearInterval(pollInterval);
|
|
842
847
|
resolve(taskStatus);
|
|
848
|
+
} else if (!subTaskStatus.length) {
|
|
849
|
+
clearInterval(pollInterval);
|
|
850
|
+
resolve(taskStatus);
|
|
843
851
|
}
|
|
844
852
|
}
|
|
845
853
|
}, POLLING_DELAY);
|
|
@@ -847,6 +855,41 @@ const makePollTaskStatusFunc = ({
|
|
|
847
855
|
};
|
|
848
856
|
};
|
|
849
857
|
|
|
858
|
+
const pollBuildAutodeployStatus = (accountId, taskName, buildId) => {
|
|
859
|
+
return new Promise((resolve, reject) => {
|
|
860
|
+
let maxIntervals = (30 * 1000) / POLLING_DELAY; // Num of intervals in ~30s
|
|
861
|
+
|
|
862
|
+
const pollInterval = setInterval(async () => {
|
|
863
|
+
let taskStatus;
|
|
864
|
+
try {
|
|
865
|
+
taskStatus = await getBuildStatus(accountId, taskName, buildId);
|
|
866
|
+
} catch (e) {
|
|
867
|
+
logger.debug(e);
|
|
868
|
+
return reject(
|
|
869
|
+
new Error(
|
|
870
|
+
i18n(`${i18nKey}.pollBuildAutodeployStatusError`, { buildId })
|
|
871
|
+
)
|
|
872
|
+
);
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
if (!taskStatus || !taskStatus.status) {
|
|
876
|
+
return reject(
|
|
877
|
+
new Error(
|
|
878
|
+
i18n(`${i18nKey}.pollBuildAutodeployStatusError`, { buildId })
|
|
879
|
+
)
|
|
880
|
+
);
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
if (taskStatus.deployStatusTaskLocator || maxIntervals <= 0) {
|
|
884
|
+
clearInterval(pollInterval);
|
|
885
|
+
resolve(taskStatus);
|
|
886
|
+
} else {
|
|
887
|
+
maxIntervals -= 1;
|
|
888
|
+
}
|
|
889
|
+
}, POLLING_DELAY);
|
|
890
|
+
});
|
|
891
|
+
};
|
|
892
|
+
|
|
850
893
|
const pollBuildStatus = makePollTaskStatusFunc({
|
|
851
894
|
linkToHubSpot: (accountId, taskName, taskId) =>
|
|
852
895
|
uiLink(
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
const { accountNameExistsInConfig } = require('@hubspot/local-dev-lib/config');
|
|
2
|
+
const { STRING_WITH_NO_SPACES_REGEX } = require('../regex');
|
|
3
|
+
const { promptUser } = require('./promptUtils');
|
|
4
|
+
const { i18n } = require('../lang');
|
|
5
|
+
const {
|
|
6
|
+
HUBSPOT_ACCOUNT_TYPES,
|
|
7
|
+
} = require('@hubspot/local-dev-lib/constants/config');
|
|
8
|
+
|
|
9
|
+
const i18nKey = 'lib.prompts.accountNamePrompt';
|
|
10
|
+
|
|
11
|
+
const getCliAccountNamePromptConfig = defaultName => ({
|
|
12
|
+
name: 'name',
|
|
13
|
+
message: i18n(`${i18nKey}.enterAccountName`),
|
|
14
|
+
default: defaultName,
|
|
15
|
+
validate(val) {
|
|
16
|
+
if (typeof val !== 'string') {
|
|
17
|
+
return i18n(`${i18nKey}.errors.invalidName`);
|
|
18
|
+
} else if (!val.length) {
|
|
19
|
+
return i18n(`${i18nKey}.errors.nameRequired`);
|
|
20
|
+
} else if (!STRING_WITH_NO_SPACES_REGEX.test(val)) {
|
|
21
|
+
return i18n(`${i18nKey}.errors.spacesInName`);
|
|
22
|
+
}
|
|
23
|
+
return accountNameExistsInConfig(val)
|
|
24
|
+
? i18n(`${i18nKey}.errors.accountNameExists`, { name: val })
|
|
25
|
+
: true;
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const cliAccountNamePrompt = defaultName => {
|
|
30
|
+
return promptUser(getCliAccountNamePromptConfig(defaultName));
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const hubspotAccountNamePrompt = ({ accountType, currentPortalCount = 0 }) => {
|
|
34
|
+
const isDevelopmentSandbox =
|
|
35
|
+
accountType === HUBSPOT_ACCOUNT_TYPES.DEVELOPMENT_SANDBOX;
|
|
36
|
+
const isSandbox =
|
|
37
|
+
accountType === HUBSPOT_ACCOUNT_TYPES.STANDARD_SANDBOX ||
|
|
38
|
+
isDevelopmentSandbox;
|
|
39
|
+
const isDeveloperTestAccount =
|
|
40
|
+
accountType === HUBSPOT_ACCOUNT_TYPES.DEVELOPER_TEST;
|
|
41
|
+
|
|
42
|
+
let promptMessageString;
|
|
43
|
+
let defaultName;
|
|
44
|
+
if (isSandbox) {
|
|
45
|
+
promptMessageString = isDevelopmentSandbox
|
|
46
|
+
? i18n(`${i18nKey}.enterDevelopmentSandboxName`)
|
|
47
|
+
: i18n(`${i18nKey}.enterStandardSandboxName`);
|
|
48
|
+
} else if (isDeveloperTestAccount) {
|
|
49
|
+
promptMessageString = i18n(`${i18nKey}.enterDeveloperTestAccountName`);
|
|
50
|
+
defaultName = i18n(`${i18nKey}.developerTestAccountDefaultName`, {
|
|
51
|
+
count: currentPortalCount + 1,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return promptUser([
|
|
56
|
+
{
|
|
57
|
+
name: 'name',
|
|
58
|
+
message: promptMessageString,
|
|
59
|
+
validate(val) {
|
|
60
|
+
if (typeof val !== 'string') {
|
|
61
|
+
return i18n(`${i18nKey}.errors.invalidName`);
|
|
62
|
+
} else if (!val.trim().length) {
|
|
63
|
+
return i18n(`${i18nKey}.errors.nameRequired`);
|
|
64
|
+
}
|
|
65
|
+
return accountNameExistsInConfig(val)
|
|
66
|
+
? i18n(`${i18nKey}.errors.accountNameExists`, { name: val })
|
|
67
|
+
: true;
|
|
68
|
+
},
|
|
69
|
+
default: defaultName,
|
|
70
|
+
},
|
|
71
|
+
]);
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
module.exports = {
|
|
75
|
+
getCliAccountNamePromptConfig,
|
|
76
|
+
cliAccountNamePrompt,
|
|
77
|
+
hubspotAccountNamePrompt,
|
|
78
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
const { promptUser } = require('./promptUtils');
|
|
2
|
+
const { i18n } = require('../lang');
|
|
3
|
+
|
|
4
|
+
const i18nKey = 'lib.prompts.activeInstallConfirmationPrompt';
|
|
5
|
+
|
|
6
|
+
const activeInstallConfirmationPrompt = async () => {
|
|
7
|
+
const { proceed } = await promptUser([
|
|
8
|
+
{
|
|
9
|
+
name: 'proceed',
|
|
10
|
+
message: i18n(`${i18nKey}.message`),
|
|
11
|
+
type: 'confirm',
|
|
12
|
+
default: false,
|
|
13
|
+
},
|
|
14
|
+
]);
|
|
15
|
+
return proceed;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
module.exports = {
|
|
19
|
+
activeInstallConfirmationPrompt,
|
|
20
|
+
};
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
|
-
const {
|
|
3
|
+
const {
|
|
4
|
+
getCwd,
|
|
5
|
+
sanitizeFileName,
|
|
6
|
+
isValidPath,
|
|
7
|
+
} = require('@hubspot/local-dev-lib/path');
|
|
4
8
|
const { PROJECT_COMPONENT_TYPES } = require('../../lib/constants');
|
|
5
9
|
const { promptUser } = require('./promptUtils');
|
|
6
10
|
const { fetchFileFromRepository } = require('@hubspot/local-dev-lib/github');
|
|
@@ -79,7 +83,10 @@ const createProjectPrompt = async (
|
|
|
79
83
|
message: i18n(`${i18nKey}.enterLocation`),
|
|
80
84
|
when: !promptOptions.location,
|
|
81
85
|
default: answers => {
|
|
82
|
-
|
|
86
|
+
const projectName = sanitizeFileName(
|
|
87
|
+
answers.name || promptOptions.name
|
|
88
|
+
);
|
|
89
|
+
return path.resolve(getCwd(), projectName);
|
|
83
90
|
},
|
|
84
91
|
validate: input => {
|
|
85
92
|
if (!input) {
|
|
@@ -88,6 +95,9 @@ const createProjectPrompt = async (
|
|
|
88
95
|
if (fs.existsSync(input)) {
|
|
89
96
|
return i18n(`${i18nKey}.errors.invalidLocation`);
|
|
90
97
|
}
|
|
98
|
+
if (!isValidPath(input)) {
|
|
99
|
+
return i18n(`${i18nKey}.errors.invalidCharacters`);
|
|
100
|
+
}
|
|
91
101
|
return true;
|
|
92
102
|
},
|
|
93
103
|
},
|