@hubspot/cli 5.0.2-beta.0 → 5.0.2

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 (62) hide show
  1. package/bin/cli.js +1 -1
  2. package/commands/accounts/clean.js +1 -1
  3. package/commands/auth.js +1 -1
  4. package/commands/config/set/defaultMode.js +1 -1
  5. package/commands/create.js +1 -1
  6. package/commands/customObject/create.js +1 -1
  7. package/commands/customObject/schema/create.js +3 -1
  8. package/commands/customObject/schema/delete.js +3 -1
  9. package/commands/customObject/schema/fetch-all.js +3 -1
  10. package/commands/customObject/schema/fetch.js +3 -1
  11. package/commands/customObject/schema/list.js +4 -2
  12. package/commands/customObject/schema/update.js +3 -1
  13. package/commands/filemanager/upload.js +2 -2
  14. package/commands/functions/deploy.js +1 -1
  15. package/commands/functions/list.js +2 -2
  16. package/commands/hubdb/clear.js +1 -1
  17. package/commands/hubdb/create.js +1 -1
  18. package/commands/hubdb/delete.js +1 -1
  19. package/commands/hubdb/fetch.js +1 -1
  20. package/commands/init.js +2 -2
  21. package/commands/lint.js +3 -5
  22. package/commands/list.js +1 -1
  23. package/commands/mv.js +1 -1
  24. package/commands/project/add.js +1 -1
  25. package/commands/project/create.js +1 -0
  26. package/commands/project/deploy.js +1 -1
  27. package/commands/project/dev.js +6 -7
  28. package/commands/project/download.js +1 -1
  29. package/commands/project/listBuilds.js +1 -1
  30. package/commands/project/logs.js +1 -1
  31. package/commands/project/upload.js +2 -4
  32. package/commands/project/watch.js +3 -3
  33. package/commands/remove.js +1 -1
  34. package/commands/sandbox/create.js +2 -4
  35. package/commands/sandbox/delete.js +7 -6
  36. package/commands/sandbox/sync.js +2 -6
  37. package/commands/secrets/addSecret.js +1 -1
  38. package/commands/secrets/deleteSecret.js +1 -1
  39. package/commands/secrets/listSecrets.js +1 -1
  40. package/commands/secrets/updateSecret.js +1 -1
  41. package/commands/upload.js +2 -2
  42. package/lang/en.lyaml +57 -2
  43. package/lib/LocalDevManager.js +7 -2
  44. package/lib/errorHandlers/apiErrors.js +352 -0
  45. package/lib/errorHandlers/fileSystemErrors.js +55 -0
  46. package/lib/errorHandlers/standardErrors.js +95 -0
  47. package/lib/getFunctionArrays.js +18 -0
  48. package/lib/hublValidate.js +32 -0
  49. package/lib/oauth.js +1 -1
  50. package/lib/process.js +42 -0
  51. package/lib/projects.js +24 -8
  52. package/lib/projectsWatch.js +225 -0
  53. package/lib/prompts/downloadProjectPrompt.js +1 -1
  54. package/lib/prompts/projectsLogsPrompt.js +1 -1
  55. package/lib/sandbox-create.js +2 -2
  56. package/lib/sandbox-sync.js +5 -5
  57. package/lib/sandboxes.js +1 -1
  58. package/lib/schema.js +31 -0
  59. package/lib/serverlessLogs.js +2 -2
  60. package/lib/ui.js +1 -0
  61. package/lib/validation.js +1 -1
  62. package/package.json +7 -4
@@ -2,8 +2,8 @@ const path = require('path');
2
2
  const chokidar = require('chokidar');
3
3
  const chalk = require('chalk');
4
4
  const { i18n } = require('./lang');
5
+ const { handleKeypress } = require('./process');
5
6
  const { logger } = require('@hubspot/cli-lib/logger');
