@hubspot/cli 3.0.10-beta.6 → 3.0.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 (90) hide show
  1. package/README.md +7 -1
  2. package/bin/cli.js +3 -4
  3. package/commands/accounts/list.js +18 -26
  4. package/commands/accounts/rename.js +13 -24
  5. package/commands/accounts.js +4 -1
  6. package/commands/auth.js +33 -16
  7. package/commands/config/set/allowUsageTracking.js +17 -33
  8. package/commands/config/set/defaultAccount.js +24 -34
  9. package/commands/config/set/defaultMode.js +25 -44
  10. package/commands/config/set/httpTimeout.js +10 -28
  11. package/commands/config/set.js +4 -1
  12. package/commands/config.js +4 -1
  13. package/commands/create/api-sample.js +20 -14
  14. package/commands/create/function.js +3 -1
  15. package/commands/create/index.js +0 -1
  16. package/commands/create/module.js +20 -7
  17. package/commands/create/template.js +22 -5
  18. package/commands/create/website-theme.js +12 -1
  19. package/commands/create.js +23 -8
  20. package/commands/customObject/create.js +22 -24
  21. package/commands/customObject/schema/create.js +30 -28
  22. package/commands/customObject/schema/delete.js +20 -20
  23. package/commands/customObject/schema/fetch-all.js +17 -24
  24. package/commands/customObject/schema/fetch.js +29 -24
  25. package/commands/customObject/schema/list.js +8 -17
  26. package/commands/customObject/schema/update.js +31 -29
  27. package/commands/customObject/schema.js +4 -1
  28. package/commands/customObject.js +10 -21
  29. package/commands/fetch.js +15 -30
  30. package/commands/filemanager/fetch.js +13 -25
  31. package/commands/filemanager/upload.js +47 -35
  32. package/commands/filemanager.js +4 -1
  33. package/commands/functions/deploy.js +34 -37
  34. package/commands/functions/list.js +9 -24
  35. package/commands/functions/server.js +13 -29
  36. package/commands/functions.js +4 -1
  37. package/commands/hubdb/clear.js +25 -21
  38. package/commands/hubdb/create.js +25 -22
  39. package/commands/hubdb/delete.js +19 -20
  40. package/commands/hubdb/fetch.js +15 -20
  41. package/commands/hubdb.js +4 -1
  42. package/commands/init.js +25 -13
  43. package/commands/lint.js +14 -23
  44. package/commands/list.js +19 -25
  45. package/commands/logs.js +23 -44
  46. package/commands/mv.js +21 -25
  47. package/commands/open.js +9 -7
  48. package/commands/project/create.js +26 -42
  49. package/commands/project/deploy.js +35 -36
  50. package/commands/project/listBuilds.js +160 -0
  51. package/commands/project/logs.js +87 -79
  52. package/commands/project/upload.js +74 -78
  53. package/commands/project/watch.js +103 -0
  54. package/commands/project.js +5 -6
  55. package/commands/remove.js +12 -20
  56. package/commands/sandbox/create.js +18 -13
  57. package/commands/secrets/addSecret.js +19 -22
  58. package/commands/secrets/deleteSecret.js +18 -21
  59. package/commands/secrets/listSecrets.js +10 -19
  60. package/commands/secrets/updateSecret.js +19 -22
  61. package/commands/secrets.js +4 -1
  62. package/commands/server.js +15 -6
  63. package/commands/{marketplaceValidate/validateTheme.js → theme/marketplace-validate.js} +26 -24
  64. package/commands/theme.js +5 -3
  65. package/commands/upload.js +66 -45
  66. package/commands/watch.js +33 -55
  67. package/lib/commonOpts.js +14 -11
  68. package/lib/enums/exitCodes.js +14 -0
  69. package/lib/links.js +0 -10
  70. package/lib/projects.js +121 -77
  71. package/lib/{createApiSamplePrompt.js → prompts/createApiSamplePrompt.js} +10 -11
  72. package/lib/{createFunctionPrompt.js → prompts/createFunctionPrompt.js} +27 -21
  73. package/lib/{createModulePrompt.js → prompts/createModulePrompt.js} +12 -9
  74. package/lib/prompts/createProjectPrompt.js +68 -0
  75. package/lib/{createTemplatePrompt.js → prompts/createTemplatePrompt.js} +7 -4
  76. package/lib/prompts/folderOverwritePrompt.js +17 -0
  77. package/lib/{prompts.js → prompts/personalAccessKeyPrompt.js} +25 -42
  78. package/lib/prompts/promptUtils.js +10 -0
  79. package/lib/prompts/sandboxesPrompt.js +24 -0
  80. package/lib/prompts/secretPrompt.js +25 -0
  81. package/lib/serverlessLogs.js +4 -3
  82. package/lib/ui.js +48 -0
  83. package/lib/validation.js +4 -3
  84. package/package.json +8 -7
  85. package/commands/app/deploy.js +0 -116
  86. package/commands/app.js +0 -14
  87. package/commands/create/project.js +0 -25
  88. package/lib/prompts/projects.js +0 -40
  89. package/lib/prompts/sandboxes.js +0 -22
  90. package/lib/secretPrompt.js +0 -22
