feat: support multiple plugins for the analyzeCommits
step
In case multiple plugins with a `analyzeCommits` step are configured, all of them will be executed and the highest release type (`major` > `minor`, `patch`) will be used.
This commit is contained in:
parent
728ea34dda
commit
5180001ae6
@ -4,16 +4,16 @@ Each [release step](../../README.md#release-steps) is implemented by configurabl
|
|||||||
|
|
||||||
A plugin is a npm module that can implement one or more of the following steps:
|
A plugin is a npm module that can implement one or more of the following steps:
|
||||||
|
|
||||||
| Step | Accept multiple | Required | Description |
|
| Step | Required | Description |
|
||||||
|--------------------|-----------------|----------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|--------------------|----------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `verifyConditions` | Yes | No | Responsible for verifying conditions necessary to proceed with the release: configuration is correct, authentication token are valid, etc... |
|
| `verifyConditions` | No | Responsible for verifying conditions necessary to proceed with the release: configuration is correct, authentication token are valid, etc... |
|
||||||
| `analyzeCommits` | No | Yes | Responsible for determining the type of the next release (`major`, `minor` or `patch`). |
|
| `analyzeCommits` | Yes | Responsible for determining the type of the next release (`major`, `minor` or `patch`). If multiple plugins with a `analyzeCommits` step are defined, the release type will be the highest one among plugins output. |
|
||||||
| `verifyRelease` | Yes | No | Responsible for verifying the parameters (version, type, dist-tag etc...) of the release that is about to be published. |
|
| `verifyRelease` | No | Responsible for verifying the parameters (version, type, dist-tag etc...) of the release that is about to be published. |
|
||||||
| `generateNotes` | Yes | No | Responsible for generating the content of the release note. If multiple `generateNotes` plugins are defined, the release notes will be the result of the concatenation of each plugin output. |
|
| `generateNotes` | No | Responsible for generating the content of the release note. If multiple plugins with a `generateNotes` step are defined, the release notes will be the result of the concatenation of each plugin output. |
|
||||||
| `prepare` | Yes | No | Responsible for preparing the release, for example creating or updating files such as `package.json`, `CHANGELOG.md`, documentation or compiled assets and pushing a commit. |
|
| `prepare` | No | Responsible for preparing the release, for example creating or updating files such as `package.json`, `CHANGELOG.md`, documentation or compiled assets and pushing a commit. |
|
||||||
| `publish` | Yes | No | Responsible for publishing the release. |
|
| `publish` | No | Responsible for publishing the release. |
|
||||||
| `success` | Yes | No | Responsible for notifying of a new release. |
|
| `success` | No | Responsible for notifying of a new release. |
|
||||||
| `fail` | Yes | No | Responsible for notifying of a failed release. |
|
| `fail` | No | Responsible for notifying of a failed release. |
|
||||||
|
|
||||||
**Note:** If no plugin with a `analyzeCommits` step is defined `@semantic-release/commit-analyzer` will be used.
|
**Note:** If no plugin with a `analyzeCommits` step is defined `@semantic-release/commit-analyzer` will be used.
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
const RELEASE_TYPE = ['major', 'premajor', 'minor', 'preminor', 'patch', 'prepatch', 'prerelease'];
|
const RELEASE_TYPE = ['prerelease', 'prepatch', 'patch', 'preminor', 'minor', 'premajor', 'major'];
|
||||||
|
|
||||||
const FIRST_RELEASE = '1.0.0';
|
const FIRST_RELEASE = '1.0.0';
|
||||||
|
|
||||||
|
@ -55,13 +55,11 @@ Your configuration for the \`tagFormat\` option is \`${stringify(tagFormat)}\`.`
|
|||||||
|
|
||||||
Your configuration for the \`tagFormat\` option is \`${stringify(tagFormat)}\`.`,
|
Your configuration for the \`tagFormat\` option is \`${stringify(tagFormat)}\`.`,
|
||||||
}),
|
}),
|
||||||
EPLUGINCONF: ({type, multiple, required, pluginConf}) => ({
|
EPLUGINCONF: ({type, required, pluginConf}) => ({
|
||||||
message: `The \`${type}\` plugin configuration is invalid.`,
|
message: `The \`${type}\` plugin configuration is invalid.`,
|
||||||
details: `The [${type} plugin configuration](${linkify(`docs/usage/plugins.md#${toLower(type)}-plugin`)}) ${
|
details: `The [${type} plugin configuration](${linkify(`docs/usage/plugins.md#${toLower(type)}-plugin`)}) ${
|
||||||
required ? 'is required and ' : ''
|
required ? 'is required and ' : ''
|
||||||
}must be ${
|
} must be a single or an array of plugins definition. A plugin definition is an npm module name, optionnaly wrapped in an array with an object.
|
||||||
multiple ? 'a single or an array of plugins' : 'a single plugin'
|
|
||||||
} definition. A plugin definition is an npm module name, optionnaly wrapped in an array with an object.
|
|
||||||
|
|
||||||
Your configuration for the \`${type}\` plugin is \`${stringify(pluginConf)}\`.`,
|
Your configuration for the \`${type}\` plugin is \`${stringify(pluginConf)}\`.`,
|
||||||
}),
|
}),
|
||||||
|
@ -6,28 +6,30 @@ const {RELEASE_TYPE, RELEASE_NOTES_SEPARATOR} = require('./constants');
|
|||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
verifyConditions: {
|
verifyConditions: {
|
||||||
multiple: true,
|
|
||||||
required: false,
|
required: false,
|
||||||
pipelineConfig: () => ({settleAll: true}),
|
pipelineConfig: () => ({settleAll: true}),
|
||||||
},
|
},
|
||||||
analyzeCommits: {
|
analyzeCommits: {
|
||||||
default: ['@semantic-release/commit-analyzer'],
|
default: ['@semantic-release/commit-analyzer'],
|
||||||
multiple: false,
|
|
||||||
required: true,
|
required: true,
|
||||||
outputValidator: output => !output || RELEASE_TYPE.includes(output),
|
outputValidator: output => !output || RELEASE_TYPE.includes(output),
|
||||||
preprocess: ({commits, ...inputs}) => ({
|
preprocess: ({commits, ...inputs}) => ({
|
||||||
...inputs,
|
...inputs,
|
||||||
commits: commits.filter(commit => !/\[skip\s+release\]|\[release\s+skip\]/i.test(commit.message)),
|
commits: commits.filter(commit => !/\[skip\s+release\]|\[release\s+skip\]/i.test(commit.message)),
|
||||||
}),
|
}),
|
||||||
postprocess: ([result]) => result,
|
postprocess: results =>
|
||||||
|
RELEASE_TYPE[
|
||||||
|
results.reduce((highest, result) => {
|
||||||
|
const typeIndex = RELEASE_TYPE.indexOf(result);
|
||||||
|
return typeIndex > highest ? typeIndex : highest;
|
||||||
|
}, -1)
|
||||||
|
],
|
||||||
},
|
},
|
||||||
verifyRelease: {
|
verifyRelease: {
|
||||||
multiple: true,
|
|
||||||
required: false,
|
required: false,
|
||||||
pipelineConfig: () => ({settleAll: true}),
|
pipelineConfig: () => ({settleAll: true}),
|
||||||
},
|
},
|
||||||
generateNotes: {
|
generateNotes: {
|
||||||
multiple: true,
|
|
||||||
required: false,
|
required: false,
|
||||||
outputValidator: output => !output || isString(output),
|
outputValidator: output => !output || isString(output),
|
||||||
pipelineConfig: () => ({
|
pipelineConfig: () => ({
|
||||||
@ -42,9 +44,8 @@ module.exports = {
|
|||||||
postprocess: (results, {env}) => hideSensitive(env)(results.filter(Boolean).join(RELEASE_NOTES_SEPARATOR)),
|
postprocess: (results, {env}) => hideSensitive(env)(results.filter(Boolean).join(RELEASE_NOTES_SEPARATOR)),
|
||||||
},
|
},
|
||||||
prepare: {
|
prepare: {
|
||||||
multiple: true,
|
|
||||||
required: false,
|
required: false,
|
||||||
pipelineConfig: ({generateNotes}, logger) => ({
|
pipelineConfig: ({generateNotes}) => ({
|
||||||
getNextInput: async context => {
|
getNextInput: async context => {
|
||||||
const newGitHead = await gitHead({cwd: context.cwd});
|
const newGitHead = await gitHead({cwd: context.cwd});
|
||||||
// If previous prepare plugin has created a commit (gitHead changed)
|
// If previous prepare plugin has created a commit (gitHead changed)
|
||||||
@ -59,7 +60,6 @@ module.exports = {
|
|||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
publish: {
|
publish: {
|
||||||
multiple: true,
|
|
||||||
required: false,
|
required: false,
|
||||||
outputValidator: output => !output || isPlainObject(output),
|
outputValidator: output => !output || isPlainObject(output),
|
||||||
pipelineConfig: () => ({
|
pipelineConfig: () => ({
|
||||||
@ -72,13 +72,11 @@ module.exports = {
|
|||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
success: {
|
success: {
|
||||||
multiple: true,
|
|
||||||
required: false,
|
required: false,
|
||||||
pipelineConfig: () => ({settleAll: true}),
|
pipelineConfig: () => ({settleAll: true}),
|
||||||
preprocess: ({releases, env, ...inputs}) => ({...inputs, env, releases: hideSensitiveValues(env, releases)}),
|
preprocess: ({releases, env, ...inputs}) => ({...inputs, env, releases: hideSensitiveValues(env, releases)}),
|
||||||
},
|
},
|
||||||
fail: {
|
fail: {
|
||||||
multiple: true,
|
|
||||||
required: false,
|
required: false,
|
||||||
pipelineConfig: () => ({settleAll: true}),
|
pipelineConfig: () => ({settleAll: true}),
|
||||||
preprocess: ({errors, env, ...inputs}) => ({...inputs, env, errors: hideSensitiveValues(env, errors)}),
|
preprocess: ({errors, env, ...inputs}) => ({...inputs, env, errors: hideSensitiveValues(env, errors)}),
|
||||||
|
@ -24,7 +24,7 @@ module.exports = (context, pluginsPath) => {
|
|||||||
writable: false,
|
writable: false,
|
||||||
enumerable: true,
|
enumerable: true,
|
||||||
});
|
});
|
||||||
plugins[type] = [...(PLUGINS_DEFINITIONS[type].multiple ? plugins[type] || [] : []), [func, config]];
|
plugins[type] = [...(plugins[type] || []), [func, config]];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@ -45,10 +45,7 @@ module.exports = (context, pluginsPath) => {
|
|||||||
options = {...plugins, ...options};
|
options = {...plugins, ...options};
|
||||||
|
|
||||||
const pluginsConf = Object.entries(PLUGINS_DEFINITIONS).reduce(
|
const pluginsConf = Object.entries(PLUGINS_DEFINITIONS).reduce(
|
||||||
(
|
(pluginsConf, [type, {required, default: def, pipelineConfig, postprocess = identity, preprocess = identity}]) => {
|
||||||
pluginsConf,
|
|
||||||
[type, {multiple, required, default: def, pipelineConfig, postprocess = identity, preprocess = identity}]
|
|
||||||
) => {
|
|
||||||
let pluginOpts;
|
let pluginOpts;
|
||||||
|
|
||||||
if (isNil(options[type]) && def) {
|
if (isNil(options[type]) && def) {
|
||||||
@ -60,8 +57,8 @@ module.exports = (context, pluginsPath) => {
|
|||||||
plugin ? [plugin[0], Object.assign(plugin[1], options[type])] : plugin
|
plugin ? [plugin[0], Object.assign(plugin[1], options[type])] : plugin
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (!validateStep({multiple, required}, options[type])) {
|
if (!validateStep({required}, options[type])) {
|
||||||
errors.push(getError('EPLUGINCONF', {type, multiple, required, pluginConf: options[type]}));
|
errors.push(getError('EPLUGINCONF', {type, required, pluginConf: options[type]}));
|
||||||
return pluginsConf;
|
return pluginsConf;
|
||||||
}
|
}
|
||||||
pluginOpts = options[type];
|
pluginOpts = options[type];
|
||||||
|
@ -2,28 +2,25 @@ const {dirname} = require('path');
|
|||||||
const {isString, isFunction, castArray, isArray, isPlainObject, isNil} = require('lodash');
|
const {isString, isFunction, castArray, isArray, isPlainObject, isNil} = require('lodash');
|
||||||
const resolveFrom = require('resolve-from');
|
const resolveFrom = require('resolve-from');
|
||||||
|
|
||||||
const validateStepArrayDefinition = conf =>
|
const validateSteps = conf => {
|
||||||
isArray(conf) &&
|
return conf.every(conf => {
|
||||||
(conf.length === 1 || conf.length === 2) &&
|
if (
|
||||||
(isString(conf[0]) || isFunction(conf[0])) &&
|
isArray(conf) &&
|
||||||
(isNil(conf[1]) || isPlainObject(conf[1]));
|
(conf.length === 1 || conf.length === 2) &&
|
||||||
|
(isString(conf[0]) || isFunction(conf[0])) &&
|
||||||
|
(isNil(conf[1]) || isPlainObject(conf[1]))
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
conf = castArray(conf);
|
||||||
|
|
||||||
const validateSingleStep = conf => {
|
if (conf.length !== 1) {
|
||||||
if (validateStepArrayDefinition(conf)) {
|
return false;
|
||||||
return true;
|
}
|
||||||
}
|
|
||||||
conf = castArray(conf);
|
|
||||||
|
|
||||||
if (conf.length !== 1) {
|
const [name, config] = parseConfig(conf[0]);
|
||||||
return false;
|
return (isString(name) || isFunction(name)) && isPlainObject(config);
|
||||||
}
|
});
|
||||||
|
|
||||||
const [name, config] = parseConfig(conf[0]);
|
|
||||||
return (isString(name) || isFunction(name)) && isPlainObject(config);
|
|
||||||
};
|
|
||||||
|
|
||||||
const validateMultipleStep = conf => {
|
|
||||||
return conf.every(conf => validateSingleStep(conf));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function validatePlugin(conf) {
|
function validatePlugin(conf) {
|
||||||
@ -37,12 +34,12 @@ function validatePlugin(conf) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateStep({multiple, required}, conf) {
|
function validateStep({required}, conf) {
|
||||||
conf = castArray(conf).filter(Boolean);
|
conf = castArray(conf).filter(Boolean);
|
||||||
if (required) {
|
if (required) {
|
||||||
return conf.length >= 1 && (multiple ? validateMultipleStep : validateSingleStep)(conf);
|
return conf.length >= 1 && validateSteps(conf);
|
||||||
}
|
}
|
||||||
return conf.length === 0 || (multiple ? validateMultipleStep : validateSingleStep)(conf);
|
return conf.length === 0 || validateSteps(conf);
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadPlugin({cwd}, name, pluginsPath) {
|
function loadPlugin({cwd}, name, pluginsPath) {
|
||||||
|
@ -51,3 +51,13 @@ test('The "generateNotes" plugins output are concatenated with separator and sen
|
|||||||
`Note 1: Exposing token ${SECRET_REPLACEMENT}${RELEASE_NOTES_SEPARATOR}Note 2: Exposing token ${SECRET_REPLACEMENT}`
|
`Note 1: Exposing token ${SECRET_REPLACEMENT}${RELEASE_NOTES_SEPARATOR}Note 2: Exposing token ${SECRET_REPLACEMENT}`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('The "analyzeCommits" plugins output are reduced to the highest release type', t => {
|
||||||
|
t.is(plugins.analyzeCommits.postprocess(['major', 'minor']), 'major');
|
||||||
|
t.is(plugins.analyzeCommits.postprocess(['', 'minor']), 'minor');
|
||||||
|
t.is(plugins.analyzeCommits.postprocess([undefined, 'patch']), 'patch');
|
||||||
|
t.is(plugins.analyzeCommits.postprocess([null, 'patch']), 'patch');
|
||||||
|
t.is(plugins.analyzeCommits.postprocess(['wrong_type', 'minor']), 'minor');
|
||||||
|
t.is(plugins.analyzeCommits.postprocess([]), undefined);
|
||||||
|
t.is(plugins.analyzeCommits.postprocess(['wrong_type']), undefined);
|
||||||
|
});
|
||||||
|
@ -105,26 +105,6 @@ test('Export plugins based on "plugins" config (single definition)', async t =>
|
|||||||
t.is(typeof plugins.fail, 'function');
|
t.is(typeof plugins.fail, 'function');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Use only last definition of single plugin steps declared in "plugins" config', async t => {
|
|
||||||
const plugin1 = {analyzeCommits: stub()};
|
|
||||||
const plugin2 = {analyzeCommits: stub()};
|
|
||||||
const plugins = getPlugins({cwd, logger: t.context.logger, options: {plugins: [plugin1, plugin2]}}, {});
|
|
||||||
|
|
||||||
await plugins.analyzeCommits({commits: []});
|
|
||||||
t.true(plugin1.analyzeCommits.notCalled);
|
|
||||||
t.true(plugin2.analyzeCommits.calledOnce);
|
|
||||||
|
|
||||||
// Verify the module returns a function for each plugin
|
|
||||||
t.is(typeof plugins.verifyConditions, 'function');
|
|
||||||
t.is(typeof plugins.analyzeCommits, 'function');
|
|
||||||
t.is(typeof plugins.verifyRelease, 'function');
|
|
||||||
t.is(typeof plugins.generateNotes, 'function');
|
|
||||||
t.is(typeof plugins.prepare, 'function');
|
|
||||||
t.is(typeof plugins.publish, 'function');
|
|
||||||
t.is(typeof plugins.success, 'function');
|
|
||||||
t.is(typeof plugins.fail, 'function');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('Merge global options, "plugins" options and step options', async t => {
|
test('Merge global options, "plugins" options and step options', async t => {
|
||||||
const plugin1 = [{verifyConditions: stub(), publish: stub()}, {pluginOpt1: 'plugin1'}];
|
const plugin1 = [{verifyConditions: stub(), publish: stub()}, {pluginOpt1: 'plugin1'}];
|
||||||
const plugin2 = [{verifyConditions: stub()}, {pluginOpt2: 'plugin2'}];
|
const plugin2 = [{verifyConditions: stub()}, {pluginOpt2: 'plugin2'}];
|
||||||
|
@ -25,7 +25,7 @@ test('validatePlugin', t => {
|
|||||||
t.false(validatePlugin({path: 1}), 'Object definition, wrong path');
|
t.false(validatePlugin({path: 1}), 'Object definition, wrong path');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('validateStep: multiple/optional plugin configuration', t => {
|
test('validateStep: optional plugin configuration', t => {
|
||||||
const type = {multiple: true, required: false};
|
const type = {multiple: true, required: false};
|
||||||
|
|
||||||
// Empty config
|
// Empty config
|
||||||
@ -107,8 +107,8 @@ test('validateStep: multiple/optional plugin configuration', t => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('validateStep: multiple/required plugin configuration', t => {
|
test('validateStep: required plugin configuration', t => {
|
||||||
const type = {multiple: true, required: true};
|
const type = {required: true};
|
||||||
|
|
||||||
// Empty config
|
// Empty config
|
||||||
t.false(validateStep(type));
|
t.false(validateStep(type));
|
||||||
@ -189,98 +189,6 @@ test('validateStep: multiple/required plugin configuration', t => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('validateStep: single/required plugin configuration', t => {
|
|
||||||
const type = {multiple: false, required: true};
|
|
||||||
|
|
||||||
// Empty config
|
|
||||||
t.false(validateStep(type));
|
|
||||||
t.false(validateStep(type, []));
|
|
||||||
|
|
||||||
// Single value definition
|
|
||||||
t.true(validateStep(type, 'plugin-path.js'));
|
|
||||||
t.true(validateStep(type, () => {}));
|
|
||||||
t.true(validateStep(type, ['plugin-path.js']));
|
|
||||||
t.true(validateStep(type, [() => {}]));
|
|
||||||
t.false(validateStep(type, {}));
|
|
||||||
t.false(validateStep(type, [{}]));
|
|
||||||
|
|
||||||
// Array type definition
|
|
||||||
t.true(validateStep(type, [['plugin-path.js']]));
|
|
||||||
t.true(validateStep(type, [['plugin-path.js', {options: 'value'}]]));
|
|
||||||
t.true(validateStep(type, [[() => {}, {options: 'value'}]]));
|
|
||||||
t.false(validateStep(type, [['plugin-path.js', 1]]));
|
|
||||||
|
|
||||||
// Object type definition
|
|
||||||
t.true(validateStep(type, {path: 'plugin-path.js'}));
|
|
||||||
t.true(validateStep(type, {path: 'plugin-path.js', options: 'value'}));
|
|
||||||
t.true(validateStep(type, {path: () => {}, options: 'value'}));
|
|
||||||
t.false(validateStep(type, {path: null}));
|
|
||||||
|
|
||||||
// Considered as one Array definition and not as an Array of 2 definitions in case of single plugin type
|
|
||||||
t.true(validateStep(type, [() => {}, {options: 'value'}]));
|
|
||||||
t.true(validateStep(type, ['plugin-path.js', {options: 'value'}]));
|
|
||||||
|
|
||||||
// Multiple definitions
|
|
||||||
t.false(
|
|
||||||
validateStep(type, [
|
|
||||||
'plugin-path.js',
|
|
||||||
() => {},
|
|
||||||
['plugin-path.js'],
|
|
||||||
['plugin-path.js', {options: 'value'}],
|
|
||||||
[() => {}, {options: 'value'}],
|
|
||||||
{path: 'plugin-path.js'},
|
|
||||||
{path: 'plugin-path.js', options: 'value'},
|
|
||||||
{path: () => {}, options: 'value'},
|
|
||||||
])
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('validateStep: single/optional plugin configuration', t => {
|
|
||||||
const type = {multiple: false, required: false};
|
|
||||||
|
|
||||||
// Empty config
|
|
||||||
t.true(validateStep(type));
|
|
||||||
t.true(validateStep(type, []));
|
|
||||||
|
|
||||||
// Single value definition
|
|
||||||
t.true(validateStep(type, 'plugin-path.js'));
|
|
||||||
t.true(validateStep(type, () => {}));
|
|
||||||
t.true(validateStep(type, ['plugin-path.js']));
|
|
||||||
t.true(validateStep(type, [() => {}]));
|
|
||||||
t.false(validateStep(type, {}));
|
|
||||||
t.false(validateStep(type, [{}]));
|
|
||||||
|
|
||||||
// Array type definition
|
|
||||||
t.true(validateStep(type, [['plugin-path.js']]));
|
|
||||||
t.true(validateStep(type, [['plugin-path.js', {options: 'value'}]]));
|
|
||||||
t.true(validateStep(type, [[() => {}, {options: 'value'}]]));
|
|
||||||
t.false(validateStep(type, [['plugin-path.js', 1]]));
|
|
||||||
|
|
||||||
// Object type definition
|
|
||||||
t.true(validateStep(type, {path: 'plugin-path.js'}));
|
|
||||||
t.true(validateStep(type, {path: 'plugin-path.js', options: 'value'}));
|
|
||||||
t.true(validateStep(type, {path: () => {}, options: 'value'}));
|
|
||||||
t.false(validateStep(type, {path: null}));
|
|
||||||
|
|
||||||
// Considered as one Array definition and not as an Array of 2 definitions in case of single plugin type
|
|
||||||
t.true(validateStep(type, [() => {}, {options: 'value'}]));
|
|
||||||
t.true(validateStep(type, ['plugin-path.js', {options: 'value'}]));
|
|
||||||
|
|
||||||
// Multiple definitions
|
|
||||||
t.false(
|
|
||||||
validateStep(type, [
|
|
||||||
'plugin-path.js',
|
|
||||||
() => {},
|
|
||||||
['plugin-path.js'],
|
|
||||||
['plugin-path.js', {options: 'value'}],
|
|
||||||
[() => {}, {options: 'value'}],
|
|
||||||
{path: 'plugin-path.js'},
|
|
||||||
{path: 'plugin-path.js', options: 'value'},
|
|
||||||
{path: () => {}, options: 'value'},
|
|
||||||
])
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('loadPlugin', t => {
|
test('loadPlugin', t => {
|
||||||
const cwd = process.cwd();
|
const cwd = process.cwd();
|
||||||
const func = () => {};
|
const func = () => {};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user