feat: allow plugins to throw an iterable list of errors

This commit is contained in:
Pierre Vanduynslager 2018-02-06 19:54:17 -05:00
parent 9360caf253
commit 9b2f6bfed2
4 changed files with 43 additions and 6 deletions

View File

@ -1,4 +1,4 @@
const {template} = require('lodash');
const {template, isFunction} = require('lodash');
const marked = require('marked');
const TerminalRenderer = require('marked-terminal');
const envCi = require('env-ci');
@ -108,7 +108,7 @@ module.exports = async opts => {
unhook();
return result;
} catch (err) {
const errors = err.name === 'AggregateError' ? Array.from(err).sort(error => !error.semanticRelease) : [err];
const errors = err && isFunction(err[Symbol.iterator]) ? [...err].sort(error => !error.semanticRelease) : [err];
for (const error of errors) {
if (error.semanticRelease) {
logger.log(`%s ${error.message}`, error.code);

View File

@ -1,4 +1,4 @@
const {identity} = require('lodash');
const {identity, isFunction} = require('lodash');
const pReflect = require('p-reflect');
const pReduce = require('p-reduce');
const AggregateError = require('aggregate-error');
@ -15,7 +15,11 @@ module.exports = steps => async (input, settleAll = false, getNextInput = identi
if (settleAll) {
const {isFulfilled, value, reason} = await pReflect(nextStep(prevResult));
result = isFulfilled ? value : reason;
(isFulfilled ? results : errors).push(result);
if (isFulfilled) {
results.push(result);
} else {
errors.push(...(result && isFunction(result[Symbol.iterator]) ? result : [result]));
}
} else {
result = await nextStep(prevResult);
results.push(result);

View File

@ -3,6 +3,7 @@ import proxyquire from 'proxyquire';
import {stub} from 'sinon';
import tempy from 'tempy';
import clearModule from 'clear-module';
import AggregateError from 'aggregate-error';
import SemanticReleaseError from '@semantic-release/error';
import DEFINITIONS from '../lib/plugins/definitions';
import {
@ -229,7 +230,7 @@ test.serial('Log all "verifyConditions" errors', async t => {
const options = {
branch: 'master',
repositoryUrl,
verifyConditions: [stub().rejects(error1), stub().rejects(error2), stub().rejects(error3)],
verifyConditions: [stub().rejects(new AggregateError([error1, error2])), stub().rejects(error3)],
};
const semanticRelease = proxyquire('..', {

View File

@ -1,5 +1,6 @@
import test from 'ava';
import {stub} from 'sinon';
import AggregateError from 'aggregate-error';
import pipeline from '../../lib/plugins/pipeline';
test('Execute each function in series passing the same input', async t => {
@ -65,6 +66,22 @@ test('Stop execution and throw error is a step rejects', async t => {
t.true(step3.notCalled);
});
test('Throw all errors from the first step throwing an AggregateError', async t => {
const error1 = new Error('test error 1');
const error2 = new Error('test error 2');
const step1 = stub().resolves(1);
const step2 = stub().rejects(new AggregateError([error1, error2]));
const step3 = stub().resolves(3);
const errors = await t.throws(pipeline([step1, step2, step3])(0));
t.deepEqual(Array.from(errors), [error1, error2]);
t.true(step1.calledWith(0));
t.true(step2.calledWith(0));
t.true(step3.notCalled);
});
test('Execute all even if a Promise rejects', async t => {
const error1 = new Error('test error 1');
const error2 = new Error('test error 2');
@ -80,7 +97,22 @@ test('Execute all even if a Promise rejects', async t => {
t.true(step3.calledWith(0));
});
test('Execute each function in series passing a transformed input even if a Promise rejects', async t => {
test('Throw all errors from all steps throwing an AggregateError', async t => {
const error1 = new Error('test error 1');
const error2 = new Error('test error 2');
const error3 = new Error('test error 3');
const error4 = new Error('test error 4');
const step1 = stub().rejects(new AggregateError([error1, error2]));
const step2 = stub().rejects(new AggregateError([error3, error4]));
const errors = await t.throws(pipeline([step1, step2])(0, true));
t.deepEqual(Array.from(errors), [error1, error2, error3, error4]);
t.true(step1.calledWith(0));
t.true(step2.calledWith(0));
});
test('Execute each function in series passing a transformed input even if a step rejects', async t => {
const error2 = new Error('test error 2');
const error3 = new Error('test error 3');
const step1 = stub().resolves(1);