@hubspot/cli 5.2.1-beta.1 → 5.2.1-beta.11

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 (146) hide show
  1. package/bin/cli.js +1 -1
  2. package/bin/hs +1 -1
  3. package/commands/accounts/clean.js +7 -7
  4. package/commands/accounts/info.js +3 -3
  5. package/commands/accounts/list.js +7 -18
  6. package/commands/accounts/remove.js +1 -1
  7. package/commands/accounts/rename.js +3 -3
  8. package/commands/accounts/use.js +1 -1
  9. package/commands/accounts.js +3 -3
  10. package/commands/auth.js +7 -9
  11. package/commands/cms/convertFields.js +1 -1
  12. package/commands/cms/lighthouseScore.js +4 -4
  13. package/commands/cms/reactModules.js +1 -1
  14. package/commands/cms.js +3 -3
  15. package/commands/config/set/allowUsageTracking.js +1 -2
  16. package/commands/config/set/defaultMode.js +1 -1
  17. package/commands/config/set/httpTimeout.js +1 -1
  18. package/commands/config/set.js +1 -1
  19. package/commands/config.js +3 -3
  20. package/commands/create/api-sample.js +1 -1
  21. package/commands/create/module.js +1 -1
  22. package/commands/create/template.js +1 -1
  23. package/commands/create.js +1 -1
  24. package/commands/customObject/create.js +1 -1
  25. package/commands/customObject/schema/create.js +2 -3
  26. package/commands/customObject/schema/delete.js +1 -2
  27. package/commands/customObject/schema/fetch-all.js +1 -2
  28. package/commands/customObject/schema/fetch.js +1 -2
  29. package/commands/customObject/schema/list.js +1 -1
  30. package/commands/customObject/schema/update.js +2 -3
  31. package/commands/customObject/schema.js +1 -1
  32. package/commands/customObject.js +3 -3
  33. package/commands/feedback.js +4 -6
  34. package/commands/fetch.js +6 -6
  35. package/commands/filemanager/fetch.js +4 -4
  36. package/commands/filemanager/upload.js +4 -4
  37. package/commands/filemanager.js +4 -4
  38. package/commands/functions/deploy.js +9 -25
  39. package/commands/functions/list.js +4 -4
  40. package/commands/functions/server.js +4 -4
  41. package/commands/functions.js +3 -3
  42. package/commands/hubdb/clear.js +4 -4
  43. package/commands/hubdb/create.js +4 -4
  44. package/commands/hubdb/delete.js +4 -4
  45. package/commands/hubdb/fetch.js +4 -4
  46. package/commands/hubdb.js +3 -3
  47. package/commands/init.js +6 -8
  48. package/commands/lint.js +3 -3
  49. package/commands/list.js +4 -4
  50. package/commands/logs.js +4 -4
  51. package/commands/module/marketplace-validate.js +5 -5
  52. package/commands/module.js +3 -3
  53. package/commands/mv.js +4 -4
  54. package/commands/open.js +4 -4
  55. package/commands/project/__tests__/deploy.test.js +431 -0
  56. package/commands/project/add.js +1 -1
  57. package/commands/project/cloneApp.js +161 -0
  58. package/commands/project/create.js +4 -4
  59. package/commands/project/deploy.js +79 -25
  60. package/commands/project/dev.js +70 -27
  61. package/commands/project/download.js +11 -7
  62. package/commands/project/listBuilds.js +5 -5
  63. package/commands/project/logs.js +5 -5
  64. package/commands/project/migrateApp.js +244 -0
  65. package/commands/project/open.js +12 -8
  66. package/commands/project/upload.js +13 -8
  67. package/commands/project/watch.js +4 -4
  68. package/commands/project.js +7 -3
  69. package/commands/remove.js +4 -4
  70. package/commands/sandbox/create.js +22 -18
  71. package/commands/sandbox/delete.js +10 -7
  72. package/commands/sandbox/sync.js +8 -8
  73. package/commands/sandbox.js +5 -4
  74. package/commands/secrets/addSecret.js +4 -4
  75. package/commands/secrets/deleteSecret.js +4 -4
  76. package/commands/secrets/listSecrets.js +4 -4
  77. package/commands/secrets/updateSecret.js +4 -4
  78. package/commands/secrets.js +3 -3
  79. package/commands/theme/generate-selectors.js +1 -1
  80. package/commands/theme/marketplace-validate.js +5 -5
  81. package/commands/theme/preview.js +52 -17
  82. package/commands/theme.js +1 -1
  83. package/commands/upload.js +5 -5
  84. package/commands/watch.js +61 -18
  85. package/jest.config.js +1 -0
  86. package/lang/en.lyaml +1450 -1371
  87. package/lib/DevServerManager.js +3 -2
  88. package/lib/LocalDevManager.js +169 -7
  89. package/lib/__tests__/{commonOpts.js → commonOpts.test.js} +3 -0
  90. package/lib/__tests__/downloadProjectPrompt.test.js +31 -0
  91. package/lib/__tests__/projects.test.js +13 -17
  92. package/lib/__tests__/{serverlessLogs.js → serverlessLogs.test.js} +1 -0
  93. package/lib/buildAccount.js +197 -0
  94. package/lib/commonOpts.js +1 -1
  95. package/lib/constants.js +12 -1
  96. package/lib/developerTestAccounts.js +52 -4
  97. package/lib/errorHandlers/apiErrors.js +1 -1
  98. package/lib/errorHandlers/overrideErrors.js +1 -1
  99. package/lib/errorHandlers/standardErrors.js +1 -1
  100. package/lib/generate-selectors.js +1 -1
  101. package/lib/localDev.js +102 -52
  102. package/lib/marketplace-validate.js +11 -3
  103. package/lib/polling.js +31 -0
  104. package/lib/process.js +1 -1
  105. package/lib/projectStructure.js +5 -2
  106. package/lib/projects.js +68 -15
  107. package/lib/projectsWatch.js +1 -1
  108. package/lib/prompts/accountNamePrompt.js +81 -0
  109. package/lib/prompts/accountsPrompt.js +1 -1
  110. package/lib/prompts/activeInstallConfirmationPrompt.js +20 -0
  111. package/lib/prompts/buildIdPrompt.js +8 -17
  112. package/lib/prompts/cleanUploadPrompt.js +1 -1
  113. package/lib/prompts/cloneAppLocationPrompt.js +32 -0
  114. package/lib/prompts/cmsFieldPrompt.js +1 -1
  115. package/lib/prompts/createApiSamplePrompt.js +1 -1
  116. package/lib/prompts/createFunctionPrompt.js +1 -1
  117. package/lib/prompts/createModulePrompt.js +1 -1
  118. package/lib/prompts/createProjectPrompt.js +32 -10
  119. package/lib/prompts/createTemplatePrompt.js +1 -1
  120. package/lib/prompts/downloadProjectPrompt.js +5 -6
  121. package/lib/prompts/feedbackPrompt.js +1 -1
  122. package/lib/prompts/folderOverwritePrompt.js +1 -1
  123. package/lib/prompts/installPublicAppPrompt.js +51 -0
  124. package/lib/prompts/personalAccessKeyPrompt.js +3 -3
  125. package/lib/prompts/previewPrompt.js +19 -1
  126. package/lib/prompts/projectAddPrompt.js +1 -1
  127. package/lib/prompts/projectDevTargetAccountPrompt.js +48 -6
  128. package/lib/prompts/projectNamePrompt.js +2 -2
  129. package/lib/prompts/projectsLogsPrompt.js +1 -1
  130. package/lib/prompts/sandboxesPrompt.js +13 -42
  131. package/lib/prompts/secretPrompt.js +1 -1
  132. package/lib/prompts/selectPublicAppPrompt.js +84 -0
  133. package/lib/prompts/setAsDefaultAccountPrompt.js +1 -1
  134. package/lib/prompts/uploadPrompt.js +1 -1
  135. package/lib/sandboxSync.js +1 -1
  136. package/lib/sandboxes.js +167 -14
  137. package/lib/serverlessLogs.js +2 -2
  138. package/lib/ui/git.js +1 -1
  139. package/lib/ui/index.js +5 -22
  140. package/lib/ui/serverlessFunctionLogs.js +1 -1
  141. package/package.json +7 -6
  142. package/lib/developerTestAccountCreate.js +0 -186
  143. package/lib/prompts/developerTestAccountNamePrompt.js +0 -29
  144. package/lib/prompts/enterAccountNamePrompt.js +0 -33
  145. package/lib/sandboxCreate.js +0 -319
  146. /package/lib/__tests__/{validation.js → validation.test.js} +0 -0
