@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.
Files changed (43) hide show
  1. package/commands/auth.js +2 -4
  2. package/commands/functions/deploy.js +2 -2
  3. package/commands/init.js +2 -4
  4. package/commands/module/marketplace-validate.js +1 -1
  5. package/commands/project/__tests__/deploy.test.js +432 -0
  6. package/commands/project/cloneApp.js +208 -0
  7. package/commands/project/deploy.js +82 -27
  8. package/commands/project/listBuilds.js +1 -1
  9. package/commands/project/logs.js +1 -1
  10. package/commands/project/migrateApp.js +85 -30
  11. package/commands/project/upload.js +1 -1
  12. package/commands/project.js +15 -12
  13. package/commands/sandbox/create.js +17 -48
  14. package/commands/sandbox/delete.js +5 -2
  15. package/commands/sandbox/sync.js +12 -2
  16. package/commands/sandbox.js +2 -1
  17. package/commands/theme/marketplace-validate.js +1 -1
  18. package/lang/en.lyaml +77 -76
  19. package/lib/LocalDevManager.js +59 -11
  20. package/lib/buildAccount.js +3 -3
  21. package/lib/constants.js +3 -1
  22. package/lib/interpolationHelpers.js +3 -0
  23. package/lib/localDev.js +21 -11
  24. package/lib/marketplace-validate.js +11 -3
  25. package/lib/polling.js +16 -10
  26. package/lib/projects.js +143 -100
  27. package/lib/prompts/accountNamePrompt.js +78 -0
  28. package/lib/prompts/activeInstallConfirmationPrompt.js +20 -0
  29. package/lib/prompts/createProjectPrompt.js +12 -2
  30. package/lib/prompts/deployBuildIdPrompt.js +22 -0
  31. package/lib/prompts/installPublicAppPrompt.js +13 -4
  32. package/lib/prompts/personalAccessKeyPrompt.js +2 -2
  33. package/lib/prompts/sandboxesPrompt.js +12 -41
  34. package/lib/prompts/selectPublicAppPrompt.js +41 -22
  35. package/lib/sandboxSync.js +49 -68
  36. package/lib/sandboxes.js +8 -149
  37. package/lib/serverlessLogs.js +2 -2
  38. package/lib/ui/index.js +74 -0
  39. package/package.json +5 -4
  40. package/lib/prompts/buildIdPrompt.js +0 -35
  41. package/lib/prompts/developerTestAccountNamePrompt.js +0 -29
  42. package/lib/prompts/enterAccountNamePrompt.js +0 -33
  43. package/lib/ui/CliProgressMultibarManager.js +0 -66
