fix(deps): bump @semantic-release/npm to ^10.0.0-beta.1 (#2670)

This commit is contained in:
Gregor Martynus
2023-01-14 14:14:04 -08:00
committed by GitHub
parent e607e234f3
commit 6a83cb53e5
39 changed files with 1686 additions and 1453 deletions
+7 -7
View File
@@ -1,18 +1,18 @@
import {isString, mapValues, omit, remove, template} from 'lodash-es';
import micromatch from 'micromatch';
import {getBranches} from '../git.js';
import { isString, mapValues, omit, remove, template } from "lodash-es";
import micromatch from "micromatch";
import { getBranches } from "../git.js";
export default async (repositoryUrl, {cwd}, branches) => {
const gitBranches = await getBranches(repositoryUrl, {cwd});
export default async (repositoryUrl, { cwd }, branches) => {
const gitBranches = await getBranches(repositoryUrl, { cwd });
return branches.reduce(
(branches, branch) => [
...branches,
...remove(gitBranches, (name) => micromatch(gitBranches, branch.name).includes(name)).map((name) => ({
name,
...mapValues(omit(branch, 'name'), (value) => (isString(value) ? template(value)({name}) : value)),
...mapValues(omit(branch, "name"), (value) => (isString(value) ? template(value)({ name }) : value)),
})),
],
[]
);
}
};
+13 -14
View File
@@ -1,36 +1,35 @@
import {escapeRegExp, template} from 'lodash-es';
import semver from 'semver';
import pReduce from 'p-reduce';
import debugTags from 'debug';
import {getNote, getTags} from '../../lib/git.js';
import { escapeRegExp, template } from "lodash-es";
import semver from "semver";
import pReduce from "p-reduce";
import debugTags from "debug";
import { getNote, getTags } from "../../lib/git.js";
const debug = debugTags('semantic-release:get-tags');
const debug = debugTags("semantic-release:get-tags");
export default async ({cwd, env, options: {tagFormat}}, branches) => {
export default async ({ cwd, env, options: { tagFormat } }, branches) => {
// Generate a regex to parse tags formatted with `tagFormat`
// by replacing the `version` variable in the template by `(.+)`.
// The `tagFormat` is compiled with space as the `version` as it's an invalid tag character,
// so it's guaranteed to no be present in the `tagFormat`.
const tagRegexp = `^${escapeRegExp(template(tagFormat)({version: ' '})).replace(' ', '(.+)')}`;
const tagRegexp = `^${escapeRegExp(template(tagFormat)({ version: " " })).replace(" ", "(.+)")}`;
return pReduce(
branches,
async (branches, branch) => {
const branchTags = await pReduce(
await getTags(branch.name, {cwd, env}),
await getTags(branch.name, { cwd, env }),
async (branchTags, tag) => {
const [, version] = tag.match(tagRegexp) || [];
return version && semver.valid(semver.clean(version))
? [...branchTags, {gitTag: tag, version, channels: (await getNote(tag, {cwd, env})).channels || [null]}]
? [...branchTags, { gitTag: tag, version, channels: (await getNote(tag, { cwd, env })).channels || [null] }]
: branchTags;
},
[]
);
debug('found tags for branch %s: %o', branch.name, branchTags);
return [...branches, {...branch, tags: branchTags}];
debug("found tags for branch %s: %o", branch.name, branchTags);
return [...branches, { ...branch, tags: branchTags }];
},
[]
);
}
};
+22 -22
View File
@@ -1,51 +1,51 @@
import {isRegExp, isString} from 'lodash-es';
import AggregateError from 'aggregate-error';
import pEachSeries from 'p-each-series';
import * as DEFINITIONS from '../definitions/branches.js';
import getError from '../get-error.js';
import {fetch, fetchNotes, verifyBranchName} from '../git.js';
import expand from './expand.js';
import getTags from './get-tags.js';
import * as normalize from './normalize.js';
import { isRegExp, isString } from "lodash-es";
import AggregateError from "aggregate-error";
import pEachSeries from "p-each-series";
import * as DEFINITIONS from "../definitions/branches.js";
import getError from "../get-error.js";
import { fetch, fetchNotes, verifyBranchName } from "../git.js";
import expand from "./expand.js";
import getTags from "./get-tags.js";
import * as normalize from "./normalize.js";
export default async (repositoryUrl, ciBranch, context) => {
const {cwd, env} = context;
const { cwd, env } = context;
const remoteBranches = await expand(
repositoryUrl,
context,
context.options.branches.map((branch) => (isString(branch) || isRegExp(branch) ? {name: branch} : branch))
context.options.branches.map((branch) => (isString(branch) || isRegExp(branch) ? { name: branch } : branch))
);
await pEachSeries(remoteBranches, async ({name}) => {
await fetch(repositoryUrl, name, ciBranch, {cwd, env});
await pEachSeries(remoteBranches, async ({ name }) => {
await fetch(repositoryUrl, name, ciBranch, { cwd, env });
});
await fetchNotes(repositoryUrl, {cwd, env});
await fetchNotes(repositoryUrl, { cwd, env });
const branches = await getTags(context, remoteBranches);
const errors = [];
const branchesByType = Object.entries(DEFINITIONS).reduce(
// eslint-disable-next-line unicorn/no-fn-reference-in-iterator
(branchesByType, [type, {filter}]) => ({[type]: branches.filter(filter), ...branchesByType}),
(branchesByType, [type, { filter }]) => ({ [type]: branches.filter(filter), ...branchesByType }),
{}
);
const result = Object.entries(DEFINITIONS).reduce((result, [type, {branchesValidator, branchValidator}]) => {
const result = Object.entries(DEFINITIONS).reduce((result, [type, { branchesValidator, branchValidator }]) => {
branchesByType[type].forEach((branch) => {
if (branchValidator && !branchValidator(branch)) {
errors.push(getError(`E${type.toUpperCase()}BRANCH`, {branch}));
errors.push(getError(`E${type.toUpperCase()}BRANCH`, { branch }));
}
});
const branchesOfType = normalize[type](branchesByType);
if (!branchesValidator(branchesOfType)) {
errors.push(getError(`E${type.toUpperCase()}BRANCHES`, {branches: branchesOfType}));
errors.push(getError(`E${type.toUpperCase()}BRANCHES`, { branches: branchesOfType }));
}
return {...result, [type]: branchesOfType};
return { ...result, [type]: branchesOfType };
}, {});
const duplicates = [...branches]
@@ -54,12 +54,12 @@ export default async (repositoryUrl, ciBranch, context) => {
.filter((_, idx, array) => array[idx] === array[idx + 1] && array[idx] !== array[idx - 1]);
if (duplicates.length > 0) {
errors.push(getError('EDUPLICATEBRANCHES', {duplicates}));
errors.push(getError("EDUPLICATEBRANCHES", { duplicates }));
}
await pEachSeries(branches, async (branch) => {
if (!(await verifyBranchName(branch.name))) {
errors.push(getError('EINVALIDBRANCHNAME', branch));
errors.push(getError("EINVALIDBRANCHNAME", branch));
}
});
@@ -68,4 +68,4 @@ export default async (repositoryUrl, ciBranch, context) => {
}
return [...result.maintenance, ...result.release, ...result.prerelease];
}
};
+18 -17
View File
@@ -1,27 +1,28 @@
import {isNil, sortBy} from 'lodash-es';
import semverDiff from 'semver-diff';
import {FIRST_RELEASE, RELEASE_TYPE} from '../definitions/constants.js';
import { isNil, sortBy } from "lodash-es";
import semverDiff from "semver-diff";
import { FIRST_RELEASE, RELEASE_TYPE } from "../definitions/constants.js";
import {
getFirstVersion,
getLatestVersion,
getLowerBound, getRange,
getLowerBound,
getRange,
getUpperBound,
highest,
isMajorRange,
lowest,
tagsToVersions
} from '../utils.js';
tagsToVersions,
} from "../utils.js";
export function maintenance({maintenance, release}) {
export function maintenance({ maintenance, release }) {
return sortBy(
maintenance.map(({name, range, channel, ...rest}) => ({
maintenance.map(({ name, range, channel, ...rest }) => ({
...rest,
name,
range: range || name,
channel: isNil(channel) ? name : channel,
})),
'range'
).map(({name, range, tags, ...rest}, idx, branches) => {
"range"
).map(({ name, range, tags, ...rest }, idx, branches) => {
const versions = tagsToVersions(tags);
// Find the lower bound based on Maintenance branches
const maintenanceMin =
@@ -44,7 +45,7 @@ export function maintenance({maintenance, release}) {
const diff = semverDiff(min, max);
return {
...rest,
type: 'maintenance',
type: "maintenance",
name,
tags,
range: getRange(min, max),
@@ -54,7 +55,7 @@ export function maintenance({maintenance, release}) {
});
}
export function release({release}) {
export function release({ release }) {
if (release.length === 0) {
return release;
}
@@ -62,7 +63,7 @@ export function release({release}) {
// The intial lastVersion is the last release from the base branch of `FIRST_RELEASE` (1.0.0)
let lastVersion = getLatestVersion(tagsToVersions(release[0].tags)) || FIRST_RELEASE;
return release.map(({name, tags, channel, ...rest}, idx) => {
return release.map(({ name, tags, channel, ...rest }, idx) => {
const versions = tagsToVersions(tags);
// The new lastVersion is the highest version between the current branch last release and the previous branch lastVersion
lastVersion = highest(getLatestVersion(versions), lastVersion);
@@ -79,7 +80,7 @@ export function release({release}) {
...rest,
channel: idx === 0 ? channel : isNil(channel) ? name : channel,
tags,
type: 'release',
type: "release",
name,
range: getRange(lastVersion, bound),
accept: bound ? RELEASE_TYPE.slice(0, RELEASE_TYPE.indexOf(diff)) : RELEASE_TYPE,
@@ -88,13 +89,13 @@ export function release({release}) {
});
}
export function prerelease({prerelease}) {
return prerelease.map(({name, prerelease, channel, tags, ...rest}) => {
export function prerelease({ prerelease }) {
return prerelease.map(({ name, prerelease, channel, tags, ...rest }) => {
const preid = prerelease === true ? name : prerelease;
return {
...rest,
channel: isNil(channel) ? name : channel,
type: 'prerelease',
type: "prerelease",
name,
prerelease: preid,
tags,
+9 -9
View File
@@ -1,18 +1,18 @@
import {isNil, uniqBy} from 'lodash-es';
import semver from 'semver';
import {isMaintenanceRange} from '../utils.js';
import { isNil, uniqBy } from "lodash-es";
import semver from "semver";
import { isMaintenanceRange } from "../utils.js";
export const maintenance = {
filter: ({name, range}) => (!isNil(range) && range !== false) || isMaintenanceRange(name),
branchValidator: ({range}) => (isNil(range) ? true : isMaintenanceRange(range)),
branchesValidator: (branches) => uniqBy(branches, ({range}) => semver.validRange(range)).length === branches.length,
filter: ({ name, range }) => (!isNil(range) && range !== false) || isMaintenanceRange(name),
branchValidator: ({ range }) => (isNil(range) ? true : isMaintenanceRange(range)),
branchesValidator: (branches) => uniqBy(branches, ({ range }) => semver.validRange(range)).length === branches.length,
};
export const prerelease = {
filter: ({prerelease}) => !isNil(prerelease) && prerelease !== false,
branchValidator: ({name, prerelease}) =>
filter: ({ prerelease }) => !isNil(prerelease) && prerelease !== false,
branchValidator: ({ name, prerelease }) =>
Boolean(prerelease) && Boolean(semver.valid(`1.0.0-${prerelease === true ? name : prerelease}.1`)),
branchesValidator: (branches) => uniqBy(branches, 'prerelease').length === branches.length,
branchesValidator: (branches) => uniqBy(branches, "prerelease").length === branches.length,
};
export const release = {
+8 -8
View File
@@ -1,17 +1,17 @@
export const RELEASE_TYPE = ['patch', 'minor', 'major'];
export const RELEASE_TYPE = ["patch", "minor", "major"];
export const FIRST_RELEASE = '1.0.0';
export const FIRST_RELEASE = "1.0.0";
export const FIRSTPRERELEASE = '1';
export const FIRSTPRERELEASE = "1";
export const COMMIT_NAME = 'semantic-release-bot';
export const COMMIT_NAME = "semantic-release-bot";
export const COMMIT_EMAIL = 'semantic-release-bot@martynus.net';
export const COMMIT_EMAIL = "semantic-release-bot@martynus.net";
export const RELEASE_NOTES_SEPARATOR = '\n\n';
export const RELEASE_NOTES_SEPARATOR = "\n\n";
export const SECRET_REPLACEMENT = '[secure]';
export const SECRET_REPLACEMENT = "[secure]";
export const SECRET_MIN_SIZE = 5;
export const GIT_NOTE_REF = 'semantic-release';
export const GIT_NOTE_REF = "semantic-release";
+81 -81
View File
@@ -1,21 +1,21 @@
import {inspect} from 'node:util';
import {createRequire} from 'node:module';
import {isString, toLower, trim} from 'lodash-es';
import {RELEASE_TYPE} from './constants.js';
import { inspect } from "node:util";
import { createRequire } from "node:module";
import { isString, toLower, trim } from "lodash-es";
import { RELEASE_TYPE } from "./constants.js";
const require = createRequire(import.meta.url);
const pkg = require('../../package.json');
const pkg = require("../../package.json");
const [homepage] = pkg.homepage.split('#');
const [homepage] = pkg.homepage.split("#");
const stringify = (object) =>
isString(object) ? object : inspect(object, {breakLength: Infinity, depth: 2, maxArrayLength: 5});
isString(object) ? object : inspect(object, { breakLength: Infinity, depth: 2, maxArrayLength: 5 });
const linkify = (file) => `${homepage}/blob/master/${file}`;
const wordsList = (words) =>
`${words.slice(0, -1).join(', ')}${words.length > 1 ? ` or ${words[words.length - 1]}` : trim(words[0])}`;
`${words.slice(0, -1).join(", ")}${words.length > 1 ? ` or ${words[words.length - 1]}` : trim(words[0])}`;
export function ENOGITREPO({cwd}) {
export function ENOGITREPO({ cwd }) {
return {
message: 'Not running from a git repository.',
message: "Not running from a git repository.",
details: `The \`semantic-release\` command must be executed from a Git repository.
The current working directory is \`${cwd}\`.
@@ -26,76 +26,76 @@ Please verify your CI configuration to make sure the \`semantic-release\` comman
export function ENOREPOURL() {
return {
message: 'The `repositoryUrl` option is required.',
message: "The `repositoryUrl` option is required.",
details: `The [repositoryUrl option](${linkify(
'docs/usage/configuration.md#repositoryurl'
"docs/usage/configuration.md#repositoryurl"
)}) cannot be determined from the semantic-release configuration, the \`package.json\` nor the [git origin url](https://git-scm.com/book/en/v2/Git-Basics-Working-with-Remotes).
Please make sure to add the \`repositoryUrl\` to the [semantic-release configuration] (${linkify(
'docs/usage/configuration.md'
"docs/usage/configuration.md"
)}).`,
};
}
export function EGITNOPERMISSION({options: {repositoryUrl}, branch: {name}}) {
export function EGITNOPERMISSION({ options: { repositoryUrl }, branch: { name } }) {
return {
message: 'Cannot push to the Git repository.',
message: "Cannot push to the Git repository.",
details: `**semantic-release** cannot push the version tag to the branch \`${name}\` on the remote Git repository with URL \`${repositoryUrl}\`.
This can be caused by:
- a misconfiguration of the [repositoryUrl](${linkify('docs/usage/configuration.md#repositoryurl')}) option
- a misconfiguration of the [repositoryUrl](${linkify("docs/usage/configuration.md#repositoryurl")}) option
- the repository being unavailable
- or missing push permission for the user configured via the [Git credentials on your CI environment](${linkify(
'docs/usage/ci-configuration.md#authentication'
)})`,
"docs/usage/ci-configuration.md#authentication"
)})`,
};
}
export function EINVALIDTAGFORMAT({options: {tagFormat}}) {
export function EINVALIDTAGFORMAT({ options: { tagFormat } }) {
return {
message: 'Invalid `tagFormat` option.',
message: "Invalid `tagFormat` option.",
details: `The [tagFormat](${linkify(
'docs/usage/configuration.md#tagformat'
"docs/usage/configuration.md#tagformat"
)}) must compile to a [valid Git reference](https://git-scm.com/docs/git-check-ref-format#_description).
Your configuration for the \`tagFormat\` option is \`${stringify(tagFormat)}\`.`,
};
}
export function ETAGNOVERSION({options: {tagFormat}}) {
export function ETAGNOVERSION({ options: { tagFormat } }) {
return {
message: 'Invalid `tagFormat` option.',
message: "Invalid `tagFormat` option.",
details: `The [tagFormat](${linkify(
'docs/usage/configuration.md#tagformat'
"docs/usage/configuration.md#tagformat"
)}) option must contain the variable \`version\` exactly once.
Your configuration for the \`tagFormat\` option is \`${stringify(tagFormat)}\`.`,
};
}
export function EPLUGINCONF({type, required, pluginConf}) {
export function EPLUGINCONF({ type, required, pluginConf }) {
return {
message: `The \`${type}\` plugin configuration is invalid.`,
details: `The [${type} plugin configuration](${linkify(`docs/usage/plugins.md#${toLower(type)}-plugin`)}) ${
required ? 'is required and ' : ''
required ? "is required and " : ""
} must be a single or an array of plugins definition. A plugin definition is an npm module name, optionally wrapped in an array with an object.
Your configuration for the \`${type}\` plugin is \`${stringify(pluginConf)}\`.`,
};
}
export function EPLUGINSCONF({plugin}) {
export function EPLUGINSCONF({ plugin }) {
return {
message: 'The `plugins` configuration is invalid.',
message: "The `plugins` configuration is invalid.",
details: `The [plugins](${linkify(
'docs/usage/configuration.md#plugins'
"docs/usage/configuration.md#plugins"
)}) option must be an array of plugin definitions. A plugin definition is an npm module name, optionally wrapped in an array with an object.
The invalid configuration is \`${stringify(plugin)}\`.`,
};
}
export function EPLUGIN({pluginName, type}) {
export function EPLUGIN({ pluginName, type }) {
return {
message: `A plugin configured in the step ${type} is not a valid semantic-release plugin.`,
details: `A valid \`${type}\` **semantic-release** plugin must be a function or an object with a function in the property \`${type}\`.
@@ -103,17 +103,17 @@ export function EPLUGIN({pluginName, type}) {
The plugin \`${pluginName}\` doesn't have the property \`${type}\` and cannot be used for the \`${type}\` step.
Please refer to the \`${pluginName}\` and [semantic-release plugins configuration](${linkify(
'docs/usage/plugins.md'
"docs/usage/plugins.md"
)}) documentation for more details.`,
};
}
export function EANALYZECOMMITSOUTPUT({result, pluginName}) {
export function EANALYZECOMMITSOUTPUT({ result, pluginName }) {
return {
message: 'The `analyzeCommits` plugin returned an invalid value. It must return a valid semver release type.',
message: "The `analyzeCommits` plugin returned an invalid value. It must return a valid semver release type.",
details: `The \`analyzeCommits\` plugin must return a valid [semver](https://semver.org) release type. The valid values are: ${RELEASE_TYPE.map(
(type) => `\`${type}\``
).join(', ')}.
).join(", ")}.
The \`analyzeCommits\` function of the \`${pluginName}\` returned \`${stringify(result)}\` instead.
@@ -121,15 +121,15 @@ We recommend to report the issue to the \`${pluginName}\` authors, providing the
- The **semantic-release** version: \`${pkg.version}\`
- The **semantic-release** logs from your CI job
- The value returned by the plugin: \`${stringify(result)}\`
- A link to the **semantic-release** plugin developer guide: [${linkify('docs/developer-guide/plugin.md')}](${linkify(
'docs/developer-guide/plugin.md'
- A link to the **semantic-release** plugin developer guide: [${linkify("docs/developer-guide/plugin.md")}](${linkify(
"docs/developer-guide/plugin.md"
)})`,
};
}
export function EGENERATENOTESOUTPUT({result, pluginName}) {
export function EGENERATENOTESOUTPUT({ result, pluginName }) {
return {
message: 'The `generateNotes` plugin returned an invalid value. It must return a `String`.',
message: "The `generateNotes` plugin returned an invalid value. It must return a `String`.",
details: `The \`generateNotes\` plugin must return a \`String\`.
The \`generateNotes\` function of the \`${pluginName}\` returned \`${stringify(result)}\` instead.
@@ -138,15 +138,15 @@ We recommend to report the issue to the \`${pluginName}\` authors, providing the
- The **semantic-release** version: \`${pkg.version}\`
- The **semantic-release** logs from your CI job
- The value returned by the plugin: \`${stringify(result)}\`
- A link to the **semantic-release** plugin developer guide: [${linkify('docs/developer-guide/plugin.md')}](${linkify(
'docs/developer-guide/plugin.md'
- A link to the **semantic-release** plugin developer guide: [${linkify("docs/developer-guide/plugin.md")}](${linkify(
"docs/developer-guide/plugin.md"
)})`,
};
}
export function EPUBLISHOUTPUT({result, pluginName}) {
export function EPUBLISHOUTPUT({ result, pluginName }) {
return {
message: 'A `publish` plugin returned an invalid value. It must return an `Object`.',
message: "A `publish` plugin returned an invalid value. It must return an `Object`.",
details: `The \`publish\` plugins must return an \`Object\`.
The \`publish\` function of the \`${pluginName}\` returned \`${stringify(result)}\` instead.
@@ -155,15 +155,15 @@ We recommend to report the issue to the \`${pluginName}\` authors, providing the
- The **semantic-release** version: \`${pkg.version}\`
- The **semantic-release** logs from your CI job
- The value returned by the plugin: \`${stringify(result)}\`
- A link to the **semantic-release** plugin developer guide: [${linkify('docs/developer-guide/plugin.md')}](${linkify(
'docs/developer-guide/plugin.md'
- A link to the **semantic-release** plugin developer guide: [${linkify("docs/developer-guide/plugin.md")}](${linkify(
"docs/developer-guide/plugin.md"
)})`,
};
}
export function EADDCHANNELOUTPUT({result, pluginName}) {
export function EADDCHANNELOUTPUT({ result, pluginName }) {
return {
message: 'A `addChannel` plugin returned an invalid value. It must return an `Object`.',
message: "A `addChannel` plugin returned an invalid value. It must return an `Object`.",
details: `The \`addChannel\` plugins must return an \`Object\`.
The \`addChannel\` function of the \`${pluginName}\` returned \`${stringify(result)}\` instead.
@@ -172,72 +172,72 @@ We recommend to report the issue to the \`${pluginName}\` authors, providing the
- The **semantic-release** version: \`${pkg.version}\`
- The **semantic-release** logs from your CI job
- The value returned by the plugin: \`${stringify(result)}\`
- A link to the **semantic-release** plugin developer guide: [${linkify('docs/developer-guide/plugin.md')}](${linkify(
'docs/developer-guide/plugin.md'
- A link to the **semantic-release** plugin developer guide: [${linkify("docs/developer-guide/plugin.md")}](${linkify(
"docs/developer-guide/plugin.md"
)})`,
};
}
export function EINVALIDBRANCH({branch}) {
export function EINVALIDBRANCH({ branch }) {
return {
message: 'A branch is invalid in the `branches` configuration.',
message: "A branch is invalid in the `branches` configuration.",
details: `Each branch in the [branches configuration](${linkify(
'docs/usage/configuration.md#branches'
"docs/usage/configuration.md#branches"
)}) must be either a string, a regexp or an object with a \`name\` property.
Your configuration for the problematic branch is \`${stringify(branch)}\`.`,
};
}
export function EINVALIDBRANCHNAME({branch}) {
export function EINVALIDBRANCHNAME({ branch }) {
return {
message: 'A branch name is invalid in the `branches` configuration.',
message: "A branch name is invalid in the `branches` configuration.",
details: `Each branch in the [branches configuration](${linkify(
'docs/usage/configuration.md#branches'
"docs/usage/configuration.md#branches"
)}) must be a [valid Git reference](https://git-scm.com/docs/git-check-ref-format#_description).
Your configuration for the problematic branch is \`${stringify(branch)}\`.`,
};
}
export function EDUPLICATEBRANCHES({duplicates}) {
export function EDUPLICATEBRANCHES({ duplicates }) {
return {
message: 'The `branches` configuration has duplicate branches.',
message: "The `branches` configuration has duplicate branches.",
details: `Each branch in the [branches configuration](${linkify(
'docs/usage/configuration.md#branches'
"docs/usage/configuration.md#branches"
)}) must havea unique name.
Your configuration contains duplicates for the following branch names: \`${stringify(duplicates)}\`.`,
};
}
export function EMAINTENANCEBRANCH({branch}) {
export function EMAINTENANCEBRANCH({ branch }) {
return {
message: 'A maintenance branch is invalid in the `branches` configuration.',
message: "A maintenance branch is invalid in the `branches` configuration.",
details: `Each maintenance branch in the [branches configuration](${linkify(
'docs/usage/configuration.md#branches'
"docs/usage/configuration.md#branches"
)}) must have a \`range\` property formatted like \`N.x\`, \`N.x.x\` or \`N.N.x\` (\`N\` is a number).
Your configuration for the problematic branch is \`${stringify(branch)}\`.`,
};
}
export function EMAINTENANCEBRANCHES({branches}) {
export function EMAINTENANCEBRANCHES({ branches }) {
return {
message: 'The maintenance branches are invalid in the `branches` configuration.',
message: "The maintenance branches are invalid in the `branches` configuration.",
details: `Each maintenance branch in the [branches configuration](${linkify(
'docs/usage/configuration.md#branches'
"docs/usage/configuration.md#branches"
)}) must have a unique \`range\` property.
Your configuration for the problematic branches is \`${stringify(branches)}\`.`,
};
}
export function ERELEASEBRANCHES({branches}) {
export function ERELEASEBRANCHES({ branches }) {
return {
message: 'The release branches are invalid in the `branches` configuration.',
message: "The release branches are invalid in the `branches` configuration.",
details: `A minimum of 1 and a maximum of 3 release branches are required in the [branches configuration](${linkify(
'docs/usage/configuration.md#branches'
"docs/usage/configuration.md#branches"
)}).
This may occur if your repository does not have a release branch, such as \`master\`.
@@ -246,53 +246,53 @@ Your configuration for the problematic branches is \`${stringify(branches)}\`.`,
};
}
export function EPRERELEASEBRANCH({branch}) {
export function EPRERELEASEBRANCH({ branch }) {
return {
message: 'A pre-release branch configuration is invalid in the `branches` configuration.',
message: "A pre-release branch configuration is invalid in the `branches` configuration.",
details: `Each pre-release branch in the [branches configuration](${linkify(
'docs/usage/configuration.md#branches'
"docs/usage/configuration.md#branches"
)}) must have a \`prerelease\` property valid per the [Semantic Versioning Specification](https://semver.org/#spec-item-9). If the \`prerelease\` property is set to \`true\`, then the \`name\` property is used instead.
Your configuration for the problematic branch is \`${stringify(branch)}\`.`,
};
}
export function EPRERELEASEBRANCHES({branches}) {
export function EPRERELEASEBRANCHES({ branches }) {
return {
message: 'The pre-release branches are invalid in the `branches` configuration.',
message: "The pre-release branches are invalid in the `branches` configuration.",
details: `Each pre-release branch in the [branches configuration](${linkify(
'docs/usage/configuration.md#branches'
"docs/usage/configuration.md#branches"
)}) must have a unique \`prerelease\` property. If the \`prerelease\` property is set to \`true\`, then the \`name\` property is used instead.
Your configuration for the problematic branches is \`${stringify(branches)}\`.`,
};
}
export function EINVALIDNEXTVERSION({nextRelease: {version}, branch: {name, range}, commits, validBranches}) {
export function EINVALIDNEXTVERSION({ nextRelease: { version }, branch: { name, range }, commits, validBranches }) {
return {
message: `The release \`${version}\` on branch \`${name}\` cannot be published as it is out of range.`,
details: `Based on the releases published on other branches, only versions within the range \`${range}\` can be published from branch \`${name}\`.
The following commit${commits.length > 1 ? 's are' : ' is'} responsible for the invalid release:
${commits.map(({commit: {short}, subject}) => `- ${subject} (${short})`).join('\n')}
The following commit${commits.length > 1 ? "s are" : " is"} responsible for the invalid release:
${commits.map(({ commit: { short }, subject }) => `- ${subject} (${short})`).join("\n")}
${
commits.length > 1 ? 'Those commits' : 'This commit'
} should be moved to a valid branch with [git merge](https://git-scm.com/docs/git-merge) or [git cherry-pick](https://git-scm.com/docs/git-cherry-pick) and removed from branch \`${name}\` with [git revert](https://git-scm.com/docs/git-revert) or [git reset](https://git-scm.com/docs/git-reset).
commits.length > 1 ? "Those commits" : "This commit"
} should be moved to a valid branch with [git merge](https://git-scm.com/docs/git-merge) or [git cherry-pick](https://git-scm.com/docs/git-cherry-pick) and removed from branch \`${name}\` with [git revert](https://git-scm.com/docs/git-revert) or [git reset](https://git-scm.com/docs/git-reset).
A valid branch could be ${wordsList(validBranches.map(({name}) => `\`${name}\``))}.
A valid branch could be ${wordsList(validBranches.map(({ name }) => `\`${name}\``))}.
See the [workflow configuration documentation](${linkify('docs/usage/workflow-configuration.md')}) for more details.`,
See the [workflow configuration documentation](${linkify("docs/usage/workflow-configuration.md")}) for more details.`,
};
}
export function EINVALIDMAINTENANCEMERGE({nextRelease: {channel, gitTag, version}, branch: {mergeRange, name}}) {
export function EINVALIDMAINTENANCEMERGE({ nextRelease: { channel, gitTag, version }, branch: { mergeRange, name } }) {
return {
message: `The release \`${version}\` on branch \`${name}\` cannot be published as it is out of range.`,
details: `Only releases within the range \`${mergeRange}\` can be merged into the maintenance branch \`${name}\` and published to the \`${channel}\` distribution channel.
The branch \`${name}\` head should be [reset](https://git-scm.com/docs/git-reset) to a previous commit so the commit with tag \`${gitTag}\` is removed from the branch history.
See the [workflow configuration documentation](${linkify('docs/usage/workflow-configuration.md')}) for more details.`,
See the [workflow configuration documentation](${linkify("docs/usage/workflow-configuration.md")}) for more details.`,
};
}
+20 -20
View File
@@ -1,23 +1,23 @@
/* eslint require-atomic-updates: off */
import {isPlainObject, isString} from 'lodash-es';
import {getGitHead} from '../git.js';
import hideSensitive from '../hide-sensitive.js';
import {hideSensitiveValues} from '../utils.js';
import {RELEASE_NOTES_SEPARATOR, RELEASE_TYPE} from './constants.js';
import { isPlainObject, isString } from "lodash-es";
import { getGitHead } from "../git.js";
import hideSensitive from "../hide-sensitive.js";
import { hideSensitiveValues } from "../utils.js";
import { RELEASE_NOTES_SEPARATOR, RELEASE_TYPE } from "./constants.js";
export default {
verifyConditions: {
required: false,
dryRun: true,
pipelineConfig: () => ({settleAll: true}),
pipelineConfig: () => ({ settleAll: true }),
},
analyzeCommits: {
default: ['@semantic-release/commit-analyzer'],
default: ["@semantic-release/commit-analyzer"],
required: true,
dryRun: true,
outputValidator: (output) => !output || RELEASE_TYPE.includes(output),
preprocess: ({commits, ...inputs}) => ({
preprocess: ({ commits, ...inputs }) => ({
...inputs,
commits: commits.filter((commit) => !/\[skip\s+release]|\[release\s+skip]/i.test(commit.message)),
}),
@@ -32,29 +32,29 @@ export default {
verifyRelease: {
required: false,
dryRun: true,
pipelineConfig: () => ({settleAll: true}),
pipelineConfig: () => ({ settleAll: true }),
},
generateNotes: {
required: false,
dryRun: true,
outputValidator: (output) => !output || isString(output),
pipelineConfig: () => ({
getNextInput: ({nextRelease, ...context}, notes) => ({
getNextInput: ({ nextRelease, ...context }, notes) => ({
...context,
nextRelease: {
...nextRelease,
notes: `${nextRelease.notes ? `${nextRelease.notes}${RELEASE_NOTES_SEPARATOR}` : ''}${notes}`,
notes: `${nextRelease.notes ? `${nextRelease.notes}${RELEASE_NOTES_SEPARATOR}` : ""}${notes}`,
},
}),
}),
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: {
required: false,
dryRun: false,
pipelineConfig: ({generateNotes}) => ({
pipelineConfig: ({ generateNotes }) => ({
getNextInput: async (context) => {
const newGitHead = await getGitHead({cwd: context.cwd});
const newGitHead = await getGitHead({ cwd: context.cwd });
// If previous prepare plugin has created a commit (gitHead changed)
if (context.nextRelease.gitHead !== newGitHead) {
context.nextRelease.gitHead = newGitHead;
@@ -73,7 +73,7 @@ export default {
outputValidator: (output) => !output || isPlainObject(output),
pipelineConfig: () => ({
// Add `nextRelease` and plugin properties to published release
transform: (release, step, {nextRelease}) => ({
transform: (release, step, { nextRelease }) => ({
...(release === false ? {} : nextRelease),
...release,
...step,
@@ -86,7 +86,7 @@ export default {
outputValidator: (output) => !output || isPlainObject(output),
pipelineConfig: () => ({
// Add `nextRelease` and plugin properties to published release
transform: (release, step, {nextRelease}) => ({
transform: (release, step, { nextRelease }) => ({
...(release === false ? {} : nextRelease),
...release,
...step,
@@ -96,13 +96,13 @@ export default {
success: {
required: false,
dryRun: false,
pipelineConfig: () => ({settleAll: true}),
preprocess: ({releases, env, ...inputs}) => ({...inputs, env, releases: hideSensitiveValues(env, releases)}),
pipelineConfig: () => ({ settleAll: true }),
preprocess: ({ releases, env, ...inputs }) => ({ ...inputs, env, releases: hideSensitiveValues(env, releases) }),
},
fail: {
required: false,
dryRun: false,
pipelineConfig: () => ({settleAll: true}),
preprocess: ({errors, env, ...inputs}) => ({...inputs, env, errors: hideSensitiveValues(env, errors)}),
pipelineConfig: () => ({ settleAll: true }),
preprocess: ({ errors, env, ...inputs }) => ({ ...inputs, env, errors: hideSensitiveValues(env, errors) }),
},
};
+18 -18
View File
@@ -1,13 +1,13 @@
import {castArray, identity, isNil, isPlainObject, isString, omit} from 'lodash-es';
import AggregateError from 'aggregate-error';
import getError from '../get-error.js';
import PLUGINS_DEFINITIONS from '../definitions/plugins.js';
import {loadPlugin, parseConfig, validatePlugin, validateStep} from './utils.js';
import pipeline from './pipeline.js';
import normalize from './normalize.js';
import { castArray, identity, isNil, isPlainObject, isString, omit } from "lodash-es";
import AggregateError from "aggregate-error";
import getError from "../get-error.js";
import PLUGINS_DEFINITIONS from "../definitions/plugins.js";
import { loadPlugin, parseConfig, validatePlugin, validateStep } from "./utils.js";
import pipeline from "./pipeline.js";
import normalize from "./normalize.js";
export default async (context, pluginsPath) => {
let {options, logger} = context;
let { options, logger } = context;
const errors = [];
const plugins = options.plugins
@@ -20,8 +20,8 @@ export default async (context, pluginsPath) => {
if (isPlainObject(plugin)) {
Object.entries(plugin).forEach(([type, func]) => {
if (PLUGINS_DEFINITIONS[type]) {
Reflect.defineProperty(func, 'pluginName', {
value: isPlainObject(name) ? 'Inline plugin' : name,
Reflect.defineProperty(func, "pluginName", {
value: isPlainObject(name) ? "Inline plugin" : name,
writable: false,
enumerable: true,
});
@@ -29,10 +29,10 @@ export default async (context, pluginsPath) => {
}
});
} else {
errors.push(getError('EPLUGINSCONF', {plugin}));
errors.push(getError("EPLUGINSCONF", { plugin }));
}
} else {
errors.push(getError('EPLUGINSCONF', {plugin}));
errors.push(getError("EPLUGINSCONF", { plugin }));
}
return pluginsList;
@@ -43,12 +43,12 @@ export default async (context, pluginsPath) => {
throw new AggregateError(errors);
}
options = {...plugins, ...options};
options = { ...plugins, ...options };
const pluginsConfig = await Object.entries(PLUGINS_DEFINITIONS).reduce(
async (
eventualPluginsConfigAccumulator,
[type, {required, default: def, pipelineConfig, postprocess = identity, preprocess = identity}]
[type, { required, default: def, pipelineConfig, postprocess = identity, preprocess = identity }]
) => {
let pluginOptions;
const pluginsConfigAccumulator = await eventualPluginsConfigAccumulator;
@@ -63,8 +63,8 @@ export default async (context, pluginsPath) => {
);
}
if (!validateStep({required}, options[type])) {
errors.push(getError('EPLUGINCONF', {type, required, pluginConf: options[type]}));
if (!validateStep({ required }, options[type])) {
errors.push(getError("EPLUGINCONF", { type, required, pluginConf: options[type] }));
return pluginsConfigAccumulator;
}
@@ -74,7 +74,7 @@ export default async (context, pluginsPath) => {
const steps = await Promise.all(
castArray(pluginOptions).map(async (pluginOpt) =>
normalize(
{...context, options: omit(options, Object.keys(PLUGINS_DEFINITIONS), 'plugins')},
{ ...context, options: omit(options, Object.keys(PLUGINS_DEFINITIONS), "plugins") },
type,
pluginOpt,
pluginsPath
@@ -100,4 +100,4 @@ export default async (context, pluginsPath) => {
}
return pluginsConfig;
}
};
+17 -17
View File
@@ -1,14 +1,14 @@
import {cloneDeep, isFunction, isPlainObject, noop, omit} from 'lodash-es';
import debugPlugins from 'debug';
import getError from '../get-error.js';
import {extractErrors} from '../utils.js';
import PLUGINS_DEFINITIONS from '../definitions/plugins.js';
import {loadPlugin, parseConfig} from './utils.js';
import { cloneDeep, isFunction, isPlainObject, noop, omit } from "lodash-es";
import debugPlugins from "debug";
import getError from "../get-error.js";
import { extractErrors } from "../utils.js";
import PLUGINS_DEFINITIONS from "../definitions/plugins.js";
import { loadPlugin, parseConfig } from "./utils.js";
const debug = debugPlugins('semantic-release:plugins');
const debug = debugPlugins("semantic-release:plugins");
export default async (context, type, pluginOpt, pluginsPath) => {
const {stdout, stderr, options, logger} = context;
const { stdout, stderr, options, logger } = context;
if (!pluginOpt) {
return noop;
}
@@ -21,26 +21,26 @@ export default async (context, type, pluginOpt, pluginsPath) => {
let func;
if (isFunction(plugin)) {
func = plugin.bind(null, cloneDeep({...options, ...config}));
func = plugin.bind(null, cloneDeep({ ...options, ...config }));
} else if (isPlainObject(plugin) && plugin[type] && isFunction(plugin[type])) {
func = plugin[type].bind(null, cloneDeep({...options, ...config}));
func = plugin[type].bind(null, cloneDeep({ ...options, ...config }));
} else {
throw getError('EPLUGIN', {type, pluginName});
throw getError("EPLUGIN", { type, pluginName });
}
const validator = async (input) => {
const {dryRun, outputValidator} = PLUGINS_DEFINITIONS[type] || {};
const { dryRun, outputValidator } = PLUGINS_DEFINITIONS[type] || {};
try {
if (!input.options.dryRun || dryRun) {
logger.log(`Start step "${type}" of plugin "${pluginName}"`);
const result = await func({
...cloneDeep(omit(input, ['stdout', 'stderr', 'logger'])),
...cloneDeep(omit(input, ["stdout", "stderr", "logger"])),
stdout,
stderr,
logger: logger.scope(logger.scopeName, pluginName),
});
if (outputValidator && !outputValidator(result)) {
throw getError(`E${type.toUpperCase()}OUTPUT`, {result, pluginName});
throw getError(`E${type.toUpperCase()}OUTPUT`, { result, pluginName });
}
logger.success(`Completed step "${type}" of plugin "${pluginName}"`);
@@ -50,12 +50,12 @@ export default async (context, type, pluginOpt, pluginsPath) => {
logger.warn(`Skip step "${type}" of plugin "${pluginName}" in dry-run mode`);
} catch (error) {
logger.error(`Failed step "${type}" of plugin "${pluginName}"`);
extractErrors(error).forEach((err) => Object.assign(err, {pluginName}));
extractErrors(error).forEach((err) => Object.assign(err, { pluginName }));
throw error;
}
};
Reflect.defineProperty(validator, 'pluginName', {value: pluginName, writable: false, enumerable: true});
Reflect.defineProperty(validator, "pluginName", { value: pluginName, writable: false, enumerable: true });
if (!isFunction(pluginOpt)) {
if (pluginsPath[name]) {
@@ -66,4 +66,4 @@ export default async (context, type, pluginOpt, pluginsPath) => {
}
return validator;
}
};
+33 -32
View File
@@ -1,7 +1,7 @@
import {identity} from 'lodash-es';
import pReduce from 'p-reduce';
import AggregateError from 'aggregate-error';
import {extractErrors} from '../utils.js';
import { identity } from "lodash-es";
import pReduce from "p-reduce";
import AggregateError from "aggregate-error";
import { extractErrors } from "../utils.js";
/**
* A Function that execute a list of function sequencially. If at least one Function ins the pipeline throws an Error or rejects, the pipeline function rejects as well.
@@ -25,34 +25,35 @@ import {extractErrors} from '../utils.js';
*
* @return {Pipeline} A Function that execute the `steps` sequentially
*/
export default (steps, {settleAll = false, getNextInput = identity, transform = identity} = {}) => async (input) => {
const results = [];
const errors = [];
await pReduce(
steps,
async (lastInput, step) => {
let result;
try {
// Call the step with the input computed at the end of the previous iteration and save intermediary result
result = await transform(await step(lastInput), step, lastInput);
results.push(result);
} catch (error) {
if (settleAll) {
errors.push(...extractErrors(error));
result = error;
} else {
throw error;
export default (steps, { settleAll = false, getNextInput = identity, transform = identity } = {}) =>
async (input) => {
const results = [];
const errors = [];
await pReduce(
steps,
async (lastInput, step) => {
let result;
try {
// Call the step with the input computed at the end of the previous iteration and save intermediary result
result = await transform(await step(lastInput), step, lastInput);
results.push(result);
} catch (error) {
if (settleAll) {
errors.push(...extractErrors(error));
result = error;
} else {
throw error;
}
}
}
// Prepare input for the next step, passing the input of the last iteration (or initial parameter for the first iteration) and the result of the current one
return getNextInput(lastInput, result);
},
input
);
if (errors.length > 0) {
throw new AggregateError(errors);
}
// Prepare input for the next step, passing the input of the last iteration (or initial parameter for the first iteration) and the result of the current one
return getNextInput(lastInput, result);
},
input
);
if (errors.length > 0) {
throw new AggregateError(errors);
}
return results;
}
return results;
};
+20 -9
View File
@@ -1,7 +1,7 @@
import {dirname} from 'node:path';
import {fileURLToPath} from 'node:url';
import {castArray, isArray, isFunction, isNil, isPlainObject, isString} from 'lodash-es';
import resolveFrom from 'resolve-from';
import { dirname } from "node:path";
import { fileURLToPath } from "node:url";
import { castArray, isArray, isFunction, isNil, isPlainObject, isString } from "lodash-es";
import resolveFrom from "resolve-from";
const __dirname = dirname(fileURLToPath(import.meta.url));
@@ -38,7 +38,7 @@ export function validatePlugin(conf) {
);
}
export function validateStep({required}, conf) {
export function validateStep({ required }, conf) {
conf = castArray(conf).filter(Boolean);
if (required) {
return conf.length >= 1 && validateSteps(conf);
@@ -47,14 +47,25 @@ export function validateStep({required}, conf) {
return conf.length === 0 || validateSteps(conf);
}
export async function loadPlugin({cwd}, name, pluginsPath) {
export async function loadPlugin({ cwd }, name, pluginsPath) {
const basePath = pluginsPath[name]
? dirname(resolveFrom.silent(__dirname, pluginsPath[name]) || resolveFrom(cwd, pluginsPath[name]))
: __dirname;
// See https://github.com/mysticatea/eslint-plugin-node/issues/250
// eslint-disable-next-line node/no-unsupported-features/es-syntax
return isFunction(name) ? name : (await import(resolveFrom.silent(basePath, name) || resolveFrom(cwd, name))).default;
if (isFunction(name)) {
return name;
}
const { default: cjsExport, ...esmNamedExports } = await import(
resolveFrom.silent(basePath, name) || resolveFrom(cwd, name)
);
if (cjsExport) {
return cjsExport;
}
return esmNamedExports;
}
export function parseConfig(plugin) {
@@ -63,7 +74,7 @@ export function parseConfig(plugin) {
if (isArray(plugin)) {
[path, config] = plugin;
} else if (isPlainObject(plugin) && !isNil(plugin.path)) {
({path, ...config} = plugin);
({ path, ...config } = plugin);
} else {
path = plugin;
}