package/lib/constants.js CHANGED
@@ -22,6 +22,13 @@ const CONFIG_FLAGS = {
22
22
 
23
23
  const POLLING_DELAY = 2000;
24
24
 
25
+ const POLLING_STATUS = {
26
+ SUCCESS: 'SUCCESS',
27
+ ERROR: 'ERROR',
28
+ REVERTED: 'REVERTED',
29
+ FAILURE: 'FAILURE',
30
+ };
31
+
25
32
  const PROJECT_CONFIG_FILE = 'hsproject.json';
26
33
  const PROJECT_BUILD_STATES = {
27
34
  BUILDING: 'BUILDING',
@@ -54,11 +61,14 @@ const PROJECT_ERROR_TYPES = {
54
61
  PROJECT_LOCKED: 'BuildPipelineErrorType.PROJECT_LOCKED',
55
62
  MISSING_PROJECT_PROVISION: 'BuildPipelineErrorType.MISSING_PROJECT_PROVISION',
56
63
  BUILD_NOT_IN_PROGRESS: 'BuildPipelineErrorType.BUILD_NOT_IN_PROGRESS',
64
+ SUBBUILD_FAILED: 'BuildPipelineErrorType.DEPENDENT_SUBBUILD_FAILED',
65
+ SUBDEPLOY_FAILED: 'DeployPipelineErrorType.DEPENDENT_SUBDEPLOY_FAILED',
57
66
  };
58
67
  const PROJECT_TASK_TYPES = {
59
68
  PRIVATE_APP: 'private app',
69
+ PUBLIC_APP: 'public app',
60
70
  APP_FUNCTION: 'function',
61
- CRM_CARD_V2: 'crm card',
71
+ CRM_CARD_V2: 'card',
62
72
  };
63
73
  const PROJECT_COMPONENT_TYPES = {
64
74
  PROJECTS: 'projects',
@@ -82,6 +92,7 @@ module.exports = {
82
92
  MARKETPLACE_FOLDER,
83
93
  CONFIG_FLAGS,
84
94
  POLLING_DELAY,
95
+ POLLING_STATUS,
85
96
  PROJECT_CONFIG_FILE,
86
97
  PROJECT_BUILD_TEXT,
87
98
  PROJECT_DEPLOY_TEXT,
@@ -6,6 +6,14 @@ const { i18n } = require('./lang');
6
6
  const {
7
7
  fetchDeveloperTestAccounts,
8
8
  } = require('@hubspot/local-dev-lib/developerTestAccounts');
9
+ const {
10
+ isMissingScopeError,
11
+ isSpecifiedError,
12
+ } = require('@hubspot/local-dev-lib/errors/apiErrors');
13
+ const { logger } = require('@hubspot/local-dev-lib/logger');
14
+ const { uiAccountDescription } = require('./ui');
15
+ const { getHubSpotWebsiteOrigin } = require('@hubspot/local-dev-lib/urls');
16
+ const { logErrorInstance } = require('./errorHandlers/standardErrors');
9
17
 
10
18
  const getHasDevTestAccounts = appDeveloperAccountConfig => {
11
19
  const config = getConfig();
@@ -22,8 +30,6 @@ const getHasDevTestAccounts = appDeveloperAccountConfig => {
22
30
  return false;
23
31
  };
24
32
 
25
- const i18nKey = 'cli.lib.developerTestAccount';
26
-
27
33
  const validateDevTestAccountUsageLimits = async accountConfig => {
28
34
  const accountId = getAccountId(accountConfig.portalId);
29
35
  const response = await fetchDeveloperTestAccounts(accountId);
@@ -34,14 +40,14 @@ const validateDevTestAccountUsageLimits = async accountConfig => {
34
40
  const hasDevTestAccounts = getHasDevTestAccounts(accountConfig);
35
41
  if (hasDevTestAccounts) {
36
42
  throw new Error(
37
- i18n(`${i18nKey}.create.failure.alreadyInConfig`, {
43
+ i18n('lib.developerTestAccount.create.failure.alreadyInConfig', {
38
44
  accountName: accountConfig.name || accountId,
39
45
  limit,
40
46
  })
41
47
  );
42
48
  } else {
43
49
  throw new Error(
44
- i18n(`${i18nKey}.create.failure.limit`, {
50
+ i18n('lib.developerTestAccount.create.failure.limit', {
45
51
  accountName: accountConfig.name || accountId,
46
52
  limit,
47
53
  })
@@ -52,6 +58,48 @@ const validateDevTestAccountUsageLimits = async accountConfig => {
52
58
  }
53
59
  return null;
54
60
  };
61
+
62
+ function handleDeveloperTestAccountCreateError({
63
+ err,
64
+ accountId,
65
+ env,
66
+ portalLimit,
67
+ }) {
68
+ if (isMissingScopeError(err)) {
69
+ logger.error(
70
+ i18n('lib.developerTestAccount.create.failure.scopes.message', {
71
+ accountName: uiAccountDescription(accountId),
72
+ })
73
+ );
74
+ const websiteOrigin = getHubSpotWebsiteOrigin(env);
75
+ const url = `${websiteOrigin}/personal-access-key/${accountId}`;
76
+ logger.info(
77
+ i18n('lib.developerTestAccount.create.failure.scopes.instructions', {
78
+ accountName: uiAccountDescription(accountId),
79
+ url,
80
+ })
81
+ );
82
+ } else if (
83
+ isSpecifiedError(err, {
84
+ statusCode: 400,
85
+ errorType: 'TEST_PORTAL_LIMIT_REACHED',
86
+ })
87
+ ) {
88
+ logger.log('');
89
+ logger.error(
90
+ i18n('lib.developerTestAccount.create.failure.limit', {
91
+ accountName: uiAccountDescription(accountId),
92
+ limit: portalLimit,
93
+ })
94
+ );
95
+ logger.log('');
96
+ } else {
97
+ logErrorInstance(err);
98
+ }
99
+ throw err;
100
+ }
101
+
55
102
  module.exports = {
56
103
  validateDevTestAccountUsageLimits,
104
+ handleDeveloperTestAccountCreateError,
57
105
  };
@@ -19,7 +19,7 @@ const {
19
19
  const { overrideErrors } = require('./overrideErrors');
20
20
  const { i18n } = require('../lang');
21
21
 
22
- const i18nKey = 'cli.lib.errorHandlers.apiErrors';
22
+ const i18nKey = 'lib.errorHandlers.apiErrors';
23
23
 
24
24
  class ApiErrorContext extends ErrorContext {
25
25
  constructor(props = {}) {
@@ -5,7 +5,7 @@ const { PLATFORM_VERSION_ERROR_TYPES } = require('../constants');
5
5
  const { i18n } = require('../lang');
6
6
  const { uiLine, uiLink } = require('../ui');
7
7
 
8
- const i18nKey = 'cli.lib.errorHandlers.overrideErrors';
8
+ const i18nKey = 'lib.errorHandlers.overrideErrors';
9
9
 
10
10
  function createPlatformVersionError(subCategory, errData) {
11
11
  const docsLink = uiLink(
@@ -5,7 +5,7 @@ const {
5
5
  } = require('@hubspot/local-dev-lib/errors/standardErrors');
6
6
  const { i18n } = require('../lang');
7
7
 
8
- const i18nKey = 'cli.lib.errorHandlers.standardErrors';
8
+ const i18nKey = 'lib.errorHandlers.standardErrors';
9
9
 
10
10
  // TODO: Make these TS interfaces
11
11
  class ErrorContext {
@@ -8,7 +8,7 @@ const CSS_PSEUDO_CLASS_REGEX = new RegExp(
8
8
  /:active|:checked|:disabled|:empty|:enabled|:first-of-type|:focus|:hover|:in-range|:invalid|:link|:optional|:out-of-range|:read-only|:read-write|:required|:target|:valid|:visited/,
9
9
  'g'
10
10
  );
11
- const i18nKey = 'cli.commands.theme.subcommands.generateSelectors';
11
+ const i18nKey = 'commands.theme.subcommands.generateSelectors';
12
12
 
13
13
  let maxFieldsDepth = 0;
14
14
 
package/lib/localDev.js CHANGED
@@ -8,30 +8,26 @@ 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
-
13
+ const {
14
+ ENVIRONMENTS,
15
+ } = require('@hubspot/local-dev-lib/constants/environments');
14
16
  const {
15
17
  confirmDefaultAccountPrompt,
16
18
  selectSandboxTargetAccountPrompt,
17
19
  selectDeveloperTestTargetAccountPrompt,
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,
26
- getSandboxTypeAsString,
27
25
  getAvailableSyncTypes,
28
26
  } = require('./sandboxes');
29
- const { buildSandbox } = require('./sandboxCreate');
30
27
  const { syncSandbox } = require('./sandboxSync');
31
28
  const {
32
29
  validateDevTestAccountUsageLimits,
33
30
  } = require('./developerTestAccounts');
34
- const { buildDeveloperTestAccount } = require('./developerTestAccountCreate');
35
31
  const { logErrorInstance } = require('./errorHandlers/standardErrors');
36
32
  const { uiCommandReference, uiLine, uiAccountDescription } = require('./ui');
37
33
  const SpinniesManager = require('./ui/SpinniesManager');
@@ -55,8 +51,13 @@ const {
55
51
  logApiErrorInstance,
56
52
  ApiErrorContext,
57
53
  } = require('./errorHandlers/apiErrors');
54
+ const {
55
+ PERSONAL_ACCESS_KEY_AUTH_METHOD,
56
+ } = require('@hubspot/local-dev-lib/constants/auth');
57
+ const { buildNewAccount, saveAccountToConfig } = require('./buildAccount');
58
+ const { hubspotAccountNamePrompt } = require('./prompts/accountNamePrompt');
58
59
 
59
- const i18nKey = 'cli.lib.localDev';
60
+ const i18nKey = 'lib.localDev';
60
61
 
61
62
  // If the user passed in the --account flag, confirm they want to use that account as
62
63
  // their target account, otherwise exit
@@ -64,9 +65,7 @@ const confirmDefaultAccountIsTarget = async accountConfig => {
64
65
  logger.log();
65
66
  const useDefaultAccount = await confirmDefaultAccountPrompt(
66
67
  accountConfig.name,
67
- isDeveloperTestAccount(accountConfig)
68
- ? HUBSPOT_ACCOUNT_TYPE_STRINGS[HUBSPOT_ACCOUNT_TYPES.DEVELOPER_TEST]
69
- : `${getSandboxTypeAsString(accountConfig.accountType)} sandbox`
68
+ HUBSPOT_ACCOUNT_TYPE_STRINGS[accountConfig.accountType]
70
69
  );
71
70
 
72
71
  if (!useDefaultAccount) {
@@ -86,11 +85,15 @@ const confirmDefaultAccountIsTarget = async accountConfig => {
86
85
  // Confirm the default account is a developer account if developing public apps
87
86
  const checkIfAppDeveloperAccount = accountConfig => {
88
87
  if (!isAppDeveloperAccount(accountConfig)) {
89
- logger.error(
90
- i18n(
91
- `${i18nKey}.checkCorrectParentAccountType.standardAccountNotSupported`
92
- )
93
- );
88
+ logger.error(i18n(`${i18nKey}.checkIfAppDevloperAccount`));
89
+ process.exit(EXIT_CODES.SUCCESS);
90
+ }
91
+ };
92
+
93
+ // Confirm the default account is a developer account if developing public apps
94
+ const checkIfDeveloperTestAccount = accountConfig => {
95
+ if (!isDeveloperTestAccount(accountConfig)) {
96
+ logger.error(i18n(`${i18nKey}.checkIfDeveloperTestAccount`));
94
97
  process.exit(EXIT_CODES.SUCCESS);
95
98
  }
96
99
  };
@@ -104,19 +107,20 @@ const suggestRecommendedNestedAccount = async (
104
107
  logger.log();
105
108
  uiLine();
106
109
  if (hasPublicApps) {
107
- logger.warn(
110
+ logger.log(
108
111
  i18n(
109
112
  `${i18nKey}.suggestRecommendedNestedAccount.publicAppNonDeveloperTestAccountWarning`
110
113
  )
111
114
  );
112
115
  } else if (isAppDeveloperAccount(accountConfig)) {
113
- logger.warn(
116
+ logger.error(
114
117
  i18n(
115
- `${i18nKey}.suggestRecommendedNestedAccount.publicAppNonDeveloperTestAccountWarning`
118
+ `${i18nKey}.suggestRecommendedNestedAccount.privateAppInAppDeveloperAccountError`
116
119
  )
117
120
  );
121
+ process.exit(EXIT_CODES.ERROR);
118
122
  } else {
119
- logger.warn(
123
+ logger.log(
120
124
  i18n(`${i18nKey}.suggestRecommendedNestedAccount.nonSandboxWarning`)
121
125
  );
122
126
  }
@@ -141,14 +145,14 @@ const createSandboxForLocalDev = async (accountId, accountConfig, env) => {
141
145
  } catch (err) {
142
146
  if (isMissingScopeError(err)) {
143
147
  logger.error(
144
- i18n('cli.lib.sandbox.create.failure.scopes.message', {
148
+ i18n('lib.sandbox.create.failure.scopes.message', {
145
149
  accountName: accountConfig.name || accountId,
146
150
  })
147
151
  );
148
152
  const websiteOrigin = getHubSpotWebsiteOrigin(env);
149
153
  const url = `${websiteOrigin}/personal-access-key/${accountId}`;
150
154
  logger.info(
151
- i18n('cli.lib.sandbox.create.failure.scopes.instructions', {
155
+ i18n('lib.sandbox.create.failure.scopes.instructions', {
152
156
  accountName: accountConfig.name || accountId,
153
157
  url,
154
158
  })
@@ -159,9 +163,9 @@ const createSandboxForLocalDev = async (accountId, accountConfig, env) => {
159
163
  process.exit(EXIT_CODES.ERROR);
160
164
  }
161
165
  try {
162
- const { name } = await sandboxNamePrompt(
163
- HUBSPOT_ACCOUNT_TYPES.DEVELOPMENT_SANDBOX
164
- );
166
+ const { name } = await hubspotAccountNamePrompt({
167
+ accountType: HUBSPOT_ACCOUNT_TYPES.DEVELOPMENT_SANDBOX,
168
+ });
165
169
 
166
170
  trackCommandMetadataUsage(
167
171
  'sandbox-create',
@@ -169,9 +173,9 @@ const createSandboxForLocalDev = async (accountId, accountConfig, env) => {
169
173
  accountId
170
174
  );
171
175
 
172
- const { result } = await buildSandbox({
176
+ const { result } = await buildNewAccount({
173
177
  name,
174
- type: HUBSPOT_ACCOUNT_TYPES.DEVELOPMENT_SANDBOX,
178
+ accountType: HUBSPOT_ACCOUNT_TYPES.DEVELOPMENT_SANDBOX,
175
179
  accountConfig,
176
180
  env,
177
181
  });
@@ -219,20 +223,17 @@ const createDeveloperTestAccountForLocalDev = async (
219
223
  } catch (err) {
220
224
  if (isMissingScopeError(err)) {
221
225
  logger.error(
222
- i18n('cli.lib.developerTestAccount.create.failure.scopes.message', {
226
+ i18n('lib.developerTestAccount.create.failure.scopes.message', {
223
227
  accountName: accountConfig.name || accountId,
224
228
  })
225
229
  );
226
230
  const websiteOrigin = getHubSpotWebsiteOrigin(env);
227
231
  const url = `${websiteOrigin}/personal-access-key/${accountId}`;
228
232
  logger.info(
229
- i18n(
230
- 'cli.lib.developerTestAccount.create.failure.scopes.instructions',
231
- {
232
- accountName: accountConfig.name || accountId,
233
- url,
234
- }
235
- )
233
+ i18n('lib.developerTestAccount.create.failure.scopes.instructions', {
234
+ accountName: accountConfig.name || accountId,
235
+ url,
236
+ })
236
237
  );
237
238
  } else {
238
239
  logErrorInstance(err);
@@ -241,18 +242,22 @@ const createDeveloperTestAccountForLocalDev = async (
241
242
  }
242
243
 
243
244
  try {
244
- const { name } = await developerTestAccountNamePrompt(currentPortalCount);
245
+ const { name } = await hubspotAccountNamePrompt({
246
+ currentPortalCount,
247
+ accountType: HUBSPOT_ACCOUNT_TYPES.DEVELOPER_TEST,
248
+ });
245
249
  trackCommandMetadataUsage(
246
250
  'developer-test-account-create',
247
251
  { step: 'project-dev' },
248
252
  accountId
249
253
  );
250
254
 
251
- const { result } = await buildDeveloperTestAccount({
255
+ const { result } = await buildNewAccount({
252
256
  name,
257
+ accountType: HUBSPOT_ACCOUNT_TYPES.DEVELOPER_TEST,
253
258
  accountConfig,
254
259
  env,
255
- maxTestPortals,
260
+ portalLimit: maxTestPortals,
256
261
  });
257
262
 
258
263
  return result.id;
@@ -262,27 +267,61 @@ const createDeveloperTestAccountForLocalDev = async (
262
267
  }
263
268
  };
264
269
 
270
+ // Prompt user to confirm usage of an existing developer test account that is not currently in the config
271
+ const useExistingDevTestAccount = async (env, account) => {
272
+ const useExistingDevTestAcct = await confirmUseExistingDeveloperTestAccountPrompt(
273
+ account
274
+ );
275
+ if (!useExistingDevTestAcct) {
276
+ logger.log('');
277
+ logger.log(
278
+ i18n(
279
+ `${i18nKey}.confirmDefaultAccountIsTarget.declineDefaultAccountExplanation`,
280
+ {
281
+ useCommand: uiCommandReference('hs accounts use'),
282
+ devCommand: uiCommandReference('hs project dev'),
283
+ }
284
+ )
285
+ );
286
+ logger.log('');
287
+ process.exit(EXIT_CODES.SUCCESS);
288
+ }
289
+ const devTestAcctConfigName = await saveAccountToConfig({
290
+ env,
291
+ accountName: account.accountName,
292
+ accountId: account.id,
293
+ });
294
+ logger.success(
295
+ i18n(`lib.developerTestAccount.create.success.configFileUpdated`, {
296
+ accountName: devTestAcctConfigName,
297
+ authType: PERSONAL_ACCESS_KEY_AUTH_METHOD.name,
298
+ })
299
+ );
300
+ };
301
+
265
302
  // Prompt the user to create a new project if one doesn't exist on their target account
266
303
  const createNewProjectForLocalDev = async (
267
304
  projectConfig,
268
305
  targetAccountId,
269
- shouldCreateWithoutConfirmation
306
+ shouldCreateWithoutConfirmation,
307
+ hasPublicApps
270
308
  ) => {
271
309
  // Create the project without prompting if this is a newly created sandbox
272
310
  let shouldCreateProject = shouldCreateWithoutConfirmation;
273
311
 
274
312
  if (!shouldCreateProject) {
313
+ const explanationString = i18n(
314
+ hasPublicApps
315
+ ? `${i18nKey}.createNewProjectForLocalDev.publicAppProjectMustExistExplanation`
316
+ : `${i18nKey}.createNewProjectForLocalDev.projectMustExistExplanation`,
317
+ {
318
+ accountIdentifier: uiAccountDescription(targetAccountId),
319
+ projectName: projectConfig.name,
320
+ }
321
+ );
275
322
  logger.log();
276
323
  uiLine();
277
- logger.warn(
278
- i18n(
279
- `${i18nKey}.createNewProjectForLocalDev.projectMustExistExplanation`,
280
- {
281
- accountIdentifier: uiAccountDescription(targetAccountId),
282
- projectName: projectConfig.name,
283
- }
284
- )
285
- );
324
+ logger.log(explanationString);
286
325
  uiLine();
287
326
 
288
327
  shouldCreateProject = await confirmPrompt(
@@ -302,7 +341,7 @@ const createNewProjectForLocalDev = async (
302
341
  });
303
342
 
304
343
  try {
305
- await createProject(targetAccountId, projectConfig.name);
344
+ const project = await createProject(targetAccountId, projectConfig.name);
306
345
  SpinniesManager.succeed('createProject', {
307
346
  text: i18n(`${i18nKey}.createNewProjectForLocalDev.createdProject`, {
308
347
  accountIdentifier: uiAccountDescription(targetAccountId),
@@ -310,6 +349,7 @@ const createNewProjectForLocalDev = async (
310
349
  }),
311
350
  succeedColor: 'white',
312
351
  });
352
+ return project;
313
353
  } catch (err) {
314
354
  SpinniesManager.fail('createProject');
315
355
  logger.log(
@@ -380,7 +420,7 @@ const createInitialBuildForNewProject = async (
380
420
 
381
421
  logger.log();
382
422
  failedSubTasks.forEach(failedSubTask => {
383
- console.error(failedSubTask.errorMessage);
423
+ logger.error(failedSubTask.errorMessage);
384
424
  });
385
425
  logger.log();
386
426
 
@@ -390,12 +430,22 @@ const createInitialBuildForNewProject = async (
390
430
  return initialUploadResult.buildResult;
391
431
  };
392
432
 
433
+ const getAccountHomeUrl = accountId => {
434
+ const baseUrl = getHubSpotWebsiteOrigin(
435
+ getEnv(accountId) === 'qa' ? ENVIRONMENTS.QA : ENVIRONMENTS.PROD
436
+ );
437
+ return `${baseUrl}/home?portalId=${accountId}`;
438
+ };
439
+
393
440
  module.exports = {
394
441
  confirmDefaultAccountIsTarget,
395
442
  checkIfAppDeveloperAccount,
443
+ checkIfDeveloperTestAccount,
396
444
  suggestRecommendedNestedAccount,
397
445
  createSandboxForLocalDev,
398
446
  createDeveloperTestAccountForLocalDev,
447
+ useExistingDevTestAccount,
399
448
  createNewProjectForLocalDev,
400
449
  createInitialBuildForNewProject,
450
+ getAccountHomeUrl,
401
451
  };
@@ -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
- logger.error(`${err.context}`);
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 ADDED
@@ -0,0 +1,31 @@
1
+ const { POLLING_DELAY, POLLING_STATUS } = require('./constants');
2
+
3
+ const poll = (callback, accountId, taskId) => {
4
+ return new Promise((resolve, reject) => {
5
+ const pollInterval = setInterval(async () => {
6
+ try {
7
+ const pollResp = await callback(accountId, taskId);
8
+ const { status } = pollResp;
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) {
22
+ clearInterval(pollInterval);
23
+ reject(error);
24
+ }
25
+ }, POLLING_DELAY);
26
+ });
27
+ };
28
+
29
+ module.exports = {
30
+ poll,
31
+ };
package/lib/process.js CHANGED
@@ -6,7 +6,7 @@ const {
6
6
  } = require('@hubspot/local-dev-lib/logger');
7
7
  const { i18n } = require('./lang');
8
8
 
9
- const i18nKey = 'cli.lib.process';
9
+ const i18nKey = 'lib.process';
10
10
 
11
11
  const handleExit = callback => {
12
12
  const terminationSignals = [
@@ -7,11 +7,13 @@ const { logErrorInstance } = require('./errorHandlers/standardErrors');
7
7
  const COMPONENT_TYPES = Object.freeze({
8
8
  privateApp: 'private-app',
9
9
  publicApp: 'public-app',
10
+ hublTheme: 'hubl-theme',
10
11
  });
11
12
 
12
13
  const CONFIG_FILES = {
13
14
  [COMPONENT_TYPES.privateApp]: 'app.json',
14
15
  [COMPONENT_TYPES.publicApp]: 'public-app.json',
16
+ [COMPONENT_TYPES.hublTheme]: 'theme.json',
15
17
  };
16
18
 
17
19
  function getTypeFromConfigFile(configFile) {
@@ -102,13 +104,14 @@ async function findProjectComponents(projectSourceDir) {
102
104
  if (Object.values(CONFIG_FILES).includes(base)) {
103
105
  const parsedAppConfig = loadConfigFile(projectFile);
104
106
 
105
- if (parsedAppConfig && parsedAppConfig.name) {
107
+ if (parsedAppConfig) {
106
108
  const isLegacy = getIsLegacyApp(parsedAppConfig, dir);
109
+ const isHublTheme = base === CONFIG_FILES[COMPONENT_TYPES.hublTheme];
107
110
 
108
111
  components.push({
109
112
  type: getTypeFromConfigFile(base),
110
113
  config: parsedAppConfig,
111
- runnable: !isLegacy,
114
+ runnable: !isLegacy && !isHublTheme,
112
115
  path: dir,
113
116
  });
114
117
  }