package/lib/projects.js CHANGED
@@ -3,7 +3,6 @@ const path = require('path');
3
3
 
4
4
  const chalk = require('chalk');
5
5
  const findup = require('findup-sync');
6
- const { prompt } = require('inquirer');
7
6
  const Spinnies = require('spinnies');
8
7
  const { logger } = require('@hubspot/cli-lib/logger');
9
8
  const { getEnv } = require('@hubspot/cli-lib/lib/config');
@@ -11,12 +10,12 @@ const {
11
10
  createProject: createProjectTemplate,
12
11
  } = require('@hubspot/cli-lib/projects');
13
12
  const { getHubSpotWebsiteOrigin } = require('@hubspot/cli-lib/lib/urls');
14
-
15
13
  const {
16
14
  ENVIRONMENTS,
17
15
  POLLING_DELAY,
18
- PROJECT_TEMPLATE_REPO,
16
+ PROJECT_TEMPLATES,
19
17
  PROJECT_TEXT,
18
+ PROJECT_CONFIG_FILE,
20
19
  } = require('@hubspot/cli-lib/lib/constants');
21
20
  const {
22
21
  createProject,
@@ -28,6 +27,10 @@ const {
28
27
  logApiErrorInstance,
29
28
  ApiErrorContext,
30
29
  } = require('@hubspot/cli-lib/errorHandlers');
30
+ const { getCwd } = require('@hubspot/cli-lib/path');
31
+ const { promptUser } = require('./prompts/promptUtils');
32
+ const { EXIT_CODES } = require('./enums/exitCodes');
33
+ const { uiLine, uiAccountDescription } = require('../lib/ui');
31
34
 
32
35
  const PROJECT_STRINGS = {
33
36
  BUILD: {
@@ -37,6 +40,10 @@ const PROJECT_STRINGS = {
37
40
  } in this project ...\n`,
38
41
  SUCCESS: name => `Built ${chalk.bold(name)}`,
39
42
  FAIL: name => `Failed to build ${chalk.bold(name)}`,
43
+ SUBTASK_FAIL: (taskId, name) =>
44
+ `Build #${taskId} failed because there was a problem\nbuilding ${chalk.bold(
45
+ name
46
+ )}`,
40
47
  },
41
48
  DEPLOY: {
42
49
  INITIALIZE: (name, numOfComponents) =>
@@ -45,6 +52,10 @@ const PROJECT_STRINGS = {
45
52
  } in this project ...\n`,
46
53
  SUCCESS: name => `Deployed ${chalk.bold(name)}`,
47
54
  FAIL: name => `Failed to deploy ${chalk.bold(name)}`,
55
+ SUBTASK_FAIL: (taskId, name) =>
56
+ `Deploy for build #${taskId} failed because there was a\nproblem deploying ${chalk.bold(
57
+ name
58
+ )}`,
48
59
  },
49
60
  };
50
61
 
@@ -58,89 +69,93 @@ const writeProjectConfig = (configPath, config) => {
58
69
  }
59
70
  };
60
71
 
