@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/projects.js CHANGED
@@ -17,6 +17,7 @@ const {
17
17
  PROJECT_DEPLOY_TEXT,
18
18
  PROJECT_CONFIG_FILE,
19
19
  PROJECT_TASK_TYPES,
20
+ PROJECT_ERROR_TYPES,
20
21
  } = require('./constants');
21
22
  const {
22
23
  createProject,
@@ -47,7 +48,7 @@ const {
47
48
  } = require('./errorHandlers/apiErrors');
48
49
  const { HUBSPOT_PROJECT_COMPONENTS_GITHUB_PATH } = require('./constants');
49
50
 
50
- const i18nKey = 'cli.lib.projects';
51
+ const i18nKey = 'lib.projects';
51
52
 
52
53
  const SPINNER_STATUS = {
53
54
  SPINNING: 'spinning',
@@ -252,7 +253,7 @@ const ensureProjectExists = async (
252
253
  const project = withPolling
253
254
  ? await pollFetchProject(accountId, projectName)
254
255
  : await fetchProject(accountId, projectName);
255
- return !!project;
256
+ return { projectExists: !!project, project };
256
257
  } catch (err) {
257
258
  if (isSpecifiedError(err, { statusCode: 404 })) {
258
259
  let shouldCreateProject = forceCreate;
@@ -273,14 +274,14 @@ const ensureProjectExists = async (
273
274
 
274
275
  if (shouldCreateProject) {
275
276
  try {
276
- await createProject(accountId, projectName);
277
+ const project = await createProject(accountId, projectName);
277
278
  logger.success(
278
279
  i18n(`${i18nKey}.ensureProjectExists.createSuccess`, {
279
280
  projectName,
280
281
  accountIdentifier,
281
282
  })
282
283
  );
283
- return true;
284
+ return { projectExists: true, project };
284
285
  } catch (err) {
285
286
  return logApiErrorInstance(
286
287
  err,
@@ -296,7 +297,7 @@ const ensureProjectExists = async (
296
297
  })
297
298
  );
298
299
  }
299
- return false;
300
+ return { projectExists: false };
300
301
  }
301
302
  }
302
303
  if (
@@ -634,9 +635,9 @@ const makePollTaskStatusFunc = ({
634
635
 
635
636
  const tasksById = initialTaskStatus[statusText.SUBTASK_KEY].reduce(
636
637
  (acc, task) => {
637
- const type = task[statusText.TYPE_KEY];
638
- if (type !== 'APP_ID' && type !== 'SERVERLESS_PKG') {
639
- acc[task.id] = task;
638
+ const { id, visible } = task;
639
+ if (visible) {
640
+ acc[id] = task;
640
641
  }
641
642
  return acc;
642
643
  },
@@ -698,9 +699,51 @@ const makePollTaskStatusFunc = ({
698
699
 
699
700
  return new Promise((resolve, reject) => {
700
701
  const pollInterval = setInterval(async () => {
701
- const taskStatus = await statusFn(accountId, taskName, taskId).catch(
702
- reject
703
- );
702
+ let taskStatus;
703
+ try {
704
+ taskStatus = await statusFn(accountId, taskName, taskId);
705
+ } catch (e) {
706
+ logApiErrorInstance(
707
+ e,
708
+ new ApiErrorContext({
709
+ accountId,
710
+ projectName: taskName,
711
+ })
712
+ );
713
+ return reject(
714
+ new Error(
715
+ i18n(
716
+ `${i18nKey}.makePollTaskStatusFunc.errorFetchingTaskStatus`,
717
+ {
718
+ taskType:
719
+ statusText.TYPE_KEY === PROJECT_BUILD_TEXT.TYPE_KEY
720
+ ? 'build'
721
+ : 'deploy',
722
+ }
723
+ )
724
+ )
725
+ );
726
+ }
727
+
728
+ if (
729
+ !taskStatus ||
730
+ !taskStatus.status ||
731
+ !taskStatus[statusText.SUBTASK_KEY]
732
+ ) {
733
+ return reject(
734
+ new Error(
735
+ i18n(
736
+ `${i18nKey}.makePollTaskStatusFunc.errorFetchingTaskStatus`,
737
+ {
738
+ taskType:
739
+ statusText.TYPE_KEY === PROJECT_BUILD_TEXT.TYPE_KEY
740
+ ? 'build'
741
+ : 'deploy',
742
+ }
743
+ )
744
+ )
745
+ );
746
+ }
704
747
 
705
748
  const { status, [statusText.SUBTASK_KEY]: subTaskStatus } = taskStatus;
706
749
 
@@ -772,7 +815,9 @@ const makePollTaskStatusFunc = ({
772
815
  const displayErrors = failedSubtasks.filter(
773
816
  subtask =>
774
817
  subtask.standardError.subCategory !==
775
- 'BuildPipelineErrorType.DEPENDENT_SUBBUILD_FAILED'
818
+ PROJECT_ERROR_TYPES.SUBBUILD_FAILED &&
819
+ subtask.standardError.subCategory !==
820
+ PROJECT_ERROR_TYPES.SUBDEPLOY_FAILED
776
821
  );
777
822
 
778
823
  displayErrors.forEach(subTask => {
@@ -859,7 +904,7 @@ const createProjectComponent = async (
859
904
  name,
860
905
  projectComponentsVersion
861
906
  ) => {
862
- const i18nKey = 'cli.commands.project.subcommands.add';
907
+ const i18nKey = 'commands.project.subcommands.add';
863
908
  let componentName = name;
864
909
 
865
910
  const configInfo = await getProjectConfig();
@@ -893,9 +938,17 @@ const displayWarnLogs = async (
893
938
  let result;
894
939
 
895
940
  if (isDeploy) {
896
- result = await fetchDeployWarnLogs(accountId, projectName, taskId);
941
+ try {
942
+ result = await fetchDeployWarnLogs(accountId, projectName, taskId);
943
+ } catch (e) {
944
+ logApiErrorInstance(e);
945
+ }
897
946
  } else {
898
- result = await fetchBuildWarnLogs(accountId, projectName, taskId);
947
+ try {
948
+ result = await fetchBuildWarnLogs(accountId, projectName, taskId);
949
+ } catch (e) {
950
+ logApiErrorInstance(e);
951
+ }
899
952
  }
900
953
 
901
954
  if (result && result.logs.length) {
@@ -20,7 +20,7 @@ const {
20
20
  const { isSpecifiedError } = require('@hubspot/local-dev-lib/errors/apiErrors');
21
21
  const { PROJECT_ERROR_TYPES } = require('./constants');
22
22
 
23
- const i18nKey = 'cli.commands.project.subcommands.watch';
23
+ const i18nKey = 'commands.project.subcommands.watch';
24
24
 
25
25
  const queue = new PQueue({
26
26
  concurrency: 10,
@@ -0,0 +1,81 @@
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
+ defaultName = i18n(`${i18nKey}.sandboxDefaultName`, {
49
+ sandboxType: isDevelopmentSandbox ? 'development' : 'standard',
50
+ });
51
+ } else if (isDeveloperTestAccount) {
52
+ promptMessageString = i18n(`${i18nKey}.enterDeveloperTestAccountName`);
53
+ defaultName = i18n(`${i18nKey}.developerTestAccountDefaultName`, {
54
+ count: currentPortalCount + 1,
55
+ });
56
+ }
57
+
58
+ return promptUser([
59
+ {
60
+ name: 'name',
61
+ message: promptMessageString,
62
+ validate(val) {
63
+ if (typeof val !== 'string') {
64
+ return i18n(`${i18nKey}.errors.invalidName`);
65
+ } else if (!val.length) {
66
+ return i18n(`${i18nKey}.errors.nameRequired`);
67
+ }
68
+ return accountNameExistsInConfig(val)
69
+ ? i18n(`${i18nKey}.errors.accountNameExists`, { name: val })
70
+ : true;
71
+ },
72
+ default: defaultName,
73
+ },
74
+ ]);
75
+ };
76
+
77
+ module.exports = {
78
+ getCliAccountNamePromptConfig,
79
+ cliAccountNamePrompt,
80
+ hubspotAccountNamePrompt,
81
+ };
@@ -9,7 +9,7 @@ const mapAccountChoices = portals =>
9
9
  value: p.name || p.portalId,
10
10
  }));
11
11
 
12
- const i18nKey = 'cli.commands.accounts.subcommands.use';
12
+ const i18nKey = 'commands.accounts.subcommands.use';
13
13
 
14
14
  const selectAccountFromConfig = async (config, prompt) => {
15
15
  const { default: selectedDefault } = await promptUser([
@@ -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,9 +1,13 @@
1
1
  const { promptUser } = require('./promptUtils');
2
2
  const { i18n } = require('../lang');
3
3
 
4
- const i18nKey = 'cli.lib.prompts.buildIdPrompt';
5
-
6
- const buildIdPrompt = (latestBuildId, deployedBuildId, projectName) => {
4
+ const i18nKey = 'lib.prompts.buildIdPrompt';
5
+ const buildIdPrompt = (
6
+ latestBuildId,
7
+ deployedBuildId,
8
+ projectName,
9
+ validate
10
+ ) => {
7
11
  return promptUser({
8
12
  name: 'buildId',
9
13
  message: i18n(`${i18nKey}.enterBuildId`),
@@ -13,20 +17,7 @@ const buildIdPrompt = (latestBuildId, deployedBuildId, projectName) => {
13
17
  }
14
18
  return latestBuildId;
15
19
  },
16
- validate: val => {
17
- if (Number(val) > latestBuildId) {
18
- return i18n(`${i18nKey}.errors.buildIdDoesNotExist`, {
19
- buildId: val,
20
- projectName,
21
- });
22
- }
23
- if (Number(val) === deployedBuildId) {
24
- return i18n(`${i18nKey}.errors.buildAlreadyDeployed`, {
25
- buildId: val,
26
- });
27
- }
28
- return true;
29
- },
20
+ validate,
30
21
  });
31
22
  };
32
23
 
@@ -1,7 +1,7 @@
1
1
  const { promptUser } = require('./promptUtils');
2
2
  const { i18n } = require('../lang');
3
3
 
4
- const i18nKey = 'cli.lib.prompts.cleanUploadPrompt';
4
+ const i18nKey = 'lib.prompts.cleanUploadPrompt';
5
5
 
6
6
  const cleanUploadPrompt = async (accountId, filePath) => {
7
7
  const promptAnswer = await promptUser([
@@ -0,0 +1,32 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const { promptUser } = require('./promptUtils');
4
+ const { i18n } = require('../lang');
5
+ const { getCwd, isValidPath } = require('@hubspot/local-dev-lib/path');
6
+
7
+ const i18nKey = 'lib.prompts.cloneAppLocationPrompt';
8
+
9
+ const cloneAppLocationPrompt = (promptOptions, appName) => {
10
+ return promptUser({
11
+ name: 'location',
12
+ message: i18n(`${i18nKey}.enterLocation`),
13
+ when: !promptOptions.location,
14
+ default: path.resolve(getCwd(), appName),
15
+ validate: input => {
16
+ if (!input) {
17
+ return i18n(`${i18nKey}.errors.locationRequired`);
18
+ }
19
+ if (fs.existsSync(input)) {
20
+ return i18n(`${i18nKey}.errors.invalidLocation`);
21
+ }
22
+ if (!isValidPath(input)) {
23
+ return i18n(`${i18nKey}.errors.invalidCharacters`);
24
+ }
25
+ return true;
26
+ },
27
+ });
28
+ };
29
+
30
+ module.exports = {
31
+ cloneAppLocationPrompt,
32
+ };
@@ -3,7 +3,7 @@ const fs = require('fs');
3
3
  const { promptUser } = require('./promptUtils');
4
4
  const { i18n } = require('../lang');
5
5
  const escapeRegExp = require('@hubspot/local-dev-lib/escapeRegExp');
6
- const i18nKey = 'cli.lib.prompts.uploadPrompt';
6
+ const i18nKey = 'lib.prompts.uploadPrompt';
7
7
  const FIELDS_FILES = ['fields.json', 'fields.js', 'fields.cjs', 'fields.mjs'];
8
8
 
9
9
  const fieldsJsPrompt = async (filePath, projectDir, skipFiles = []) => {
@@ -1,7 +1,7 @@
1
1
  const { promptUser } = require('./promptUtils');
2
2
  const { i18n } = require('../lang');
3
3
 
4
- const i18nKey = 'cli.lib.prompts.createApiSamplePrompt';
4
+ const i18nKey = 'lib.prompts.createApiSamplePrompt';
5
5
 
6
6
  const getSampleTypesPrompt = choices => ({
7
7
  type: 'rawlist',
@@ -3,7 +3,7 @@ const { i18n } = require('../lang');
3
3
 
4
4
  const { STRING_WITH_NO_SPACES_REGEX } = require('../regex');
5
5
 
6
- const i18nKey = 'cli.lib.prompts.createFunctionPrompt';
6
+ const i18nKey = 'lib.prompts.createFunctionPrompt';
7
7
 
8
8
  const FUNCTIONS_FOLDER_PROMPT = {
9
9
  name: 'functionsFolder',
@@ -1,7 +1,7 @@
1
1
  const { promptUser } = require('./promptUtils');
2
2
  const { i18n } = require('../lang');
3
3
 
4
- const i18nKey = 'cli.lib.prompts.createModulePrompt';
4
+ const i18nKey = 'lib.prompts.createModulePrompt';
5
5
 
6
6
  const MODULE_LABEL_PROMPT = {
7
7
  name: 'moduleLabel',
@@ -1,5 +1,10 @@
1
+ const fs = require('fs');
1
2
  const path = require('path');
2
- const { getCwd } = require('@hubspot/local-dev-lib/path');
3
+ const {
4
+ getCwd,
5
+ sanitizeFileName,
6
+ isValidPath,
7
+ } = require('@hubspot/local-dev-lib/path');
3
8
  const { PROJECT_COMPONENT_TYPES } = require('../../lib/constants');
4
9
  const { promptUser } = require('./promptUtils');
5
10
  const { fetchFileFromRepository } = require('@hubspot/local-dev-lib/github');
@@ -11,7 +16,7 @@ const {
11
16
  DEFAULT_PROJECT_TEMPLATE_BRANCH,
12
17
  } = require('../constants');
13
18
 
14
- const i18nKey = 'cli.lib.prompts.createProjectPrompt';
19
+ const i18nKey = 'lib.prompts.createProjectPrompt';
15
20
 
16
21
  const PROJECT_PROPERTIES = ['name', 'label', 'path', 'insertPath'];
17
22
 
@@ -48,11 +53,18 @@ const createTemplateOptions = async (templateSource, githubRef) => {
48
53
  return config[PROJECT_COMPONENT_TYPES.PROJECTS];
49
54
  };
50
55
 
51
- const createProjectPrompt = async (githubRef, promptOptions = {}) => {
52
- const projectTemplates = await createTemplateOptions(
53
- promptOptions.templateSource,
54
- githubRef
55
- );
56
+ const createProjectPrompt = async (
57
+ githubRef,
58
+ promptOptions = {},
59
+ skipTemplatePrompt = false
60
+ ) => {
61
+ let projectTemplates = [];
62
+ if (!skipTemplatePrompt) {
63
+ projectTemplates = await createTemplateOptions(
64
+ promptOptions.templateSource,
65
+ githubRef
66
+ );
67
+ }
56
68
 
57
69
  return promptUser([
58
70
  {
@@ -71,12 +83,21 @@ const createProjectPrompt = async (githubRef, promptOptions = {}) => {
71
83
  message: i18n(`${i18nKey}.enterLocation`),
72
84
  when: !promptOptions.location,
73
85
  default: answers => {
74
- return path.resolve(getCwd(), answers.name || promptOptions.name);
86
+ const projectName = sanitizeFileName(
87
+ answers.name || promptOptions.name
88
+ );
89
+ return path.resolve(getCwd(), projectName);
75
90
  },
76
91
  validate: input => {
77
92
  if (!input) {
78
93
  return i18n(`${i18nKey}.errors.locationRequired`);
79
94
  }
95
+ if (fs.existsSync(input)) {
96
+ return i18n(`${i18nKey}.errors.invalidLocation`);
97
+ }
98
+ if (!isValidPath(input)) {
99
+ return i18n(`${i18nKey}.errors.invalidCharacters`);
100
+ }
80
101
  return true;
81
102
  },
82
103
  },
@@ -91,8 +112,9 @@ const createProjectPrompt = async (githubRef, promptOptions = {}) => {
91
112
  : i18n(`${i18nKey}.selectTemplate`);
92
113
  },
93
114
  when:
94
- !promptOptions.template ||
95
- !projectTemplates.find(t => t.name === promptOptions.template),
115
+ !skipTemplatePrompt &&
116
+ (!promptOptions.template ||
117
+ !projectTemplates.find(t => t.name === promptOptions.template)),
96
118
  type: 'list',
97
119
  choices: projectTemplates.map(template => {
98
120
  return {
@@ -1,7 +1,7 @@
1
1
  const { promptUser } = require('./promptUtils');
2
2
  const { i18n } = require('../lang');
3
3
 
4
- const i18nKey = 'cli.lib.prompts.createTemplatePrompt';
4
+ const i18nKey = 'lib.prompts.createTemplatePrompt';
5
5
 
6
6
  const TEMPLATE_TYPE_PROMPT = {
7
7
  type: 'list',
@@ -8,11 +8,9 @@ const {
8
8
  const { EXIT_CODES } = require('../enums/exitCodes');
9
9
  const { i18n } = require('../lang');
10
10
 
11
- const i18nKey = 'cli.lib.prompts.downloadProjectPrompt';
12
-
13
- const createProjectsList = async () => {
14
- const accountId = getAccountId();
11
+ const i18nKey = 'lib.prompts.downloadProjectPrompt';
15
12
 
13
+ const createProjectsList = async accountId => {
16
14
  try {
17
15
  const projects = await fetchProjects(accountId);
18
16
  return projects.results;
@@ -23,7 +21,8 @@ const createProjectsList = async () => {
23
21
  };
24
22
 
25
23
  const downloadProjectPrompt = async (promptOptions = {}) => {
26
- const projectsList = await createProjectsList();
24
+ const accountId = getAccountId(promptOptions.account);
25
+ const projectsList = await createProjectsList(accountId);
27
26
 
28
27
  return promptUser([
29
28
  {
@@ -33,7 +32,7 @@ const downloadProjectPrompt = async (promptOptions = {}) => {
33
32
  !projectsList.find(p => p.name === promptOptions.name)
34
33
  ? i18n(`${i18nKey}.errors.projectNotFound`, {
35
34
  projectName: promptOptions.project,
36
- accountId: getAccountId(),
35
+ accountId,
37
36
  })
38
37
  : i18n(`${i18nKey}.selectProject`);
39
38
  },
@@ -2,7 +2,7 @@ const { promptUser } = require('./promptUtils');
2
2
  const { i18n } = require('../lang');
3
3
  const { FEEDBACK_OPTIONS } = require('../constants');
4
4
 
5
- const i18nKey = 'cli.lib.prompts.feedbackPrompt';
5
+ const i18nKey = 'lib.prompts.feedbackPrompt';
6
6
 
7
7
  const feedbackTypePrompt = bypassPrompt => {
8
8
  return promptUser([
@@ -1,7 +1,7 @@
1
1
  const { promptUser } = require('./promptUtils');
2
2
  const { i18n } = require('../lang');
3
3
 
4
- const i18nKey = 'cli.lib.prompts.folderOverwritePrompt';
4
+ const i18nKey = 'lib.prompts.folderOverwritePrompt';
5
5
 
6
6
  const folderOverwritePrompt = folderName => {
7
7
  return promptUser({
@@ -0,0 +1,51 @@
1
+ const open = require('open');
2
+ const { getHubSpotWebsiteOrigin } = require('@hubspot/local-dev-lib/urls');
3
+ const { logger } = require('@hubspot/local-dev-lib/logger');
4
+ const { promptUser } = require('./promptUtils');
5
+ const { i18n } = require('../lang');
6
+ const { EXIT_CODES } = require('../enums/exitCodes');
7
+
8
+ const i18nKey = 'lib.prompts.installPublicAppPrompt';
9
+
10
+ const installPublicAppPrompt = async (
11
+ env,
12
+ targetAccountId,
13
+ clientId,
14
+ scopes,
15
+ redirectUrls,
16
+ isReinstall = false
17
+ ) => {
18
+ logger.log('');
19
+ if (isReinstall) {
20
+ logger.log(i18n(`${i18nKey}.reinstallExplanation`));
21
+ } else {
22
+ logger.log(i18n(`${i18nKey}.explanation`));
23
+ }
24
+
25
+ const { shouldOpenBrowser } = await promptUser({
26
+ name: 'shouldOpenBrowser',
27
+ type: 'confirm',
28
+ message: i18n(
29
+ isReinstall ? `${i18nKey}.reinstallPrompt` : `${i18nKey}.prompt`
30
+ ),
31
+ });
32
+
33
+ if (!isReinstall && !shouldOpenBrowser) {
34
+ logger.log(i18n(`${i18nKey}.decline`));
35
+ process.exit(EXIT_CODES.SUCCESS);
36
+ } else if (!shouldOpenBrowser) {
37
+ return;
38
+ }
39
+
40
+ const websiteOrigin = getHubSpotWebsiteOrigin(env);
41
+
42
+ const url =
43
+ `${websiteOrigin}/oauth/${targetAccountId}/authorize` +
44
+ `?client_id=${encodeURIComponent(clientId)}` +
45
+ `&scope=${encodeURIComponent(scopes.join(' '))}` +
46
+ `&redirect_uri=${encodeURIComponent(redirectUrls[0])}`;
47
+
48
+ open(url);
49
+ };
50
+
51
+ module.exports = { installPublicAppPrompt };
@@ -7,12 +7,12 @@ 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');
14
14
 
15
- const i18nKey = 'cli.lib.prompts.personalAccessKeyPrompt';
15
+ const i18nKey = 'lib.prompts.personalAccessKeyPrompt';
16
16
 
17
17
  /**
18
18
  * Displays notification to user that we are about to open the browser,
@@ -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,
@@ -3,7 +3,7 @@ const { getCwd } = require('@hubspot/local-dev-lib/path');
3
3
  const { promptUser } = require('./promptUtils');
4
4
  const { i18n } = require('../lang');
5
5
 
6
- const i18nKey = 'cli.lib.prompts.previewPrompt';
6
+ const i18nKey = 'lib.prompts.previewPrompt';
7
7
 
8
8
  const previewPrompt = (promptOptions = {}) => {
9
9
  return promptUser([
@@ -34,6 +34,24 @@ const previewPrompt = (promptOptions = {}) => {
34
34
  ]);
35
35
  };
36
36
 
37
+ const previewProjectPrompt = async themeComponents => {
38
+ return promptUser([
39
+ {
40
+ name: 'themeComponentPath',
41
+ message: i18n(`${i18nKey}.themeProjectSelect`),
42
+ type: 'list',
43
+ choices: themeComponents.map(t => {
44
+ const themeName = path.basename(t.path);
45
+ return {
46
+ name: themeName,
47
+ value: t.path,
48
+ };
49
+ }),
50
+ },
51
+ ]);
52
+ };
53
+
37
54
  module.exports = {
38
55
  previewPrompt,
56
+ previewProjectPrompt,
39
57
  };
@@ -4,7 +4,7 @@ const { i18n } = require('../lang');
4
4
  const { HUBSPOT_PROJECT_COMPONENTS_GITHUB_PATH } = require('../constants');
5
5
  const { PROJECT_COMPONENT_TYPES } = require('../constants');
6
6
 
7
- const i18nKey = 'cli.lib.prompts.projectAddPrompt';
7
+ const i18nKey = 'lib.prompts.projectAddPrompt';
8
8
 
9
9
  const createTypeOptions = async projectComponentsVersion => {
10
10
  const config = await fetchFileFromRepository(