Socket
Socket
Sign inDemoInstall

semantic-release

Package Overview
Dependencies
Maintainers
4
Versions
409
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

semantic-release - npm Package Compare versions

Comparing version 20.1.3 to 21.0.7

2

docs/developer-guide/js-api.md

@@ -145,3 +145,3 @@ # JavaScript API

**Notes**: If no previous release is found, `lastRelease` will be an empty `Object`.
**Note**: If no previous release is found, `lastRelease` will be an empty `Object`.

@@ -148,0 +148,0 @@ Example:

@@ -177,1 +177,9 @@ # Plugins list

- `publish` add a release tag to Coralogix
- [semantic-release-major-tag](https://github.com/doteric/semantic-release-major-tag)
- `success` Create major version tag, for example `v1`.
- [semantic-release-yarn](https://github.com/hongaar/semantic-release-yarn)
- **Note**: this is an alternative to the default `@semantic-release/npm` plugin and adds support for monorepos.
- `verifyConditions` Verify Yarn 2 or higher is installed, verify the presence of a NPM auth token (either in an environment variable or a `.yarnrc.yml` file) and verify the authentication method is valid.
- `prepare` Update the `package.json` version and create the package tarball.
- `addChannel` Add a tag for the release.
- `publish` Publish to the npm registry.

@@ -9,2 +9,7 @@ # Using semantic-release with [GitHub Actions](https://help.github.com/en/categories/automating-your-workflow-with-github-actions)

## npm provenance
Since GitHub Actions is a [supported provider](https://docs.npmjs.com/generating-provenance-statements#provenance-limitations) for [npm provenance](https://docs.npmjs.com/generating-provenance-statements), it is recommended to enable this to increase supply-chain security for your npm packages.
Find more detail about configuring npm to publish with provenance through semantic-release [in the documentation for our npm plugin](https://github.com/semantic-release/npm#npm-provenance).
## Node project configuration

@@ -27,2 +32,6 @@

- master
permissions:
contents: read # for checkout
jobs:

@@ -32,2 +41,7 @@ release:

runs-on: ubuntu-latest
permissions:
contents: write # to be able to publish a GitHub release
issues: write # to be able to comment on released issues
pull-requests: write # to be able to comment on released pull requests
id-token: write # to enable use of OIDC for npm provenance
steps:

@@ -43,3 +57,5 @@ - name: Checkout

- name: Install dependencies
run: npm ci
run: npm clean-install
- name: Verify the integrity of provenance attestations and registry signatures for installed dependencies
run: npm audit signatures
- name: Release

@@ -46,0 +62,0 @@ env:

@@ -161,10 +161,2 @@ # Frequently Asked Questions

## Can I use semantic-release to publish a package on Artifactory?
Any npm compatible registry is supported with the [`@semantic-release/npm`](https://github.com/semantic-release/npm) plugin. For Artifactory versions prior to 5.4, the legacy authentication has to be used (with `NPM_USERNAME`, `NPM_PASSWORD` and `NPM_EMAIL` [environment variables](https://github.com/semantic-release/npm#environment-variables)).
See [npm registry authentication](https://github.com/semantic-release/npm#npm-registry-authentication) for more details.
See [Artifactory - npm Registry](https://www.jfrog.com/confluence/display/RTF/Npm+Registry#NpmRegistry-AuthenticatingthenpmClient) documentation for Artifactory configuration.
## Can I manually trigger the release of a specific version?

@@ -171,0 +163,0 @@

@@ -27,7 +27,26 @@ # Installation

**Note**: For a global installation, it's recommended to specify the major **semantic-release** version to install (for example with `npx semantic-release@18`).
This way your build will not automatically use the next major **semantic-release** release that could possibly break your build.
You will have to upgrade manually when a new major version is released.
### Notes
**Note**: `npx` is a tool bundled with `npm@>=5.2.0`. It is used to conveniently install the semantic-release binary and to execute it.
See [What is npx](../support/FAQ.md#what-is-npx) for more details.
1. If you've globally installed **semantic-release** then we recommend that you set the major **semantic-release** version to install.
For example, by using `npx semantic-release@18`.
This way you control which major version of **semantic-release** is used by your build, and thus avoid breaking the build when there's a new major version of **semantic-release**.
This also means you, or a bot, must upgrade **semantic-release** when a new major version is released.
2. Pinning **semantic-release** to an exact version makes your releases even more deterministic.
But pinning also means you, or a bot, must update to newer versions of **semantic-release** more often.
3. You can use [Renovate's regex manager](https://docs.renovatebot.com/modules/manager/regex/) to get automatic updates for **semantic-release** in either of the above scenarios.
Put this in your Renovate configuration file:
```json
{
"regexManagers": [
{
"description": "Update semantic-release version used by npx",
"fileMatch": ["^\\.github/workflows/[^/]+\\.ya?ml$"],
"matchStrings": ["\\srun: npx semantic-release@(?<currentValue>.*?)\\s"],
"datasourceTemplate": "npm",
"depNameTemplate": "semantic-release"
}
]
}
```
4. `npx` is a tool bundled with `npm@>=5.2.0`. You can use it to install (and run) the **semantic-release** binary.
See [What is npx](../support/FAQ.md#what-is-npx) for more details.

@@ -1,7 +0,7 @@

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 });

@@ -13,3 +13,3 @@ return branches.reduce(

name,
...mapValues(omit(branch, 'name'), (value) => (isString(value) ? template(value)({name}) : value)),
...mapValues(omit(branch, "name"), (value) => (isString(value) ? template(value)({ name }) : value)),
})),

@@ -19,2 +19,2 @@ ],

);
}
};

@@ -1,11 +0,10 @@

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`

@@ -15,3 +14,3 @@ // by replacing the `version` variable in the template by `(.+)`.

// 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(" ", "(.+)")}`;

@@ -22,7 +21,7 @@ return pReduce(

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;

@@ -33,7 +32,7 @@ },

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 }];
},
[]
);
}
};

