@hubspot/cli 4.0.1-beta.4 → 4.0.2-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/cli.js CHANGED
@@ -35,6 +35,7 @@ const moduleCommand = require('../commands/module');
35
35
  const configCommand = require('../commands/config');
36
36
  const accountsCommand = require('../commands/accounts');
37
37
  const sandboxesCommand = require('../commands/sandbox');
38
+ const processCommand = require('../commands/process');
38
39
  const cmsCommand = require('../commands/cms');
39
40
  const { EXIT_CODES } = require('../lib/enums/exitCodes');
40
41
 
@@ -154,6 +155,7 @@ const argv = yargs
154
155
  .command(configCommand)
155
156
  .command(accountsCommand)
156
157
  .command(sandboxesCommand)
158
+ .command(processCommand, false)
157
159
  .help()
158
160
  .recommendCommands()
159
161
  .demandCommand(1, '')
@@ -49,7 +49,10 @@ const selectTheme = async accountId => {
49
49
  message: i18n(`${i18nKey}.info.promptMessage`),
50
50
  choices: async () => {
51
51
  try {
52
- const result = await fetchThemes(accountId);
52
+ const result = await fetchThemes(accountId, {
53
+ limit: 500,
54
+ sorting: 'MOST_USED',
55
+ });
53
56
  if (result && result.objects) {
54
57
  return result.objects
55
58
  .map(({ theme }) => theme.path)
package/commands/init.js CHANGED
@@ -8,6 +8,7 @@ const {
8
8
  } = require('@hubspot/cli-lib/lib/config');
9
9
  const { addConfigOptions } = require('../lib/commonOpts');
10
10
  const { handleExit } = require('@hubspot/cli-lib/lib/process');
11
+ const { checkAndUpdateGitignore } = require('@hubspot/cli-lib/lib/git');
11
12
  const { logErrorInstance } = require('@hubspot/cli-lib/errorHandlers');
12
13
  const {
13
14
  DEFAULT_HUBSPOT_CONFIG_YAML_FILE_NAME,
@@ -116,6 +117,8 @@ exports.handler = async options => {
116
117
  );
117
118
  const configPath = getConfigPath();
118
119
 
120
+ checkAndUpdateGitignore(configPath);
121
+
119
122
  logger.log('');
120
123
  logger.success(
121
124
  i18n(`${i18nKey}.success.configFileCreated`, {
@@ -0,0 +1,85 @@
1
+ const path = require('path');
2
+ const fs = require('fs');
3
+ const { createIgnoreFilter } = require('@hubspot/cli-lib/ignoreRules');
4
+ const { isAllowedExtension } = require('@hubspot/cli-lib//path');
5
+ const { logger } = require('@hubspot/cli-lib/logger');
6
+ const { walk } = require('@hubspot/cli-lib/lib/walk');
7
+ const { getThemeJSONPath } = require('@hubspot/cli-lib/lib/files');
8
+ const { i18n } = require('@hubspot/cli-lib/lib/lang');
9
+ const {
10
+ FieldsJs,
11
+ isProcessableFieldsJs,
12
+ } = require('@hubspot/cli-lib/lib/handleFieldsJs');
13
+ const i18nKey = 'cli.commands.process';
14
+
15
+ exports.command = 'process';
16
+ exports.describe = false;
17
+
18
+ const invalidPath = src => {
19
+ logger.error(
20
+ i18n(`${i18nKey}.errors.invalidPath`, {
21
+ path: src,
22
+ })
23
+ );
24
+ };
25
+
26
+ exports.handler = async options => {
27
+ const src = options.src;
28
+ const projectRoot = path.dirname(getThemeJSONPath(src));
29
+ let stats;
30
+ try {
31
+ stats = fs.statSync(src);
32
+ if (!stats.isFile() && !stats.isDirectory()) {
33
+ invalidPath(src);
34
+ return;
35
+ }
36
+ } catch (e) {
37
+ invalidPath(src);
38
+ }
39
+
40
+ if (stats.isFile()) {
41
+ const fieldsJs = await new FieldsJs(
42
+ projectRoot,
43
+ src,
44
+ undefined,
45
+ options.fieldOptions
46
+ ).init();
47
+ if (fieldsJs.rejected) return;
48
+ fieldsJs.saveOutput();
49
+ } else if (stats.isDirectory()) {
50
+ const filePaths = await walk(src);
51
+ const allowedFilePaths = filePaths
52
+ .filter(file => {
53
+ if (!isAllowedExtension(file)) {
54
+ return false;
55
+ }
56
+ return true;
57
+ })
58
+ .filter(createIgnoreFilter());
59
+ for (const filePath of allowedFilePaths) {
60
+ if (isProcessableFieldsJs(projectRoot, filePath, true)) {
61
+ const fieldsJs = await new FieldsJs(
62
+ projectRoot,
63
+ filePath,
64
+ undefined,
65
+ options.fieldOptions
66
+ ).init();
67
+ if (fieldsJs.rejected) return;
68
+ fieldsJs.saveOutput();
69
+ }
70
+ }
71
+ }
72
+ };
73
+
74
+ exports.builder = yargs => {
75
+ yargs.positional('src', {
76
+ describe: i18n(`${i18nKey}.positionals.src.describe`),
77
+ type: 'string',
78
+ });
79
+ yargs.option('fieldOptions', {
80
+ describe: i18n(`${i18nKey}.options.options.describe`),
81
+ type: 'array',
82
+ default: [''],
83
+ });
84
+ return yargs;
85
+ };
@@ -13,6 +13,9 @@ const { loadAndValidateOptions } = require('../../lib/validation');
13
13
  const { createSandboxPrompt } = require('../../lib/prompts/sandboxesPrompt');
14
14
  const { i18n } = require('@hubspot/cli-lib/lib/lang');
15
15
  const { logErrorInstance } = require('@hubspot/cli-lib/errorHandlers');
16
+ const {
17
+ debugErrorAndContext,
18
+ } = require('@hubspot/cli-lib/errorHandlers/standardErrors');
16
19
  const {
17
20
  ENVIRONMENTS,
18
21
  PERSONAL_ACCESS_KEY_AUTH_METHOD,
@@ -103,7 +106,7 @@ const personalAccessKeyFlow = async (env, account, name) => {
103
106
  ]);
104
107
  };
105
108
 
106
- exports.command = 'create [name]';
109
+ exports.command = 'create [--name]';
107
110
  exports.describe = i18n(`${i18nKey}.describe`);
108
111
 
109
112
  exports.handler = async options => {
@@ -117,10 +120,10 @@ exports.handler = async options => {
117
120
  succeedColor: 'white',
118
121
  });
119
122
 
120
- let namePrompt;
121
-
122
123
  trackCommandUsage('sandbox-create', {}, accountId);
123
124
 
125
+ let namePrompt;
126
+
124
127
  if (!name) {
125
128
  namePrompt = await createSandboxPrompt();
126
129
  }
@@ -146,11 +149,16 @@ exports.handler = async options => {
146
149
  }),
147
150
  });
148
151
  } catch (err) {
152
+ debugErrorAndContext(err);
153
+
154
+ trackCommandUsage('sandbox-create', { success: false }, accountId);
155
+
149
156
  spinnies.fail('sandboxCreate', {
150
157
  text: i18n(`${i18nKey}.loading.fail`, {
151
158
  sandboxName,
152
159
  }),
153
160
  });
161
+
154
162
  if (isMissingScopeError(err)) {
155
163
  logger.error(
156
164
  i18n(`${i18nKey}.failure.scopes.message`, {
@@ -180,13 +188,16 @@ exports.handler = async options => {
180
188
  };
181
189
 
182
190
  exports.builder = yargs => {
183
- yargs.positional('name', {
184
- describe: i18n(`${i18nKey}.positionals.name.describe`),
191
+ yargs.option('name', {
192
+ describe: i18n(`${i18nKey}.options.name.describe`),
185
193
  type: 'string',
186
194
  });
187
195
 
188
196
  yargs.example([
189
- ['$0 sandbox create MySandboxAccount', i18n(`${i18nKey}.examples.default`)],
197
+ [
198
+ '$0 sandbox create --name=MySandboxAccount',
199
+ i18n(`${i18nKey}.examples.default`),
200
+ ],
190
201
  ]);
191
202
 
192
203
  addConfigOptions(yargs, true);
@@ -8,12 +8,17 @@ const {
8
8
  const { logger } = require('@hubspot/cli-lib/logger');
9
9
  const { trackCommandUsage } = require('../../lib/usageTracking');
10
10
  const { loadAndValidateOptions } = require('../../lib/validation');
11
+ const {
12
+ debugErrorAndContext,
13
+ } = require('@hubspot/cli-lib/errorHandlers/standardErrors');
11
14
 
12
15
  const { deleteSandbox } = require('@hubspot/cli-lib/sandboxes');
13
16
  const { i18n } = require('@hubspot/cli-lib/lib/lang');
14
17
  const { getConfig, getEnv } = require('@hubspot/cli-lib');
15
18
  const { deleteSandboxPrompt } = require('../../lib/prompts/sandboxesPrompt');
16
- const { removeAccountFromConfig } = require('@hubspot/cli-lib/lib/config');
19
+ const {
20
+ removeSandboxAccountFromConfig,
21
+ } = require('@hubspot/cli-lib/lib/config');
17
22
  const {
18
23
  selectAndSetAsDefaultAccountPrompt,
19
24
  } = require('../../lib/prompts/accountsPrompt');
@@ -111,12 +116,18 @@ exports.handler = async options => {
111
116
  );
112
117
  logger.log('');
113
118
 
114
- const promptDefaultAccount = removeAccountFromConfig(sandboxAccountId);
119
+ const promptDefaultAccount = removeSandboxAccountFromConfig(
120
+ sandboxAccountId
121
+ );
115
122
  if (promptDefaultAccount) {
116
123
  await selectAndSetAsDefaultAccountPrompt(config);
117
124
  }
118
125
  process.exit(EXIT_CODES.SUCCESS);
119
126
  } catch (err) {
127
+ debugErrorAndContext(err);
128
+
129
+ trackCommandUsage('sandbox-delete', { success: false }, sandboxAccountId);
130
+
120
131
  if (
121
132
  err.error &&
122
133
  err.error.category === OBJECT_NOT_FOUND &&
@@ -130,7 +141,9 @@ exports.handler = async options => {
130
141
  );
131
142
  logger.log('');
132
143
 
133
- const promptDefaultAccount = removeAccountFromConfig(sandboxAccountId);
144
+ const promptDefaultAccount = removeSandboxAccountFromConfig(
145
+ sandboxAccountId
146
+ );
134
147
  if (promptDefaultAccount) {
135
148
  await selectAndSetAsDefaultAccountPrompt(config);
136
149
  }
@@ -1,6 +1,5 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
-
4
3
  const { uploadFolder, hasUploadErrors } = require('@hubspot/cli-lib');
5
4
  const { getFileMapperQueryValues } = require('@hubspot/cli-lib/fileMapper');
6
5
  const { upload } = require('@hubspot/cli-lib/api/fileMapper');
@@ -29,11 +28,18 @@ const {
29
28
  const { uploadPrompt } = require('../lib/prompts/uploadPrompt');
30
29
  const { validateMode, loadAndValidateOptions } = require('../lib/validation');
31
30
  const { trackCommandUsage } = require('../lib/usageTracking');
32
- const { getThemePreviewUrl } = require('@hubspot/cli-lib/lib/files');
31
+ const {
32
+ getThemePreviewUrl,
33
+ getThemeJSONPath,
34
+ } = require('@hubspot/cli-lib/lib/files');
33
35
  const { i18n } = require('@hubspot/cli-lib/lib/lang');
34
-
35
36
  const i18nKey = 'cli.commands.upload';
36
37
  const { EXIT_CODES } = require('../lib/enums/exitCodes');
38
+ const {
39
+ FieldsJs,
40
+ isProcessableFieldsJs,
41
+ cleanupTmpDirSync,
42
+ } = require('@hubspot/cli-lib/lib/handleFieldsJs');
37
43
 
38
44
  exports.command = 'upload [--src] [--dest]';
39
45
  exports.describe = i18n(`${i18nKey}.describe`);
@@ -61,11 +67,34 @@ exports.handler = async options => {
61
67
  const mode = getMode(options);
62
68
 
63
69
  const uploadPromptAnswers = await uploadPrompt(options);
64
-
65
70
  const src = options.src || uploadPromptAnswers.src;
66
- const dest = options.dest || uploadPromptAnswers.dest;
67
-
68
- const absoluteSrcPath = path.resolve(getCwd(), src);
71
+ const saveOutput = options.saveOutput;
72
+ let dest = options.dest || uploadPromptAnswers.dest;
73
+ let absoluteSrcPath = path.resolve(getCwd(), src);
74
+ if (!dest) {
75
+ logger.error(i18n(`${i18nKey}.errors.destinationRequired`));
76
+ return;
77
+ }
78
+ // The theme.json file must always be at the root of the project - so we look for that and determine the root path based on it.
79
+ const projectRoot = path.dirname(getThemeJSONPath(absoluteSrcPath));
80
+ const processFieldsJs = isProcessableFieldsJs(
81
+ projectRoot,
82
+ absoluteSrcPath,
83
+ options.processFieldsJs
84
+ );
85
+ let fieldsJs;
86
+ if (processFieldsJs) {
87
+ fieldsJs = await new FieldsJs(
88
+ projectRoot,
89
+ absoluteSrcPath,
90
+ undefined,
91
+ options.fieldOptions
92
+ ).init();
93
+ if (fieldsJs.rejected) return;
94
+ // Ensures that the dest path is a .json. The user might pass '.js' accidentally - this ensures it just works.
95
+ absoluteSrcPath = fieldsJs.outputPath;
96
+ dest = path.join(path.dirname(dest), 'fields.json');
97
+ }
69
98
  let stats;
70
99
  try {
71
100
  stats = fs.statSync(absoluteSrcPath);
@@ -86,10 +115,6 @@ exports.handler = async options => {
86
115
  return;
87
116
  }
88
117
 
89
- if (!dest) {
90
- logger.error(i18n(`${i18nKey}.errors.destinationRequired`));
91
- return;
92
- }
93
118
  const normalizedDest = convertToUnixPath(dest);
94
119
  trackCommandUsage(
95
120
  'upload',
@@ -106,7 +131,7 @@ exports.handler = async options => {
106
131
  process.exit(EXIT_CODES.WARNING);
107
132
  }
108
133
  if (stats.isFile()) {
109
- if (!isAllowedExtension(src)) {
134
+ if (!isAllowedExtension(src) && !processFieldsJs) {
110
135
  logger.error(
111
136
  i18n(`${i18nKey}.errors.invalidPath`, {
112
137
  path: src,
@@ -123,7 +148,6 @@ exports.handler = async options => {
123
148
  );
124
149
  return;
125
150
  }
126
-
127
151
  upload(
128
152
  accountId,
129
153
  absoluteSrcPath,
@@ -156,6 +180,13 @@ exports.handler = async options => {
156
180
  })
157
181
  );
158
182
  process.exit(EXIT_CODES.WARNING);
183
+ })
184
+ .finally(() => {
185
+ if (!processFieldsJs) return;
186
+ if (saveOutput) {
187
+ fieldsJs.saveOutput();
188
+ }
189
+ cleanupTmpDirSync(fieldsJs.rootWriteDir);
159
190
  });
160
191
  } else {
161
192
  logger.log(
@@ -165,9 +196,15 @@ exports.handler = async options => {
165
196
  src,
166
197
  })
167
198
  );
168
- uploadFolder(accountId, absoluteSrcPath, dest, {
169
- mode,
170
- })
199
+ uploadFolder(
200
+ accountId,
201
+ absoluteSrcPath,
202
+ dest,
203
+ {
204
+ mode,
205
+ },
206
+ options
207
+ )
171
208
  .then(results => {
172
209
  if (!hasUploadErrors(results)) {
173
210
  logger.success(
@@ -214,5 +251,24 @@ exports.builder = yargs => {
214
251
  describe: i18n(`${i18nKey}.positionals.dest.describe`),
215
252
  type: 'string',
216
253
  });
254
+ yargs.option('fieldOptions', {
255
+ describe: i18n(`${i18nKey}.options.options.describe`),
256
+ type: 'array',
257
+ default: [''],
258
+ hidden: true,
259
+ });
260
+ yargs.option('saveOutput', {
261
+ describe: i18n(`${i18nKey}.options.saveOutput.describe`),
262
+ type: 'boolean',
263
+ default: false,
264
+ hidden: true,
265
+ });
266
+ yargs.option('processFieldsJs', {
267
+ describe: i18n(`${i18nKey}.options.processFields.describe`),
268
+ alias: ['processFields'],
269
+ type: 'boolean',
270
+ default: false,
271
+ hidden: true,
272
+ });
217
273
  return yargs;
218
274
  };
package/commands/watch.js CHANGED
@@ -82,6 +82,7 @@ exports.handler = async options => {
82
82
  remove,
83
83
  disableInitial: initialUpload ? false : true,
84
84
  notify,
85
+ commandOptions: options,
85
86
  });
86
87
  };
87
88
 
@@ -99,6 +100,12 @@ exports.builder = yargs => {
99
100
  describe: i18n(`${i18nKey}.positionals.dest.describe`),
100
101
  type: 'string',
101
102
  });
103
+ yargs.option('fieldOptions', {
104
+ describe: i18n(`${i18nKey}.options.options.describe`),
105
+ type: 'array',
106
+ default: [''],
107
+ hidden: true,
108
+ });
102
109
  yargs.option('remove', {
103
110
  alias: 'r',
104
111
  describe: i18n(`${i18nKey}.options.remove.describe`),
@@ -121,6 +128,18 @@ exports.builder = yargs => {
121
128
  type: 'string',
122
129
  requiresArg: true,
123
130
  });
124
-
131
+ yargs.option('processFieldsJs', {
132
+ describe: i18n(`${i18nKey}.options.processFields.describe`),
133
+ alias: ['processFields'],
134
+ type: 'boolean',
135
+ default: false,
136
+ hidden: true,
137
+ });
138
+ yargs.option('saveOutput', {
139
+ describe: i18n(`${i18nKey}.options.saveOutput.describe`),
140
+ type: 'boolean',
141
+ default: false,
142
+ hidden: true,
143
+ });
125
144
  return yargs;
126
145
  };
package/lib/projects.js CHANGED
@@ -224,6 +224,13 @@ const getProjectBuildDetailUrl = (projectName, buildId, accountId) => {
224
224
  return `${getProjectDetailUrl(projectName, accountId)}/build/${buildId}`;
225
225
  };
226
226
 
227
+ const getProjectDeployDetailUrl = (projectName, deployId, accountId) => {
228
+ if (!projectName || !deployId || !accountId) return;
229
+ return `${getProjectDetailUrl(
230
+ projectName,
231
+ accountId
232
+ )}/activity/deploy/${deployId}`;
233
+ };
227
234
  const uploadProjectFiles = async (accountId, projectName, filePath) => {
228
235
  const i18nKey = 'cli.commands.project.subcommands.upload';
229
236
  const spinnies = new Spinnies({
@@ -343,10 +350,13 @@ const makePollTaskStatusFunc = ({
343
350
  }
344
351
  };
345
352
 
346
- return async (accountId, taskName, taskId) => {
347
- let hubspotLinkText = '';
353
+ return async (accountId, taskName, taskId, deployedBuildId = null) => {
354
+ const displayId = deployedBuildId || taskId;
355
+
348
356
  if (linkToHubSpot) {
349
- logger.log(`\n${linkToHubSpot(taskName, taskId, accountId)}\n`);
357
+ logger.log(
358
+ `\n${linkToHubSpot(accountId, taskName, taskId, deployedBuildId)}\n`
359
+ );
350
360
  }
351
361
 
352
362
  const spinnies = new Spinnies({
@@ -372,7 +382,7 @@ const makePollTaskStatusFunc = ({
372
382
  const subTaskName = subTask[statusText.SUBTASK_NAME_KEY];
373
383
 
374
384
  spinnies.add(subTaskName, {
375
- text: `${chalk.bold(subTaskName)} #${taskId} ${
385
+ text: `${chalk.bold(subTaskName)} #${displayId} ${
376
386
  statusText.STATUS_TEXT[statusText.STATES.ENQUEUED]
377
387
  }\n`,
378
388
  indent: 2,
@@ -395,7 +405,7 @@ const makePollTaskStatusFunc = ({
395
405
  return;
396
406
  }
397
407
 
398
- const updatedText = `${chalk.bold(subTaskName)} #${taskId} ${
408
+ const updatedText = `${chalk.bold(subTaskName)} #${displayId} ${
399
409
  statusText.STATUS_TEXT[subTask.status]
400
410
  }\n`;
401
411
 
@@ -413,17 +423,17 @@ const makePollTaskStatusFunc = ({
413
423
  });
414
424
 
415
425
  if (isTaskComplete(taskStatus)) {
416
- subTaskStatus.forEach(subTask => {
417
- spinnies.remove(subTask[statusText.SUBTASK_NAME_KEY]);
418
- });
426
+ // subTaskStatus.forEach(subTask => {
427
+ // spinnies.remove(subTask[statusText.SUBTASK_NAME_KEY]);
428
+ // });
419
429
 
420
430
  if (status === statusText.STATES.SUCCESS) {
421
431
  spinnies.succeed('overallTaskStatus', {
422
- text: `${statusStrings.SUCCESS(taskName)}${hubspotLinkText}`,
432
+ text: statusStrings.SUCCESS(taskName),
423
433
  });
424
434
  } else if (status === statusText.STATES.FAILURE) {
425
435
  spinnies.fail('overallTaskStatus', {
426
- text: `${statusStrings.FAIL(taskName)}${hubspotLinkText}`,
436
+ text: statusStrings.FAIL(taskName),
427
437
  });
428
438
 
429
439
  const failedSubtask = subTaskStatus.filter(
@@ -433,7 +443,7 @@ const makePollTaskStatusFunc = ({
433
443
  uiLine();
434
444
  logger.log(
435
445
  `${statusStrings.SUBTASK_FAIL(
436
- taskId,
446
+ displayId,
437
447
  failedSubtask.length === 1
438
448
  ? failedSubtask[0][statusText.SUBTASK_NAME_KEY]
439
449
  : failedSubtask.length + ' components'
@@ -470,10 +480,10 @@ const makePollTaskStatusFunc = ({
470
480
  };
471
481
 
472
482
  const pollBuildStatus = makePollTaskStatusFunc({
473
- linkToHubSpot: (projectName, buildId, accountId) =>
483
+ linkToHubSpot: (accountId, taskName, taskId) =>
474
484
  uiLink(
475
- `View build #${buildId} in HubSpot`,
476
- getProjectBuildDetailUrl(projectName, buildId, accountId)
485
+ `View build #${taskId} in HubSpot`,
486
+ getProjectBuildDetailUrl(taskName, taskId, accountId)
477
487
  ),
478
488
  statusFn: getBuildStatus,
479
489
  statusText: PROJECT_BUILD_TEXT,
@@ -481,22 +491,27 @@ const pollBuildStatus = makePollTaskStatusFunc({
481
491
  INITIALIZE: name => `Building ${chalk.bold(name)}`,
482
492
  SUCCESS: name => `Built ${chalk.bold(name)}`,
483
493
  FAIL: name => `Failed to build ${chalk.bold(name)}`,
484
- SUBTASK_FAIL: (taskId, name) =>
485
- `Build #${taskId} failed because there was a problem\nbuilding ${chalk.bold(
494
+ SUBTASK_FAIL: (buildId, name) =>
495
+ `Build #${buildId} failed because there was a problem\nbuilding ${chalk.bold(
486
496
  name
487
497
  )}`,
488
498
  },
489
499
  });
490
500
 
491
501
  const pollDeployStatus = makePollTaskStatusFunc({
502
+ linkToHubSpot: (accountId, taskName, taskId, deployedBuildId) =>
503
+ uiLink(
504
+ `View deploy of build #${deployedBuildId} in HubSpot`,
505
+ getProjectDeployDetailUrl(taskName, taskId, accountId)
506
+ ),
492
507
  statusFn: getDeployStatus,
493
508
  statusText: PROJECT_DEPLOY_TEXT,
494
509
  statusStrings: {
495
510
  INITIALIZE: name => `Deploying ${chalk.bold(name)}`,
496
511
  SUCCESS: name => `Deployed ${chalk.bold(name)}`,
497
512
  FAIL: name => `Failed to deploy ${chalk.bold(name)}`,
498
- SUBTASK_FAIL: (taskId, name) =>
499
- `Deploy for build #${taskId} failed because there was a\nproblem deploying ${chalk.bold(
513
+ SUBTASK_FAIL: (deployedBuildId, name) =>
514
+ `Deploy for build #${deployedBuildId} failed because there was a\nproblem deploying ${chalk.bold(
500
515
  name
501
516
  )}`,
502
517
  },
@@ -0,0 +1,50 @@
1
+ const path = require('path');
2
+ const fs = require('fs');
3
+ const { promptUser } = require('./promptUtils');
4
+ const { i18n } = require('@hubspot/cli-lib/lib/lang');
5
+ const escapeRegExp = require('@hubspot/cli-lib/lib/escapeRegExp');
6
+ const i18nKey = 'cli.lib.prompts.uploadPrompt';
7
+ const FIELDS_FILES = ['fields.json', 'fields.js', 'fields.cjs', 'fields.mjs'];
8
+
9
+ const fieldsJsPrompt = async (filePath, projectDir, skipFiles = []) => {
10
+ const dirName = path.dirname(filePath);
11
+
12
+ // Get a list of all field files in the directory, resolve their absolute path, and remove the ones that we already skipped.
13
+ const fileChoices = fs
14
+ .readdirSync(dirName)
15
+ .filter(file => FIELDS_FILES.includes(file))
16
+ .map(file => path.resolve(dirName, file))
17
+ .filter(file => !skipFiles.includes(file));
18
+
19
+ if (!fileChoices.length) return [filePath, []];
20
+ if (fileChoices.length == 1) return [fileChoices[0], []];
21
+
22
+ // We get the directory above the project one so that relative paths are printed with the root of the project dir attached.
23
+ projectDir = projectDir.substring(0, projectDir.lastIndexOf('/'));
24
+ const projectDirRegex = new RegExp(`^${escapeRegExp(projectDir)}`);
25
+ const fileDir = path.dirname(fileChoices[0]).replace(projectDirRegex, '');
26
+
27
+ const selection = [];
28
+ fileChoices.forEach(fileChoice => {
29
+ selection.push({
30
+ name: fileChoice.replace(projectDirRegex, ''),
31
+ value: fileChoice,
32
+ });
33
+ });
34
+ const promptVal = await promptUser([
35
+ {
36
+ message: i18n(`${i18nKey}.fieldsPrompt`, { dir: fileDir }),
37
+ type: 'list',
38
+ name: 'filePathChoice',
39
+ choices: selection,
40
+ },
41
+ ]);
42
+ const choice = promptVal.filePathChoice;
43
+
44
+ // Add the ones that were not picked to skip files array.
45
+ const notPicked = fileChoices.filter(item => item !== choice);
46
+ skipFiles.push(...notPicked);
47
+ return [choice, skipFiles];
48
+ };
49
+
50
+ module.exports = { fieldsJsPrompt };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hubspot/cli",
3
- "version": "4.0.1-beta.4",
3
+ "version": "4.0.2-beta.0",
4
4
  "description": "CLI for working with HubSpot",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -8,8 +8,8 @@
8
8
  "url": "https://github.com/HubSpot/hubspot-cms-tools"
9
9
  },
10
10
  "dependencies": {
11
- "@hubspot/cli-lib": "4.0.1-beta.4",
12
- "@hubspot/serverless-dev-runtime": "4.0.1-beta.4",
11
+ "@hubspot/cli-lib": "4.0.2-beta.0",
12
+ "@hubspot/serverless-dev-runtime": "4.0.2-beta.0",
13
13
  "archiver": "^5.3.0",
14
14
  "chalk": "^4.1.2",
15
15
  "express": "^4.17.1",
@@ -37,5 +37,5 @@
37
37
  "publishConfig": {
38
38
  "access": "public"
39
39
  },
40
- "gitHead": "38cd22d1d1a3d8d06d65dfb40ba4d6b3b659e205"
40
+ "gitHead": "861cd70866ca2e8f803d5b61c73fccd04f3d6c75"
41
41
  }