@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.
@@ -11,7 +11,11 @@ const {
11
11
  logApiErrorInstance,
12
12
  ApiErrorContext,
13
13
  } = require('@hubspot/cli-lib/errorHandlers');
14
- const { ERROR_TYPES } = require('@hubspot/cli-lib/lib/constants');
14
+ const {
15
+ PROJECT_BUILD_TEXT,
16
+ PROJECT_DEPLOY_TEXT,
17
+ ERROR_TYPES,
18
+ } = require('@hubspot/cli-lib/lib/constants');
15
19
  const { isAllowedExtension } = require('@hubspot/cli-lib/path');
16
20
  const { shouldIgnoreFile } = require('@hubspot/cli-lib/ignoreRules');
17
21
  const {
@@ -53,26 +57,25 @@ class LocalDevManager {
53
57
  this.uploadPermission =
54
58
  options.uploadPermission || UPLOAD_PERMISSIONS.always;
55
59
  this.debug = options.debug || false;
60
+
56
61
  this.projectSourceDir = path.join(
57
62
  this.projectDir,
58
63
  this.projectConfig.srcDir
59
64
  );
60
- this.spinnies = null;
61
65
  this.watcher = null;
62
66
  this.uploadQueue = null;
63
67
  this.standbyChanges = [];
64
68
  this.debouncedBuild = null;
65
69
  this.currentStagedBuildId = null;
66
- this.port = options.port;
67
- this.devServerPath = null;
68
70
 
69
71
  if (!this.targetAccountId || !this.projectConfig || !this.projectDir) {
72
+ logger.log(i18n(`${i18nKey}.failedToInitialize`));
70
73
  process.exit(EXIT_CODES.ERROR);
71
74
  }
72
75
  }
73
76
 
74
77
  async start() {
75
- this.spinnies = SpinniesManager.init();
78
+ SpinniesManager.init();
76
79
 
77
80
  this.watcher = chokidar.watch(this.projectSourceDir, {
78
81
  ignoreInitial: true,
@@ -88,26 +91,32 @@ class LocalDevManager {
88
91
  }
89
92
 
90
93
  console.clear();
94
+ SpinniesManager.removeAll();
91
95
 
92
- this.uploadQueue.start();
96
+ logger.log(i18n(`${i18nKey}.header.betaMessage`));
97
+ logger.log();
93
98
 
94
- await this.startServers();
99
+ this.updateConsoleHeader();
95
100
 
96
- this.logConsoleHeader();
101
+ await this.devServerStart();
102
+
103
+ this.uploadQueue.start();
97
104
  await this.startWatching();
105
+
98
106
  this.updateKeypressListeners();
107
+
108
+ this.updateConsoleHeader();
99
109
  }
100
110
 
101
111
  async stop() {
102
112
  this.clearConsoleContent();
103
113
 
104
- this.spinnies.add('cleanupMessage', {
114
+ SpinniesManager.add('cleanupMessage', {
105
115
  text: i18n(`${i18nKey}.exitingStart`),
106
116
  });
107
117
 
108
118
  await this.stopWatching();
109
-
110
- await this.cleanupServers();
119
+ await this.devServerCleanup();
111
120
 
112
121
  let exitCode = EXIT_CODES.SUCCESS;
113
122
 
@@ -133,11 +142,11 @@ class LocalDevManager {
133
142
  }
134
143
 
135
144
  if (exitCode === EXIT_CODES.SUCCESS) {
136
- this.spinnies.succeed('cleanupMessage', {
145
+ SpinniesManager.succeed('cleanupMessage', {
137
146
  text: i18n(`${i18nKey}.exitingSucceed`),
138
147
  });
139
148
  } else {
140
- this.spinnies.fail('cleanupMessage', {
149
+ SpinniesManager.fail('cleanupMessage', {
141
150
  text: i18n(`${i18nKey}.exitingFail`),
142
151
  });
143
152
  }
@@ -145,29 +154,8 @@ class LocalDevManager {
145
154
  process.exit(exitCode);
146
155
  }
147
156
 
148
- logConsoleHeader() {
149
- this.spinnies.removeAll();
150
- this.spinnies.add('betaMessage', {
151
- text: i18n(`${i18nKey}.header.betaMessage`),
152
- category: 'header',
153
- status: 'non-spinnable',
154
- });
155
-
156
- // this.spinnies.add('learnMoreLink', {
157
- // text: uiLink(
158
- // i18n(`${i18nKey}.header.learnMoreLink`),
159
- // this.generateLocalURL(`/hs/learnMore`),
160
- // { inSpinnies: true }
161
- // ),
162
- // category: 'header',
163
- // status: 'non-spinnable',
164
- // });
165
- this.spinnies.add('spacer-1', {
166
- text: ' ',
167
- status: 'non-spinnable',
168
- category: 'header',
169
- });
170
- this.spinnies.add('devModeRunning', {
157
+ updateConsoleHeader() {
158
+ SpinniesManager.addOrUpdate('devModeRunning', {
171
159
  text: i18n(`${i18nKey}.header.running`, {
172
160
  accountIdentifier: uiAccountDescription(this.targetAccountId),
173
161
  projectName: this.projectConfig.name,
@@ -175,34 +163,41 @@ class LocalDevManager {
175
163
  isParent: true,
176
164
  category: 'header',
177
165
  });
178
- this.spinnies.add('devModeStatus', {
166
+ SpinniesManager.addOrUpdate('devModeStatus', {
179
167
  text: i18n(`${i18nKey}.header.status.clean`),
180
168
  status: 'non-spinnable',
181
169
  indent: 1,
182
170
  category: 'header',
183
171
  });
184
- this.spinnies.add('viewInHubSpotLink', {
185
- text: uiLink(
186
- i18n(`${i18nKey}.header.viewInHubSpotLink`),
187
- this.generateLocalURL(`/hs/project`),
188
- { inSpinnies: true }
189
- ),
172
+
173
+ const viewText = DevServerManager.initialized
174
+ ? uiLink(
175
+ i18n(`${i18nKey}.header.viewInHubSpotLink`),
176
+ DevServerManager.generateURL(`hs/project`),
177
+ {
178
+ inSpinnies: true,
179
+ }
180
+ )
181
+ : ' ';
182
+
183
+ SpinniesManager.addOrUpdate('viewInHubSpotLink', {
184
+ text: viewText,
190
185
  status: 'non-spinnable',
191
186
  indent: 1,
192
187
  category: 'header',
193
188
  });
194
- this.spinnies.add('spacer-2', {
189
+ SpinniesManager.addOrUpdate('spacer-1', {
195
190
  text: ' ',
196
191
  status: 'non-spinnable',
197
192
  category: 'header',
198
193
  });
199
- this.spinnies.add('keypressMessage', {
194
+ SpinniesManager.addOrUpdate('quitHelper', {
200
195
  text: i18n(`${i18nKey}.header.quitHelper`),
201
196
  status: 'non-spinnable',
202
197
  indent: 1,
203
198
  category: 'header',
204
199
  });
205
- this.spinnies.add('lineSeparator', {
200
+ SpinniesManager.addOrUpdate('lineSeparator', {
206
201
  text: '-'.repeat(50),
207
202
  status: 'non-spinnable',
208
203
  noIndent: true,
@@ -211,7 +206,7 @@ class LocalDevManager {
211
206
  }
212
207
 
213
208
  clearConsoleContent() {
214
- this.spinnies.removeAll({ preserveCategory: 'header' });
209
+ SpinniesManager.removeAll({ preserveCategory: 'header' });
215
210
  }
216
211
 
217
212
  updateKeypressListeners() {
@@ -223,13 +218,13 @@ class LocalDevManager {
223
218
  this.uploadPermission === UPLOAD_PERMISSIONS.manual &&
224
219
  this.hasAnyUnsupportedStandbyChanges()
225
220
  ) {
226
- this.spinnies.remove('manualUploadRequired');
227
- this.spinnies.remove('manualUploadExplanation1');
228
- this.spinnies.remove('manualUploadExplanation2');
229
- this.spinnies.remove('manualUploadPrompt');
221
+ SpinniesManager.remove('manualUploadRequired');
222
+ SpinniesManager.remove('manualUploadExplanation1');
223
+ SpinniesManager.remove('manualUploadExplanation2');
224
+ SpinniesManager.remove('manualUploadPrompt');
230
225
 
231
226
  if (key.name === 'y') {
232
- this.spinnies.add(null, {
227
+ SpinniesManager.add(null, {
233
228
  text: i18n(`${i18nKey}.upload.manualUploadConfirmed`),
234
229
  status: 'succeed',
235
230
  succeedColor: 'white',
@@ -237,10 +232,10 @@ class LocalDevManager {
237
232
  });
238
233
  this.updateDevModeStatus('manualUpload');
239
234
  await this.createNewStagingBuild();
240
- await this.flushStandbyChanges();
235
+ this.flushStandbyChanges();
241
236
  await this.queueBuild();
242
237
  } else if (key.name === 'n') {
243
- this.spinnies.add(null, {
238
+ SpinniesManager.add(null, {
244
239
  text: i18n(`${i18nKey}.upload.manualUploadSkipped`),
245
240
  status: 'fail',
246
241
  failColor: 'white',
@@ -251,12 +246,44 @@ class LocalDevManager {
251
246
  });
252
247
  }
253
248
 
254
- generateLocalURL(path) {
255
- return this.devServerPath ? `${this.devServerPath}${path}` : null;
249
+ logBuildError(buildStatus = {}) {
250
+ const subTasks = buildStatus[PROJECT_BUILD_TEXT.SUBTASK_KEY] || [];
251
+ const failedSubTasks = subTasks.filter(task => task.status === 'FAILURE');
252
+
253
+ if (failedSubTasks.length) {
254
+ this.updateDevModeStatus('buildError');
255
+
256
+ failedSubTasks.forEach(failedSubTask => {
257
+ SpinniesManager.add(null, {
258
+ text: failedSubTask.errorMessage,
259
+ status: 'fail',
260
+ failColor: 'white',
261
+ indent: 1,
262
+ });
263
+ });
264
+ }
265
+ }
266
+
267
+ logDeployError(deployStatus = {}) {
268
+ const subTasks = deployStatus[PROJECT_DEPLOY_TEXT.SUBTASK_KEY] || [];
269
+ const failedSubTasks = subTasks.filter(task => task.status === 'FAILURE');
270
+
271
+ if (failedSubTasks.length) {
272
+ this.updateDevModeStatus('deployError');
273
+
274
+ failedSubTasks.forEach(failedSubTask => {
275
+ SpinniesManager.add(null, {
276
+ text: failedSubTask.errorMessage,
277
+ status: 'fail',
278
+ failColor: 'white',
279
+ indent: 1,
280
+ });
281
+ });
282
+ }
256
283
  }
257
284
 
258
285
  updateDevModeStatus(langKey) {
259
- this.spinnies.update('devModeStatus', {
286
+ SpinniesManager.update('devModeStatus', {
260
287
  text: i18n(`${i18nKey}.header.status.${langKey}`),
261
288
  status: 'non-spinnable',
262
289
  noIndent: true,
@@ -283,9 +310,12 @@ class LocalDevManager {
283
310
  logger.debug(err);
284
311
  if (isSpecifiedError(err, { subCategory: ERROR_TYPES.PROJECT_LOCKED })) {
285
312
  await cancelStagedBuild(this.targetAccountId, this.projectConfig.name);
286
- logger.log(i18n(`${i18nKey}.previousStagingBuildCancelled`));
313
+ SpinniesManager.add(null, {
314
+ text: i18n(`${i18nKey}.previousStagingBuildCancelled`),
315
+ status: 'non-spinnable',
316
+ });
287
317
  }
288
- process.exit(EXIT_CODES.ERROR);
318
+ this.stop();
289
319
  }
290
320
  }
291
321
 
@@ -315,13 +345,7 @@ class LocalDevManager {
315
345
  remotePath: path.relative(this.projectSourceDir, filePath),
316
346
  };
317
347
 
318
- const notifyResponse = await this.notifyServers(changeInfo);
319
-
320
- if (!notifyResponse.uploadRequired) {
321
- this.updateDevModeStatus('supportedChange');
322
- this.addChangeToStandbyQueue({ ...changeInfo, supported: true });
323
-
324
- await this.executeServers(notifyResponse, changeInfo);
348
+ if (changeInfo.filePath.includes('dist')) {
325
349
  return;
326
350
  }
327
351
 
@@ -330,18 +354,10 @@ class LocalDevManager {
330
354
  return;
331
355
  }
332
356
 
333
- if (this.uploadQueue.isPaused) {
334
- this.addChangeToStandbyQueue({ ...changeInfo, supported: false });
335
- } else {
336
- await this.flushStandbyChanges();
337
-
338
- if (!this.uploadQueue.isPaused) {
339
- this.debounceQueueBuild(changeInfo);
340
- }
357
+ this.addChangeToStandbyQueue({ ...changeInfo, supported: false });
341
358
 
342
- return this.uploadQueue.add(async () => {
343
- await this.sendChanges(changeInfo);
344
- });
359
+ if (!this.uploadQueue.isPaused) {
360
+ this.flushStandbyChanges();
345
361
  }
346
362
  }
347
363
 
@@ -351,7 +367,7 @@ class LocalDevManager {
351
367
  if (this.uploadPermission === UPLOAD_PERMISSIONS.never) {
352
368
  this.updateDevModeStatus('noUploadsAllowed');
353
369
 
354
- this.spinnies.add('noUploadsAllowed', {
370
+ SpinniesManager.add('noUploadsAllowed', {
355
371
  text: i18n(`${i18nKey}.upload.noUploadsAllowed`, {
356
372
  filePath: remotePath,
357
373
  }),
@@ -362,29 +378,34 @@ class LocalDevManager {
362
378
  } else {
363
379
  this.updateDevModeStatus('manualUploadRequired');
364
380
 
365
- this.addChangeToStandbyQueue({ ...changeInfo, supported: false });
366
-
367
- this.spinnies.add('manualUploadRequired', {
368
- text: i18n(`${i18nKey}.upload.manualUploadRequired`),
369
- status: 'fail',
370
- failColor: 'white',
371
- noIndent: true,
372
- });
373
- this.spinnies.add('manualUploadExplanation1', {
374
- text: i18n(`${i18nKey}.upload.manualUploadExplanation1`),
375
- status: 'non-spinnable',
376
- indent: 1,
377
- });
378
- this.spinnies.add('manualUploadExplanation2', {
379
- text: i18n(`${i18nKey}.upload.manualUploadExplanation2`),
380
- status: 'non-spinnable',
381
- indent: 1,
382
- });
383
- this.spinnies.add('manualUploadPrompt', {
384
- text: i18n(`${i18nKey}.upload.manualUploadPrompt`),
385
- status: 'non-spinnable',
386
- indent: 1,
381
+ const addedToQueue = this.addChangeToStandbyQueue({
382
+ ...changeInfo,
383
+ supported: false,
387
384
  });
385
+
386
+ if (addedToQueue) {
387
+ SpinniesManager.add('manualUploadRequired', {
388
+ text: i18n(`${i18nKey}.upload.manualUploadRequired`),
389
+ status: 'fail',
390
+ failColor: 'white',
391
+ noIndent: true,
392
+ });
393
+ SpinniesManager.add('manualUploadExplanation1', {
394
+ text: i18n(`${i18nKey}.upload.manualUploadExplanation1`),
395
+ status: 'non-spinnable',
396
+ indent: 1,
397
+ });
398
+ SpinniesManager.add('manualUploadExplanation2', {
399
+ text: i18n(`${i18nKey}.upload.manualUploadExplanation2`),
400
+ status: 'non-spinnable',
401
+ indent: 1,
402
+ });
403
+ SpinniesManager.add('manualUploadPrompt', {
404
+ text: i18n(`${i18nKey}.upload.manualUploadPrompt`),
405
+ status: 'non-spinnable',
406
+ indent: 1,
407
+ });
408
+ }
388
409
  }
389
410
  }
390
411
 
@@ -392,14 +413,24 @@ class LocalDevManager {
392
413
  const { event, filePath } = changeInfo;
393
414
 
394
415
  if (event === WATCH_EVENTS.add || event === WATCH_EVENTS.change) {
395
- if (!isAllowedExtension(filePath)) {
396
- logger.debug(`Extension not allowed: ${filePath}`);
397
- return;
416
+ if (!isAllowedExtension(filePath, ['jsx', 'tsx'])) {
417
+ SpinniesManager.add(null, {
418
+ text: i18n(`${i18nKey}.upload.extensionNotAllowed`, {
419
+ filePath,
420
+ }),
421
+ status: 'non-spinnable',
422
+ });
423
+ return false;
398
424
  }
399
425
  }
400
426
  if (shouldIgnoreFile(filePath, true)) {
401
- logger.debug(`File ignored: ${filePath}`);
402
- return;
427
+ SpinniesManager.add(null, {
428
+ text: i18n(`${i18nKey}.upload.fileIgnored`, {
429
+ filePath,
430
+ }),
431
+ status: 'non-spinnable',
432
+ });
433
+ return false;
403
434
  }
404
435
 
405
436
  const existingIndex = this.standbyChanges.findIndex(
@@ -412,6 +443,7 @@ class LocalDevManager {
412
443
  } else {
413
444
  this.standbyChanges.push(changeInfo);
414
445
  }
446
+ return true;
415
447
  }
416
448
 
417
449
  async sendChanges(changeInfo) {
@@ -419,7 +451,7 @@ class LocalDevManager {
419
451
 
420
452
  try {
421
453
  if (event === WATCH_EVENTS.add || event === WATCH_EVENTS.change) {
422
- const spinniesKey = this.spinnies.add(null, {
454
+ const { name: spinnerName } = SpinniesManager.add(null, {
423
455
  text: i18n(`${i18nKey}.upload.uploadingAddChange`, {
424
456
  filePath: remotePath,
425
457
  }),
@@ -431,7 +463,7 @@ class LocalDevManager {
431
463
  filePath,
432
464
  remotePath
433
465
  );
434
- this.spinnies.update(spinniesKey, {
466
+ SpinniesManager.update(spinnerName, {
435
467
  text: i18n(`${i18nKey}.upload.uploadedAddChange`, {
436
468
  filePath: remotePath,
437
469
  }),
@@ -441,18 +473,20 @@ class LocalDevManager {
441
473
  event === WATCH_EVENTS.unlink ||
442
474
  event === WATCH_EVENTS.unlinkDir
443
475
  ) {
444
- const spinniesKey = this.spinnies.add(null, {
476
+ const { name: spinnerName } = SpinniesManager.add(null, {
445
477
  text: i18n(`${i18nKey}.upload.uploadingRemoveChange`, {
446
478
  filePath: remotePath,
447
479
  }),
448
480
  status: 'non-spinnable',
449
481
  });
482
+ const path =
483
+ event === WATCH_EVENTS.unlinkDir ? `${remotePath}/` : remotePath;
450
484
  await deleteFileFromBuild(
451
485
  this.targetAccountId,
452
486
  this.projectConfig.name,
453
- remotePath
487
+ path
454
488
  );
455
- this.spinnies.update(spinniesKey, {
489
+ SpinniesManager.update(spinnerName, {
456
490
  text: i18n(`${i18nKey}.upload.uploadedRemoveChange`, {
457
491
  filePath: remotePath,
458
492
  }),
@@ -487,7 +521,9 @@ class LocalDevManager {
487
521
  }
488
522
 
489
523
  async queueBuild() {
490
- const spinniesKey = this.spinnies.add(null, {
524
+ SpinniesManager.add(null, { text: ' ', status: 'non-spinnable' });
525
+
526
+ const { name: spinnerName } = SpinniesManager.add(null, {
491
527
  text: i18n(`${i18nKey}.upload.uploadingChanges`, {
492
528
  accountIdentifier: uiAccountDescription(this.targetAccountId),
493
529
  buildId: this.currentStagedBuildId,
@@ -497,60 +533,94 @@ class LocalDevManager {
497
533
 
498
534
  await this.pauseUploadQueue();
499
535
 
536
+ let queueBuildError;
537
+
500
538
  try {
501
539
  await queueBuild(this.targetAccountId, this.projectConfig.name);
502
540
  } catch (err) {
503
- logger.debug(err);
504
- if (
505
- isSpecifiedError(err, {
506
- subCategory: ERROR_TYPES.MISSING_PROJECT_PROVISION,
507
- })
508
- ) {
509
- logger.log(i18n(`${i18nKey}.cancelledFromUI`));
510
- this.stop();
511
- } else {
512
- logApiErrorInstance(
513
- err,
514
- new ApiErrorContext({
515
- accountId: this.targetAccountId,
516
- projectName: this.projectConfig.name,
517
- })
518
- );
519
- }
520
- return;
541
+ queueBuildError = err;
521
542
  }
522
543
 
523
- const result = await pollProjectBuildAndDeploy(
524
- this.targetAccountId,
525
- this.projectConfig,
526
- null,
527
- this.currentStagedBuildId,
528
- true
529
- );
544
+ if (queueBuildError) {
545
+ this.updateDevModeStatus('buildError');
530
546
 
531
- if (result && result.succeeded) {
532
- this.spinnies.succeed(spinniesKey, {
533
- text: i18n(`${i18nKey}.upload.uploadedChangesSucceeded`, {
534
- accountIdentifier: uiAccountDescription(this.targetAccountId),
535
- buildId: result.buildId,
536
- }),
537
- succeedColor: 'white',
538
- noIndent: true,
539
- });
540
- } else {
541
- this.spinnies.fail(spinniesKey, {
547
+ logger.debug(queueBuildError);
548
+
549
+ SpinniesManager.fail(spinnerName, {
542
550
  text: i18n(`${i18nKey}.upload.uploadedChangesFailed`, {
543
551
  accountIdentifier: uiAccountDescription(this.targetAccountId),
544
- buildId: result.buildId,
552
+ buildId: this.currentStagedBuildId,
545
553
  }),
546
554
  failColor: 'white',
547
555
  noIndent: true,
548
556
  });
557
+
558
+ if (
559
+ isSpecifiedError(queueBuildError, {
560
+ subCategory: ERROR_TYPES.MISSING_PROJECT_PROVISION,
561
+ })
562
+ ) {
563
+ SpinniesManager.add(null, {
564
+ text: i18n(`${i18nKey}.cancelledFromUI`),
565
+ status: 'non-spinnable',
566
+ indent: 1,
567
+ });
568
+ this.stop();
569
+ } else if (
570
+ queueBuildError &&
571
+ queueBuildError.error &&
572
+ queueBuildError.error.message
573
+ ) {
574
+ SpinniesManager.add(null, {
575
+ text: queueBuildError.error.message,
576
+ status: 'non-spinnable',
577
+ indent: 1,
578
+ });
579
+ }
580
+ } else {
581
+ const result = await pollProjectBuildAndDeploy(
582
+ this.targetAccountId,
583
+ this.projectConfig,
584
+ null,
585
+ this.currentStagedBuildId,
586
+ true
587
+ );
588
+
589
+ if (result.succeeded) {
590
+ this.updateDevModeStatus('clean');
591
+
592
+ SpinniesManager.succeed(spinnerName, {
593
+ text: i18n(`${i18nKey}.upload.uploadedChangesSucceeded`, {
594
+ accountIdentifier: uiAccountDescription(this.targetAccountId),
595
+ buildId: result.buildId,
596
+ }),
597
+ succeedColor: 'white',
598
+ noIndent: true,
599
+ });
600
+ } else {
601
+ SpinniesManager.fail(spinnerName, {
602
+ text: i18n(`${i18nKey}.upload.uploadedChangesFailed`, {
603
+ accountIdentifier: uiAccountDescription(this.targetAccountId),
604
+ buildId: result.buildId,
605
+ }),
606
+ failColor: 'white',
607
+ noIndent: true,
608
+ });
609
+
610
+ if (result.buildResult.status === 'FAILURE') {
611
+ this.logBuildError(result.buildResult);
612
+ } else if (result.deployResult.status === 'FAILURE') {
613
+ this.logDeployError(result.deployResult);
614
+ }
615
+ }
549
616
  }
550
617
 
551
- this.spinnies.removeAll({ targetCategory: 'projectPollStatus' });
618
+ SpinniesManager.removeAll({ targetCategory: 'projectPollStatus' });
552
619
 
553
- if (this.uploadPermission === UPLOAD_PERMISSIONS.always) {
620
+ if (
621
+ !queueBuildError &&
622
+ this.uploadPermission === UPLOAD_PERMISSIONS.always
623
+ ) {
554
624
  await this.createNewStagingBuild();
555
625
  }
556
626
 
@@ -558,14 +628,12 @@ class LocalDevManager {
558
628
 
559
629
  if (this.hasAnyUnsupportedStandbyChanges()) {
560
630
  this.flushStandbyChanges();
561
- } else {
562
- this.updateDevModeStatus('clean');
563
631
  }
564
632
  }
565
633
 
566
- async flushStandbyChanges() {
634
+ flushStandbyChanges() {
567
635
  if (this.standbyChanges.length) {
568
- await this.uploadQueue.addAll(
636
+ this.uploadQueue.addAll(
569
637
  this.standbyChanges.map(changeInfo => {
570
638
  return async () => {
571
639
  if (
@@ -586,25 +654,45 @@ class LocalDevManager {
586
654
  await this.watcher.close();
587
655
  }
588
656
 
589
- async startServers() {
590
- this.devServerPath = await DevServerManager.start({
591
- accountId: this.targetAccountId,
592
- projectConfig: this.projectConfig,
593
- port: this.port,
657
+ handleServerLog(serverKey, ...args) {
658
+ SpinniesManager.add(null, {
659
+ text: `${args.join('')}`,
660
+ status: 'non-spinnable',
594
661
  });
595
662
  }
596
663
 
597
- async notifyServers(changeInfo) {
598
- const notifyResponse = await DevServerManager.notify(changeInfo);
599
- return notifyResponse;
600
- }
601
-
602
- async executeServers(notifyResponse, changeInfo) {
603
- await DevServerManager.execute(notifyResponse, changeInfo);
664
+ async devServerStart() {
665
+ try {
666
+ await DevServerManager.start({
667
+ accountId: this.targetAccountId,
668
+ debug: this.debug,
669
+ spinniesLogger: this.handleServerLog,
670
+ projectConfig: this.projectConfig,
671
+ projectSourceDir: this.projectSourceDir,
672
+ });
673
+ } catch (e) {
674
+ if (this.debug) {
675
+ logger.error(e);
676
+ }
677
+ SpinniesManager.add(null, {
678
+ text: i18n(`${i18nKey}.devServer.startError`),
679
+ status: 'non-spinnable',
680
+ });
681
+ }
604
682
  }
605
683
 
606
- async cleanupServers() {
607
- await DevServerManager.cleanup();
684
+ async devServerCleanup() {
685
+ try {
686
+ await DevServerManager.cleanup();
687
+ } catch (e) {
688
+ if (this.debug) {
689
+ logger.error(e);
690
+ }
691
+ SpinniesManager.add(null, {
692
+ text: i18n(`${i18nKey}.devServer.cleanupError`),
693
+ status: 'non-spinnable',
694
+ });
695
+ }
608
696
  }
609
697
  }
610
698