6
- const { handleKeypress } = require('@hubspot/cli-lib/lib/process');
7
7
  const {
8
8
  getAccountId,
9
9
  getConfigDefaultAccount,
@@ -89,7 +89,12 @@ class LocalDevManager {
89
89
 
90
90
  // The project does not contain any components that support local development
91
91
  if (!runnableComponents.length) {
92
- logger.error(i18n(`${i18nKey}.noRunnableComponents`));
92
+ logger.error(
93
+ i18n(`${i18nKey}.noRunnableComponents`, {
94
+ projectSourceDir: this.projectSourceDir,
95
+ command: uiCommandReference('hs project add'),
96
+ })
97
+ );
93
98
  process.exit(EXIT_CODES.SUCCESS);
94
99
  }
95
100
 
@@ -0,0 +1,352 @@
1
+ const { logger } = require('@hubspot/cli-lib/logger');
2
+ const { getAccountConfig } = require('@hubspot/cli-lib/lib/config');
3
+ const {
4
+ SCOPE_GROUPS,
5
+ PERSONAL_ACCESS_KEY_AUTH_METHOD,
6
+ } = require('@hubspot/cli-lib/lib/constants');
7
+ const {
8
+ fetchScopeData,
9
+ } = require('@hubspot/cli-lib/api/localDevAuth/authenticated');
10
+ const {
11
+ debugErrorAndContext,
12
+ logErrorInstance,
13
+ ErrorContext,
14
+ } = require('./standardErrors');
15
+ const { i18n } = require('../lang');
16
+
17
+ const i18nKey = 'cli.lib.errorHandlers.apiErrors';
18
+
19
+ const isApiStatusCodeError = err =>
20
+ err.name === 'StatusCodeError' ||
21
+ (err.statusCode >= 100 && err.statusCode < 600);
22
+
23
+ const isApiUploadValidationError = err =>
24
+ !!(
25
+ err.statusCode === 400 &&
26
+ err.response &&
27
+ err.response.body &&
28
+ (err.response.body.message || err.response.body.errors)
29
+ );
30
+
31
+ const isMissingScopeError = err =>
32
+ err.name === 'StatusCodeError' &&
33
+ err.statusCode === 403 &&
34
+ err.error &&
35
+ err.error.category === 'MISSING_SCOPES';
36
+
37
+ const isGatingError = err =>
38
+ isSpecifiedError(err, { statusCode: 403, category: 'GATED' });
39
+
40
+ const isSpecifiedError = (err, { statusCode, category, subCategory } = {}) => {
41
+ const statusCodeErr = !statusCode || err.statusCode === statusCode;
42
+ const categoryErr =
43
+ !category || (err.error && err.error.category === category);
44
+ const subCategoryErr =
45
+ !subCategory || (err.error && err.error.subCategory === subCategory);
46
+
47
+ return (
48
+ err.name === 'StatusCodeError' &&
49
+ statusCodeErr &&
50
+ categoryErr &&
51
+ subCategoryErr
52
+ );
53
+ };
54
+
55
+ const isSpecifiedHubSpotAuthError = (
56
+ err,
57
+ { statusCode, category, subCategory }
58
+ ) => {
59
+ const statusCodeErr = !statusCode || err.statusCode === statusCode;
60
+ const categoryErr = !category || err.category === category;
61
+ const subCategoryErr = !subCategory || err.subCategory === subCategory;
62
+ return (
63
+ err.name === 'HubSpotAuthError' &&
64
+ statusCodeErr &&
65
+ categoryErr &&
66
+ subCategoryErr
67
+ );
68
+ };
69
+
70
+ const parseValidationErrors = (responseBody = {}) => {
71
+ const errorMessages = [];
72
+
73
+ const { errors, message } = responseBody;
74
+
75
+ if (message) {
76
+ errorMessages.push(message);
77
+ }
78
+
79
+ if (errors) {
80
+ const specificErrors = errors.map(error => {
81
+ let errorMessage = error.message;
82
+ if (error.errorTokens && error.errorTokens.line) {
83
+ errorMessage = `line ${error.errorTokens.line}: ${errorMessage}`;
84
+ }
85
+ return errorMessage;
86
+ });
87
+ errorMessages.push(...specificErrors);
88
+ }
89
+
90
+ return errorMessages;
91
+ };
92
+
93
+ class ApiErrorContext extends ErrorContext {
94
+ constructor(props = {}) {
95
+ super(props);
96
+ /** @type {string} */
97
+ this.request = props.request || '';
98
+ /** @type {string} */
99
+ this.payload = props.payload || '';
100
+ /** @type {string} */
101
+ this.projectName = props.projectName || '';
102
+ }
103
+ }
104
+
105
+ /**
106
+ * @param {Error} error
107
+ * @param {ApiErrorContext} context
108
+ */
109
+ function logValidationErrors(error, context) {
110
+ const { response = {} } = error;
111
+ const validationErrors = parseValidationErrors(response.body);
112
+ if (validationErrors.length) {
113
+ validationErrors.forEach(err => {
114
+ logger.error(err);
115
+ });
116
+ }
117
+ debugErrorAndContext(error, context);
118
+ }
119
+
120
+ /**
121
+ * Message segments for API messages.
122
+ *
123
+ * @enum {string}
124
+ */
125
+ const ApiMethodVerbs = {
126
+ DEFAULT: 'request',
127
+ DELETE: 'delete',
128
+ GET: 'request',
129
+ PATCH: 'update',
130
+ POST: 'post',
131
+ PUT: 'update',
132
+ };
133
+
134
+ /**
135
+ * Message segments for API messages.
136
+ *
137
+ * @enum {string}
138
+ */
139
+ const ApiMethodPrepositions = {
140
+ DEFAULT: 'for',
141
+ DELETE: 'of',
142
+ GET: 'for',
143
+ PATCH: 'to',
144
+ POST: 'to',
145
+ PUT: 'to',
146
+ };
147
+
148
+ /**
149
+ * Logs messages for an error instance resulting from API interaction.
150
+ *
151
+ * @param {StatusCodeError} error
152
+ * @param {ApiErrorContext} context
153
+ */
154
+ function logApiStatusCodeError(error, context) {
155
+ const { statusCode } = error;
156
+ const { method } = error.options || {};
157
+ const { projectName } = context;
158
+ const isPutOrPost = method === 'PUT' || method === 'POST';
159
+ const action = ApiMethodVerbs[method] || ApiMethodVerbs.DEFAULT;
160
+ const preposition =
161
+ ApiMethodPrepositions[method] || ApiMethodPrepositions.DEFAULT;
162
+ let messageDetail = '';
163
+ {
164
+ const request = context.request
165
+ ? `${action} ${preposition} "${context.request}"`
166
+ : action;
167
+ messageDetail = `${request} in account ${context.accountId}`;
168
+ }
169
+ const errorMessage = [];
170
+ if (isPutOrPost && context.payload) {
171
+ errorMessage.push(`Unable to upload "${context.payload}".`);
172
+ }
173
+ const isProjectMissingScopeError = isMissingScopeError(error) && projectName;
174
+ const isProjectGatingError = isGatingError(error) && projectName;
175
+ switch (statusCode) {
176
+ case 400:
177
+ errorMessage.push(i18n(`${i18nKey}.codes.400`, { messageDetail }));
178
+ break;
179
+ case 401:
180
+ errorMessage.push(i18n(`${i18nKey}.codes.401`, { messageDetail }));
181
+ break;
182
+ case 403:
183
+ if (isProjectMissingScopeError) {
184
+ errorMessage.push(
185
+ i18n(`${i18nKey}.codes.403MissingScope`, {
186
+ accountId: context.accountId || '',
187
+ })
188
+ );
189
+ } else if (isProjectGatingError) {
190
+ errorMessage.push(
191
+ i18n(`${i18nKey}.codes.403Gating`, {
192
+ accountId: context.accountId || '',
193
+ })
194
+ );
195
+ } else {
196
+ errorMessage.push(i18n(`${i18nKey}.codes.403`, { messageDetail }));
197
+ }
198
+ break;
199
+ case 404:
200
+ if (context.request) {
201
+ errorMessage.push(
202
+ i18n(`${i18nKey}.codes.404Request`, {
203
+ action: action || 'request',
204
+ request: context.request,
205
+ account: context.accountId || '',
206
+ })
207
+ );
208
+ } else {
209
+ errorMessage.push(i18n(`${i18nKey}.codes.404`, { messageDetail }));
210
+ }
211
+ break;
212
+ case 429:
213
+ errorMessage.push(i18n(`${i18nKey}.codes.429`, { messageDetail }));
214
+ break;
215
+ case 503:
216
+ errorMessage.push(i18n(`${i18nKey}.codes.503`, { messageDetail }));
217
+ break;
218
+ default:
219
+ if (statusCode >= 500 && statusCode < 600) {
220
+ errorMessage.push(
221
+ i18n(`${i18nKey}.codes.500Generic`, { messageDetail })
222
+ );
223
+ } else if (statusCode >= 400 && statusCode < 500) {
224
+ i18n(`${i18nKey}.codes.400Generic`, { messageDetail });
225
+ } else {
226
+ errorMessage.push(i18n(`${i18nKey}.codes.generic`, { messageDetail }));
227
+ }
228
+ break;
229
+ }
230
+ if (
231
+ error.error &&
232
+ error.error.message &&
233
+ !isProjectMissingScopeError &&
234
+ !isProjectGatingError
235
+ ) {
236
+ errorMessage.push(error.error.message);
237
+ }
238
+ if (error.error && error.error.errors) {
239
+ error.error.errors.forEach(err => {
240
+ errorMessage.push('\n- ' + err.message);
241
+ });
242
+ }
243
+ logger.error(errorMessage.join(' '));
244
+ debugErrorAndContext(error, context);
245
+ }
246
+
247
+ /**
248
+ * Logs a message for an error instance resulting from API interaction.
249
+ *
250
+ * @param {Error|SystemError|Object} error
251
+ * @param {ApiErrorContext} context
252
+ */
253
+ function logApiErrorInstance(error, context) {
254
+ // StatusCodeError
255
+ if (isApiStatusCodeError(error)) {
256
+ logApiStatusCodeError(error, context);
257
+ return;
258
+ }
259
+ logErrorInstance(error, context);
260
+ }
261
+
262
+ /**
263
+ * Logs a message for an error instance resulting from filemapper API upload.
264
+ *
265
+ * @param {Error|SystemError|Object} error
266
+ * @param {ApiErrorContext} context
267
+ */
268
+ function logApiUploadErrorInstance(error, context) {
269
+ if (isApiUploadValidationError(error)) {
270
+ logValidationErrors(error, context);
271
+ return;
272
+ }
273
+ logApiErrorInstance(error, context);
274
+ }
275
+
276
+ async function verifyAccessKeyAndUserAccess(accountId, scopeGroup) {
277
+ const accountConfig = getAccountConfig(accountId);
278
+ const { authType } = accountConfig;
279
+ if (authType !== PERSONAL_ACCESS_KEY_AUTH_METHOD.value) {
280
+ return;
281
+ }
282
+
283
+ let scopesData;
284
+ try {
285
+ scopesData = await fetchScopeData(accountId, scopeGroup);
286
+ } catch (e) {
287
+ logger.debug(
288
+ i18n(`${i18nKey}.verifyAccessKeyAndUserAccess.fetchScopeDataError`, {
289
+ scopeGroup,
290
+ error: e,
291
+ })
292
+ );
293
+ return;
294
+ }
295
+ const { portalScopesInGroup, userScopesInGroup } = scopesData;
296
+
297
+ if (!portalScopesInGroup.length) {
298
+ logger.error(
299
+ i18n(`${i18nKey}.verifyAccessKeyAndUserAccess.portalMissingScope`)
300
+ );
301
+ return;
302
+ }
303
+
304
+ if (!portalScopesInGroup.every(s => userScopesInGroup.includes(s))) {
305
+ logger.error(
306
+ i18n(`${i18nKey}.verifyAccessKeyAndUserAccess.userMissingScope`)
307
+ );
308
+ return;
309
+ } else {
310
+ logger.error(
311
+ i18n(`${i18nKey}.verifyAccessKeyAndUserAccess.genericMissingScope`)
312
+ );
313
+ return;
314
+ }
315
+ }
316
+
317
+ /**
318
+ * Logs a message for an error instance resulting from API interaction
319
+ * related to serverless function.
320
+ *
321
+ * @param {int} accountId
322
+ * @param {Error|SystemError|Object} error
323
+ * @param {ApiErrorContext} context
324
+ */
325
+ async function logServerlessFunctionApiErrorInstance(
326
+ accountId,
327
+ error,
328
+ context
329
+ ) {
330
+ if (isMissingScopeError(error)) {
331
+ await verifyAccessKeyAndUserAccess(accountId, SCOPE_GROUPS.functions);
332
+ return;
333
+ }
334
+
335
+ // StatusCodeError
336
+ if (isApiStatusCodeError(error)) {
337
+ logApiStatusCodeError(error, context);
338
+ return;
339
+ }
340
+ logErrorInstance(error, context);
341
+ }
342
+
343
+ module.exports = {
344
+ ApiErrorContext,
345
+ parseValidationErrors,
346
+ logApiErrorInstance,
347
+ logApiUploadErrorInstance,
348
+ logServerlessFunctionApiErrorInstance,
349
+ isMissingScopeError,
350
+ isSpecifiedError,
351
+ isSpecifiedHubSpotAuthError,
352
+ };
@@ -0,0 +1,55 @@
1
+ const { logger } = require('@hubspot/cli-lib/logger');
2
+ const {
3
+ ErrorContext,
4
+ isSystemError,
5
+ debugErrorAndContext,
6
+ } = require('./standardErrors');
7
+ const { i18n } = require('../lang');
8
+
9
+ const i18nKey = 'cli.lib.errorHandlers.fileSystemErrors';
10
+
11
+ class FileSystemErrorContext extends ErrorContext {
12
+ constructor(props = {}) {
13
+ super(props);
14
+ /** @type {string} */
15
+ this.filepath = props.filepath || '';
16
+ /** @type {boolean} */
17
+ this.read = !!props.read;
18
+ /** @type {boolean} */
19
+ this.write = !!props.write;
20
+ }
21
+ }
22
+
23
+ /**
24
+ * Logs a message for an error instance resulting from filesystem interaction.
25
+ *
26
+ * @param {Error|SystemError|Object} error
27
+ * @param {FileSystemErrorContext} context
28
+ */
29
+ function logFileSystemErrorInstance(error, context) {
30
+ let fileAction = '';
31
+ if (context.read) {
32
+ fileAction = 'reading from';
33
+ } else if (context.write) {
34
+ fileAction = 'writing to';
35
+ } else {
36
+ fileAction = 'accessing';
37
+ }
38
+ const filepath = context.filepath
39
+ ? `"${context.filepath}"`
40
+ : 'a file or folder';
41
+ const message = [i18n(`${i18nKey}.errorOccurred`, { fileAction, filepath })];
42
+ // Many `fs` errors will be `SystemError`s
43
+ if (isSystemError(error)) {
44
+ message.push(
45
+ i18n(`${i18nKey}.errorExplanation`, { errorMessage: error.message })
46
+ );
47
+ }
48
+ logger.error(message.join(' '));
49
+ debugErrorAndContext(error, context);
50
+ }
51
+
52
+ module.exports = {
53
+ FileSystemErrorContext,
54
+ logFileSystemErrorInstance,
55
+ };
@@ -0,0 +1,95 @@
1
+ const { HubSpotAuthError } = require('@hubspot/cli-lib/lib/models/Errors');
2
+ const { logger } = require('@hubspot/cli-lib/logger');
3
+ const { i18n } = require('../lang');
4
+
5
+ const i18nKey = 'cli.lib.errorHandlers.standardErrors';
6
+
7
+ const isSystemError = err =>
8
+ err.errno != null && err.code != null && err.syscall != null;
9
+ const isFatalError = err => err instanceof HubSpotAuthError;
10
+
11
+ // TODO: Make these TS interfaces
12
+ class ErrorContext {
13
+ constructor(props = {}) {
14
+ /** @type {number} */
15
+ this.accountId = props.accountId;
16
+ }
17
+ }
18
+
19
+ /**
20
+ * Logs (debug) the error and context objects.
21
+ *
22
+ * @param {SystemError} error
23
+ * @param {ErrorContext} context
24
+ */
25
+ function debugErrorAndContext(error, context) {
26
+ if (error.name === 'StatusCodeError') {
27
+ const { statusCode, message, response } = error;
28
+ logger.debug(
29
+ i18n(`${i18nKey}.errorOccurred`, {
30
+ error: {
31
+ statusCode,
32
+ message,
33
+ url: response.request.href,
34
+ method: response.request.method,
35
+ response: response.body,
36
+ headers: response.headers,
37
+ },
38
+ })
39
+ );
40
+ } else {
41
+ logger.debug(i18n(`${i18nKey}.errorOccurred`, { error }));
42
+ }
43
+ logger.debug(i18n(`${i18nKey}.errorContext`, { context }));
44
+ }
45
+
46
+ /**
47
+ * Logs a SystemError
48
+ * @see {@link https://nodejs.org/api/errors.html#errors_class_systemerror}
49
+ *
50
+ * @param {SystemError} error
51
+ * @param {ErrorContext} context
52
+ */
53
+ function logSystemError(error, context) {
54
+ logger.error(
55
+ i18n(`${i18nKey}.systemErrorOccurred`, { error: error.message })
56
+ );
57
+ debugErrorAndContext(error, context);
58
+ }
59
+
60
+ /**
61
+ * Logs a message for an error instance of type not asserted.
62
+ *
63
+ * @param {Error|SystemError|Object} error
64
+ * @param {ErrorContext} context
65
+ */
66
+ function logErrorInstance(error, context) {
67
+ // SystemError
68
+ if (isSystemError(error)) {
69
+ logSystemError(error, context);
70
+ return;
71
+ }
72
+ if (error instanceof Error || error.message || error.reason) {
73
+ // Error or Error subclass
74
+ const name = error.name || 'Error';
75
+ const message = [i18n(`${i18nKey}.genericErrorOccurred`, { name })];
76
+ [(error.message, error.reason)].forEach(msg => {
77
+ if (msg) {
78
+ message.push(msg);
79
+ }
80
+ });
81
+ logger.error(message.join(' '));
82
+ } else {
83
+ // Unknown errors
84
+ logger.error(i18n(`${i18nKey}.unknownErrorOccurred`));
85
+ }
86
+ debugErrorAndContext(error, context);
87
+ }
88
+
89
+ module.exports = {
90
+ debugErrorAndContext,
91
+ ErrorContext,
92
+ isFatalError,
93
+ isSystemError,
94
+ logErrorInstance,
95
+ };
@@ -0,0 +1,18 @@
1
+ const moment = require('moment');
2
+
3
+ const getFunctionArrays = resp => {
4
+ return resp.objects.map(func => {
5
+ const { route, method, created, updated, secretNames } = func;
6
+ return [
7
+ route,
8
+ method,
9
+ secretNames.join(', '),
10
+ moment(created).format(),
11
+ moment(updated).format(),
12
+ ];
13
+ });
14
+ };
15
+
16
+ module.exports = {
17
+ getFunctionArrays,
18
+ };
@@ -0,0 +1,32 @@
1
+ const { logger } = require('@hubspot/cli-lib/logger');
2
+
3
+ const getErrorsFromHublValidationObject = validation =>
4
+ (validation && validation.meta && validation.meta.template_errors) || [];
5
+
6
+ function printHublValidationError(err) {
7
+ const { severity, message, lineno, startPosition } = err;
8
+ const method = severity === 'FATAL' ? 'error' : 'warn';
9
+ logger[method]('[%d, %d]: %s', lineno, startPosition, message);
10
+ }
11
+
12
+ function printHublValidationResult({ file, validation }) {
13
+ let count = 0;
14
+ const errors = getErrorsFromHublValidationObject(validation);
15
+ if (!errors.length) {
16
+ return count;
17
+ }
18
+ logger.group(file);
19
+ errors.forEach(err => {
20
+ if (err.reason !== 'SYNTAX_ERROR') {
21
+ return;
22
+ }
23
+ ++count;
24
+ printHublValidationError(err);
25
+ });
26
+ logger.groupEnd(file);
27
+ return count;
28
+ }
29
+
30
+ module.exports = {
31
+ printHublValidationResult,
32
+ };
package/lib/oauth.js CHANGED
@@ -3,7 +3,7 @@ const open = require('open');
3
3
  const OAuth2Manager = require('@hubspot/cli-lib/lib/models/OAuth2Manager');
4
4
  const { getAccountConfig } = require('@hubspot/cli-lib/lib/config');
5
5
  const { addOauthToAccountConfig } = require('@hubspot/cli-lib/oauth');
6
- const { handleExit } = require('@hubspot/cli-lib/lib/process');
6
+ const { handleExit } = require('./process');
7
7
  const { getHubSpotWebsiteOrigin } = require('@hubspot/cli-lib/lib/urls');
8
8
  const { logger } = require('@hubspot/cli-lib/logger');
9
9
  const { ENVIRONMENTS } = require('@hubspot/cli-lib/lib/constants');
package/lib/process.js ADDED
@@ -0,0 +1,42 @@
1
+ const readline = require('readline');
2
+
3
+ const handleExit = callback => {
4
+ const terminationSignals = [
5
+ 'beforeExit',
6
+ 'SIGINT',
7
+ 'SIGUSR1',
8
+ 'SIGUSR2',
9
+ 'uncaughtException',
10
+ 'SIGTERM',
11
+ 'SIGHUP',
12
+ ];
13
+ terminationSignals.forEach(signal => {
14
+ process.removeAllListeners(signal);
15
+
16
+ process.on(signal, async () => {
17
+ await callback();
18
+ });
19
+ });
20
+ };
21
+
22
+ const handleKeypress = callback => {
23
+ readline.createInterface(process.stdin, process.stdout);
24
+ readline.emitKeypressEvents(process.stdin);
25
+
26
+ if (process.stdin.isTTY) {
27
+ process.stdin.setRawMode(true);
28
+ }
29
+
30
+ process.stdin.removeAllListeners('keypress');
31
+
32
+ process.stdin.on('keypress', (str, key) => {
33
+ if (key) {
34
+ callback(key);
35
+ }
36
+ });
37
+ };
38
+
39
+ module.exports = {
40
+ handleExit,
41
+ handleKeypress,
42
+ };
package/lib/projects.js CHANGED
@@ -29,10 +29,6 @@ const {
29
29
  fetchProject,
30
30
  uploadProject,
31
31
  } = require('@hubspot/cli-lib/api/dfs');
32
- const {
33
- logApiErrorInstance,
34
- ApiErrorContext,
35
- } = require('@hubspot/cli-lib/errorHandlers');
36
32
  const { shouldIgnoreFile } = require('@hubspot/cli-lib/ignoreRules');
37
33
  const { getCwd, getAbsoluteFilePath } = require('@hubspot/cli-lib/path');
38
34
  const { downloadGitHubRepoContents } = require('@hubspot/cli-lib/github');
@@ -42,9 +38,11 @@ const { uiLine, uiLink, uiAccountDescription } = require('../lib/ui');
42
38
  const { i18n } = require('./lang');
43
39
  const SpinniesManager = require('./SpinniesManager');
44
40
  const {
41
+ logApiErrorInstance,
42
+ ApiErrorContext,
45
43
  isSpecifiedError,
46
44
  isSpecifiedHubSpotAuthError,
47
- } = require('@hubspot/cli-lib/errorHandlers/apiErrors');
45
+ } = require('./errorHandlers/apiErrors');
48
46
  const { HUBSPOT_PROJECT_COMPONENTS_GITHUB_PATH } = require('./constants');
49
47
 
50
48
  const i18nKey = 'cli.lib.projects';
@@ -522,9 +520,27 @@ const handleProjectUpload = async (
522
520
 
523
521
  archive.pipe(output);
524
522
 
525
- archive.directory(srcDir, false, file =>
526
- shouldIgnoreFile(file.name, true) ? false : file
527
- );
523
+ let loggedIgnoredNodeModule = false;
524
+
525
+ archive.directory(srcDir, false, file => {
526
+ const ignored = shouldIgnoreFile(file.name, true);
527
+ if (ignored) {
528
+ const isNodeModule = file.name.includes('node_modules');
529
+
530
+ if (!isNodeModule || !loggedIgnoredNodeModule) {
531
+ logger.debug(
532
+ i18n(`${i18nKey}.handleProjectUpload.fileFiltered`, {
533
+ filename: file.name,
534
+ })
535
+ );
536
+ }
537
+
538
+ if (isNodeModule && !loggedIgnoredNodeModule) {
539
+ loggedIgnoredNodeModule = true;
540
+ }
541
+ }
542
+ return ignored ? false : file;
543
+ });
528
544
 
529
545
  archive.finalize();
530
546