Skip to content

Commit

Permalink
perf: straighten plugins execution pipeline
Browse files Browse the repository at this point in the history
closes #4
  • Loading branch information
antongolub committed May 28, 2020
1 parent 747f11c commit e57fe2f
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 35 deletions.
38 changes: 34 additions & 4 deletions lib/createInlinePluginCreator.js
Expand Up @@ -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>} 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.
Expand Down Expand Up @@ -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);

Expand All @@ -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.
Expand Down
42 changes: 13 additions & 29 deletions 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");
Expand Down Expand Up @@ -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 };
}

/**
Expand All @@ -137,50 +137,34 @@ 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.
pkg.result = await semanticRelease(options, {
cwd: dir,
env,
stdout: new RescopedStream(stdout, name),
stderr: new RescopedStream(stdout, name),
stderr: new RescopedStream(stderr, name),
});
}
5 changes: 3 additions & 2 deletions test/lib/multiSemanticRelease.test.js
Expand Up @@ -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);
Expand Down

0 comments on commit e57fe2f

Please sign in to comment.