61
- const getProjectConfig = async projectPath => {
62
- const configPath = findup('hsproject.json', {
63
- cwd: projectPath,
72
+ const getIsInProject = async _dir => {
73
+ const configPath = await getProjectConfigPath(_dir);
74
+ return !!configPath;
75
+ };
76
+
77
+ const getProjectConfigPath = async _dir => {
78
+ const projectDir = _dir ? path.resolve(getCwd(), _dir) : getCwd();
79
+
80
+ const configPath = findup(PROJECT_CONFIG_FILE, {
81
+ cwd: projectDir,
64
82
  nocase: true,
65
83
  });
66
84
 
85
+ return configPath;
86
+ };
87
+
88
+ const getProjectConfig = async _dir => {
89
+ const configPath = await getProjectConfigPath(_dir);
67
90
  if (!configPath) {
68
- return null;
91
+ return { projectConfig: null, projectDir: null };
69
92
  }
70
93
 
71
94
  try {
72
- const projectConfig = fs.readFileSync(configPath);
73
- return JSON.parse(projectConfig);
95
+ const config = fs.readFileSync(configPath);
96
+ const projectConfig = JSON.parse(config);
97
+ return {
98
+ projectDir: path.dirname(configPath),
99
+ projectConfig,
100
+ };
74
101
  } catch (e) {
75
102
  logger.error('Could not read from project config');
76
103
  }
77
104
  };
78
105
 
79
- const createProjectConfig = async (projectPath, projectName) => {
80
- const projectConfig = await getProjectConfig(projectPath);
81
- const projectConfigPath = path.join(projectPath, 'hsproject.json');
106
+ const createProjectConfig = async (projectPath, projectName, template) => {
107
+ const { projectConfig, projectDir } = await getProjectConfig(projectPath);
82
108
 
83
109
  if (projectConfig) {
84
- logger.log(
85
- `Found an existing project config in this folder (${chalk.bold(
86
- projectConfig.name
87
- )})`
88
- );
89
- } else {
90
- logger.log(
91
- `Creating project in ${projectPath ? projectPath : 'the current folder'}`
110
+ logger.warn(
111
+ projectPath === projectDir
112
+ ? 'A project already exists in that location.'
113
+ : `Found an existing project definition in ${projectDir}.`
92
114
  );
93
- const { name, template, srcDir } = await prompt([
115
+
116
+ const { shouldContinue } = await promptUser([
94
117
  {
95
- name: 'name',
96
- message: 'Please enter a project name:',
97
- when: !projectName,
98
- validate: input => {
99
- if (!input) {
100
- return 'A project name is required';
101
- }
102
- return true;
118
+ name: 'shouldContinue',
119
+ message: () => {
120
+ return projectPath === projectDir
121
+ ? 'Do you want to overwrite the existing project definition with a new one?'
122
+ : `Continue creating a new project in ${projectPath}?`;
103
123
  },
104
- },
105
- {
106
- name: 'template',
107
- message: 'Start from a template?',
108
- type: 'rawlist',
109
- choices: [
110
- {
111
- name: 'No template',
112
- value: 'none',
113
- },
114
- {
115
- name: 'Getting Started Project',
116
- value: 'getting-started',
117
- },
118
- ],
124
+ type: 'confirm',
125
+ default: false,
119
126
  },
120
127
  ]);
121
128
 
122
- if (template === 'none') {
123
- fs.ensureDirSync(path.join(projectPath, 'src'));
124
-
125
- writeProjectConfig(projectConfigPath, {
126
- name: projectName || name,
127
- srcDir: 'src',
128
- });
129
- } else {
130
- await createProjectTemplate(
131
- projectPath,
132
- 'project',
133
- PROJECT_TEMPLATE_REPO[template],
134
- ''
135
- );
136
- const _config = JSON.parse(fs.readFileSync(projectConfigPath));
137
- writeProjectConfig(projectConfigPath, {
138
- ..._config,
139
- name: projectName || name,
140
- });
129
+ if (!shouldContinue) {
130
+ return;
141
131
  }
132
+ }
133
+
134
+ const projectConfigPath = path.join(projectPath, PROJECT_CONFIG_FILE);
135
+
136
+ logger.log(
137
+ `Creating project in ${projectPath ? projectPath : 'the current folder'}`
138
+ );
139
+
140
+ if (template === 'none') {
141
+ fs.ensureDirSync(path.join(projectPath, 'src'));
142
142
 
143
- return { name, srcDir };
143
+ writeProjectConfig(projectConfigPath, {
144
+ name: projectName,
145
+ srcDir: 'src',
146
+ });
147
+ } else {
148
+ await createProjectTemplate(
149
+ projectPath,
150
+ 'project',
151
+ PROJECT_TEMPLATES.find(t => t.name === template).repo,
152
+ ''
153
+ );
154
+ const _config = JSON.parse(fs.readFileSync(projectConfigPath));
155
+ writeProjectConfig(projectConfigPath, {
156
+ ..._config,
157
+ name: projectName,
158
+ });
144
159
  }
145
160
 
146
161
  return projectConfig;
@@ -149,23 +164,23 @@ const createProjectConfig = async (projectPath, projectName) => {
149
164
  const validateProjectConfig = (projectConfig, projectDir) => {
150
165
  if (!projectConfig) {
151
166
  logger.error(
152
- `Project config not found. Try running 'hs project init' first.`
167
+ `Project config not found. Try running 'hs project create' first.`
153
168
  );
154
- process.exit(1);
169
+ process.exit(EXIT_CODES.ERROR);
155
170
  }
156
171
 
157
172
  if (!projectConfig.name || !projectConfig.srcDir) {
158
173
  logger.error(
159
- 'Project config is missing required fields. Try running `hs project init`.'
174
+ 'Project config is missing required fields. Try running `hs project create`.'
160
175
  );
161
- process.exit(1);
176
+ process.exit(EXIT_CODES.ERROR);
162
177
  }
163
178
 
164
179
  if (!fs.existsSync(path.resolve(projectDir, projectConfig.srcDir))) {
165
180
  logger.error(
166
- `Project source directory '${projectConfig.srcDir}' does not exist.`
181
+ `Project source directory '${projectConfig.srcDir}' could not be found in ${projectDir}.`
167
182
  );
168
- process.exit(1);
183
+ process.exit(EXIT_CODES.ERROR);
169
184
  }
170
185
  };
171
186
 
@@ -177,10 +192,12 @@ const ensureProjectExists = async (accountId, projectName, forceCreate) => {
177
192
  let shouldCreateProject = forceCreate;
178
193
 
179
194
  if (!shouldCreateProject) {
180
- const promptResult = await prompt([
195
+ const promptResult = await promptUser([
181
196
  {
182
197
  name: 'shouldCreateProject',
183
- message: `The project ${projectName} does not exist in ${accountId}. Would you like to create it?`,
198
+ message: `The project ${projectName} does not exist in ${uiAccountDescription(
199
+ accountId
200
+ )}. Would you like to create it?`,
184
201
  type: 'confirm',
185
202
  },
186
203
  ]);
@@ -222,7 +239,7 @@ const showWelcomeMessage = () => {
222
239
  '\n-------------------------------------------------------------\n'
223
240
  );
224
241
  logger.log(chalk.bold("What's next?\n"));
225
- logger.log('🎨 Add deployables to your project with `hs create`.\n');
242
+ logger.log('🎨 Add components to your project with `hs create`.\n');
226
243
  logger.log(
227
244
  `🏗 Run \`hs project upload\` to upload your files to HubSpot and trigger builds.\n`
228
245
  );
@@ -264,6 +281,7 @@ const makeGetTaskStatus = taskType => {
264
281
  const spinnies = new Spinnies({
265
282
  succeedColor: 'white',
266
283
  failColor: 'white',
284
+ failPrefix: chalk.bold('!'),
267
285
  });
268
286
 
269
287
  spinnies.add('overallTaskStatus', { text: 'Beginning' });
@@ -309,12 +327,12 @@ const makeGetTaskStatus = taskType => {
309
327
  });
310
328
  break;
311
329
  case statusText.STATES.FAILURE:
312
- spinnies.fail(subTask.buildName, {
330
+ spinnies.fail(subTask[statusText.SUBTASK_NAME_KEY], {
313
331
  text: updatedText,
314
332
  });
315
333
  break;
316
334
  default:
317
- spinnies.update(subTask.buildName, {
335
+ spinnies.update(subTask[statusText.SUBTASK_NAME_KEY], {
318
336
  text: updatedText,
319
337
  });
320
338
  break;
@@ -322,8 +340,8 @@ const makeGetTaskStatus = taskType => {
322
340
  });
323
341
 
324
342
  if (isTaskComplete(taskStatus)) {
325
- subTaskStatus.forEach(subBuild => {
326
- spinnies.remove(subBuild[statusText.SUBTASK_NAME_KEY]);
343
+ subTaskStatus.forEach(subTask => {
344
+ spinnies.remove(subTask[statusText.SUBTASK_NAME_KEY]);
327
345
  });
328
346
 
329
347
  if (status === statusText.STATES.SUCCESS) {
@@ -334,6 +352,31 @@ const makeGetTaskStatus = taskType => {
334
352
  spinnies.fail('overallTaskStatus', {
335
353
  text: statusStrings.FAIL(taskName),
336
354
  });
355
+
356
+ const failedSubtask = subTaskStatus.filter(
357
+ subtask => subtask.status === 'FAILURE'
358
+ );
359
+
360
+ uiLine();
361
+ logger.log(
362
+ `${statusStrings.SUBTASK_FAIL(
363
+ buildId || taskId,
364
+ failedSubtask.length === 1
365
+ ? failedSubtask[0][statusText.SUBTASK_NAME_KEY]
366
+ : failedSubtask.length + ' components'
367
+ )}\n`
368
+ );
369
+ logger.log('See below for a summary of errors.');
370
+ uiLine();
371
+
372
+ failedSubtask.forEach(subTask => {
373
+ logger.log(
374
+ `\n--- ${chalk.bold(subTask[statusText.SUBTASK_NAME_KEY])} ${
375
+ statusText.STATUS_TEXT[subTask.status]
376
+ } with the following error ---`
377
+ );
378
+ logger.error(subTask.errorMessage);
379
+ });
337
380
  }
338
381
 
339
382
  clearInterval(pollInterval);
@@ -348,6 +391,7 @@ const makeGetTaskStatus = taskType => {
348
391
  module.exports = {
349
392
  writeProjectConfig,
350
393
  getProjectConfig,
394
+ getIsInProject,
351
395
  createProjectConfig,
352
396
  validateProjectConfig,
353
397
  showWelcomeMessage,
@@ -1,9 +1,12 @@
1
- const inquirer = require('inquirer');
1
+ const { promptUser } = require('./promptUtils');
2
+ const { i18n } = require('@hubspot/cli-lib/lib/lang');
3
+
4
+ const i18nKey = 'cli.lib.prompts.createApiSamplePrompt';
2
5
 
3
6
  const getSampleTypesPrompt = choices => ({
4
7
  type: 'rawlist',
5
8
  name: 'sampleType',
6
- message: 'Please, select API sample app',
9
+ message: i18n(`${i18nKey}.selectApiSampleApp`),
7
10
  choices: choices.map(choice => ({
8
11
  name: `${choice.name} - ${choice.description}`,
9
12
  value: choice.id,
@@ -13,7 +16,7 @@ const getSampleTypesPrompt = choices => ({
13
16
  if (input.length > 0) {
14
17
  resolve(true);
15
18
  }
16
- reject('Please select API sample app');
19
+ reject(i18n(`${i18nKey}.errors.apiSampleAppRequired`));
17
20
  });
18
21
  },
19
22
  });
@@ -21,7 +24,7 @@ const getSampleTypesPrompt = choices => ({
21
24
  const getLanguagesPrompt = choices => ({
22
25
  type: 'rawlist',
23
26
  name: 'sampleLanguage',
24
- message: "Please, select sample app's language",
27
+ message: i18n(`${i18nKey}.selectLanguage`),
25
28
  choices: choices.map(choice => ({
26
29
  name: choice,
27
30
  value: choice,
@@ -31,7 +34,7 @@ const getLanguagesPrompt = choices => ({
31
34
  if (input.length > 0) {
32
35
  resolve(true);
33
36
  }
34
- reject("Please select API sample app's language");
37
+ reject(i18n(`${i18nKey}.errors.languageRequired`));
35
38
  });
36
39
  },
37
40
  });
@@ -39,16 +42,12 @@ const getLanguagesPrompt = choices => ({
39
42
  const createApiSamplePrompt = async samplesConfig => {
40
43
  try {
41
44
  const { samples } = samplesConfig;
42
- const sampleTypeAnswer = await inquirer.prompt(
43
- getSampleTypesPrompt(samples)
44
- );
45
+ const sampleTypeAnswer = await promptUser(getSampleTypesPrompt(samples));
45
46
  const chosenSample = samples.find(
46
47
  sample => sample.id === sampleTypeAnswer.sampleType
47
48
  );
48
49
  const { languages } = chosenSample;
49
- const languagesAnswer = await inquirer.prompt(
50
- getLanguagesPrompt(languages)
51
- );
50
+ const languagesAnswer = await promptUser(getLanguagesPrompt(languages));
52
51
  return {
53
52
  ...sampleTypeAnswer,
54
53
  ...languagesAnswer,
@@ -1,66 +1,72 @@
1
- const inquirer = require('inquirer');
1
+ const { promptUser } = require('./promptUtils');
2
+ const { i18n } = require('@hubspot/cli-lib/lib/lang');
2
3
 
3
- const { STRING_WITH_NO_SPACES_REGEX } = require('./regex');
4
+ const { STRING_WITH_NO_SPACES_REGEX } = require('../regex');
5
+
6
+ const i18nKey = 'cli.lib.prompts.createFunctionPrompt';
4
7
 
5
8
  const FUNCTIONS_FOLDER_PROMPT = {
6
9
  name: 'functionsFolder',
7
- message: 'Name of the folder where your function will be created',
10
+ message: i18n(`${i18nKey}.enterFolder`),
8
11
  validate(val) {
9
12
  if (typeof val !== 'string') {
10
- return 'You entered an invalid name. Please try again.';
13
+ return i18n(`${i18nKey}.errors.invalid`);
11
14
  } else if (!val.length) {
12
- return 'The name may not be blank. Please try again.';
15
+ return i18n(`${i18nKey}.errors.blank`);
13
16
  } else if (!STRING_WITH_NO_SPACES_REGEX.test(val)) {
14
- return 'The name may not contain spaces. Please try again.';
17
+ return i18n(`${i18nKey}.errors.space`);
15
18
  }
16
19
  return true;
17
20
  },
18
21
  };
19
- const ENDPOINT_PATH_PROMPT = {
20
- name: 'endpointPath',
21
- message: 'Path portion of the URL created for the function',
22
+
23
+ const FUNCTION_FILENAME_PROMPT = {
24
+ name: 'filename',
25
+ message: i18n(`${i18nKey}.enterFilename`),
22
26
  validate(val) {
23
27
  if (typeof val !== 'string') {
24
- return 'You entered an invalid name. Please try again.';
28
+ return i18n(`${i18nKey}.errors.invalid`);
25
29
  } else if (!val.length) {
26
- return 'The name may not be blank. Please try again.';
30
+ return i18n(`${i18nKey}.errors.blank`);
27
31
  } else if (!STRING_WITH_NO_SPACES_REGEX.test(val)) {
28
- return 'The name may not contain spaces. Please try again.';
32
+ return i18n(`${i18nKey}.errors.space`);
29
33
  }
30
34
  return true;
31
35
  },
32
36
  };
37
+
33
38
  const ENDPOINT_METHOD_PROMPT = {
34
39
  type: 'list',
35
40
  name: 'endpointMethod',
36
- message: 'Select the HTTP method for the endpoint',
41
+ message: i18n(`${i18nKey}.selectEndpointMethod`),
37
42
  default: 'GET',
38
43
  choices: ['DELETE', 'GET', 'PATCH', 'POST', 'PUT'],
39
44
  };
40
- const FUNCTION_FILENAME_PROMPT = {
41
- name: 'filename',
42
- message: 'Name of the JavaScript file for your function',
45
+
46
+ const ENDPOINT_PATH_PROMPT = {
47
+ name: 'endpointPath',
48
+ message: i18n(`${i18nKey}.enterEndpointPath`),
43
49
  validate(val) {
44
50
  if (typeof val !== 'string') {
45
- return 'You entered an invalid name. Please try again.';
51
+ return i18n(`${i18nKey}.errors.invalid`);
46
52
  } else if (!val.length) {
47
- return 'The name may not be blank. Please try again.';
53
+ return i18n(`${i18nKey}.errors.blank`);
48
54
  } else if (!STRING_WITH_NO_SPACES_REGEX.test(val)) {
49
- return 'The name may not contain spaces. Please try again.';
55
+ return i18n(`${i18nKey}.errors.space`);
50
56
  }
51
57
  return true;
52
58
  },
53
59
  };
54
60
 
55
61
  function createFunctionPrompt() {
56
- const prompt = inquirer.createPromptModule();
57
- return prompt([
62
+ return promptUser([
58
63
  FUNCTIONS_FOLDER_PROMPT,
59
64
  FUNCTION_FILENAME_PROMPT,
60
65
  ENDPOINT_METHOD_PROMPT,
61
66
  ENDPOINT_PATH_PROMPT,
62
67
  ]);
63
68
  }
69
+
64
70
  module.exports = {
65
71
  createFunctionPrompt,
66
72
  };
@@ -1,13 +1,16 @@
1
- const inquirer = require('inquirer');
1
+ const { promptUser } = require('./promptUtils');
2
+ const { i18n } = require('@hubspot/cli-lib/lib/lang');
3
+
4
+ const i18nKey = 'cli.lib.prompts.createModulePrompt';
2
5
 
3
6
  const MODULE_LABEL_PROMPT = {
4
7
  name: 'moduleLabel',
5
- message: 'What should the module label be?',
8
+ message: i18n(`${i18nKey}.enterLabel`),
6
9
  validate(val) {
7
10
  if (typeof val !== 'string') {
8
- return 'You entered an invalid name. Please try again.';
11
+ return i18n(`${i18nKey}.errors.invalidLabel`);
9
12
  } else if (!val.length) {
10
- return 'The name may not be blank. Please try again.';
13
+ return i18n(`${i18nKey}.errors.labelRequired`);
11
14
  }
12
15
  return true;
13
16
  },
@@ -15,7 +18,7 @@ const MODULE_LABEL_PROMPT = {
15
18
  const CONTENT_TYPES_PROMPT = {
16
19
  type: 'checkbox',
17
20
  name: 'contentTypes',
18
- message: 'What types of content will this module be used in?',
21
+ message: i18n(`${i18nKey}.selectContentType`),
19
22
  default: ['PAGE'],
20
23
  choices: [
21
24
  { name: 'Page', value: 'PAGE' },
@@ -28,7 +31,7 @@ const CONTENT_TYPES_PROMPT = {
28
31
  if (input.length > 0) {
29
32
  resolve(true);
30
33
  }
31
- reject('Please select at least one content type for this module.');
34
+ reject(i18n(`${i18nKey}.errors.contentTypeRequired`));
32
35
  });
33
36
  },
34
37
  };
@@ -36,14 +39,14 @@ const CONTENT_TYPES_PROMPT = {
36
39
  const GLOBAL_PROMPT = {
37
40
  type: 'confirm',
38
41
  name: 'global',
39
- message: 'Is this a global module?',
42
+ message: i18n(`${i18nKey}.confirmGlobal`),
40
43
  default: false,
41
44
  };
42
45
 
43
46
  function createModulePrompt() {
44
- const prompt = inquirer.createPromptModule();
45
- return prompt([MODULE_LABEL_PROMPT, CONTENT_TYPES_PROMPT, GLOBAL_PROMPT]);
47
+ return promptUser([MODULE_LABEL_PROMPT, CONTENT_TYPES_PROMPT, GLOBAL_PROMPT]);
46
48
  }
49
+
47
50
  module.exports = {
48
51
  createModulePrompt,
49
52
  };
@@ -0,0 +1,68 @@
1
+ const path = require('path');
2
+ const { getCwd } = require('@hubspot/cli-lib/path');
3
+ const { PROJECT_TEMPLATES } = require('@hubspot/cli-lib/lib/constants');
4
+ const { promptUser } = require('./promptUtils');
5
+ const { i18n } = require('@hubspot/cli-lib/lib/lang');
6
+
7
+ const i18nKey = 'cli.lib.prompts.createProjectPrompt';
8
+
9
+ const createProjectPrompt = (promptOptions = {}) => {
10
+ return promptUser([
11
+ {
12
+ name: 'name',
13
+ message: i18n(`${i18nKey}.enterName`),
14
+ when: !promptOptions.name,
15
+ validate: input => {
16
+ if (!input) {
17
+ return i18n(`${i18nKey}.errors.nameRequired`);
18
+ }
19
+ return true;
20
+ },
21
+ },
22
+ {
23
+ name: 'location',
24
+ message: i18n(`${i18nKey}.enterLocation`),
25
+ when: !promptOptions.location,
26
+ default: answers => {
27
+ return path.resolve(getCwd(), answers.name || promptOptions.name);
28
+ },
29
+ validate: input => {
30
+ if (!input) {
31
+ return i18n(`${i18nKey}.errors.locationRequired`);
32
+ }
33
+ return true;
34
+ },
35
+ },
36
+ {
37
+ name: 'template',
38
+ message: () => {
39
+ return promptOptions.template &&
40
+ !PROJECT_TEMPLATES.find(t => t.name === promptOptions.template)
41
+ ? i18n(`${i18nKey}.errors.invalidTemplate`, {
42
+ template: promptOptions.template,
43
+ })
44
+ : i18n(`${i18nKey}.selectTemplate`);
45
+ },
46
+ when:
47
+ !promptOptions.template ||
48
+ !PROJECT_TEMPLATES.find(t => t.name === promptOptions.template),
49
+ type: 'list',
50
+ choices: [
51
+ {
52
+ name: i18n(`${i18nKey}.templateOptions.noTemplate`),
53
+ value: 'none',
54
+ },
55
+ ...PROJECT_TEMPLATES.map(template => {
56
+ return {
57
+ name: template.label,
58
+ value: template.name,
59
+ };
60
+ }),
61
+ ],
62
+ },
63
+ ]);
64
+ };
65
+
66
+ module.exports = {
67
+ createProjectPrompt,
68
+ };
@@ -1,9 +1,12 @@
1
- const inquirer = require('inquirer');
1
+ const { promptUser } = require('./promptUtils');
2
+ const { i18n } = require('@hubspot/cli-lib/lib/lang');
3
+
4
+ const i18nKey = 'cli.lib.prompts.createTemplatePrompt';
2
5
 
3
6
  const TEMPLATE_TYPE_PROMPT = {
4
7
  type: 'list',
5
8
  name: 'templateType',
6
- message: 'Select the type of template to create',
9
+ message: i18n(`${i18nKey}.selectTemplate`),
7
10
  default: 'page',
8
11
  choices: [
9
12
  { name: 'page', value: 'page-template' },
@@ -17,9 +20,9 @@ const TEMPLATE_TYPE_PROMPT = {
17
20
  };
18
21
 
19
22
  function createTemplatePrompt() {
20
- const prompt = inquirer.createPromptModule();
21
- return prompt([TEMPLATE_TYPE_PROMPT]);
23
+ return promptUser([TEMPLATE_TYPE_PROMPT]);
22
24
  }
25
+
23
26
  module.exports = {
24
27
  createTemplatePrompt,
25
28
  };
@@ -0,0 +1,17 @@
1
+ const { promptUser } = require('./promptUtils');
2
+ const { i18n } = require('@hubspot/cli-lib/lib/lang');
3
+
4
+ const i18nKey = 'cli.lib.prompts.folderOverwritePrompt';
5
+
6
+ const folderOverwritePrompt = folderName => {
7
+ return promptUser({
8
+ type: 'confirm',
9
+ name: 'overwrite',
10
+ message: i18n(`${i18nKey}.overwriteConfirm`, { folderName }),
11
+ default: false,
12
+ });
13
+ };
14
+
15
+ module.exports = {
16
+ folderOverwritePrompt,
17
+ };