@hubspot/cli 4.0.1 → 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, '')
@@ -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
+ };
@@ -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
  };
@@ -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",
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",
12
- "@hubspot/serverless-dev-runtime": "4.0.1",
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": "416585f18c9b856b4da3ef502d1eccaded9281d5"
40
+ "gitHead": "861cd70866ca2e8f803d5b61c73fccd04f3d6c75"
41
41
  }