Skip to content

Commit dc419f9

Browse files
committed
feat(ui): allow UI error method to handle listr errors
no issue - this allows certain places to run multiple listr checks at once and have the ui class handle any resulting errors
1 parent 0075e77 commit dc419f9

File tree

2 files changed

+97
-0
lines changed

2 files changed

+97
-0
lines changed

lib/ui/index.js

+27
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const Promise = require('bluebird');
99
const inquirer = require('inquirer');
1010
const isObject = require('lodash/isObject');
1111
const stripAnsi = require('strip-ansi');
12+
const ListrError = require('listr/lib/listr-error');
1213
const logSymbols = require('log-symbols');
1314
const isFunction = require('lodash/isFunction');
1415

@@ -330,6 +331,32 @@ class UI {
330331
this.log(`\nTry running ${(chalk.cyan('ghost doctor'))} to check your system for known issues.`);
331332

332333
this.log('\n' + error.help, 'blue');
334+
} else if (error instanceof ListrError) {
335+
// Listr errors have an array of errors appended to them
336+
this.log('One or more errors occurred.', 'red');
337+
338+
const logOutput = [];
339+
340+
error.errors.forEach((err, index) => {
341+
const verboseOutput = err.toString(true);
342+
343+
this.log(`\n${index + 1}) ${err.options && err.options.task ? err.options.task : err.type}\n`, 'red', true);
344+
this.log(this.verbose ? verboseOutput : err.toString(false), null, true);
345+
346+
if (err.logToFile && err.logToFile()) {
347+
logOutput.push(stripAnsi(verboseOutput));
348+
}
349+
});
350+
351+
this.log(debugInfo, 'yellow');
352+
353+
if (logOutput.length) {
354+
const logLocation = system.writeErrorLog(stripAnsi(`${debugInfo}\n${logOutput.join('\n\n')}`));
355+
this.log(`\nAdditional log info available in: ${logLocation}`);
356+
}
357+
358+
this.log(`\nTry running ${(chalk.cyan('ghost doctor'))} to check your system for known issues.`);
359+
this.log('\nPlease refer to https://docs.ghost.org/v1/docs/troubleshooting#section-cli-errors for troubleshooting.', 'blue');
333360
} else if (error instanceof Error) {
334361
// System errors or regular old errors go here.
335362
let output = `An error occurred.\n${chalk.yellow('Message:')} '${error.message}'\n\n`;

test/unit/ui/index-spec.js

+70
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,76 @@ describe('Unit: UI', function () {
504504
});
505505
});
506506

507+
describe('handles ListrErrors', function () {
508+
const ListrError = require('listr/lib/listr-error');
509+
const errors = require('../../../lib/errors');
510+
511+
it('verbose without log output', function () {
512+
const err = new ListrError('Something happened');
513+
err.errors = [
514+
new errors.SystemError('Error 1'),
515+
new errors.SystemError({
516+
message: 'Error 2',
517+
task: 'Task 2'
518+
})
519+
];
520+
521+
const system = {writeErrorLog: sinon.stub()};
522+
const ctx = {
523+
verbose: true,
524+
log: sinon.stub(),
525+
_formatDebug: sinon.stub().returns('cherries')
526+
};
527+
528+
ui.error.call(ctx, err, system);
529+
530+
expect(ctx.log.callCount).to.equal(8);
531+
expect(ctx._formatDebug.calledOnce).to.be.true;
532+
expect(system.writeErrorLog.called).to.be.false;
533+
expect(ctx.log.getCall(0).args[0]).to.match(/One or more errors occurred/);
534+
expect(ctx.log.getCall(1).args[0]).to.match(/1\) SystemError/);
535+
expect(stripAnsi(ctx.log.getCall(2).args[0])).to.match(/Message: Error 1/);
536+
expect(ctx.log.getCall(3).args[0]).to.match(/2\) Task 2/);
537+
expect(stripAnsi(ctx.log.getCall(4).args[0])).to.match(/Message: Error 2/);
538+
expect(ctx.log.getCall(5).args[0]).to.equal('cherries');
539+
expect(stripAnsi(ctx.log.getCall(6).args[0])).to.match(/Try running ghost doctor to check your system for known issues./);
540+
expect(ctx.log.getCall(7).args[0]).to.match(/Please refer to https:\/\/docs.ghost.org/);
541+
});
542+
543+
it('non-verbose with log output', function () {
544+
const err = new ListrError('Something happened');
545+
err.errors = [
546+
new errors.ProcessError({message: 'Error 1'}),
547+
new errors.ProcessError({
548+
message: 'Error 2',
549+
task: 'Task 2'
550+
})
551+
];
552+
553+
const system = {writeErrorLog: sinon.stub()};
554+
const ctx = {
555+
verbose: false,
556+
log: sinon.stub(),
557+
_formatDebug: sinon.stub().returns('cherries')
558+
};
559+
560+
ui.error.call(ctx, err, system);
561+
562+
expect(ctx.log.callCount).to.equal(9);
563+
expect(ctx._formatDebug.calledOnce).to.be.true;
564+
expect(system.writeErrorLog.called).to.be.true;
565+
expect(ctx.log.getCall(0).args[0]).to.match(/One or more errors occurred/);
566+
expect(ctx.log.getCall(1).args[0]).to.match(/1\) ProcessError/);
567+
expect(stripAnsi(ctx.log.getCall(2).args[0])).to.match(/Message: Error 1/);
568+
expect(ctx.log.getCall(3).args[0]).to.match(/2\) Task 2/);
569+
expect(stripAnsi(ctx.log.getCall(4).args[0])).to.match(/Message: Error 2/);
570+
expect(ctx.log.getCall(5).args[0]).to.equal('cherries');
571+
expect(ctx.log.getCall(6).args[0]).to.match(/Additional log info available in/);
572+
expect(stripAnsi(ctx.log.getCall(7).args[0])).to.match(/Try running ghost doctor to check your system for known issues./);
573+
expect(ctx.log.getCall(8).args[0]).to.match(/Please refer to https:\/\/docs.ghost.org/);
574+
});
575+
});
576+
507577
describe('handles generic errors', function () {
508578
it('verbosly', function (done) {
509579
const system = {writeErrorLog: sinon.stub()};

0 commit comments

Comments
 (0)