Skip to content

Commit 147d2f8

Browse files
pvdlggr2m
authored andcommitted
feat: return all errors
Allow to report to the user multiple config/auth errors at once
1 parent db60bbd commit 147d2f8

File tree

5 files changed

+49
-43
lines changed

5 files changed

+49
-43
lines changed

index.js

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,11 @@ let verified;
77
async function verifyConditions(pluginConfig, {options, logger}) {
88
// If the Git publish plugin is used and has `assets` or `message` configured, validate them now in order to prevent any release if the configuration is wrong
99
if (options.publish) {
10-
const publishPlugin = castArray(options.publish).find(
11-
config => config.path && config.path === '@semantic-release/git'
12-
);
13-
if (publishPlugin && publishPlugin.assets) {
14-
pluginConfig.assets = publishPlugin.assets;
15-
}
16-
if (publishPlugin && publishPlugin.message) {
17-
pluginConfig.message = publishPlugin.message;
18-
}
10+
const publishPlugin =
11+
castArray(options.publish).find(config => config.path && config.path === '@semantic-release/git') || {};
12+
13+
pluginConfig.assets = pluginConfig.assets || publishPlugin.assets;
14+
pluginConfig.message = pluginConfig.message || publishPlugin.message;
1915
}
2016
await verifyGit(pluginConfig, options, logger);
2117
verified = true;

lib/verify.js

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
const {isString, isUndefined, isArray, isPlainObject} = require('lodash');
2+
const AggregateError = require('aggregate-error');
23
const SemanticReleaseError = require('@semantic-release/error');
34
const resolveConfig = require('./resolve-config');
45

@@ -13,6 +14,7 @@ const resolveConfig = require('./resolve-config');
1314
*/
1415
module.exports = async pluginConfig => {
1516
const {message, assets} = resolveConfig(pluginConfig);
17+
const errors = [];
1618

1719
if (
1820
!isUndefined(assets) &&
@@ -22,14 +24,22 @@ module.exports = async pluginConfig => {
2224
assets.every(asset => isStringOrStringArray(asset) || (isPlainObject(asset) && isStringOrStringArray(asset.path)))
2325
)
2426
) {
25-
throw new SemanticReleaseError(
26-
'The "assets" options must be an Array of Strings or Objects with a path property.',
27-
'EINVALIDASSETS'
27+
errors.push(
28+
new SemanticReleaseError(
29+
'The "assets" options must be an Array of Strings or Objects with a path property.',
30+
'EINVALIDASSETS'
31+
)
2832
);
2933
}
3034

3135
if (!isUndefined(message) && !(isString(message) && message.trim())) {
32-
throw new SemanticReleaseError('The "message" options, if defined, must be a non empty String.', 'EINVALIDMESSAGE');
36+
errors.push(
37+
new SemanticReleaseError('The "message" options, if defined, must be a non empty String.', 'EINVALIDMESSAGE')
38+
);
39+
}
40+
41+
if (errors.length > 0) {
42+
throw new AggregateError(errors);
3343
}
3444
};
3545

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
],
1818
"dependencies": {
1919
"@semantic-release/error": "^2.1.0",
20+
"aggregate-error": "^1.0.0",
2021
"debug": "^3.1.0",
2122
"dir-glob": "^2.0.0",
2223
"execa": "^0.9.0",
@@ -76,7 +77,7 @@
7677
"all": true
7778
},
7879
"peerDependencies": {
79-
"semantic-release": "13.x.x"
80+
"semantic-release": ">=13.3.0 <14.0.0"
8081
},
8182
"prettier": {
8283
"printWidth": 120,

test/integration.test.js

Lines changed: 23 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -106,36 +106,35 @@ test.serial('Verify authentication only on the fist call', async t => {
106106
const branch = 'master';
107107
const repositoryUrl = await gitRepo(true);
108108
const nextRelease = {version: '2.0.0', gitTag: 'v2.0.0'};
109+
const options = {repositoryUrl, branch, publish: ['@semantic-release/npm']};
109110

110-
await t.notThrows(t.context.m.verifyConditions({}, {logger: t.context.logger, options: {repositoryUrl, branch}}));
111+
await t.notThrows(t.context.m.verifyConditions({}, {options, logger: t.context.logger}));
111112
await t.context.m.publish({}, {logger: t.context.logger, options: {repositoryUrl, branch}, nextRelease});
112113
});
113114

114-
test('Throw SemanticReleaseError if publish "assets" option is invalid', async t => {
115+
test('Throw SemanticReleaseError if publish config is invalid', async t => {
116+
const message = 42;
115117
const assets = true;
116-
const error = await t.throws(
117-
t.context.m.verifyConditions(
118-
{},
119-
{options: {publish: ['@semantic-release/npm', {path: '@semantic-release/git', assets}]}, logger: t.context.logger}
120-
)
121-
);
122-
123-
t.is(error.name, 'SemanticReleaseError');
124-
t.is(error.code, 'EINVALIDASSETS');
118+
const options = {publish: ['@semantic-release/npm', {path: '@semantic-release/git', message, assets}]};
119+
120+
const errors = [...(await t.throws(t.context.m.verifyConditions({}, {options, logger: t.context.logger})))];
121+
122+
t.is(errors[0].name, 'SemanticReleaseError');
123+
t.is(errors[0].code, 'EINVALIDASSETS');
124+
t.is(errors[1].name, 'SemanticReleaseError');
125+
t.is(errors[1].code, 'EINVALIDMESSAGE');
125126
});
126127

127-
test('Throw SemanticReleaseError if publish "message" option is invalid', async t => {
128+
test('Throw SemanticReleaseError if config is invalid', async t => {
128129
const message = 42;
129-
const error = await t.throws(
130-
t.context.m.verifyConditions(
131-
{},
132-
{
133-
options: {publish: ['@semantic-release/npm', {path: '@semantic-release/git', message}]},
134-
logger: t.context.logger,
135-
}
136-
)
137-
);
138-
139-
t.is(error.name, 'SemanticReleaseError');
140-
t.is(error.code, 'EINVALIDMESSAGE');
130+
const assets = true;
131+
132+
const errors = [
133+
...(await t.throws(t.context.m.verifyConditions({message, assets}, {options: {}, logger: t.context.logger}))),
134+
];
135+
136+
t.is(errors[0].name, 'SemanticReleaseError');
137+
t.is(errors[0].code, 'EINVALIDASSETS');
138+
t.is(errors[1].name, 'SemanticReleaseError');
139+
t.is(errors[1].code, 'EINVALIDMESSAGE');
141140
});

test/verify.test.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,15 @@ test.afterEach.always(() => {
2929

3030
test('Throw SemanticReleaseError if "assets" option is not a String or false or an Array of Objects', async t => {
3131
const assets = true;
32-
const error = await t.throws(verify({assets}, {}, t.context.logger));
32+
const [error] = await t.throws(verify({assets}, {}, t.context.logger));
3333

3434
t.is(error.name, 'SemanticReleaseError');
3535
t.is(error.code, 'EINVALIDASSETS');
3636
});
3737

3838
test('Throw SemanticReleaseError if "assets" option is not an Array with invalid elements', async t => {
3939
const assets = ['file.js', 42];
40-
const error = await t.throws(verify({assets}, {}, t.context.logger));
40+
const [error] = await t.throws(verify({assets}, {}, t.context.logger));
4141

4242
t.is(error.name, 'SemanticReleaseError');
4343
t.is(error.code, 'EINVALIDASSETS');
@@ -108,23 +108,23 @@ test.serial('Verify "assets" is an Array of Object with a glob Arrays in path pr
108108

109109
test('Throw SemanticReleaseError if "message" option is not a String', async t => {
110110
const message = 42;
111-
const error = await t.throws(verify({message}, {}, t.context.logger));
111+
const [error] = await t.throws(verify({message}, {}, t.context.logger));
112112

113113
t.is(error.name, 'SemanticReleaseError');
114114
t.is(error.code, 'EINVALIDMESSAGE');
115115
});
116116

117117
test('Throw SemanticReleaseError if "message" option is an empty String', async t => {
118118
const message = '';
119-
const error = await t.throws(verify({message}, {}, t.context.logger));
119+
const [error] = await t.throws(verify({message}, {}, t.context.logger));
120120

121121
t.is(error.name, 'SemanticReleaseError');
122122
t.is(error.code, 'EINVALIDMESSAGE');
123123
});
124124

125125
test('Throw SemanticReleaseError if "message" option is a whitespace String', async t => {
126126
const message = ' \n \r ';
127-
const error = await t.throws(verify({message}, {}, t.context.logger));
127+
const [error] = await t.throws(verify({message}, {}, t.context.logger));
128128

129129
t.is(error.name, 'SemanticReleaseError');
130130
t.is(error.code, 'EINVALIDMESSAGE');

0 commit comments

Comments
 (0)