feat: Extract npm and github publish to plugins
- Add a new plugin type: `publish` - Add support for multi-plugin. A plugin module can now return an object with a property for each plugin type - Uses by default [npm](https://github.com/semantic-release/npm) and [github](https://github.com/semantic-release/github) in addition of Travis for the verify condition plugin - Uses by default [npm](https://github.com/semantic-release/npm) and [github](https://github.com/semantic-release/github) for the publish plugin - `gitTag` if one can be found is passed to `generateNotes` for both `lastRelease` and `nextRelease` - `semantic-release` now verifies the plugin configuration (in the `release` property of `package.json`) and throws an error if it's invalid - `semantic-release` now verifies each plugin output and will throw an error if a plugin returns an unexpected value. BREAKING CHANGE: `githubToken`, `githubUrl` and `githubApiPathPrefix` have to be set at the [github](https://github.com/semantic-release/github) plugin level. They can be set via `GH_TOKEN`, `GH_URL` and `GH_PREFIX` environment variables. BREAKING CHANGE: the `npm` parameter is not passed to any plugin anymore. Each plugin have to read `.npmrc` if they needs to (with https://github.com/kevva/npm-conf for example).
This commit is contained in:
+6
-8
@@ -1,10 +1,8 @@
|
||||
const execa = require('execa');
|
||||
const gitLogParser = require('git-log-parser');
|
||||
const getStream = require('get-stream');
|
||||
const debug = require('debug')('semantic-release:get-commits');
|
||||
const {unshallow} = require('./git');
|
||||
const getVersionHead = require('./get-version-head');
|
||||
const {debugShell} = require('./debug');
|
||||
const logger = require('./logger');
|
||||
|
||||
/**
|
||||
* Commit message.
|
||||
@@ -47,10 +45,11 @@ const logger = require('./logger');
|
||||
* @throws {SemanticReleaseError} with code `ENOTINHISTORY` if `lastRelease.gitHead` or the commit sha derived from `config.lastRelease.version` is not in the direct history of `branch`.
|
||||
* @throws {SemanticReleaseError} with code `ENOGITHEAD` if `lastRelease.gitHead` is undefined and no commit sha can be found for the `config.lastRelease.version`.
|
||||
*/
|
||||
module.exports = async ({version, gitHead}, branch) => {
|
||||
module.exports = async ({version, gitHead}, branch, logger) => {
|
||||
let gitTag;
|
||||
if (gitHead || version) {
|
||||
try {
|
||||
gitHead = await getVersionHead(gitHead, version, branch);
|
||||
({gitHead, gitTag} = await getVersionHead(gitHead, version, branch));
|
||||
} catch (err) {
|
||||
if (err.code === 'ENOTINHISTORY') {
|
||||
logger.error(notInHistoryMessage(err.gitHead, branch, version));
|
||||
@@ -63,8 +62,7 @@ module.exports = async ({version, gitHead}, branch) => {
|
||||
} else {
|
||||
logger.log('No previous release found, retrieving all commits');
|
||||
// If there is no gitHead nor a version, there is no previous release. Unshallow the repo in order to retrieve all commits
|
||||
const shell = await execa('git', ['fetch', '--unshallow', '--tags'], {reject: false});
|
||||
debugShell('Unshallow repo', shell, debug);
|
||||
await unshallow();
|
||||
}
|
||||
|
||||
Object.assign(gitLogParser.fields, {hash: 'H', message: 'B', gitTags: 'd', committerDate: {key: 'ci', type: Date}});
|
||||
@@ -77,7 +75,7 @@ module.exports = async ({version, gitHead}, branch) => {
|
||||
);
|
||||
logger.log('Found %s commits since last release', commits.length);
|
||||
debug('Parsed commits: %o', commits);
|
||||
return {commits, lastRelease: {version, gitHead}};
|
||||
return {commits, lastRelease: {version, gitHead, gitTag}};
|
||||
};
|
||||
|
||||
function noGitHeadMessage(branch, version) {
|
||||
|
||||
+5
-29
@@ -1,43 +1,19 @@
|
||||
const url = require('url');
|
||||
const {readJson} = require('fs-extra');
|
||||
const {defaults} = require('lodash');
|
||||
const npmConf = require('npm-conf');
|
||||
const normalizeData = require('normalize-package-data');
|
||||
const debug = require('debug')('semantic-release:config');
|
||||
const logger = require('./logger');
|
||||
const getPlugins = require('./plugins');
|
||||
const getRegistry = require('./get-registry');
|
||||
const plugins = require('./plugins');
|
||||
|
||||
module.exports = async opts => {
|
||||
module.exports = async (opts, logger) => {
|
||||
const pkg = await readJson('./package.json');
|
||||
const {GH_TOKEN, GITHUB_TOKEN, GH_URL} = process.env;
|
||||
normalizeData(pkg);
|
||||
const options = defaults(opts, pkg.release, {
|
||||
branch: 'master',
|
||||
fallbackTags: {next: 'latest'},
|
||||
githubToken: GH_TOKEN || GITHUB_TOKEN,
|
||||
githubUrl: GH_URL,
|
||||
});
|
||||
const options = defaults(opts, pkg.release, {branch: 'master'});
|
||||
debug('branch: %O', options.branch);
|
||||
debug('fallbackTags: %O', options.fallbackTags);
|
||||
debug('analyzeCommits: %O', options.analyzeCommits);
|
||||
debug('generateNotes: %O', options.generateNotes);
|
||||
debug('verifyConditions: %O', options.verifyConditions);
|
||||
debug('verifyRelease: %O', options.verifyRelease);
|
||||
debug('publish: %O', options.publish);
|
||||
|
||||
const plugins = await getPlugins(options);
|
||||
const conf = npmConf();
|
||||
const npm = {
|
||||
auth: {token: process.env.NPM_TOKEN},
|
||||
registry: getRegistry(pkg, conf),
|
||||
tag: (pkg.publishConfig || {}).tag || conf.get('tag'),
|
||||
conf,
|
||||
};
|
||||
|
||||
// normalize trailing slash
|
||||
npm.registry = url.format(url.parse(npm.registry));
|
||||
|
||||
debug('npm registry: %O', npm.registry);
|
||||
debug('npm tag: %O', npm.tag);
|
||||
return {env: process.env, pkg, options, plugins, npm, logger};
|
||||
return {env: process.env, pkg, options, plugins: await plugins(options, logger), logger};
|
||||
};
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
const semver = require('semver');
|
||||
const SemanticReleaseError = require('@semantic-release/error');
|
||||
const logger = require('./logger');
|
||||
|
||||
module.exports = (type, lastRelease) => {
|
||||
module.exports = (type, lastRelease, logger) => {
|
||||
let version;
|
||||
if (!lastRelease.version) {
|
||||
version = '1.0.0';
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
module.exports = ({publishConfig, name}, conf) => {
|
||||
if (publishConfig && publishConfig.registry) {
|
||||
return publishConfig.registry;
|
||||
}
|
||||
|
||||
if (name[0] !== '@') {
|
||||
return conf.get('registry') || 'https://registry.npmjs.org/';
|
||||
}
|
||||
|
||||
return conf.get(`${name.split('/')[0]}/registry`) || conf.get('registry') || 'https://registry.npmjs.org/';
|
||||
};
|
||||
+6
-40
@@ -1,38 +1,6 @@
|
||||
const execa = require('execa');
|
||||
const debug = require('debug')('semantic-release:get-version-head');
|
||||
const SemanticReleaseError = require('@semantic-release/error');
|
||||
const {debugShell} = require('./debug');
|
||||
|
||||
/**
|
||||
* Get the commit sha for a given tag.
|
||||
*
|
||||
* @param {string} tagName Tag name for which to retrieve the commit sha.
|
||||
*
|
||||
* @return {string} The commit sha of the tag in parameter or `null`.
|
||||
*/
|
||||
async function gitTagHead(tagName) {
|
||||
try {
|
||||
const shell = await execa('git', ['rev-list', '-1', '--tags', tagName]);
|
||||
debugShell('Get git tag head', shell, debug);
|
||||
return shell.stdout;
|
||||
} catch (err) {
|
||||
debug(err);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify if the commist `sha` is in the direct history of the current branch.
|
||||
*
|
||||
* @param {string} sha The sha of the commit to look for.
|
||||
*
|
||||
* @return {boolean} `true` if the commit `sha` is in the history of the current branch, `false` otherwise.
|
||||
*/
|
||||
async function isCommitInHistory(sha) {
|
||||
const shell = await execa('git', ['merge-base', '--is-ancestor', sha, 'HEAD'], {reject: false});
|
||||
debugShell('Check if commit is in history', shell, debug);
|
||||
return shell.code === 0;
|
||||
}
|
||||
const {gitTagHead, gitCommitTag, isCommitInHistory, unshallow} = require('./git');
|
||||
|
||||
/**
|
||||
* Get the commit sha for a given version, if it's contained in the given branch.
|
||||
@@ -40,7 +8,7 @@ async function isCommitInHistory(sha) {
|
||||
* @param {string} gitHead The commit sha to look for.
|
||||
* @param {string} version The version corresponding to the commit sha to look for. Used to search in git tags.
|
||||
*
|
||||
* @return {Promise<string>} A Promise that resolves to the commit sha of the version, either `gitHead` of the commit associated with the `version` tag.
|
||||
* @return {Promise<Object>} A Promise that resolves to an object with the `gitHead` and `gitTag` for the the `version`.
|
||||
*
|
||||
* @throws {SemanticReleaseError} with code `ENOTINHISTORY` if `gitHead` or the commit sha dereived from `version` is not in the direct history of `branch`.
|
||||
* @throws {SemanticReleaseError} with code `ENOGITHEAD` if `gitHead` is undefined and no commit sha can be found for the `version`.
|
||||
@@ -49,17 +17,15 @@ module.exports = async (gitHead, version) => {
|
||||
// Check if gitHead is defined and exists in release branch
|
||||
if (gitHead && (await isCommitInHistory(gitHead))) {
|
||||
debug('Use gitHead: %s', gitHead);
|
||||
return gitHead;
|
||||
return {gitHead, gitTag: await gitCommitTag(gitHead)};
|
||||
}
|
||||
|
||||
// Ushallow the repository
|
||||
const shell = await execa('git', ['fetch', '--unshallow', '--tags'], {reject: false});
|
||||
debugShell('Unshallow repo', shell, debug);
|
||||
await unshallow();
|
||||
|
||||
// Check if gitHead is defined and exists in release branch again
|
||||
if (gitHead && (await isCommitInHistory(gitHead))) {
|
||||
debug('Use gitHead: %s', gitHead);
|
||||
return gitHead;
|
||||
return {gitHead, gitTag: await gitCommitTag(gitHead)};
|
||||
}
|
||||
|
||||
let tagHead;
|
||||
@@ -70,7 +36,7 @@ module.exports = async (gitHead, version) => {
|
||||
// Check if tagHead is found and exists in release branch again
|
||||
if (tagHead && (await isCommitInHistory(tagHead))) {
|
||||
debug('Use tagHead: %s', tagHead);
|
||||
return tagHead;
|
||||
return {gitHead: tagHead, gitTag: await gitCommitTag(tagHead)};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
const execa = require('execa');
|
||||
const debug = require('debug')('semantic-release:get-version-head');
|
||||
const {debugShell} = require('./debug');
|
||||
|
||||
/**
|
||||
* Get the commit sha for a given tag.
|
||||
*
|
||||
* @param {string} tagName Tag name for which to retrieve the commit sha.
|
||||
*
|
||||
* @return {string} The commit sha of the tag in parameter or `null`.
|
||||
*/
|
||||
async function gitTagHead(tagName) {
|
||||
try {
|
||||
const shell = await execa('git', ['rev-list', '-1', tagName]);
|
||||
debugShell('Get git tag head', shell, debug);
|
||||
return shell.stdout;
|
||||
} catch (err) {
|
||||
debug(err);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the tag associated with a commit sha.
|
||||
*
|
||||
* @param {string} gitHead The commit sha for which to retrieve the associated tag.
|
||||
*
|
||||
* @return {string} The tag associatedwith the sha in parameter or `null`.
|
||||
*/
|
||||
async function gitCommitTag(gitHead) {
|
||||
try {
|
||||
const shell = await execa('git', ['describe', '--tags', '--exact-match', gitHead]);
|
||||
debugShell('Get git commit tag', shell, debug);
|
||||
return shell.stdout;
|
||||
} catch (err) {
|
||||
debug(err);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify if the commit `sha` is in the direct history of the current branch.
|
||||
*
|
||||
* @param {string} sha The sha of the commit to look for.
|
||||
*
|
||||
* @return {boolean} `true` if the commit `sha` is in the history of the current branch, `false` otherwise.
|
||||
*/
|
||||
async function isCommitInHistory(sha) {
|
||||
const shell = await execa('git', ['merge-base', '--is-ancestor', sha, 'HEAD'], {reject: false});
|
||||
debugShell('Check if commit is in history', shell, debug);
|
||||
return shell.code === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unshallow the git repository (retriving every commits and tags).
|
||||
*/
|
||||
async function unshallow() {
|
||||
await execa('git', ['fetch', '--unshallow', '--tags'], {reject: false});
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {string} the sha of the HEAD commit.
|
||||
*/
|
||||
async function gitHead() {
|
||||
try {
|
||||
const shell = await execa('git', ['rev-parse', 'HEAD']);
|
||||
debugShell('Get git head', shell, debug);
|
||||
return shell.stdout;
|
||||
} catch (err) {
|
||||
debug(err);
|
||||
throw new Error(err.stderr);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {gitTagHead, gitCommitTag, isCommitInHistory, unshallow, gitHead};
|
||||
@@ -1,36 +0,0 @@
|
||||
const {promisify} = require('util');
|
||||
const url = require('url');
|
||||
const gitHead = require('git-head');
|
||||
const GitHubApi = require('github');
|
||||
const parseSlug = require('parse-github-repo-url');
|
||||
const debug = require('debug')('semantic-release:github-release');
|
||||
|
||||
module.exports = async (pkg, notes, version, {branch, githubUrl, githubToken, githubApiPathPrefix}) => {
|
||||
const [owner, repo] = parseSlug(pkg.repository.url);
|
||||
let {port, protocol, hostname: host} = githubUrl ? url.parse(githubUrl) : {};
|
||||
protocol = (protocol || '').split(':')[0] || null;
|
||||
const pathPrefix = githubApiPathPrefix || null;
|
||||
const github = new GitHubApi({port, protocol, host, pathPrefix});
|
||||
debug('Github host: %o', host);
|
||||
debug('Github port: %o', port);
|
||||
debug('Github protocol: %o', protocol);
|
||||
debug('Github pathPrefix: %o', pathPrefix);
|
||||
|
||||
github.authenticate({type: 'token', token: githubToken});
|
||||
|
||||
const name = `v${version}`;
|
||||
const release = {owner, repo, tag_name: name, name, target_commitish: branch, body: notes};
|
||||
debug('release owner: %o', owner);
|
||||
debug('release repo: %o', repo);
|
||||
debug('release name: %o', name);
|
||||
debug('release branch: %o', branch);
|
||||
|
||||
const sha = await promisify(gitHead)();
|
||||
const ref = `refs/tags/${name}`;
|
||||
|
||||
debug('Create git tag %o with commit %o', ref, sha);
|
||||
await github.gitdata.createReference({owner, repo, ref, sha});
|
||||
const {data: {html_url: releaseUrl}} = await github.repos.createRelease(release);
|
||||
|
||||
return releaseUrl;
|
||||
};
|
||||
@@ -1,3 +0,0 @@
|
||||
module.exports = (config, options, cb) => {
|
||||
cb(null);
|
||||
};
|
||||
@@ -1,45 +0,0 @@
|
||||
const {promisify} = require('util');
|
||||
const relative = require('require-relative');
|
||||
const pSeries = require('p-series');
|
||||
const logger = require('./logger');
|
||||
|
||||
module.exports = options => {
|
||||
const plugins = {
|
||||
analyzeCommits: normalize(options.analyzeCommits, '@semantic-release/commit-analyzer'),
|
||||
generateNotes: normalize(options.generateNotes, '@semantic-release/release-notes-generator'),
|
||||
getLastRelease: normalize(options.getLastRelease, '@semantic-release/last-release-npm'),
|
||||
};
|
||||
['verifyConditions', 'verifyRelease'].forEach(plugin => {
|
||||
if (!Array.isArray(options[plugin])) {
|
||||
plugins[plugin] = normalize(
|
||||
options[plugin],
|
||||
plugin === 'verifyConditions' ? '@semantic-release/condition-travis' : './plugin-noop'
|
||||
);
|
||||
} else {
|
||||
plugins[plugin] = async pluginOptions => {
|
||||
return pSeries(
|
||||
options[plugin].map(step => {
|
||||
return () => normalize(step, './plugin-noop')(pluginOptions);
|
||||
})
|
||||
);
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
return plugins;
|
||||
};
|
||||
|
||||
const normalize = (pluginConfig, fallback) => {
|
||||
if (typeof pluginConfig === 'string') {
|
||||
logger.log('Load plugin %s', pluginConfig);
|
||||
return promisify(relative(pluginConfig).bind(null, {}));
|
||||
}
|
||||
|
||||
if (pluginConfig && typeof pluginConfig.path === 'string') {
|
||||
logger.log('Load plugin %s', pluginConfig.path);
|
||||
return promisify(relative(pluginConfig.path).bind(null, pluginConfig));
|
||||
}
|
||||
return promisify(require(fallback).bind(null, pluginConfig || {}));
|
||||
};
|
||||
|
||||
module.exports.normalize = normalize;
|
||||
@@ -0,0 +1,78 @@
|
||||
const {isString, isObject, isFunction, isArray} = require('lodash');
|
||||
const semver = require('semver');
|
||||
const conditionTravis = require('@semantic-release/condition-travis');
|
||||
const commitAnalyzer = require('@semantic-release/commit-analyzer');
|
||||
const releaseNotesGenerator = require('@semantic-release/release-notes-generator');
|
||||
const npm = require('@semantic-release/npm');
|
||||
const github = require('@semantic-release/github');
|
||||
|
||||
const RELEASE_TYPE = ['major', 'premajor', 'minor', 'preminor', 'patch', 'prepatch', 'prerelease'];
|
||||
|
||||
module.exports = {
|
||||
verifyConditions: {
|
||||
default: [npm.verifyConditions, github.verifyConditions, conditionTravis],
|
||||
config: {
|
||||
validator: conf => !conf || (isArray(conf) ? conf : [conf]).every(conf => validatePluginConfig(conf)),
|
||||
message:
|
||||
'The "verifyConditions" plugin, if defined, must be a single or an array of plugins definition. A plugin definition is either a string or an object with a path property.',
|
||||
},
|
||||
},
|
||||
getLastRelease: {
|
||||
default: npm.getLastRelease,
|
||||
config: {
|
||||
validator: conf => Boolean(conf) && validatePluginConfig(conf),
|
||||
message:
|
||||
'The "getLastRelease" plugin is mandatory, and must be a single plugin definition. A plugin definition is either a string or an object with a path property.',
|
||||
},
|
||||
output: {
|
||||
validator: output =>
|
||||
!output ||
|
||||
(isObject(output) && !output.version) ||
|
||||
(isString(output.version) && Boolean(semver.valid(semver.clean(output.version)))),
|
||||
message:
|
||||
'The "getLastRelease" plugin output if defined, must be an object with an optionnal valid semver version in the "version" property.',
|
||||
},
|
||||
},
|
||||
analyzeCommits: {
|
||||
default: commitAnalyzer,
|
||||
config: {
|
||||
validator: conf => Boolean(conf) && validatePluginConfig(conf),
|
||||
message:
|
||||
'The "analyzeCommits" plugin is mandatory, and must be a single plugin definition. A plugin definition is either a string or an object with a path property.',
|
||||
},
|
||||
output: {
|
||||
validator: output => !output || RELEASE_TYPE.includes(output),
|
||||
message: 'The "analyzeCommits" plugin output must be either undefined or a valid semver release type.',
|
||||
},
|
||||
},
|
||||
verifyRelease: {
|
||||
default: false,
|
||||
config: {
|
||||
validator: conf => !conf || (isArray(conf) ? conf : [conf]).every(conf => validatePluginConfig(conf)),
|
||||
message:
|
||||
'The "verifyRelease" plugin, if defined, must be a single or an array of plugins definition. A plugin definition is either a string or an object with a path property.',
|
||||
},
|
||||
},
|
||||
generateNotes: {
|
||||
default: releaseNotesGenerator,
|
||||
config: {
|
||||
validator: conf => !conf || validatePluginConfig(conf),
|
||||
message:
|
||||
'The "generateNotes" plugin, if defined, must be a single plugin definition. A plugin definition is either a string or an object with a path property.',
|
||||
},
|
||||
output: {
|
||||
validator: output => isString(output),
|
||||
message: 'The "generateNotes" plugin output must be a string.',
|
||||
},
|
||||
},
|
||||
publish: {
|
||||
default: [npm.publish, github.publish],
|
||||
config: {
|
||||
validator: conf => Boolean(conf) && (isArray(conf) ? conf : [conf]).every(conf => validatePluginConfig(conf)),
|
||||
message:
|
||||
'The "publish" plugin is mandatory, and must be a single or an array of plugins definition. A plugin definition is either a string or an object with a path property.',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const validatePluginConfig = conf => isString(conf) || isString(conf.path) || isFunction(conf);
|
||||
@@ -0,0 +1,24 @@
|
||||
const {isArray} = require('lodash');
|
||||
const DEFINITIONS = require('./definitions');
|
||||
const pipeline = require('./pipeline');
|
||||
const normalize = require('./normalize');
|
||||
|
||||
module.exports = (options, logger) =>
|
||||
Object.keys(DEFINITIONS).reduce((plugins, pluginType) => {
|
||||
const {config, output, default: def} = DEFINITIONS[pluginType];
|
||||
let pluginConfs;
|
||||
if (options[pluginType]) {
|
||||
if (config && !config.validator(options[pluginType])) {
|
||||
throw new Error(config.message);
|
||||
}
|
||||
pluginConfs = options[pluginType];
|
||||
} else {
|
||||
pluginConfs = def;
|
||||
}
|
||||
|
||||
plugins[pluginType] = isArray(pluginConfs)
|
||||
? pipeline(pluginConfs.map(conf => normalize(pluginType, conf, logger, output)))
|
||||
: normalize(pluginType, pluginConfs, logger, output);
|
||||
|
||||
return plugins;
|
||||
}, {});
|
||||
@@ -0,0 +1,34 @@
|
||||
const {promisify, inspect} = require('util');
|
||||
const {isString, isObject, isFunction, noop, cloneDeep} = require('lodash');
|
||||
const importFrom = require('import-from');
|
||||
|
||||
module.exports = (pluginType, pluginConfig, logger, validator) => {
|
||||
if (!pluginConfig) {
|
||||
return noop;
|
||||
}
|
||||
const {path, ...config} = isString(pluginConfig) || isFunction(pluginConfig) ? {path: pluginConfig} : pluginConfig;
|
||||
if (!isFunction(pluginConfig)) {
|
||||
logger.log('Load plugin %s', path);
|
||||
}
|
||||
const plugin = isFunction(path) ? path : importFrom.silent(__dirname, path) || importFrom(process.cwd(), path);
|
||||
|
||||
let func;
|
||||
if (isFunction(plugin)) {
|
||||
func = promisify(plugin.bind(null, cloneDeep(config)));
|
||||
} else if (isObject(plugin) && plugin[pluginType] && isFunction(plugin[pluginType])) {
|
||||
func = promisify(plugin[pluginType].bind(null, cloneDeep(config)));
|
||||
} else {
|
||||
throw new Error(
|
||||
`The ${pluginType} plugin must be a function, or an object with a function in the property ${pluginType}.`
|
||||
);
|
||||
}
|
||||
|
||||
return async input => {
|
||||
const result = await func(cloneDeep(input));
|
||||
|
||||
if (validator && !validator.validator(result)) {
|
||||
throw new Error(`${validator.message}. Received: ${inspect(result)}`);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
const {identity} = require('lodash');
|
||||
const pReduce = require('p-reduce');
|
||||
|
||||
module.exports = steps => async (input, getNextInput = identity) => {
|
||||
const results = [];
|
||||
await pReduce(
|
||||
steps,
|
||||
async (prevResult, nextStep) => {
|
||||
// Call the next step with the input computed at the end of the previous iteration
|
||||
const result = await nextStep(prevResult);
|
||||
// Save intermediary result
|
||||
results.push(result);
|
||||
// Prepare input for next step, passing the result of the previous iteration and the current one
|
||||
return getNextInput(prevResult, result);
|
||||
},
|
||||
input
|
||||
);
|
||||
return results;
|
||||
};
|
||||
@@ -1,35 +0,0 @@
|
||||
const {appendFile, readJson, writeJson, pathExists} = require('fs-extra');
|
||||
const execa = require('execa');
|
||||
const nerfDart = require('nerf-dart');
|
||||
const debug = require('debug')('semantic-release:publish-npm');
|
||||
const {debugShell} = require('./debug');
|
||||
const logger = require('./logger');
|
||||
|
||||
module.exports = async (pkg, {conf, registry, auth}, {version}) => {
|
||||
const pkgFile = await readJson('./package.json');
|
||||
|
||||
if (await pathExists('./npm-shrinkwrap.json')) {
|
||||
const shrinkwrap = await readJson('./npm-shrinkwrap.json');
|
||||
shrinkwrap.version = version;
|
||||
await writeJson('./npm-shrinkwrap.json', shrinkwrap);
|
||||
logger.log('Wrote version %s to npm-shrinkwrap.json', version);
|
||||
}
|
||||
|
||||
await writeJson('./package.json', Object.assign(pkgFile, {version}));
|
||||
logger.log('Wrote version %s to package.json', version);
|
||||
|
||||
if (process.env.NPM_OLD_TOKEN && process.env.NPM_EMAIL) {
|
||||
// Using the old auth token format is not considered part of the public API
|
||||
// This might go away anytime (i.e. once we have a better testing strategy)
|
||||
await appendFile('./.npmrc', `_auth = \${NPM_OLD_TOKEN}\nemail = \${NPM_EMAIL}`);
|
||||
logger.log('Wrote NPM_OLD_TOKEN and NPM_EMAIL to .npmrc.');
|
||||
} else {
|
||||
await appendFile('./.npmrc', `${nerfDart(registry)}:_authToken = \${NPM_TOKEN}`);
|
||||
logger.log('Wrote NPM_TOKEN to .npmrc.');
|
||||
}
|
||||
|
||||
logger.log('Publishing version %s to npm registry %s', version, registry);
|
||||
const shell = await execa('npm', ['publish']);
|
||||
console.log(shell.stdout);
|
||||
debugShell('Publishing on npm', shell, debug);
|
||||
};
|
||||
@@ -1,11 +0,0 @@
|
||||
const SemanticReleaseError = require('@semantic-release/error');
|
||||
|
||||
module.exports = (options, env) => {
|
||||
if (!options.githubToken) {
|
||||
throw new SemanticReleaseError('No github token specified.', 'ENOGHTOKEN');
|
||||
}
|
||||
|
||||
if (!(env.NPM_TOKEN || (env.NPM_OLD_TOKEN && env.NPM_EMAIL))) {
|
||||
throw new SemanticReleaseError('No npm token specified.', 'ENONPMTOKEN');
|
||||
}
|
||||
};
|
||||
@@ -1,11 +0,0 @@
|
||||
const SemanticReleaseError = require('@semantic-release/error');
|
||||
|
||||
module.exports = pkg => {
|
||||
if (!pkg.name) {
|
||||
throw new SemanticReleaseError('No "name" found in package.json.', 'ENOPKGNAME');
|
||||
}
|
||||
|
||||
if (!pkg.repository || !pkg.repository.url) {
|
||||
throw new SemanticReleaseError('No "repository" found in package.json.', 'ENOPKGREPO');
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user