@@ -1,13 +0,13 @@

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;

@@ -17,10 +17,10 @@ const remoteBranches = await expand(

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 });

@@ -32,10 +32,10 @@ const branches = await getTags(context, remoteBranches);

// 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 }));
}

@@ -47,6 +47,6 @@ });

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 };
}, {});

@@ -60,3 +60,3 @@

if (duplicates.length > 0) {
errors.push(getError('EDUPLICATEBRANCHES', {duplicates}));
errors.push(getError("EDUPLICATEBRANCHES", { duplicates }));
}

@@ -66,3 +66,3 @@

if (!(await verifyBranchName(branch.name))) {
errors.push(getError('EINVALIDBRANCHNAME', branch));
errors.push(getError("EINVALIDBRANCHNAME", branch));
}

@@ -76,2 +76,2 @@ });

return [...result.maintenance, ...result.release, ...result.prerelease];
}
};

@@ -1,8 +0,9 @@

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,

@@ -12,8 +13,8 @@ highest,

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,

@@ -24,4 +25,4 @@ name,

})),
'range'
).map(({name, range, tags, ...rest}, idx, branches) => {
"range"
).map(({ name, range, tags, ...rest }, idx, branches) => {
const versions = tagsToVersions(tags);

@@ -49,3 +50,3 @@ // Find the lower bound based on Maintenance branches

...rest,
type: 'maintenance',
type: "maintenance",
name,

@@ -60,3 +61,3 @@ tags,

export function release({release}) {
export function release({ release }) {
if (release.length === 0) {

@@ -69,3 +70,3 @@ return release;

return release.map(({name, tags, channel, ...rest}, idx) => {
return release.map(({ name, tags, channel, ...rest }, idx) => {
const versions = tagsToVersions(tags);

@@ -87,3 +88,3 @@ // The new lastVersion is the highest version between the current branch last release and the previous branch lastVersion

tags,
type: 'release',
type: "release",
name,

@@ -97,4 +98,4 @@ range: getRange(lastVersion, bound),

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;

@@ -104,3 +105,3 @@ return {

channel: isNil(channel) ? name : channel,
type: 'prerelease',
type: "prerelease",
name,

@@ -107,0 +108,0 @@ prerelease: preid,

@@ -1,16 +0,16 @@

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,
};

@@ -17,0 +17,0 @@

@@ -1,17 +0,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";

@@ -1,19 +0,19 @@

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.

@@ -29,9 +29,9 @@

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"
)}).`,

@@ -41,21 +41,21 @@ };

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).

@@ -67,7 +67,7 @@

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.

@@ -79,7 +79,7 @@

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.

@@ -91,7 +91,7 @@

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.

@@ -103,3 +103,3 @@

export function EPLUGIN({pluginName, type}) {
export function EPLUGIN({ pluginName, type }) {
return {

@@ -112,3 +112,3 @@ message: `A plugin configured in the step ${type} is not a valid semantic-release plugin.`,

Please refer to the \`${pluginName}\` and [semantic-release plugins configuration](${linkify(
'docs/usage/plugins.md'
"docs/usage/plugins.md"
)}) documentation for more details.`,

@@ -118,8 +118,8 @@ };

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(", ")}.

@@ -132,4 +132,4 @@ The \`analyzeCommits\` function of the \`${pluginName}\` returned \`${stringify(result)}\` instead.

- 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"
)})`,

@@ -139,5 +139,5 @@ };

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\`.

@@ -151,4 +151,4 @@

- 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"
)})`,

@@ -158,5 +158,5 @@ };

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\`.

@@ -170,4 +170,4 @@

- 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"
)})`,

@@ -177,5 +177,5 @@ };

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\`.

@@ -189,4 +189,4 @@

- 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"
)})`,

@@ -196,7 +196,7 @@ };

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.

@@ -208,7 +208,7 @@

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).

