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

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 (142) 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 +7 -23
  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/add.js +1 -1
  56. package/commands/project/create.js +4 -4
  57. package/commands/project/deploy.js +4 -4
  58. package/commands/project/dev.js +70 -27
  59. package/commands/project/download.js +11 -7
  60. package/commands/project/listBuilds.js +4 -4
  61. package/commands/project/logs.js +4 -4
  62. package/commands/project/migrateApp.js +227 -0
  63. package/commands/project/open.js +12 -8
  64. package/commands/project/upload.js +13 -8
  65. package/commands/project/watch.js +4 -4
  66. package/commands/project.js +5 -3
  67. package/commands/remove.js +4 -4
  68. package/commands/sandbox/create.js +16 -16
  69. package/commands/sandbox/delete.js +5 -5
  70. package/commands/sandbox/sync.js +6 -6
  71. package/commands/sandbox.js +3 -3
  72. package/commands/secrets/addSecret.js +4 -4
  73. package/commands/secrets/deleteSecret.js +4 -4
  74. package/commands/secrets/listSecrets.js +4 -4
  75. package/commands/secrets/updateSecret.js +4 -4
  76. package/commands/secrets.js +3 -3
  77. package/commands/theme/generate-selectors.js +1 -1
  78. package/commands/theme/marketplace-validate.js +5 -5
  79. package/commands/theme/preview.js +52 -17
  80. package/commands/theme.js +1 -1
  81. package/commands/upload.js +5 -5
  82. package/commands/watch.js +61 -18
  83. package/jest.config.js +1 -0
  84. package/lang/en.lyaml +1425 -1371
  85. package/lib/DevServerManager.js +3 -2
  86. package/lib/LocalDevManager.js +165 -7
  87. package/lib/__tests__/{commonOpts.js → commonOpts.test.js} +3 -0
  88. package/lib/__tests__/downloadProjectPrompt.test.js +31 -0
  89. package/lib/__tests__/projects.test.js +13 -17
  90. package/lib/__tests__/{serverlessLogs.js → serverlessLogs.test.js} +1 -0
  91. package/lib/buildAccount.js +197 -0
  92. package/lib/commonOpts.js +1 -1
  93. package/lib/constants.js +10 -0
  94. package/lib/developerTestAccounts.js +52 -4
  95. package/lib/errorHandlers/apiErrors.js +1 -1
  96. package/lib/errorHandlers/overrideErrors.js +1 -1
  97. package/lib/errorHandlers/standardErrors.js +1 -1
  98. package/lib/generate-selectors.js +1 -1
  99. package/lib/localDev.js +102 -52
  100. package/lib/marketplace-validate.js +11 -3
  101. package/lib/polling.js +26 -0
  102. package/lib/process.js +1 -1
  103. package/lib/projectStructure.js +5 -2
  104. package/lib/projects.js +65 -12
  105. package/lib/projectsWatch.js +1 -1
  106. package/lib/prompts/accountNamePrompt.js +81 -0
  107. package/lib/prompts/accountsPrompt.js +1 -1
  108. package/lib/prompts/activeInstallConfirmationPrompt.js +20 -0
  109. package/lib/prompts/buildIdPrompt.js +1 -1
  110. package/lib/prompts/cleanUploadPrompt.js +1 -1
  111. package/lib/prompts/cmsFieldPrompt.js +1 -1
  112. package/lib/prompts/createApiSamplePrompt.js +1 -1
  113. package/lib/prompts/createFunctionPrompt.js +1 -1
  114. package/lib/prompts/createModulePrompt.js +1 -1
  115. package/lib/prompts/createProjectPrompt.js +32 -10
  116. package/lib/prompts/createTemplatePrompt.js +1 -1
  117. package/lib/prompts/downloadProjectPrompt.js +5 -6
  118. package/lib/prompts/feedbackPrompt.js +1 -1
  119. package/lib/prompts/folderOverwritePrompt.js +1 -1
  120. package/lib/prompts/installPublicAppPrompt.js +42 -0
  121. package/lib/prompts/personalAccessKeyPrompt.js +3 -3
  122. package/lib/prompts/previewPrompt.js +19 -1
  123. package/lib/prompts/projectAddPrompt.js +1 -1
  124. package/lib/prompts/projectDevTargetAccountPrompt.js +48 -6
  125. package/lib/prompts/projectNamePrompt.js +2 -2
  126. package/lib/prompts/projectsLogsPrompt.js +1 -1
  127. package/lib/prompts/sandboxesPrompt.js +13 -42
  128. package/lib/prompts/secretPrompt.js +1 -1
  129. package/lib/prompts/selectPublicAppPrompt.js +69 -0
  130. package/lib/prompts/setAsDefaultAccountPrompt.js +1 -1
  131. package/lib/prompts/uploadPrompt.js +1 -1
  132. package/lib/sandboxSync.js +1 -1
  133. package/lib/sandboxes.js +167 -14
  134. package/lib/ui/git.js +1 -1
  135. package/lib/ui/index.js +5 -22
  136. package/lib/ui/serverlessFunctionLogs.js +1 -1
  137. package/package.json +6 -6
  138. package/lib/developerTestAccountCreate.js +0 -186
  139. package/lib/prompts/developerTestAccountNamePrompt.js +0 -29
  140. package/lib/prompts/enterAccountNamePrompt.js +0 -33
  141. package/lib/sandboxCreate.js +0 -319
  142. /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 (
@@ -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,7 +1,7 @@
1
1
  const { promptUser } = require('./promptUtils');
2
2
  const { i18n } = require('../lang');
3
3
 
4
- const i18nKey = 'cli.lib.prompts.buildIdPrompt';
4
+ const i18nKey = 'lib.prompts.buildIdPrompt';
5
5
 
6
6
  const buildIdPrompt = (latestBuildId, deployedBuildId, projectName) => {
7
7
  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.cleanUploadPrompt';
4
+ const i18nKey = 'lib.prompts.cleanUploadPrompt';
5
5
 
6
6
  const cleanUploadPrompt = async (accountId, filePath) => {
7
7
  const promptAnswer = await promptUser([
@@ -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,42 @@
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
+ ) => {
17
+ logger.log('');
18
+ logger.log(i18n(`${i18nKey}.explanation`));
19
+
20
+ const { shouldOpenBrowser } = await promptUser({
21
+ name: 'shouldOpenBrowser',
22
+ type: 'confirm',
23
+ message: i18n(`${i18nKey}.prompt`),
24
+ });
25
+
26
+ if (!shouldOpenBrowser) {
27
+ logger.log(i18n(`${i18nKey}.decline`));
28
+ process.exit(EXIT_CODES.SUCCESS);
29
+ }
30
+
31
+ const websiteOrigin = getHubSpotWebsiteOrigin(env);
32
+
33
+ const url =
34
+ `${websiteOrigin}/oauth/${targetAccountId}/authorize` +
35
+ `?client_id=${encodeURIComponent(clientId)}` +
36
+ `&scope=${encodeURIComponent(scopes.join(' '))}` +
37
+ `&redirect_uri=${encodeURIComponent(redirectUrls[0])}`;
38
+
39
+ open(url);
40
+ };
41
+
42
+ 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(
@@ -13,7 +13,7 @@ const {
13
13
  fetchDeveloperTestAccounts,
14
14
  } = require('@hubspot/local-dev-lib/developerTestAccounts');
15
15
 
16
- const i18nKey = 'cli.lib.prompts.projectDevTargetAccountPrompt';
16
+ const i18nKey = 'lib.prompts.projectDevTargetAccountPrompt';
17
17
 
18
18
  const mapNestedAccount = accountConfig => ({
19
19
  name: uiAccountDescription(accountConfig.portalId, false),
@@ -24,6 +24,12 @@ const mapNestedAccount = accountConfig => ({
24
24
  },
25
25
  });
26
26
 
27
+ const getNonConfigDeveloperTestAccountName = account => {
28
+ return `${account.accountName} [${
29
+ HUBSPOT_ACCOUNT_TYPE_STRINGS[HUBSPOT_ACCOUNT_TYPES.DEVELOPER_TEST]
30
+ }] (${account.id})`;
31
+ };
32
+
27
33
  const selectSandboxTargetAccountPrompt = async (
28
34
  accounts,
29
35
  defaultAccountConfig
@@ -94,9 +100,11 @@ const selectDeveloperTestTargetAccountPrompt = async (
94
100
  ) => {
95
101
  const defaultAccountId = getAccountId(defaultAccountConfig.name);
96
102
  let choices = [];
97
- let devTestAccountUsage = undefined;
103
+ let devTestAccountsResponse = undefined;
98
104
  try {
99
- devTestAccountUsage = await fetchDeveloperTestAccounts(defaultAccountId);
105
+ devTestAccountsResponse = await fetchDeveloperTestAccounts(
106
+ defaultAccountId
107
+ );
100
108
  } catch (err) {
101
109
  logger.debug('Unable to fetch developer test account usage limits: ', err);
102
110
  }
@@ -110,17 +118,37 @@ const selectDeveloperTestTargetAccountPrompt = async (
110
118
  );
111
119
  let disabledMessage = false;
112
120
  if (
113
- devTestAccountUsage &&
114
- devTestAccountUsage.results.length >= devTestAccountUsage.maxTestPortals
121
+ devTestAccountsResponse &&
122
+ devTestAccountsResponse.results.length >=
123
+ devTestAccountsResponse.maxTestPortals
115
124
  ) {
116
125
  disabledMessage = i18n(`${i18nKey}.developerTestAccountLimit`, {
117
126
  authCommand: uiCommandReference('hs auth'),
118
- limit: devTestAccountUsage.maxTestPortals,
127
+ limit: devTestAccountsResponse.maxTestPortals,
128
+ });
129
+ }
130
+
131
+ let devTestAccountsNotInConfig = [];
132
+ if (devTestAccountsResponse && devTestAccountsResponse.results) {
133
+ const inConfigIds = devTestAccounts.map(d => d.portalId);
134
+ devTestAccountsResponse.results.forEach(acct => {
135
+ if (inConfigIds.indexOf(acct.id) < 0) {
136
+ devTestAccountsNotInConfig.push({
137
+ name: getNonConfigDeveloperTestAccountName(acct),
138
+ value: {
139
+ targetAccountId: acct.id,
140
+ createdNestedAccount: false,
141
+ parentAccountId: defaultAccountId,
142
+ notInConfigAccount: acct,
143
+ },
144
+ });
145
+ }
119
146
  });
120
147
  }
121
148
 
122
149
  choices = [
123
150
  ...devTestAccounts.map(mapNestedAccount),
151
+ ...devTestAccountsNotInConfig,
124
152
  {
125
153
  name: i18n(`${i18nKey}.createNewDeveloperTestAccountOption`),
126
154
  value: {
@@ -172,8 +200,22 @@ const confirmDefaultAccountPrompt = async (accountName, accountType) => {
172
200
  return useDefaultAccount;
173
201
  };
174
202
 
203
+ const confirmUseExistingDeveloperTestAccountPrompt = async account => {
204
+ const { confirmUseExistingDeveloperTestAccount } = await promptUser([
205
+ {
206
+ name: 'confirmUseExistingDeveloperTestAccount',
207
+ type: 'confirm',
208
+ message: i18n(`${i18nKey}.confirmUseExistingDeveloperTestAccount`, {
209
+ accountName: getNonConfigDeveloperTestAccountName(account),
210
+ }),
211
+ },
212
+ ]);
213
+ return confirmUseExistingDeveloperTestAccount;
214
+ };
215
+
175
216
  module.exports = {
176
217
  selectSandboxTargetAccountPrompt,
177
218
  selectDeveloperTestTargetAccountPrompt,
178
219
  confirmDefaultAccountPrompt,
220
+ confirmUseExistingDeveloperTestAccountPrompt,
179
221
  };