From e57fe2fc3274d66520fbeacdac488b1a29430835 Mon Sep 17 00:00:00 2001 From: Anton Golub Date: Thu, 28 May 2020 17:34:28 +0300 Subject: [PATCH] perf: straighten plugins execution pipeline closes #4 --- lib/createInlinePluginCreator.js | 38 +++++++++++++++++++++--- lib/multiSemanticRelease.js | 42 +++++++++------------------ test/lib/multiSemanticRelease.test.js | 5 ++-- 3 files changed, 50 insertions(+), 35 deletions(-) diff --git a/lib/createInlinePluginCreator.js b/lib/createInlinePluginCreator.js index 0cbea2d..c400028 100644 --- a/lib/createInlinePluginCreator.js +++ b/lib/createInlinePluginCreator.js @@ -91,6 +91,22 @@ function createInlinePluginCreator(packages, multiContext) { */ let commits; + /** + * @param {object} pluginOptions Options to configure this plugin. + * @param {object} context The semantic-release context. + * @returns {Promise} void + * @internal + */ + const verifyConditions = async (pluginOptions, context) => { + // Restore context for plugins that does not rely on parsed opts. + Object.assign(context.options, context.options._pkgOptions); + + // And bind actual logger. + Object.assign(pkg.loggerRef, context.logger); + + return plugins.verifyConditions(context); + }; + /** * Analyze commits step. * 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. @@ -198,7 +214,7 @@ function createInlinePluginCreator(packages, multiContext) { return notes.join("\n\n"); }; - const publish = async () => { + const publish = async (pluginOptions, context) => { pkg._prepared = true; const nextPkgToProcess = todo().find((p) => p._nextType && !p._prepared); @@ -209,15 +225,29 @@ function createInlinePluginCreator(packages, multiContext) { // Wait for all packages to be `prepare`d and tagged by `semantic-release` await waitFor("_prepared", (p) => p._nextType); - return {}; + const res = await plugins.publish(context); + + // istanbul ignore next + return res.length ? res[0] : {}; }; - // Exports. - return { + const inlinePlugin = { + verifyConditions, analyzeCommits, generateNotes, publish, }; + + // Add labels for logs. + Object.keys(inlinePlugin).forEach((type) => + Reflect.defineProperty(inlinePlugin[type], "pluginName", { + value: "Inline plugin", + writable: false, + enumerable: true, + }) + ); + + return inlinePlugin; } // Return creator function. diff --git a/lib/multiSemanticRelease.js b/lib/multiSemanticRelease.js index 20a2956..8c5a1cf 100644 --- a/lib/multiSemanticRelease.js +++ b/lib/multiSemanticRelease.js @@ -1,6 +1,6 @@ const { dirname } = require("path"); -const { check } = require("./blork"); const semanticRelease = require("semantic-release"); +const { check } = require("./blork"); const getLogger = require("./getLogger"); const getConfig = require("./getConfig"); const getConfigSemantic = require("./getConfigSemantic"); @@ -122,7 +122,7 @@ async function getPackage(path, { options: globalOptions, env, cwd, stdout, stde const { options, plugins } = await getConfigSemantic({ cwd: dir, env, stdout, stderr, logger }, finalOptions); // Return package object. - return { path, dir, name, manifest, deps, options, plugins }; + return { path, dir, name, manifest, deps, options, plugins, loggerRef: logger }; } /** @@ -137,43 +137,27 @@ async function getPackage(path, { options: globalOptions, env, cwd, stdout, stde */ async function releasePackage(pkg, createInlinePlugin, multiContext) { // Vars. - const { options: pkgOptions, name, path, dir } = pkg; - const { todo, options: globalOptions, cwd, env, logger, stdout, stderr } = multiContext; + const { options: pkgOptions, name, dir } = pkg; + const { env, stdout, stderr } = multiContext; + + // Make an 'inline plugin' for this package. + // The inline plugin is the only plugin we call semanticRelease() with. + // The inline plugin functions then call e.g. plugins.analyzeCommits() manually and sometimes manipulate the responses. + const inlinePlugin = createInlinePlugin(pkg); // Set the options that we call semanticRelease() with. // This consists of: // - The global options (e.g. from the top level package.json) // - The package options (e.g. from the specific package's package.json) - const options = Object.assign({}, globalOptions, pkgOptions); + const options = { ...pkgOptions, ...inlinePlugin }; // Add the package name into tagFormat. // Thought about doing a single release for the tag (merging several packages), but it's impossible to prevent Github releasing while allowing NPM to continue. // It'd also be difficult to merge all the assets into one release without full editing/overriding the plugins. options.tagFormat = name + "@${version}"; - // Make an 'inline plugin' for this package. - // The inline plugin is the only plugin we call semanticRelease() with. - // The inline plugin functions then call e.g. plugins.analyzeCommits() manually and sometimes manipulate the responses. - const inlinePlugin = createInlinePlugin(pkg); - - // If option step is defined `semrel` config resolver overrides the previous value set by `options.plugins`. - const joinedSteps = Object.keys(inlinePlugin).reduce((joined, type) => { - const a = inlinePlugin[type]; - const b = options[type]; - - // Just a label for logs. - Reflect.defineProperty(a, "pluginName", { - value: "Inline plugin", - writable: false, - enumerable: true, - }); - - joined[type] = b ? [a].concat(b) : a; - - return joined; - }, {}); - - Object.assign(options, joinedSteps); + // This options are needed for plugins that does not rely on `pluginOptions` and extracts them independently. + options._pkgOptions = pkgOptions; // Call semanticRelease() on the directory and save result to pkg. // Don't need to log out errors as semantic-release already does that. @@ -181,6 +165,6 @@ async function releasePackage(pkg, createInlinePlugin, multiContext) { cwd: dir, env, stdout: new RescopedStream(stdout, name), - stderr: new RescopedStream(stdout, name), + stderr: new RescopedStream(stderr, name), }); } diff --git a/test/lib/multiSemanticRelease.test.js b/test/lib/multiSemanticRelease.test.js index af7e66c..677d46f 100644 --- a/test/lib/multiSemanticRelease.test.js +++ b/test/lib/multiSemanticRelease.test.js @@ -386,14 +386,15 @@ describe("multiSemanticRelease()", () => { [`packages/d/package.json`], { // Override to add our own plugins. - plugins: ["@semantic-release/commit-analyzer", "@semantic-release/release-notes-generator", plugin], + plugins: ["@semantic-release/release-notes-generator", plugin], + analyzeCommits: ["@semantic-release/commit-analyzer"], }, { cwd, stdout, stderr } ); // Check calls. expect(plugin.verifyConditions).toBeCalledTimes(1); - expect(plugin.analyzeCommits).toBeCalledTimes(1); + expect(plugin.analyzeCommits).toBeCalledTimes(0); // NOTE overridden expect(plugin.verifyRelease).toBeCalledTimes(1); expect(plugin.generateNotes).toBeCalledTimes(1); expect(plugin.prepare).toBeCalledTimes(1);