refactor(plugins): switched from require to await import() when loading plugins (#2558)

This commit is contained in:
Matt Travi
2022-09-17 14:10:05 -07:00
committed by GitHub
parent 466898b3b4
commit 4cd3641dbf
7 changed files with 98 additions and 83 deletions
+35 -32
View File
@@ -19,8 +19,8 @@ test.beforeEach((t) => {
};
});
test('Normalize and load plugin from string', (t) => {
const plugin = normalize(
test('Normalize and load plugin from string', async (t) => {
const plugin = await normalize(
{cwd, options: {}, logger: t.context.logger},
'verifyConditions',
'./test/fixtures/plugin-noop',
@@ -32,8 +32,8 @@ test('Normalize and load plugin from string', (t) => {
t.deepEqual(t.context.success.args[0], ['Loaded plugin "verifyConditions" from "./test/fixtures/plugin-noop"']);
});
test('Normalize and load plugin from object', (t) => {
const plugin = normalize(
test('Normalize and load plugin from object', async (t) => {
const plugin = await normalize(
{cwd, options: {}, logger: t.context.logger},
'publish',
{path: './test/fixtures/plugin-noop'},
@@ -45,8 +45,8 @@ test('Normalize and load plugin from object', (t) => {
t.deepEqual(t.context.success.args[0], ['Loaded plugin "publish" from "./test/fixtures/plugin-noop"']);
});
test('Normalize and load plugin from a base file path', (t) => {
const plugin = normalize({cwd, options: {}, logger: t.context.logger}, 'verifyConditions', './plugin-noop', {
test('Normalize and load plugin from a base file path', async (t) => {
const plugin = await normalize({cwd, options: {}, logger: t.context.logger}, 'verifyConditions', './plugin-noop', {
'./plugin-noop': './test/fixtures',
});
@@ -58,7 +58,7 @@ test('Normalize and load plugin from a base file path', (t) => {
});
test('Wrap plugin in a function that add the "pluginName" to the error"', async (t) => {
const plugin = normalize({cwd, options: {}, logger: t.context.logger}, 'verifyConditions', './plugin-error', {
const plugin = await normalize({cwd, options: {}, logger: t.context.logger}, 'verifyConditions', './plugin-error', {
'./plugin-error': './test/fixtures',
});
@@ -68,7 +68,7 @@ test('Wrap plugin in a function that add the "pluginName" to the error"', async
});
test('Wrap plugin in a function that add the "pluginName" to multiple errors"', async (t) => {
const plugin = normalize({cwd, options: {}, logger: t.context.logger}, 'verifyConditions', './plugin-errors', {
const plugin = await normalize({cwd, options: {}, logger: t.context.logger}, 'verifyConditions', './plugin-errors', {
'./plugin-errors': './test/fixtures',
});
@@ -78,16 +78,16 @@ test('Wrap plugin in a function that add the "pluginName" to multiple errors"',
}
});
test('Normalize and load plugin from function', (t) => {
test('Normalize and load plugin from function', async (t) => {
const pluginFunction = () => {};
const plugin = normalize({cwd, options: {}, logger: t.context.logger}, '', pluginFunction, {});
const plugin = await normalize({cwd, options: {}, logger: t.context.logger}, '', pluginFunction, {});
t.is(plugin.pluginName, '[Function: pluginFunction]');
t.is(typeof plugin, 'function');
});
test('Normalize and load plugin that retuns multiple functions', (t) => {
const plugin = normalize(
test('Normalize and load plugin that retuns multiple functions', async (t) => {
const plugin = await normalize(
{cwd, options: {}, logger: t.context.logger},
'verifyConditions',
'./test/fixtures/multi-plugin',
@@ -100,7 +100,7 @@ test('Normalize and load plugin that retuns multiple functions', (t) => {
test('Wrap "analyzeCommits" plugin in a function that validate the output of the plugin', async (t) => {
const analyzeCommits = stub().resolves(2);
const plugin = normalize(
const plugin = await normalize(
{cwd, options: {}, stderr: t.context.stderr, logger: t.context.logger},
'analyzeCommits',
analyzeCommits,
@@ -118,7 +118,7 @@ test('Wrap "analyzeCommits" plugin in a function that validate the output of the
test('Wrap "generateNotes" plugin in a function that validate the output of the plugin', async (t) => {
const generateNotes = stub().resolves(2);
const plugin = normalize(
const plugin = await normalize(
{cwd, options: {}, stderr: t.context.stderr, logger: t.context.logger},
'generateNotes',
generateNotes,
@@ -136,7 +136,7 @@ test('Wrap "generateNotes" plugin in a function that validate the output of the
test('Wrap "publish" plugin in a function that validate the output of the plugin', async (t) => {
const publish = stub().resolves(2);
const plugin = normalize(
const plugin = await normalize(
{cwd, options: {}, stderr: t.context.stderr, logger: t.context.logger},
'publish',
publish,
@@ -154,7 +154,7 @@ test('Wrap "publish" plugin in a function that validate the output of the plugin
test('Wrap "addChannel" plugin in a function that validate the output of the plugin', async (t) => {
const addChannel = stub().resolves(2);
const plugin = normalize(
const plugin = await normalize(
{cwd, options: {}, stderr: t.context.stderr, logger: t.context.logger},
'addChannel',
addChannel,
@@ -174,7 +174,7 @@ test('Plugin is called with "pluginConfig" (with object definition) and input',
const pluginFunction = stub().resolves();
const pluginConf = {path: pluginFunction, conf: 'confValue'};
const options = {global: 'globalValue'};
const plugin = normalize({cwd, options, logger: t.context.logger}, '', pluginConf, {});
const plugin = await normalize({cwd, options, logger: t.context.logger}, '', pluginConf, {});
await plugin({options: {}, param: 'param'});
t.true(
@@ -189,7 +189,7 @@ test('Plugin is called with "pluginConfig" (with array definition) and input', a
const pluginFunction = stub().resolves();
const pluginConf = [pluginFunction, {conf: 'confValue'}];
const options = {global: 'globalValue'};
const plugin = normalize({cwd, options, logger: t.context.logger}, '', pluginConf, {});
const plugin = await normalize({cwd, options, logger: t.context.logger}, '', pluginConf, {});
await plugin({options: {}, param: 'param'});
t.true(
@@ -206,7 +206,7 @@ test('Prevent plugins to modify "pluginConfig"', async (t) => {
});
const pluginConf = {path: pluginFunction, conf: {subConf: 'originalConf'}};
const options = {globalConf: {globalSubConf: 'originalGlobalConf'}};
const plugin = normalize({cwd, options, logger: t.context.logger}, '', pluginConf, {});
const plugin = await normalize({cwd, options, logger: t.context.logger}, '', pluginConf, {});
await plugin({options: {}});
t.is(pluginConf.conf.subConf, 'originalConf');
@@ -218,21 +218,21 @@ test('Prevent plugins to modify its input', async (t) => {
options.param.subParam = 'otherParam';
});
const input = {param: {subParam: 'originalSubParam'}, options: {}};
const plugin = normalize({cwd, options: {}, logger: t.context.logger}, '', pluginFunction, {});
const plugin = await normalize({cwd, options: {}, logger: t.context.logger}, '', pluginFunction, {});
await plugin(input);
t.is(input.param.subParam, 'originalSubParam');
});
test('Return noop if the plugin is not defined', (t) => {
const plugin = normalize({cwd, options: {}, logger: t.context.logger});
test('Return noop if the plugin is not defined', async (t) => {
const plugin = await normalize({cwd, options: {}, logger: t.context.logger});
t.is(plugin, noop);
});
test('Always pass a defined "pluginConfig" for plugin defined with string', async (t) => {
// Call the normalize function with the path of a plugin that returns its config
const plugin = normalize(
const plugin = await normalize(
{cwd, options: {}, logger: t.context.logger},
'',
'./test/fixtures/plugin-result-config',
@@ -245,7 +245,7 @@ test('Always pass a defined "pluginConfig" for plugin defined with string', asyn
test('Always pass a defined "pluginConfig" for plugin defined with path', async (t) => {
// Call the normalize function with the path of a plugin that returns its config
const plugin = normalize(
const plugin = await normalize(
{cwd, options: {}, logger: t.context.logger},
'',
{path: './test/fixtures/plugin-result-config'},
@@ -256,8 +256,8 @@ test('Always pass a defined "pluginConfig" for plugin defined with path', async
t.deepEqual(pluginResult.pluginConfig, {});
});
test('Throws an error if the plugin return an object without the expected plugin function', (t) => {
const error = t.throws(() =>
test('Throws an error if the plugin return an object without the expected plugin function', async (t) => {
const error = await t.throwsAsync(() =>
normalize({cwd, options: {}, logger: t.context.logger}, 'inexistantPlugin', './test/fixtures/multi-plugin', {})
);
@@ -267,10 +267,13 @@ test('Throws an error if the plugin return an object without the expected plugin
t.truthy(error.details);
});
test('Throws an error if the plugin is not found', (t) => {
t.throws(() => normalize({cwd, options: {}, logger: t.context.logger}, 'inexistantPlugin', 'non-existing-path', {}), {
message: /Cannot find module 'non-existing-path'/,
code: 'MODULE_NOT_FOUND',
instanceOf: Error,
});
test('Throws an error if the plugin is not found', async (t) => {
await t.throwsAsync(
() => normalize({cwd, options: {}, logger: t.context.logger}, 'inexistantPlugin', 'non-existing-path', {}),
{
message: /Cannot find module 'non-existing-path'/,
code: 'MODULE_NOT_FOUND',
instanceOf: Error,
}
);
});
+23 -24
View File
@@ -15,8 +15,8 @@ test.beforeEach((t) => {
t.context.logger = {log: t.context.log, success: t.context.success, scope: () => t.context.logger};
});
test('Export default plugins', (t) => {
const plugins = getPlugins({cwd, options: {}, logger: t.context.logger}, {});
test('Export default plugins', async (t) => {
const plugins = await getPlugins({cwd, options: {}, logger: t.context.logger}, {});
// Verify the module returns a function for each plugin
t.is(typeof plugins.verifyConditions, 'function');
@@ -29,8 +29,8 @@ test('Export default plugins', (t) => {
t.is(typeof plugins.fail, 'function');
});
test('Export plugins based on steps config', (t) => {
const plugins = getPlugins(
test('Export plugins based on steps config', async (t) => {
const plugins = await getPlugins(
{
cwd,
logger: t.context.logger,
@@ -58,11 +58,10 @@ test('Export plugins based on steps config', (t) => {
test('Export plugins based on "plugins" config (array)', async (t) => {
const plugin1 = {verifyConditions: stub(), publish: stub()};
const plugin2 = {verifyConditions: stub(), verifyRelease: stub()};
const plugins = getPlugins(
const plugins = await getPlugins(
{cwd, logger: t.context.logger, options: {plugins: [plugin1, [plugin2, {}]], verifyRelease: () => {}}},
{}
);
await plugins.verifyConditions({options: {}});
t.true(plugin1.verifyConditions.calledOnce);
t.true(plugin2.verifyConditions.calledOnce);
@@ -86,7 +85,7 @@ test('Export plugins based on "plugins" config (array)', async (t) => {
test('Export plugins based on "plugins" config (single definition)', async (t) => {
const plugin1 = {verifyConditions: stub(), publish: stub()};
const plugins = getPlugins({cwd, logger: t.context.logger, options: {plugins: plugin1}}, {});
const plugins = await getPlugins({cwd, logger: t.context.logger, options: {plugins: plugin1}}, {});
await plugins.verifyConditions({options: {}});
t.true(plugin1.verifyConditions.calledOnce);
@@ -109,7 +108,7 @@ test('Merge global options, "plugins" options and step options', async (t) => {
const plugin1 = [{verifyConditions: stub(), publish: stub()}, {pluginOpt1: 'plugin1'}];
const plugin2 = [{verifyConditions: stub()}, {pluginOpt2: 'plugin2'}];
const plugin3 = [stub(), {pluginOpt3: 'plugin3'}];
const plugins = getPlugins(
const plugins = await getPlugins(
{
cwd,
logger: t.context.logger,
@@ -129,9 +128,9 @@ test('Merge global options, "plugins" options and step options', async (t) => {
t.deepEqual(plugin3[0].args[0][0], {globalOpt: 'global', pluginOpt3: 'plugin3'});
});
test('Unknown steps of plugins configured in "plugins" are ignored', (t) => {
test('Unknown steps of plugins configured in "plugins" are ignored', async (t) => {
const plugin1 = {verifyConditions: () => {}, unknown: () => {}};
const plugins = getPlugins({cwd, logger: t.context.logger, options: {plugins: [plugin1]}}, {});
const plugins = await getPlugins({cwd, logger: t.context.logger, options: {plugins: [plugin1]}}, {});
t.is(typeof plugins.verifyConditions, 'function');
t.is(plugins.unknown, undefined);
@@ -145,7 +144,7 @@ test('Export plugins loaded from the dependency of a shareable config module', a
);
await outputFile(path.resolve(cwd, 'node_modules/shareable-config/index.js'), '');
const plugins = getPlugins(
const plugins = await getPlugins(
{
cwd,
logger: t.context.logger,
@@ -175,7 +174,7 @@ test('Export plugins loaded from the dependency of a shareable config file', asy
await copy('./test/fixtures/plugin-noop.js', path.resolve(cwd, 'plugin/plugin-noop.js'));
await outputFile(path.resolve(cwd, 'shareable-config.js'), '');
const plugins = getPlugins(
const plugins = await getPlugins(
{
cwd,
logger: t.context.logger,
@@ -200,14 +199,14 @@ test('Export plugins loaded from the dependency of a shareable config file', asy
t.is(typeof plugins.fail, 'function');
});
test('Use default when only options are passed for a single plugin', (t) => {
test('Use default when only options are passed for a single plugin', async (t) => {
const analyzeCommits = {};
const generateNotes = {};
const publish = {};
const success = () => {};
const fail = [() => {}];
const plugins = getPlugins(
const plugins = await getPlugins(
{
cwd,
logger: t.context.logger,
@@ -235,7 +234,7 @@ test('Use default when only options are passed for a single plugin', (t) => {
});
test('Merge global options with plugin options', async (t) => {
const plugins = getPlugins(
const plugins = await getPlugins(
{
cwd,
logger: t.context.logger,
@@ -253,9 +252,9 @@ test('Merge global options with plugin options', async (t) => {
t.deepEqual(result.pluginConfig, {localOpt: 'local', globalOpt: 'global', otherOpt: 'locally-defined'});
});
test('Throw an error for each invalid plugin configuration', (t) => {
test('Throw an error for each invalid plugin configuration', async (t) => {
const errors = [
...t.throws(() =>
...(await t.throwsAsync(() =>
getPlugins(
{
cwd,
@@ -270,7 +269,7 @@ test('Throw an error for each invalid plugin configuration', (t) => {
},
{}
)
),
)),
];
t.is(errors[0].name, 'SemanticReleaseError');
@@ -283,9 +282,9 @@ test('Throw an error for each invalid plugin configuration', (t) => {
t.is(errors[3].code, 'EPLUGINCONF');
});
test('Throw EPLUGINSCONF error if the "plugins" option contains an old plugin definition (returns a function)', (t) => {
test('Throw EPLUGINSCONF error if the "plugins" option contains an old plugin definition (returns a function)', async (t) => {
const errors = [
...t.throws(() =>
...(await t.throwsAsync(() =>
getPlugins(
{
cwd,
@@ -294,7 +293,7 @@ test('Throw EPLUGINSCONF error if the "plugins" option contains an old plugin de
},
{}
)
),
)),
];
t.is(errors[0].name, 'SemanticReleaseError');
@@ -303,11 +302,11 @@ test('Throw EPLUGINSCONF error if the "plugins" option contains an old plugin de
t.is(errors[1].code, 'EPLUGINSCONF');
});
test('Throw EPLUGINSCONF error for each invalid definition if the "plugins" option', (t) => {
test('Throw EPLUGINSCONF error for each invalid definition if the "plugins" option', async (t) => {
const errors = [
...t.throws(() =>
...(await t.throwsAsync(() =>
getPlugins({cwd, logger: t.context.logger, options: {plugins: [1, {path: 1}, [() => {}, {}, {}]]}}, {})
),
)),
];
t.is(errors[0].name, 'SemanticReleaseError');
+4 -4
View File
@@ -189,17 +189,17 @@ test('validateStep: required plugin configuration', (t) => {
);
});
test('loadPlugin', (t) => {
test('loadPlugin', async (t) => {
const cwd = process.cwd();
const func = () => {};
t.is(require('../fixtures/plugin-noop'), loadPlugin({cwd: './test/fixtures'}, './plugin-noop', {}), 'From cwd');
t.is(require('../fixtures/plugin-noop'), await loadPlugin({cwd: './test/fixtures'}, './plugin-noop', {}), 'From cwd');
t.is(
require('../fixtures/plugin-noop'),
loadPlugin({cwd}, './plugin-noop', {'./plugin-noop': './test/fixtures'}),
await loadPlugin({cwd}, './plugin-noop', {'./plugin-noop': './test/fixtures'}),
'From a shareable config context'
);
t.is(func, loadPlugin({cwd}, func, {}), 'Defined as a function');
t.is(func, await loadPlugin({cwd}, func, {}), 'Defined as a function');
});
test('parseConfig', (t) => {