diff --git a/index.js b/index.js index d16bd8f8..fa6799c9 100644 --- a/index.js +++ b/index.js @@ -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); diff --git a/lib/plugins/pipeline.js b/lib/plugins/pipeline.js index ee4e8183..f8802896 100644 --- a/lib/plugins/pipeline.js +++ b/lib/plugins/pipeline.js @@ -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); diff --git a/test/index.test.js b/test/index.test.js index 11a16fcf..2f233a9f 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -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('..', { diff --git a/test/plugins/pipeline.test.js b/test/plugins/pipeline.test.js index 395b42ab..c2261846 100644 --- a/test/plugins/pipeline.test.js +++ b/test/plugins/pipeline.test.js @@ -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);