@@ -220,7 +220,7 @@

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.

@@ -232,7 +232,7 @@

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).

@@ -244,7 +244,7 @@

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.

@@ -256,7 +256,7 @@

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"
)}).

@@ -270,7 +270,7 @@

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.

@@ -282,7 +282,7 @@

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.

@@ -294,3 +294,3 @@

export function EINVALIDNEXTVERSION({nextRelease: {version}, branch: {name, range}, commits, validBranches}) {
export function EINVALIDNEXTVERSION({ nextRelease: { version }, branch: { name, range }, commits, validBranches }) {
return {

@@ -300,16 +300,16 @@ message: `The release \`${version}\` on branch \`${name}\` cannot be published as it is out of range.`,

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 {

@@ -321,4 +321,4 @@ message: `The release \`${version}\` on branch \`${name}\` cannot be published as it is out of range.`,

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.`,
};
}
/* 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";

@@ -13,10 +13,10 @@ export default {

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,

@@ -36,3 +36,3 @@ commits: commits.filter((commit) => !/\[skip\s+release]|\[release\s+skip]/i.test(commit.message)),

dryRun: true,
pipelineConfig: () => ({settleAll: true}),
pipelineConfig: () => ({ settleAll: true }),
},

@@ -44,11 +44,11 @@ generateNotes: {

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)),
},

@@ -58,5 +58,5 @@ prepare: {

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)

@@ -80,3 +80,3 @@ if (context.nextRelease.gitHead !== newGitHead) {

// Add `nextRelease` and plugin properties to published release
transform: (release, step, {nextRelease}) => ({
transform: (release, step, { nextRelease }) => ({
...(release === false ? {} : nextRelease),

@@ -94,3 +94,3 @@ ...release,

// Add `nextRelease` and plugin properties to published release
transform: (release, step, {nextRelease}) => ({
transform: (release, step, { nextRelease }) => ({
...(release === false ? {} : nextRelease),

@@ -105,4 +105,4 @@ ...release,

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) }),
},

@@ -112,5 +112,5 @@ fail: {

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) }),
},
};

@@ -33,3 +33,7 @@ import { isUndefined } from "lodash-es";

(tag) =>
((branch.type === "prerelease" && tag.channels.some((channel) => isSameChannel(branch.channel, channel))) ||
((branch.type === "prerelease" &&
tag.channels.some((channel) => isSameChannel(branch.channel, channel)) &&
semver
.parse(tag.version)
.prerelease.includes(branch.prerelease === true ? branch.name : branch.prerelease)) ||
!semver.prerelease(tag.version)) &&

@@ -36,0 +40,0 @@ (isUndefined(before) || semver.lt(tag.version, before))

@@ -1,11 +0,11 @@

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 = [];

@@ -23,4 +23,4 @@

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,

@@ -33,6 +33,6 @@ enumerable: true,

} else {
errors.push(getError('EPLUGINSCONF', {plugin}));
errors.push(getError("EPLUGINSCONF", { plugin }));
}
} else {
errors.push(getError('EPLUGINSCONF', {plugin}));
errors.push(getError("EPLUGINSCONF", { plugin }));
}

@@ -48,3 +48,3 @@

options = {...plugins, ...options};
options = { ...plugins, ...options };

@@ -54,3 +54,3 @@ const pluginsConfig = await Object.entries(PLUGINS_DEFINITIONS).reduce(

eventualPluginsConfigAccumulator,
[type, {required, default: def, pipelineConfig, postprocess = identity, preprocess = identity}]
[type, { required, default: def, pipelineConfig, postprocess = identity, preprocess = identity }]
) => {

@@ -70,4 +70,4 @@ let pluginOptions;

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;

@@ -82,3 +82,3 @@ }

normalize(
{...context, options: omit(options, Object.keys(PLUGINS_DEFINITIONS), 'plugins')},
{ ...context, options: omit(options, Object.keys(PLUGINS_DEFINITIONS), "plugins") },
type,

@@ -109,2 +109,2 @@ pluginOpt,

return pluginsConfig;
}
};

@@ -1,12 +0,12 @@

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) {

@@ -24,11 +24,11 @@ return noop;

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 {

@@ -38,3 +38,3 @@ if (!input.options.dryRun || dryRun) {

const result = await func({
...cloneDeep(omit(input, ['stdout', 'stderr', 'logger'])),
...cloneDeep(omit(input, ["stdout", "stderr", "logger"])),
stdout,

@@ -45,3 +45,3 @@ stderr,

if (outputValidator && !outputValidator(result)) {
throw getError(`E${type.toUpperCase()}OUTPUT`, {result, pluginName});
throw getError(`E${type.toUpperCase()}OUTPUT`, { result, pluginName });
}

@@ -56,3 +56,3 @@

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;

@@ -62,3 +62,3 @@ }

Reflect.defineProperty(validator, 'pluginName', {value: pluginName, writable: false, enumerable: true});
Reflect.defineProperty(validator, "pluginName", { value: pluginName, writable: false, enumerable: true });

@@ -74,2 +74,2 @@ if (!isFunction(pluginOpt)) {

return validator;
}
};

@@ -1,5 +0,5 @@

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";

@@ -28,32 +28,33 @@ /**

*/
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;
};

@@ -1,5 +0,5 @@

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";

@@ -41,3 +41,3 @@ const __dirname = dirname(fileURLToPath(import.meta.url));

export function validateStep({required}, conf) {
export function validateStep({ required }, conf) {
conf = castArray(conf).filter(Boolean);

@@ -51,3 +51,3 @@ if (required) {

export async function loadPlugin({cwd}, name, pluginsPath) {
export async function loadPlugin({ cwd }, name, pluginsPath) {
const basePath = pluginsPath[name]

@@ -77,3 +77,3 @@ ? dirname(resolveFrom.silent(__dirname, pluginsPath[name]) || resolveFrom(cwd, pluginsPath[name]))

} else if (isPlainObject(plugin) && !isNil(plugin.path)) {
({path, ...config} = plugin);
({ path, ...config } = plugin);
} else {

@@ -80,0 +80,0 @@ path = plugin;

{
"name": "semantic-release",
"description": "Automated semver compliant package publishing",
"version": "20.1.3",
"version": "21.0.7",
"type": "module",

@@ -29,11 +29,11 @@ "author": "Stephan Bönnemann <stephan@boennemann.me> (http://boennemann.me)",

"dependencies": {
"@semantic-release/commit-analyzer": "^9.0.2",
"@semantic-release/error": "^3.0.0",
"@semantic-release/github": "^8.0.0",
"@semantic-release/npm": "^9.0.0",
"@semantic-release/release-notes-generator": "^10.0.0",
"@semantic-release/commit-analyzer": "^10.0.0",
"@semantic-release/error": "^4.0.0",
"@semantic-release/github": "^9.0.0",
"@semantic-release/npm": "^10.0.2",
"@semantic-release/release-notes-generator": "^11.0.0",
"aggregate-error": "^4.0.1",
"cosmiconfig": "^8.0.0",
"debug": "^4.0.0",
"env-ci": "^8.0.0",
"env-ci": "^9.0.0",
"execa": "^7.0.0",

@@ -47,3 +47,3 @@ "figures": "^5.0.0",

"lodash-es": "^4.17.21",
"marked": "^4.1.0",
"marked": "^5.0.0",
"marked-terminal": "^5.1.1",

@@ -53,3 +53,3 @@ "micromatch": "^4.0.2",

"p-reduce": "^3.0.0",
"read-pkg-up": "^9.1.0",
"read-pkg-up": "^10.0.0",
"resolve-from": "^5.0.0",

@@ -62,20 +62,19 @@ "semver": "^7.3.2",

"devDependencies": {
"ava": "5.2.0",
"c8": "7.13.0",
"ava": "5.3.1",
"c8": "8.0.0",
"clear-module": "4.1.2",
"codecov": "3.8.3",
"delay": "5.0.0",
"dockerode": "3.3.5",
"file-url": "^4.0.0",
"fs-extra": "^11.0.0",
"got": "^12.5.0",
"file-url": "4.0.0",
"fs-extra": "11.1.1",
"got": "13.0.0",
"js-yaml": "4.1.0",
"mockserver-client": "5.15.0",
"nock": "13.3.0",
"p-retry": "^5.1.1",
"prettier": "^2.7.1",
"sinon": "15.0.2",
"nock": "13.3.1",
"p-retry": "5.1.2",
"prettier": "2.8.8",
"sinon": "15.2.0",
"stream-buffers": "3.0.2",
"tempy": "^3.0.0",
"testdouble": "3.17.0"
"tempy": "3.0.0",
"testdouble": "3.18.0"
},

@@ -124,3 +123,4 @@ "engines": {

"publishConfig": {
"access": "public"
"access": "public",
"provenance": true
},

@@ -133,4 +133,4 @@ "repository": {

"codecov": "codecov -f coverage/coverage-final.json",
"lint": "prettier --check \"*.{js,json,md}\" \".github/**/*.{md,yml}\" \"docs/**/*.md\" \"{bin,lib,test}/*.js\"",
"lint:fix": "prettier --write \"*.{js,json,md}\" \".github/**/*.{md,yml}\" \"docs/**/*.md\" \"{bin,lib,test}/*.js\"",
"lint": "prettier --check \"*.{js,json,md}\" \".github/**/*.{md,yml}\" \"docs/**/*.md\" \"{bin,lib,test}/**/*.js\"",
"lint:fix": "prettier --write \"*.{js,json,md}\" \".github/**/*.{md,yml}\" \"docs/**/*.md\" \"{bin,lib,test}/**/*.js\"",
"pretest": "npm run lint",

@@ -137,0 +137,0 @@ "semantic-release": "./bin/semantic-release.js",

@@ -10,2 +10,5 @@ <h1 align="center" style="border-bottom: none;">📦🚀 semantic-release</h1>

</a>
<a href="https://securityscorecards.dev/viewer/?uri=github.com/semantic-release/semantic-release">
<img alt="OpenSSF Scorecard" src="https://api.securityscorecards.dev/projects/github.com/semantic-release/semantic-release/badge">
</a>
<a href="#badge">

@@ -45,2 +48,3 @@ <img alt="semantic-release: angular" src="https://img.shields.io/badge/semantic--release-angular-e10079?logo=semantic-release">

- Simple and reusable configuration via [shareable configurations](docs/usage/shareable-configurations.md)
- Support for [npm package provenance](https://github.com/semantic-release/npm#npm-provenance) that promotes increased supply-chain security via signed attestations on GitHub Actions

@@ -47,0 +51,0 @@ ## How does it work?

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc