@hubspot/cli 4.2.0 → 4.2.1-beta.1

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.
@@ -1,5 +1,4 @@
1
- //const chalk = require('chalk');
2
- const Spinnies = require('spinnies');
1
+ const SpinniesManager = require('../../lib/SpinniesManager');
3
2
  const {
4
3
  addAccountOptions,
5
4
  addConfigOptions,
@@ -119,9 +118,9 @@ exports.handler = async options => {
119
118
 
120
119
  // Poll till scoring is finished
121
120
  try {
122
- const spinnies = new Spinnies();
121
+ SpinniesManager.init();
123
122
 
124
- spinnies.add('lighthouseScore', {
123
+ SpinniesManager.add('lighthouseScore', {
125
124
  text: i18n(`${i18nKey}.info.generatingScore`, { theme: themeToCheck }),
126
125
  });
127
126
 
@@ -148,7 +147,7 @@ exports.handler = async options => {
148
147
 
149
148
  await checkScoreStatus();
150
149
 
151
- spinnies.remove('lighthouseScore');
150
+ SpinniesManager.remove('lighthouseScore');
152
151
  } catch (err) {
153
152
  logger.debug(err);
154
153
  process.exit(EXIT_CODES.ERROR);
@@ -1,5 +1,4 @@
1
- const Spinnies = require('spinnies');
2
-
1
+ const SpinniesManager = require('../../lib/SpinniesManager');
3
2
  const {
4
3
  addConfigOptions,
5
4
  addAccountOptions,
@@ -31,8 +30,9 @@ exports.handler = async options => {
31
30
 
32
31
  trackCommandUsage('validate', null, accountId);
33
32
 
34
- const spinnies = new Spinnies();
35
- spinnies.add('marketplaceValidation', {
33
+ SpinniesManager.init();
34
+
35
+ SpinniesManager.add('marketplaceValidation', {
36
36
  text: i18n(`${i18nKey}.logs.validatingModule`, {
37
37
  path: src,
38
38
  }),
@@ -42,7 +42,7 @@ exports.handler = async options => {
42
42
  const validationId = await kickOffValidation(accountId, assetType, src);
43
43
  await pollForValidationFinish(accountId, validationId);
44
44
 
45
- spinnies.remove('marketplaceValidation');
45
+ SpinniesManager.remove('marketplaceValidation');
46
46
 
47
47
  const validationResults = await fetchValidationResults(
48
48
  accountId,
@@ -19,7 +19,7 @@ const {
19
19
  pollProjectBuildAndDeploy,
20
20
  } = require('../../lib/projects');
21
21
  const { EXIT_CODES } = require('../../lib/enums/exitCodes');
22
- const { uiAccountDescription, uiLine } = require('../../lib/ui');
22
+ const { uiAccountDescription, uiBetaMessage, uiLine } = require('../../lib/ui');
23
23
  const { confirmPrompt } = require('../../lib/prompts/promptUtils');
24
24
  const {
25
25
  selectTargetAccountPrompt,
@@ -29,6 +29,7 @@ const {
29
29
  LocalDevManager,
30
30
  UPLOAD_PERMISSIONS,
31
31
  } = require('../../lib/LocalDevManager');
32
+ const LocalDevManagerV2 = require('../../lib/LocalDevManagerV2');
32
33
  const { isSandbox } = require('../../lib/sandboxes');
33
34
  const { getAccountConfig, getEnv } = require('@hubspot/cli-lib');
34
35
  const { sandboxNamePrompt } = require('../../lib/prompts/sandboxesPrompt');
@@ -38,7 +39,11 @@ const {
38
39
  getAvailableSyncTypes,
39
40
  } = require('../../lib/sandboxes');
40
41
  const { getValidEnv } = require('@hubspot/cli-lib/lib/environment');
41
- const { ERROR_TYPES } = require('@hubspot/cli-lib/lib/constants');
42
+ const {
43
+ PROJECT_BUILD_TEXT,
44
+ PROJECT_DEPLOY_TEXT,
45
+ ERROR_TYPES,
46
+ } = require('@hubspot/cli-lib/lib/constants');
42
47
  const {
43
48
  logErrorInstance,
44
49
  logApiErrorInstance,
@@ -54,7 +59,7 @@ const {
54
59
 
55
60
  const i18nKey = 'cli.commands.project.subcommands.dev';
56
61
 
57
- exports.command = 'dev [--account] [--port]';
62
+ exports.command = 'dev [--account]';
58
63
  exports.describe = null; //i18n(`${i18nKey}.describe`);
59
64
 
60
65
  exports.handler = async options => {
@@ -67,7 +72,7 @@ exports.handler = async options => {
67
72
 
68
73
  const { projectConfig, projectDir } = await getProjectConfig();
69
74
 
70
- logger.log(i18n(`${i18nKey}.logs.betaMessage`));
75
+ uiBetaMessage(i18n(`${i18nKey}.logs.betaMessage`));
71
76
 
72
77
  if (!projectConfig) {
73
78
  logger.error(i18n(`${i18nKey}.errors.noProjectConfig`));
@@ -84,7 +89,6 @@ exports.handler = async options => {
84
89
  }
85
90
 
86
91
  if (!targetAccountId) {
87
- //logger.log(i18n(`${i18nKey}.logs.learnMoreLink`));
88
92
  logger.log();
89
93
  uiLine();
90
94
  logger.warn(i18n(`${i18nKey}.logs.nonSandboxWarning`));
@@ -177,12 +181,12 @@ exports.handler = async options => {
177
181
  targetAccountId,
178
182
  projectConfig.name
179
183
  );
180
- if (sourceIntegration) {
184
+ if (options.extension || sourceIntegration) {
181
185
  uploadPermission = UPLOAD_PERMISSIONS.never;
182
186
  }
183
187
  }
184
188
 
185
- const spinnies = SpinniesManager.init();
189
+ SpinniesManager.init();
186
190
 
187
191
  if (!projectExists) {
188
192
  // Create the project without prompting if this is a newly created sandbox
@@ -208,14 +212,14 @@ exports.handler = async options => {
208
212
 
209
213
  if (shouldCreateProject) {
210
214
  try {
211
- spinnies.add('createProject', {
215
+ SpinniesManager.add('createProject', {
212
216
  text: i18n(`${i18nKey}.status.creatingProject`, {
213
217
  accountIdentifier: uiAccountDescription(targetAccountId),
214
218
  projectName: projectConfig.name,
215
219
  }),
216
220
  });
217
221
  await createProject(targetAccountId, projectConfig.name);
218
- spinnies.succeed('createProject', {
222
+ SpinniesManager.succeed('createProject', {
219
223
  text: i18n(`${i18nKey}.status.createdProject`, {
220
224
  accountIdentifier: uiAccountDescription(targetAccountId),
221
225
  projectName: projectConfig.name,
@@ -233,60 +237,114 @@ exports.handler = async options => {
233
237
  }
234
238
  }
235
239
 
236
- spinnies.add('devModeSetup', {
240
+ SpinniesManager.add('devModeSetup', {
237
241
  text: i18n(`${i18nKey}.status.startupMessage`, {
238
242
  projectName: projectConfig.name,
239
243
  }),
240
244
  isParent: true,
241
245
  });
242
246
 
243
- let result;
247
+ let initialUploadResult;
248
+
244
249
  // Create an initial build if the project was newly created in the account or if
245
250
  // our upload permission is set to "always"
246
251
  if (!projectExists || uploadPermission === UPLOAD_PERMISSIONS.always) {
247
- result = await handleProjectUpload(
252
+ initialUploadResult = await handleProjectUpload(
248
253
  targetAccountId,
249
254
  projectConfig,
250
255
  projectDir,
251
256
  (...args) => pollProjectBuildAndDeploy(...args, true),
252
257
  i18n(`${i18nKey}.logs.initialUploadMessage`)
253
258
  );
254
- }
255
259
 
256
- if (result && result.error) {
257
- if (
258
- isSpecifiedError(result.error, {
259
- subCategory: ERROR_TYPES.PROJECT_LOCKED,
260
- })
261
- ) {
262
- logger.log();
263
- logger.error(i18n(`${i18nKey}.errors.projectLockedError`));
264
- logger.log();
265
- } else {
266
- logApiErrorInstance(
267
- result.error,
268
- new ApiErrorContext({
269
- accountId,
270
- projectName: projectConfig.name,
260
+ if (initialUploadResult.uploadError) {
261
+ SpinniesManager.fail('devModeSetup');
262
+
263
+ if (
264
+ isSpecifiedError(initialUploadResult.uploadError, {
265
+ subCategory: ERROR_TYPES.PROJECT_LOCKED,
271
266
  })
272
- );
267
+ ) {
268
+ logger.log();
269
+ logger.error(i18n(`${i18nKey}.errors.projectLockedError`));
270
+ logger.log();
271
+ } else {
272
+ logApiErrorInstance(
273
+ initialUploadResult.uploadError,
274
+ new ApiErrorContext({
275
+ accountId,
276
+ projectName: projectConfig.name,
277
+ })
278
+ );
279
+ }
280
+ process.exit(EXIT_CODES.ERROR);
281
+ }
282
+ }
283
+
284
+ // Let the user know when the initial build or deploy fails
285
+ // Do this before starting the dev server for v2 behavior because we cannot
286
+ // run a server on a broken project
287
+ if (
288
+ options.extension &&
289
+ initialUploadResult &&
290
+ !initialUploadResult.succeeded
291
+ ) {
292
+ SpinniesManager.fail('devModeSetup');
293
+
294
+ let subTasks = [];
295
+
296
+ if (initialUploadResult.buildResult.status === 'FAILURE') {
297
+ subTasks =
298
+ initialUploadResult.buildResult[PROJECT_BUILD_TEXT.SUBTASK_KEY];
299
+ } else if (initialUploadResult.deployResult.status === 'FAILURE') {
300
+ subTasks =
301
+ initialUploadResult.deployResult[PROJECT_DEPLOY_TEXT.SUBTASK_KEY];
273
302
  }
303
+
304
+ const failedSubTasks = subTasks.filter(task => task.status === 'FAILURE');
305
+
306
+ logger.log();
307
+ failedSubTasks.forEach(failedSubTask => {
308
+ console.log(failedSubTask.errorMessage);
309
+ });
310
+ logger.log();
311
+
274
312
  process.exit(EXIT_CODES.ERROR);
275
- } else {
276
- spinnies.remove('devModeSetup');
277
313
  }
278
314
 
279
- const LocalDev = new LocalDevManager({
280
- debug: options.debug,
281
- projectConfig,
282
- projectDir,
283
- targetAccountId,
284
- uploadPermission,
285
- port: options.port,
286
- });
315
+ SpinniesManager.remove('devModeSetup');
316
+
317
+ const LocalDev = options.extension
318
+ ? new LocalDevManagerV2({
319
+ debug: options.debug,
320
+ extension: options.extension,
321
+ projectConfig,
322
+ projectDir,
323
+ targetAccountId,
324
+ })
325
+ : new LocalDevManager({
326
+ debug: options.debug,
327
+ projectConfig,
328
+ projectDir,
329
+ targetAccountId,
330
+ uploadPermission,
331
+ });
287
332
 
288
333
  await LocalDev.start();
289
334
 
335
+ // Let the user know when the initial build or deploy fails
336
+ if (
337
+ !options.extension &&
338
+ initialUploadResult &&
339
+ !initialUploadResult.succeeded
340
+ ) {
341
+ if (initialUploadResult.buildResult.status === 'FAILURE') {
342
+ LocalDev.logBuildError(initialUploadResult.buildResult);
343
+ } else if (initialUploadResult.deployResult.status === 'FAILURE') {
344
+ LocalDev.logDeployError(initialUploadResult.deployResult);
345
+ }
346
+ }
347
+
290
348
  handleExit(LocalDev.stop);
291
349
  };
292
350
 
@@ -296,9 +354,10 @@ exports.builder = yargs => {
296
354
  addUseEnvironmentOptions(yargs, true);
297
355
  addTestingOptions(yargs, true);
298
356
 
299
- yargs.option('port', {
300
- describe: i18n(`${i18nKey}.options.port.describe`),
301
- type: 'number',
357
+ yargs.option('extension', {
358
+ describe: i18n(`${i18nKey}.options.extension.describe`),
359
+ type: 'string',
360
+ hidden: true,
302
361
  });
303
362
 
304
363
  yargs.example([['$0 project dev', i18n(`${i18nKey}.examples.default`)]]);
@@ -9,7 +9,7 @@ const {
9
9
  } = require('../../lib/commonOpts');
10
10
  const { trackCommandUsage } = require('../../lib/usageTracking');
11
11
  const { logger } = require('@hubspot/cli-lib/logger');
12
- const { outputLogs } = require('@hubspot/cli-lib/lib/logs');
12
+ // const { outputLogs } = require('@hubspot/cli-lib/lib/logs');
13
13
  const {
14
14
  fetchProject,
15
15
  fetchDeployComponentsMetadata,
@@ -18,25 +18,25 @@ const {
18
18
  getTableContents,
19
19
  getTableHeader,
20
20
  } = require('@hubspot/cli-lib/lib/table');
21
- const {
22
- getProjectAppFunctionLogs,
23
- getLatestProjectAppFunctionLog,
24
- } = require('@hubspot/cli-lib/api/functions');
25
- const {
26
- logApiErrorInstance,
27
- ApiErrorContext,
28
- } = require('@hubspot/cli-lib/errorHandlers');
29
- const {
30
- getFunctionLogs,
31
- getLatestFunctionLog,
32
- } = require('@hubspot/cli-lib/api/results');
21
+ // const {
22
+ // getProjectAppFunctionLogs,
23
+ // getLatestProjectAppFunctionLog,
24
+ // } = require('@hubspot/cli-lib/api/functions');
25
+ // const {
26
+ // logApiErrorInstance,
27
+ // ApiErrorContext,
28
+ // } = require('@hubspot/cli-lib/errorHandlers');
29
+ // const {
30
+ // getFunctionLogs,
31
+ // getLatestFunctionLog,
32
+ // } = require('@hubspot/cli-lib/api/results');
33
33
  const { ensureProjectExists } = require('../../lib/projects');
34
34
  const { loadAndValidateOptions } = require('../../lib/validation');
35
35
  const { uiLine, uiLink } = require('../../lib/ui');
36
36
  const { projectLogsPrompt } = require('../../lib/prompts/projectsLogsPrompt');
37
- const { tailLogs } = require('../../lib/serverlessLogs');
37
+ // const { tailLogs } = require('../../lib/serverlessLogs');
38
38
  const { i18n } = require('../../lib/lang');
39
- const { EXIT_CODES } = require('../../lib/enums/exitCodes');
39
+ // const { EXIT_CODES } = require('../../lib/enums/exitCodes');
40
40
 
41
41
  const i18nKey = 'cli.commands.project.subcommands.logs';
42
42
 
@@ -48,90 +48,92 @@ const getPrivateAppsUrl = accountId => {
48
48
  return `${baseUrl}/private-apps/${accountId}`;
49
49
  };
50
50
 
51
- const handleLogsError = (e, name, projectName) => {
52
- if (e.statusCode === 404) {
53
- logger.debug(`Log fetch error: ${e.message}`);
54
- logger.log(i18n(`${i18nKey}.logs.noLogsFound`, { name }));
55
- } else {
56
- logApiErrorInstance(
57
- e,
58
- new ApiErrorContext({ accountId: getAccountId(), projectName })
59
- );
60
- process.exit(EXIT_CODES.ERROR);
61
- }
62
- };
63
-
64
- const handleFunctionLog = async (accountId, options) => {
65
- const {
66
- latest,
67
- follow,
68
- compact,
69
- appPath,
70
- functionName,
71
- projectName,
72
- } = options;
73
-
74
- let logsResp;
75
-
76
- const tailCall = async after => {
77
- try {
78
- return appPath
79
- ? getProjectAppFunctionLogs(
80
- accountId,
81
- functionName,
82
- projectName,
83
- appPath,
84
- {
85
- after,
86
- }
87
- )
88
- : getFunctionLogs(accountId, functionName, { after });
89
- } catch (e) {
90
- handleLogsError(e, functionName, projectName);
91
- }
92
- };
93
-
94
- const fetchLatest = async () => {
95
- return appPath
96
- ? getLatestProjectAppFunctionLog(
97
- accountId,
98
- functionName,
99
- projectName,
100
- appPath
101
- )
102
- : getLatestFunctionLog(accountId, functionName, projectName);
103
- };
104
-
105
- if (follow) {
106
- await tailLogs({
107
- accountId,
108
- compact,
109
- tailCall,
110
- fetchLatest,
111
- name: functionName,
112
- });
113
- } else if (latest) {
114
- try {
115
- logsResp = await fetchLatest();
116
- } catch (e) {
117
- handleLogsError(e, functionName, projectName);
118
- return true;
119
- }
120
- } else {
121
- try {
122
- logsResp = await tailCall();
123
- } catch (e) {
124
- handleLogsError(e, functionName, projectName);
125
- return true;
126
- }
127
- }
128
-
129
- if (logsResp) {
130
- outputLogs(logsResp, options);
131
- return true;
132
- }
133
- return false;
134
- };
51
+ // We currently cannot fetch logs directly to the CLI. See internal CLI issue #413 for more information.
52
+
53
+ // const handleLogsError = (e, name, projectName) => {
54
+ // if (e.statusCode === 404) {
55
+ // logger.debug(`Log fetch error: ${e.message}`);
56
+ // logger.log(i18n(`${i18nKey}.logs.noLogsFound`, { name }));
57
+ // } else {
58
+ // logApiErrorInstance(
59
+ // e,
60
+ // new ApiErrorContext({ accountId: getAccountId(), projectName })
61
+ // );
62
+ // process.exit(EXIT_CODES.ERROR);
63
+ // }
64
+ // };
65
+
66
+ // const handleFunctionLog = async (accountId, options) => {
67
+ // const {
68
+ // latest,
69
+ // follow,
70
+ // compact,
71
+ // appPath,
72
+ // functionName,
73
+ // projectName,
74
+ // } = options;
75
+
76
+ // let logsResp;
77
+
78
+ // const tailCall = async after => {
79
+ // try {
80
+ // return appPath
81
+ // ? getProjectAppFunctionLogs(
82
+ // accountId,
83
+ // functionName,
84
+ // projectName,
85
+ // appPath,
86
+ // {
87
+ // after,
88
+ // }
89
+ // )
90
+ // : getFunctionLogs(accountId, functionName, { after });
91
+ // } catch (e) {
92
+ // handleLogsError(e, functionName, projectName);
93
+ // }
94
+ // };
95
+
96
+ // const fetchLatest = async () => {
97
+ // return appPath
98
+ // ? getLatestProjectAppFunctionLog(
99
+ // accountId,
100
+ // functionName,
101
+ // projectName,
102
+ // appPath
103
+ // )
104
+ // : getLatestFunctionLog(accountId, functionName, projectName);
105
+ // };
106
+
107
+ // if (follow) {
108
+ // await tailLogs({
109
+ // accountId,
110
+ // compact,
111
+ // tailCall,
112
+ // fetchLatest,
113
+ // name: functionName,
114
+ // });
115
+ // } else if (latest) {
116
+ // try {
117
+ // logsResp = await fetchLatest();
118
+ // } catch (e) {
119
+ // handleLogsError(e, functionName, projectName);
120
+ // return true;
121
+ // }
122
+ // } else {
123
+ // try {
124
+ // logsResp = await tailCall();
125
+ // } catch (e) {
126
+ // handleLogsError(e, functionName, projectName);
127
+ // return true;
128
+ // }
129
+ // }
130
+
131
+ // if (logsResp) {
132
+ // outputLogs(logsResp, options);
133
+ // return true;
134
+ // }
135
+ // return false;
136
+ // };
135
137
 
136
138
  exports.command = 'logs [--project] [--app] [--function] [--endpoint]';
137
139
  exports.describe = i18n(`${i18nKey}.describe`);
@@ -154,7 +156,7 @@ exports.handler = async options => {
154
156
  options.function || promptFunctionName || options.endpoint;
155
157
  const endpointName = options.endpoint || promptEndpointName;
156
158
 
157
- let relativeAppPath;
159
+ // let relativeAppPath;
158
160
  let appId;
159
161
 
160
162
  if (appName && !endpointName) {
@@ -162,10 +164,11 @@ exports.handler = async options => {
162
164
  allowCreate: false,
163
165
  });
164
166
 
165
- const { deployedBuild, id: projectId } = await fetchProject(
166
- accountId,
167
- projectName
168
- );
167
+ // const { deployedBuild, id: projectId } = await fetchProject(
168
+ // accountId,
169
+ // projectName
170
+ // );
171
+ const { id: projectId } = await fetchProject(accountId, projectName);
169
172
 
170
173
  const { results: deployComponents } = await fetchDeployComponentsMetadata(
171
174
  accountId,
@@ -180,22 +183,22 @@ exports.handler = async options => {
180
183
  appId = appComponent.componentIdentifier;
181
184
  }
182
185
 
183
- if (deployedBuild && deployedBuild.subbuildStatuses) {
184
- const appSubbuild = deployedBuild.subbuildStatuses.find(
185
- subbuild => subbuild.buildName === appName
186
- );
187
- if (appSubbuild) {
188
- relativeAppPath = appSubbuild.rootPath;
189
- } else {
190
- logger.error(
191
- i18n(`${i18nKey}.errors.invalidAppName`, {
192
- appName: options.app,
193
- projectName,
194
- })
195
- );
196
- process.exit(EXIT_CODES.ERROR);
197
- }
198
- }
186
+ // if (deployedBuild && deployedBuild.subbuildStatuses) {
187
+ // const appSubbuild = deployedBuild.subbuildStatuses.find(
188
+ // subbuild => subbuild.buildName === appName
189
+ // );
190
+ // if (appSubbuild) {
191
+ // relativeAppPath = appSubbuild.rootPath;
192
+ // } else {
193
+ // logger.error(
194
+ // i18n(`${i18nKey}.errors.invalidAppName`, {
195
+ // appName: options.app,
196
+ // projectName,
197
+ // })
198
+ // );
199
+ // process.exit(EXIT_CODES.ERROR);
200
+ // }
201
+ // }
199
202
  }
200
203
 
201
204
  trackCommandUsage('project-logs', null, accountId);
@@ -240,16 +243,16 @@ exports.handler = async options => {
240
243
  logger.log();
241
244
  uiLine();
242
245
 
243
- const showFinalMessage = await handleFunctionLog(accountId, {
244
- ...options,
245
- projectName,
246
- appPath: relativeAppPath,
247
- functionName: functionName || endpointName,
248
- });
246
+ // const showFinalMessage = await handleFunctionLog(accountId, {
247
+ // ...options,
248
+ // projectName,
249
+ // appPath: relativeAppPath,
250
+ // functionName: functionName || endpointName,
251
+ // });
249
252
 
250
- if (showFinalMessage) {
251
- uiLine();
252
- }
253
+ // if (showFinalMessage) {
254
+ // uiLine();
255
+ // }
253
256
  };
254
257
 
255
258
  exports.builder = yargs => {
@@ -59,9 +59,9 @@ exports.handler = async options => {
59
59
  message
60
60
  );
61
61
 
62
- if (result.error) {
62
+ if (result.uploadError) {
63
63
  if (
64
- isSpecifiedError(result.error, {
64
+ isSpecifiedError(result.uploadError, {
65
65
  subCategory: ERROR_TYPES.PROJECT_LOCKED,
66
66
  })
67
67
  ) {
@@ -70,7 +70,7 @@ exports.handler = async options => {
70
70
  logger.log();
71
71
  } else {
72
72
  logApiErrorInstance(
73
- result.error,
73
+ result.uploadError,
74
74
  new ApiErrorContext({
75
75
  accountId,
76
76
  projectName: projectConfig.name,
@@ -79,7 +79,7 @@ exports.handler = async options => {
79
79
  }
80
80
  process.exit(EXIT_CODES.ERROR);
81
81
  }
82
- if (result.buildSucceeded && !result.autodeployEnabled) {
82
+ if (result.succeeded && !result.buildResult.isAutoDeployEnabled) {
83
83
  uiLine();
84
84
  logger.log(
85
85
  chalk.bold(