@@ -0,0 +1,22 @@
1
+ const { promptUser } = require('./promptUtils');
2
+ const { i18n } = require('../lang');
3
+
4
+ const i18nKey = 'lib.prompts.deployBuildIdPrompt';
5
+
6
+ const deployBuildIdPrompt = (latestBuildId, deployedBuildId, validate) => {
7
+ return promptUser({
8
+ name: 'buildId',
9
+ message: i18n(`${i18nKey}.enterBuildId`),
10
+ default: () => {
11
+ if (latestBuildId === deployedBuildId) {
12
+ return;
13
+ }
14
+ return latestBuildId;
15
+ },
16
+ validate,
17
+ });
18
+ };
19
+
20
+ module.exports = {
21
+ deployBuildIdPrompt,
22
+ };
@@ -12,20 +12,29 @@ const installPublicAppPrompt = async (
12
12
  targetAccountId,
13
13
  clientId,
14
14
  scopes,
15
- redirectUrls
15
+ redirectUrls,
16
+ isReinstall = false
16
17
  ) => {
17
18
  logger.log('');
18
- logger.log(i18n(`${i18nKey}.explanation`));
19
+ if (isReinstall) {
20
+ logger.log(i18n(`${i18nKey}.reinstallExplanation`));
21
+ } else {
22
+ logger.log(i18n(`${i18nKey}.explanation`));
23
+ }
19
24
 
20
25
  const { shouldOpenBrowser } = await promptUser({
21
26
  name: 'shouldOpenBrowser',
22
27
  type: 'confirm',
23
- message: i18n(`${i18nKey}.prompt`),
28
+ message: i18n(
29
+ isReinstall ? `${i18nKey}.reinstallPrompt` : `${i18nKey}.prompt`
30
+ ),
24
31
  });
25
32
 
26
- if (!shouldOpenBrowser) {
33
+ if (!isReinstall && !shouldOpenBrowser) {
27
34
  logger.log(i18n(`${i18nKey}.decline`));
28
35
  process.exit(EXIT_CODES.SUCCESS);
36
+ } else if (!shouldOpenBrowser) {
37
+ return;
29
38
  }
30
39
 
31
40
  const websiteOrigin = getHubSpotWebsiteOrigin(env);
@@ -7,7 +7,7 @@ const { deleteEmptyConfigFile } = require('@hubspot/local-dev-lib/config');
7
7
  const { getHubSpotWebsiteOrigin } = require('@hubspot/local-dev-lib/urls');
8
8
  const { logger } = require('@hubspot/local-dev-lib/logger');
9
9
  const { promptUser } = require('./promptUtils');
10
- const { accountNamePrompt } = require('./enterAccountNamePrompt');
10
+ const { getCliAccountNamePromptConfig } = require('./accountNamePrompt');
11
11
  const { i18n } = require('../lang');
12
12
  const { uiInfoSection } = require('../ui');
13
13
  const { EXIT_CODES } = require('../enums/exitCodes');
@@ -124,7 +124,7 @@ const SCOPES = {
124
124
  };
125
125
 
126
126
  const OAUTH_FLOW = [
127
- accountNamePrompt(),
127
+ getCliAccountNamePromptConfig(),
128
128
  ACCOUNT_ID,
129
129
  CLIENT_ID,
130
130
  CLIENT_SECRET,
@@ -1,6 +1,5 @@
1
1
  const { promptUser } = require('./promptUtils');
2
2
  const { i18n } = require('../lang');
3
- const { accountNameExistsInConfig } = require('@hubspot/local-dev-lib/config');
4
3
  const { uiAccountDescription } = require('../ui');
5
4
  const {
6
5
  HUBSPOT_ACCOUNT_TYPES,
@@ -29,42 +28,6 @@ const mapNonSandboxAccountChoices = portals =>
29
28
  };
30
29
  });
31
30
 
32
- const sandboxNamePrompt = (type = HUBSPOT_ACCOUNT_TYPES.STANDARD_SANDBOX) => {
33
- const isDevelopmentSandbox =
34
- type === HUBSPOT_ACCOUNT_TYPES.DEVELOPMENT_SANDBOX;
35
- const namePromptMessage = isDevelopmentSandbox
36
- ? `${i18nKey}.name.developmentSandboxMessage`
37
- : `${i18nKey}.name.message`;
38
- return promptUser([
39
- {
40
- name: 'name',
41
- message: i18n(namePromptMessage),
42
- validate(val) {
43
- if (typeof val !== 'string') {
44
- return i18n(`${i18nKey}.name.errors.invalidName`);
45
- } else if (!val.length) {
46
- return i18n(`${i18nKey}.name.errors.nameRequired`);
47
- }
48
- return accountNameExistsInConfig(val)
49
- ? i18n(`${i18nKey}.name.errors.accountNameExists`, { name: val })
50
- : true;
51
- },
52
- default: `New ${isDevelopmentSandbox ? 'development ' : ''}sandbox`,
53
- },
54
- ]);
55
- };
56
-
57
- const sandboxTypeChoices = [
58
- {
59
- name: i18n(`${i18nKey}.type.developer`),
60
- value: HUBSPOT_ACCOUNT_TYPES.DEVELOPMENT_SANDBOX,
61
- },
62
- {
63
- name: i18n(`${i18nKey}.type.standard`),
64
- value: HUBSPOT_ACCOUNT_TYPES.STANDARD_SANDBOX,
65
- },
66
- ];
67
-
68
31
  const sandboxTypePrompt = () => {
69
32
  return promptUser([
70
33
  {
@@ -72,7 +35,16 @@ const sandboxTypePrompt = () => {
72
35
  message: i18n(`${i18nKey}.type.message`),
73
36
  type: 'list',
74
37
  look: false,
75
- choices: sandboxTypeChoices,
38
+ choices: [
39
+ {
40
+ name: i18n(`${i18nKey}.type.developer`),
41
+ value: HUBSPOT_ACCOUNT_TYPES.DEVELOPMENT_SANDBOX,
42
+ },
43
+ {
44
+ name: i18n(`${i18nKey}.type.standard`),
45
+ value: HUBSPOT_ACCOUNT_TYPES.STANDARD_SANDBOX,
46
+ },
47
+ ],
76
48
  default: HUBSPOT_ACCOUNT_TYPES.DEVELOPMENT_SANDBOX,
77
49
  },
78
50
  ]);
@@ -90,8 +62,8 @@ const deleteSandboxPrompt = (config, promptParentAccount = false) => {
90
62
  name: 'account',
91
63
  message: i18n(
92
64
  promptParentAccount
93
- ? `${i18nKey}.name.selectParentAccountName`
94
- : `${i18nKey}.name.selectAccountName`
65
+ ? `${i18nKey}.selectParentAccountName`
66
+ : `${i18nKey}.selectAccountName`
95
67
  ),
96
68
  type: 'list',
97
69
  look: false,
@@ -103,7 +75,6 @@ const deleteSandboxPrompt = (config, promptParentAccount = false) => {
103
75
  };
104
76
 
105
77
  module.exports = {
106
- sandboxNamePrompt,
107
78
  sandboxTypePrompt,
108
79
  deleteSandboxPrompt,
109
80
  };
@@ -10,17 +10,35 @@ const { EXIT_CODES } = require('../../lib/enums/exitCodes');
10
10
 
11
11
  const i18nKey = 'lib.prompts.selectPublicAppPrompt';
12
12
 
13
- const fetchPublicAppOptions = async (accountId, accountName) => {
13
+ const fetchPublicAppOptions = async (
14
+ accountId,
15
+ accountName,
16
+ isMigratingApp = false
17
+ ) => {
14
18
  try {
15
19
  const publicApps = await fetchPublicAppsForPortal(accountId);
16
20
  const filteredPublicApps = publicApps.filter(
17
21
  app => !app.projectId && !app.sourceId
18
22
  );
19
23
 
20
- if (!filteredPublicApps.length) {
24
+ if (
25
+ !filteredPublicApps.length ||
26
+ (isMigratingApp &&
27
+ !filteredPublicApps.some(
28
+ app => !app.preventProjectMigrations || !app.listingInfo
29
+ ))
30
+ ) {
31
+ const headerTranslationKey = isMigratingApp
32
+ ? 'noAppsMigration'
33
+ : 'noAppsClone';
34
+ const messageTranslationKey = isMigratingApp
35
+ ? 'noAppsMigrationMessage'
36
+ : 'noAppsCloneMessage';
21
37
  uiLine();
22
- logger.error(i18n(`${i18nKey}.errors.noApps`));
23
- logger.log(i18n(`${i18nKey}.errors.noAppsMessage`, { accountName }));
38
+ logger.error(i18n(`${i18nKey}.errors.${headerTranslationKey}`));
39
+ logger.log(
40
+ i18n(`${i18nKey}.errors.${messageTranslationKey}`, { accountName })
41
+ );
24
42
  uiLine();
25
43
  process.exit(EXIT_CODES.SUCCESS);
26
44
  }
@@ -35,30 +53,32 @@ const fetchPublicAppOptions = async (accountId, accountName) => {
35
53
  const selectPublicAppPrompt = async ({
36
54
  accountId,
37
55
  accountName,
38
- promptOptions = {},
39
- migrateApp = false,
56
+ isMigratingApp = false,
40
57
  }) => {
41
- const publicApps = await fetchPublicAppOptions(accountId, accountName);
42
- const translationKey = migrateApp ? 'selectAppIdMigrate' : 'selectAppIdClone';
58
+ const publicApps = await fetchPublicAppOptions(
59
+ accountId,
60
+ accountName,
61
+ isMigratingApp
62
+ );
63
+ const translationKey = isMigratingApp
64
+ ? 'selectAppIdMigrate'
65
+ : 'selectAppIdClone';
43
66
 
44
67
  return promptUser([
45
68
  {
46
69
  name: 'appId',
47
- message: () => {
48
- return promptOptions.appId &&
49
- !publicApps.find(a => a.id === promptOptions.appId)
50
- ? i18n(`${i18nKey}.errors.invalidAppId`, {
51
- appId: promptOptions.appId,
52
- })
53
- : i18n(`${i18nKey}.${translationKey}`, {
54
- accountName,
55
- });
56
- },
57
- when:
58
- !promptOptions.appId ||
59
- !publicApps.find(a => a.id === promptOptions.appId),
70
+ message: i18n(`${i18nKey}.${translationKey}`, {
71
+ accountName,
72
+ }),
60
73
  type: 'list',
61
74
  choices: publicApps.map(app => {
75
+ const { preventProjectMigrations, listingInfo } = app;
76
+ if (isMigratingApp && preventProjectMigrations && listingInfo) {
77
+ return {
78
+ name: `${app.name} (${app.id})`,
79
+ disabled: i18n(`${i18nKey}.errors.cannotBeMigrated`),
80
+ };
81
+ }
62
82
  return {
63
83
  name: `${app.name} (${app.id})`,
64
84
  value: app.id,
@@ -69,6 +89,5 @@ const selectPublicAppPrompt = async ({
69
89
  };
70
90
 
71
91
  module.exports = {
72
- fetchPublicAppOptions,
73
92
  selectPublicAppPrompt,
74
93
  };
@@ -2,12 +2,7 @@ const SpinniesManager = require('./ui/SpinniesManager');
2
2
  const { getHubSpotWebsiteOrigin } = require('@hubspot/local-dev-lib/urls');
3
3
  const { logger } = require('@hubspot/local-dev-lib/logger');
4
4
  const { i18n } = require('./lang');
5
- const { isDevelopmentSandbox } = require('./accountTypes');
6
- const {
7
- getAvailableSyncTypes,
8
- pollSyncTaskStatus,
9
- syncTypes,
10
- } = require('./sandboxes');
5
+ const { getAvailableSyncTypes } = require('./sandboxes');
11
6
  const { initiateSync } = require('@hubspot/local-dev-lib/sandboxes');
12
7
  const {
13
8
  debugErrorAndContext,
@@ -19,7 +14,13 @@ const {
19
14
  } = require('@hubspot/local-dev-lib/errors/apiErrors');
20
15
  const { getSandboxTypeAsString } = require('./sandboxes');
21
16
  const { getAccountId } = require('@hubspot/local-dev-lib/config');
22
- const { uiAccountDescription } = require('./ui');
17
+ const {
18
+ uiAccountDescription,
19
+ uiLine,
20
+ uiLink,
21
+ uiCommandDisabledBanner,
22
+ } = require('./ui');
23
+ const { isDevelopmentSandbox } = require('./accountTypes');
23
24
 
24
25
  const i18nKey = 'lib.sandbox.sync';
25
26
 
@@ -28,8 +29,6 @@ const i18nKey = 'lib.sandbox.sync';
28
29
  * @param {Object} parentAccountConfig - Account config of parent portal
29
30
  * @param {String} env - Environment (QA/Prod)
30
31
  * @param {Array} syncTasks - Array of available sync tasks
31
- * @param {Boolean} allowEarlyTermination - Option to allow a keypress to terminate early
32
- * @param {Boolean} skipPolling - Option to skip progress bars for polling and let sync run in background
33
32
  * @returns
34
33
  */
35
34
  const syncSandbox = async ({
@@ -37,15 +36,14 @@ const syncSandbox = async ({
37
36
  parentAccountConfig,
38
37
  env,
39
38
  syncTasks,
40
- allowEarlyTermination = true,
41
- skipPolling = false,
39
+ slimInfoMessage = false,
42
40
  }) => {
43
41
  const accountId = getAccountId(accountConfig.portalId);
44
42
  const parentAccountId = getAccountId(parentAccountConfig.portalId);
43
+ const isDevSandbox = isDevelopmentSandbox(accountConfig);
45
44
  SpinniesManager.init({
46
45
  succeedColor: 'white',
47
46
  });
48
- let initiateSyncResponse;
49
47
  let availableSyncTasks = syncTasks;
50
48
 
51
49
  const baseUrl = getHubSpotWebsiteOrigin(env);
@@ -70,29 +68,27 @@ const syncSandbox = async ({
70
68
  text: i18n(`${i18nKey}.loading.startSync`),
71
69
  });
72
70
 
73
- initiateSyncResponse = await initiateSync(
71
+ await initiateSync(
74
72
  parentAccountId,
75
73
  accountId,
76
74
  availableSyncTasks,
77
75
  accountId
78
76
  );
79
-
80
- if (allowEarlyTermination) {
81
- logger.log(i18n(`${i18nKey}.info.earlyExit`));
82
- }
77
+ let spinniesText = isDevSandbox
78
+ ? `${i18nKey}.loading.succeedDevSb`
79
+ : `${i18nKey}.loading.succeed`;
83
80
  SpinniesManager.succeed('sandboxSync', {
84
- text: i18n(`${i18nKey}.loading.succeed`, {
85
- accountName: uiAccountDescription(accountId),
86
- }),
81
+ text: i18n(
82
+ slimInfoMessage ? `${i18nKey}.loading.successDevSbInfo` : spinniesText,
83
+ {
84
+ accountName: uiAccountDescription(accountId),
85
+ url: uiLink(
86
+ i18n(`${i18nKey}.info.syncStatusDetailsLinkText`),
87
+ syncStatusUrl
88
+ ),
89
+ }
90
+ ),
87
91
  });
88
- if (skipPolling && isDevelopmentSandbox(accountConfig)) {
89
- if (syncTasks.some(t => t.type === syncTypes.OBJECT_RECORDS)) {
90
- logger.log(i18n(`${i18nKey}.loading.skipPollingWithContacts`));
91
- } else {
92
- logger.log(i18n(`${i18nKey}.loading.skipPolling`));
93
- }
94
- logger.log('');
95
- }
96
92
  } catch (err) {
97
93
  debugErrorAndContext(err);
98
94
 
@@ -157,6 +153,15 @@ const syncSandbox = async ({
157
153
  account: uiAccountDescription(accountId),
158
154
  })
159
155
  );
156
+ } else if (
157
+ isSpecifiedError(err, {
158
+ statusCode: 404,
159
+ })
160
+ ) {
161
+ uiCommandDisabledBanner(
162
+ 'hs sandbox sync',
163
+ 'https://app.hubspot.com/l/docs/guides/crm/project-cli-commands#developer-projects-cli-commands-beta'
164
+ );
160
165
  } else {
161
166
  logErrorInstance(err);
162
167
  }
@@ -164,46 +169,22 @@ const syncSandbox = async ({
164
169
  throw err;
165
170
  }
166
171
 
167
- if (!skipPolling) {
168
- try {
169
- logger.log('');
170
- logger.log('Sync progress:');
171
- // Poll sync task status to show progress bars
172
- await pollSyncTaskStatus(
173
- parentAccountId,
174
- initiateSyncResponse.id,
175
- syncStatusUrl,
176
- allowEarlyTermination
177
- );
178
-
179
- logger.log('');
180
- SpinniesManager.add('syncComplete', {
181
- text: i18n(`${i18nKey}.polling.syncing`),
182
- });
183
- SpinniesManager.succeed('syncComplete', {
184
- text: i18n(`${i18nKey}.polling.succeed`),
185
- });
186
- logger.log('');
187
- logger.log(
188
- i18n(`${i18nKey}.info.syncStatus`, {
189
- url: syncStatusUrl,
190
- })
191
- );
192
- } catch (err) {
193
- // If polling fails at this point, we do not track a failed sync since it is running in the background.
194
- logErrorInstance(err);
195
-
196
- SpinniesManager.add('syncComplete', {
197
- text: i18n(`${i18nKey}.polling.syncing`),
198
- });
199
- SpinniesManager.fail('syncComplete', {
200
- text: i18n(`${i18nKey}.polling.fail`, {
201
- url: syncStatusUrl,
202
- }),
203
- });
204
-
205
- throw err;
206
- }
172
+ if (!slimInfoMessage) {
173
+ logger.log();
174
+ uiLine();
175
+ logger.info(
176
+ i18n(
177
+ `${i18nKey}.info.${isDevSandbox ? 'syncMessageDevSb' : 'syncMessage'}`,
178
+ {
179
+ url: uiLink(
180
+ i18n(`${i18nKey}.info.syncStatusDetailsLinkText`),
181
+ syncStatusUrl
182
+ ),
183
+ }
184
+ )
185
+ );
186
+ uiLine();
187
+ logger.log();
207
188
  }
208
189
  };
209
190
 
package/lib/sandboxes.js CHANGED
@@ -1,9 +1,6 @@
1
- const { i18n, MISSING_LANGUAGE_DATA_PREFIX } = require('./lang');
2
- const { handleExit, handleKeypress } = require('./process');
1
+ const { i18n } = require('./lang');
3
2
  const { logger } = require('@hubspot/local-dev-lib/logger');
4
- const { EXIT_CODES } = require('./enums/exitCodes');
5
3
  const {
6
- fetchTaskStatus,
7
4
  fetchTypes,
8
5
  getSandboxUsageLimits,
9
6
  } = require('@hubspot/local-dev-lib/sandboxes');
@@ -12,7 +9,6 @@ const {
12
9
  getAccountId,
13
10
  getEnv,
14
11
  } = require('@hubspot/local-dev-lib/config');
15
- const CliProgressMultibarManager = require('./ui/CliProgressMultibarManager');
16
12
  const { promptUser } = require('./prompts/promptUtils');
17
13
  const { isDevelopmentSandbox } = require('./accountTypes');
18
14
  const { getHubSpotWebsiteOrigin } = require('@hubspot/local-dev-lib/urls');
@@ -97,21 +93,22 @@ const getSyncTypesWithContactRecordsPrompt = async (
97
93
  syncTasks,
98
94
  skipPrompt = false
99
95
  ) => {
100
- // Fetches sync types based on default account. Parent account required for fetch
101
-
96
+ // TODO: remove this entire helper once hs sandbox sync is fully deprecated
97
+ const isDevSandbox = isDevelopmentSandbox(accountConfig);
98
+ if (isDevSandbox) {
99
+ // Disable dev sandbox from syncing contacts
100
+ return syncTasks.filter(t => t.type !== syncTypes.OBJECT_RECORDS);
101
+ }
102
102
  if (
103
103
  syncTasks &&
104
104
  syncTasks.some(t => t.type === syncTypes.OBJECT_RECORDS) &&
105
105
  !skipPrompt
106
106
  ) {
107
- const langKey = isDevelopmentSandbox(accountConfig)
108
- ? 'developer'
109
- : 'standard';
110
107
  const { contactRecordsSyncPrompt } = await promptUser([
111
108
  {
112
109
  name: 'contactRecordsSyncPrompt',
113
110
  type: 'confirm',
114
- message: i18n(`lib.sandbox.sync.confirm.syncContactRecords.${langKey}`),
111
+ message: i18n('lib.sandbox.sync.confirm.syncContactRecords.standard'),
115
112
  },
116
113
  ]);
117
114
  if (!contactRecordsSyncPrompt) {
@@ -356,143 +353,6 @@ function handleSandboxCreateError({
356
353
  throw err;
357
354
  }
358
355
 
359
- const ACTIVE_TASK_POLL_INTERVAL = 1000;
360
-
361
- const isTaskComplete = task => {
362
- if (!task) {
363
- return false;
364
- }
365
- return task.status === 'COMPLETE';
366
- };
367
-
368
- const incrementBy = (value, multiplier = 3) => {
369
- return Math.min(value + Math.floor(Math.random() * multiplier), 99);
370
- };
371
-
372
- /**
373
- * @param {Number} accountId - Parent portal ID (needs sandbox scopes)
374
- * @param {String} taksId - Task ID to poll
375
- * @param {String} syncStatusUrl - Link to UI to check polling status
376
- * @param {Boolean} allowEarlyTermination - Option to allow a keypress to terminate early
377
- * @returns {Promise} Interval runs until sync task status is equal to 'COMPLETE'
378
- */
379
- function pollSyncTaskStatus(
380
- accountId,
381
- taskId,
382
- syncStatusUrl,
383
- allowEarlyTermination = true
384
- ) {
385
- const i18nKey = 'lib.sandbox.sync.types';
386
- const progressBar = CliProgressMultibarManager.init();
387
- const mergeTasks = {
388
- 'lead-flows': 'forms', // lead-flows are a subset of forms. We combine these in the UI as a single item, so we want to merge here for consistency.
389
- };
390
- let progressCounter = {};
391
- let pollInterval;
392
- // Handle manual exit for return key and ctrl+c
393
- const onTerminate = () => {
394
- clearInterval(pollInterval);
395
- progressBar.stop();
396
- logger.log('');
397
- logger.log('Exiting, sync will continue in the background.');
398
- logger.log('');
399
- logger.log(
400
- i18n('lib.sandbox.sync.info.syncStatus', {
401
- url: syncStatusUrl,
402
- })
403
- );
404
- process.exit(EXIT_CODES.SUCCESS);
405
- };
406
- if (allowEarlyTermination) {
407
- handleExit(onTerminate);
408
- handleKeypress(key => {
409
- if (
410
- (key && key.ctrl && key.name == 'c') ||
411
- key.name === 'enter' ||
412
- key.name === 'return'
413
- ) {
414
- onTerminate();
415
- }
416
- });
417
- }
418
- return new Promise((resolve, reject) => {
419
- pollInterval = setInterval(async () => {
420
- const taskResult = await fetchTaskStatus(accountId, taskId).catch(reject);
421
- if (taskResult.tasks) {
422
- // Array of sync tasks, eg: workflows, pipelines, object-schemas, etc. with each task containing a status of 'PENDING', 'IN_PROGRESS', 'COMPLETE', and 'FAILURE'
423
- for (const task of taskResult.tasks) {
424
- // For each sync task, show a progress bar and increment bar each time we run this interval until status is 'COMPLETE'
425
- let taskType = task.type;
426
- const taskTypeLabel = i18n(`${i18nKey}.${taskType}.label`);
427
- if (taskTypeLabel.startsWith(MISSING_LANGUAGE_DATA_PREFIX)) {
428
- continue;
429
- }
430
- if (!progressBar.get(taskType) && !mergeTasks[taskType]) {
431
- // skip creation of lead-flows bar because we're combining lead-flows into the forms bar, otherwise create a bar instance for the type
432
- progressCounter[taskType] = 0;
433
- progressBar.create(taskType, 100, 0, {
434
- label: taskTypeLabel,
435
- });
436
- } else if (mergeTasks[taskType]) {
437
- // It's a lead-flow here, merge status into the forms progress bar
438
- if (!progressCounter[mergeTasks[taskType]]) {
439
- progressCounter[mergeTasks[taskType]] = 0;
440
- }
441
- const formsTask = taskResult.tasks.filter(
442
- t => t.type === mergeTasks[taskType]
443
- )[0];
444
- const formsTaskStatus = formsTask.status;
445
- const leadFlowsTaskStatus = task.status;
446
- if (
447
- formsTaskStatus !== 'COMPLETE' ||
448
- leadFlowsTaskStatus !== 'COMPLETE'
449
- ) {
450
- // Randomly increment bar while sync is in progress. Sandboxes currently does not have an accurate measurement for progress.
451
- progressCounter[mergeTasks[taskType]] = incrementBy(
452
- progressCounter[mergeTasks[taskType]]
453
- );
454
- progressBar.update(
455
- mergeTasks[taskType],
456
- progressCounter[mergeTasks[taskType]],
457
- {
458
- label: i18n(`${i18nKey}.${mergeTasks[taskType]}.label`),
459
- }
460
- );
461
- }
462
- }
463
- if (progressBar.get(taskType) && task.status === 'COMPLETE') {
464
- progressBar.update(taskType, 100, {
465
- label: taskTypeLabel,
466
- });
467
- } else if (
468
- // Do not start incrementing for tasks still in PENDING state
469
- progressBar.get(taskType) &&
470
- task.status === 'PROCESSING'
471
- ) {
472
- // Randomly increment bar while sync is in progress. Sandboxes currently does not have an accurate measurement for progress.
473
- progressCounter[taskType] = incrementBy(
474
- progressCounter[taskType],
475
- taskType === syncTypes.OBJECT_RECORDS ? 2 : 3 // slower progress for object-records, sync can take up to a few minutes
476
- );
477
- progressBar.update(taskType, progressCounter[taskType], {
478
- label: taskTypeLabel,
479
- });
480
- }
481
- }
482
- } else {
483
- clearInterval(pollInterval);
484
- reject();
485
- progressBar.stop();
486
- }
487
- if (isTaskComplete(taskResult)) {
488
- clearInterval(pollInterval);
489
- resolve(taskResult);
490
- progressBar.stop();
491
- }
492
- }, ACTIVE_TASK_POLL_INTERVAL);
493
- });
494
- }
495
-
496
356
  module.exports = {
497
357
  sandboxTypeMap,
498
358
  sandboxApiTypeMap,
@@ -503,6 +363,5 @@ module.exports = {
503
363
  validateSandboxUsageLimits,
504
364
  getAvailableSyncTypes,
505
365
  getSyncTypesWithContactRecordsPrompt,
506
- pollSyncTaskStatus,
507
366
  handleSandboxCreateError,
508
367
  };
@@ -52,7 +52,7 @@ const tailLogs = async ({
52
52
  initialAfter = latestLog && base64EncodeString(latestLog.id);
53
53
  } catch (e) {
54
54
  // A 404 means no latest log exists(never executed)
55
- if (e.statusCode !== 404) {
55
+ if (e.response && e.response.status !== 404) {
56
56
  await logServerlessFunctionApiErrorInstance(
57
57
  accountId,
58
58
  e,
@@ -68,7 +68,7 @@ const tailLogs = async ({
68
68
  latestLog = await tailCall(after);
69
69
  nextAfter = latestLog.paging.next.after;
70
70
  } catch (e) {
71
- if (e.statusCode !== 404) {
71
+ if (e.response && e.response.status !== 404) {
72
72
  logApiErrorInstance(
73
73
  e,
74
74
  new ApiErrorContext({