refactor: Use ES6, Test with AVA
- Use async/await instead of callbacks - Use execa to run command line - Use AVA for tests - Add several assertions in the unit tests - Add documentation (comments) in the tests - Run tests with a real git repo instead of mocking child_process and add test helpers to create repos, commits and checkout - Simplify test directory structure - Simplify code readability (mostly with async/await) - Use eslint for for linting, prettier for formatting
This commit is contained in:
committed by
Pierre Vanduynslager
parent
7fe0890350
commit
abf92ad03d
+124
-134
@@ -1,163 +1,153 @@
|
||||
var fs = require('fs')
|
||||
var path = require('path')
|
||||
var url = require('url')
|
||||
const path = require('path');
|
||||
const {promisify} = require('util');
|
||||
const url = require('url');
|
||||
const {readJson, writeJson} = require('fs-extra');
|
||||
const {cloneDeep, defaults, mapKeys, camelCase, assign} = require('lodash');
|
||||
const log = require('npmlog');
|
||||
const nopt = require('nopt');
|
||||
const npmconf = require('npmconf');
|
||||
const normalizeData = require('normalize-package-data');
|
||||
|
||||
var _ = require('lodash')
|
||||
var log = require('npmlog')
|
||||
var nopt = require('nopt')
|
||||
var npmconf = require('npmconf')
|
||||
var normalizeData = require('normalize-package-data')
|
||||
|
||||
log.heading = 'semantic-release'
|
||||
var env = process.env
|
||||
var pkg = JSON.parse(fs.readFileSync('./package.json'))
|
||||
var originalPkg = _.cloneDeep(pkg)
|
||||
normalizeData(pkg)
|
||||
var knownOptions = {
|
||||
branch: String,
|
||||
debug: Boolean,
|
||||
'github-token': String,
|
||||
'github-url': String,
|
||||
'analyze-commits': [path, String],
|
||||
'generate-notes': [path, String],
|
||||
'verify-conditions': [path, String],
|
||||
'verify-release': [path, String]
|
||||
}
|
||||
var options = _.defaults(
|
||||
_.mapKeys(nopt(knownOptions), function (value, key) {
|
||||
return _.camelCase(key)
|
||||
}),
|
||||
pkg.release,
|
||||
{
|
||||
branch: 'master',
|
||||
fallbackTags: {
|
||||
next: 'latest'
|
||||
},
|
||||
debug: !env.CI,
|
||||
githubToken: env.GH_TOKEN || env.GITHUB_TOKEN,
|
||||
githubUrl: env.GH_URL
|
||||
}
|
||||
)
|
||||
var plugins = require('../src/lib/plugins')(options)
|
||||
|
||||
npmconf.load({}, function (err, conf) {
|
||||
if (err) {
|
||||
log.error('init', 'Failed to load npm config.', err)
|
||||
process.exit(1)
|
||||
module.exports = async () => {
|
||||
log.heading = 'semantic-release';
|
||||
const env = process.env;
|
||||
const pkg = await readJson('./package.json');
|
||||
const originalPkg = cloneDeep(pkg);
|
||||
normalizeData(pkg);
|
||||
const knownOptions = {
|
||||
branch: String,
|
||||
debug: Boolean,
|
||||
'github-token': String,
|
||||
'github-url': String,
|
||||
'analyze-commits': [path, String],
|
||||
'generate-notes': [path, String],
|
||||
'verify-conditions': [path, String],
|
||||
'verify-release': [path, String],
|
||||
};
|
||||
const options = defaults(
|
||||
mapKeys(nopt(knownOptions), (value, key) => {
|
||||
return camelCase(key);
|
||||
}),
|
||||
pkg.release,
|
||||
{
|
||||
branch: 'master',
|
||||
fallbackTags: {next: 'latest'},
|
||||
debug: !env.CI,
|
||||
githubToken: env.GH_TOKEN || env.GITHUB_TOKEN,
|
||||
githubUrl: env.GH_URL,
|
||||
}
|
||||
);
|
||||
const plugins = require('../src/lib/plugins')(options);
|
||||
let conf;
|
||||
try {
|
||||
conf = await promisify(npmconf.load)({});
|
||||
} catch (err) {
|
||||
log.error('init', 'Failed to load npm config.', err);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
var npm = {
|
||||
auth: {
|
||||
token: env.NPM_TOKEN
|
||||
},
|
||||
const npm = {
|
||||
auth: {token: env.NPM_TOKEN},
|
||||
cafile: conf.get('cafile'),
|
||||
loglevel: conf.get('loglevel'),
|
||||
registry: require('../src/lib/get-registry')(pkg, conf),
|
||||
tag: (pkg.publishConfig || {}).tag || conf.get('tag') || 'latest'
|
||||
}
|
||||
tag: (pkg.publishConfig || {}).tag || conf.get('tag') || 'latest',
|
||||
};
|
||||
|
||||
// normalize trailing slash
|
||||
npm.registry = url.format(url.parse(npm.registry))
|
||||
npm.registry = url.format(url.parse(npm.registry));
|
||||
log.level = npm.loglevel;
|
||||
|
||||
log.level = npm.loglevel
|
||||
const config = {env: env, pkg: pkg, options: options, plugins: plugins, npm: npm};
|
||||
const hide = {};
|
||||
if (options.githubToken) hide.githubToken = '***';
|
||||
|
||||
var config = {
|
||||
env: env,
|
||||
pkg: pkg,
|
||||
options: options,
|
||||
plugins: plugins,
|
||||
npm: npm
|
||||
}
|
||||
log.verbose('init', 'options:', assign({}, options, hide));
|
||||
log.verbose('init', 'Verifying config.');
|
||||
|
||||
var hide = {}
|
||||
if (options.githubToken) hide.githubToken = '***'
|
||||
|
||||
log.verbose('init', 'options:', _.assign({}, options, hide))
|
||||
log.verbose('init', 'Verifying config.')
|
||||
|
||||
var errors = require('../src/lib/verify')(config)
|
||||
errors.forEach(function (err) {
|
||||
log.error('init', err.message + ' ' + err.code)
|
||||
})
|
||||
if (errors.length) process.exit(1)
|
||||
const errors = require('../src/lib/verify')(config);
|
||||
errors.forEach(err => {
|
||||
log.error('init', err.message + ' ' + err.code);
|
||||
});
|
||||
if (errors.length) process.exit(1);
|
||||
|
||||
if (options.argv.remain[0] === 'pre') {
|
||||
log.verbose('pre', 'Running pre-script.')
|
||||
log.verbose('pre', 'Veriying conditions.')
|
||||
log.verbose('pre', 'Running pre-script.');
|
||||
log.verbose('pre', 'Veriying conditions.');
|
||||
try {
|
||||
await promisify(plugins.verifyConditions)(config);
|
||||
} catch (err) {
|
||||
log[options.debug ? 'warn' : 'error']('pre', err.message);
|
||||
if (!options.debug) process.exit(1);
|
||||
}
|
||||
|
||||
plugins.verifyConditions(config, function (err) {
|
||||
if (err) {
|
||||
log[options.debug ? 'warn' : 'error']('pre', err.message)
|
||||
if (!options.debug) process.exit(1)
|
||||
}
|
||||
const nerfDart = require('nerf-dart')(npm.registry);
|
||||
let wroteNpmRc = false;
|
||||
|
||||
var nerfDart = require('nerf-dart')(npm.registry)
|
||||
var wroteNpmRc = false
|
||||
if (env.NPM_OLD_TOKEN && 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)
|
||||
conf.set('_auth', '${NPM_OLD_TOKEN}', 'project'); // eslint-disable-line no-template-curly-in-string
|
||||
conf.set('email', '${NPM_EMAIL}', 'project'); // eslint-disable-line no-template-curly-in-string
|
||||
wroteNpmRc = true;
|
||||
} else if (env.NPM_TOKEN) {
|
||||
conf.set(nerfDart + ':_authToken', '${NPM_TOKEN}', 'project'); // eslint-disable-line no-template-curly-in-string
|
||||
wroteNpmRc = true;
|
||||
}
|
||||
|
||||
if (env.NPM_OLD_TOKEN && 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)
|
||||
conf.set('_auth', '${NPM_OLD_TOKEN}', 'project') // eslint-disable-line no-template-curly-in-string
|
||||
conf.set('email', '${NPM_EMAIL}', 'project') // eslint-disable-line no-template-curly-in-string
|
||||
wroteNpmRc = true
|
||||
} else if (env.NPM_TOKEN) {
|
||||
conf.set(nerfDart + ':_authToken', '${NPM_TOKEN}', 'project') // eslint-disable-line no-template-curly-in-string
|
||||
wroteNpmRc = true
|
||||
}
|
||||
try {
|
||||
await promisify(conf.save.bind(conf))('project');
|
||||
} catch (err) {
|
||||
return log.error('pre', 'Failed to save npm config.', err);
|
||||
}
|
||||
|
||||
conf.save('project', function (err) {
|
||||
if (err) return log.error('pre', 'Failed to save npm config.', err)
|
||||
if (wroteNpmRc) log.verbose('pre', 'Wrote authToken to .npmrc.');
|
||||
|
||||
if (wroteNpmRc) log.verbose('pre', 'Wrote authToken to .npmrc.')
|
||||
let release;
|
||||
try {
|
||||
release = await require('../src/pre')(config);
|
||||
} catch (err) {
|
||||
log.error('pre', 'Failed to determine new version.');
|
||||
|
||||
require('../src/pre')(config, function (err, release) {
|
||||
if (err) {
|
||||
log.error('pre', 'Failed to determine new version.')
|
||||
const args = ['pre', (err.code ? err.code + ' ' : '') + err.message];
|
||||
if (err.stack) args.push(err.stack);
|
||||
log.error.apply(log, args);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
var args = ['pre', (err.code ? err.code + ' ' : '') + err.message]
|
||||
if (err.stack) args.push(err.stack)
|
||||
log.error.apply(log, args)
|
||||
process.exit(1)
|
||||
}
|
||||
const message = 'Determined version ' + release.version + ' as "' + npm.tag + '".';
|
||||
|
||||
var message = 'Determined version ' + release.version + ' as "' + npm.tag + '".'
|
||||
log.verbose('pre', message);
|
||||
|
||||
log.verbose('pre', message)
|
||||
if (options.debug) {
|
||||
log.error('pre', message + ' Not publishing in debug mode.', release);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (options.debug) {
|
||||
log.error('pre', message + ' Not publishing in debug mode.', release)
|
||||
process.exit(1)
|
||||
}
|
||||
try {
|
||||
const shrinkwrap = await readJson('./npm-shrinkwrap.json');
|
||||
shrinkwrap.version = release.version;
|
||||
await writeJson('./npm-shrinkwrap.json', shrinkwrap);
|
||||
log.verbose('pre', 'Wrote version ' + release.version + 'to npm-shrinkwrap.json.');
|
||||
} catch (e) {
|
||||
log.silly('pre', "Couldn't find npm-shrinkwrap.json.");
|
||||
}
|
||||
|
||||
try {
|
||||
var shrinkwrap = JSON.parse(fs.readFileSync('./npm-shrinkwrap.json'))
|
||||
shrinkwrap.version = release.version
|
||||
fs.writeFileSync('./npm-shrinkwrap.json', JSON.stringify(shrinkwrap, null, 2))
|
||||
log.verbose('pre', 'Wrote version ' + release.version + 'to npm-shrinkwrap.json.')
|
||||
} catch (e) {
|
||||
log.silly('pre', 'Couldn\'t find npm-shrinkwrap.json.')
|
||||
}
|
||||
await writeJson('./package.json', assign(originalPkg, {version: release.version}));
|
||||
|
||||
fs.writeFileSync('./package.json', JSON.stringify(_.assign(originalPkg, {
|
||||
version: release.version
|
||||
}), null, 2))
|
||||
|
||||
log.verbose('pre', 'Wrote version ' + release.version + ' to package.json.')
|
||||
})
|
||||
})
|
||||
})
|
||||
log.verbose('pre', 'Wrote version ' + release.version + ' to package.json.');
|
||||
} else if (options.argv.remain[0] === 'post') {
|
||||
log.verbose('post', 'Running post-script.')
|
||||
log.verbose('post', 'Running post-script.');
|
||||
|
||||
require('../src/post')(config, function (err, published, release) {
|
||||
if (err) {
|
||||
log.error('post', 'Failed to publish release notes.', err)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
log.verbose('post', (published ? 'Published' : 'Generated') + ' release notes.', release)
|
||||
})
|
||||
let published, release;
|
||||
try {
|
||||
({published, release} = await require('../src/post')(config));
|
||||
log.verbose('post', (published ? 'Published' : 'Generated') + ' release notes.', release);
|
||||
} catch (err) {
|
||||
log.error('post', 'Failed to publish release notes.', err);
|
||||
process.exit(1);
|
||||
}
|
||||
} else {
|
||||
log.error('post', 'Command "' + options.argv.remain[0] + '" not recognized. Use either "pre" or "post"')
|
||||
log.error('post', 'Command "' + options.argv.remain[0] + '" not recognized. Use either "pre" or "post"');
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
var childProcess = require('child_process')
|
||||
|
||||
var log = require('npmlog')
|
||||
|
||||
var SemanticReleaseError = require('@semantic-release/error')
|
||||
|
||||
module.exports = function (config, cb) {
|
||||
var lastRelease = config.lastRelease
|
||||
var options = config.options
|
||||
var branch = options.branch
|
||||
var from = lastRelease.gitHead
|
||||
var range = (from ? from + '..' : '') + 'HEAD'
|
||||
|
||||
if (!from) return extract()
|
||||
|
||||
childProcess.exec('git branch --no-color --contains ' + from, function (err, stdout) {
|
||||
var inHistory = false
|
||||
var branches
|
||||
|
||||
if (!err && stdout) {
|
||||
branches = stdout.split('\n')
|
||||
.map(function (result) {
|
||||
if (branch === result.replace('*', '').trim()) {
|
||||
inHistory = true
|
||||
return null
|
||||
}
|
||||
return result.trim()
|
||||
})
|
||||
.filter(function (branch) {
|
||||
return !!branch
|
||||
})
|
||||
}
|
||||
|
||||
if (!inHistory) {
|
||||
log.error('commits',
|
||||
'The commit the last release of this package was derived from is not in the direct history of the "' + branch + '" branch.\n' +
|
||||
'This means semantic-release can not extract the commits between now and then.\n' +
|
||||
'This is usually caused by force pushing, releasing from an unrelated branch, or using an already existing package name.\n' +
|
||||
'You can recover from this error by publishing manually or restoring the commit "' + from + '".' + (branches && branches.length
|
||||
? '\nHere is a list of branches that still contain the commit in question: \n * ' + branches.join('\n * ')
|
||||
: ''
|
||||
))
|
||||
return cb(new SemanticReleaseError('Commit not in history', 'ENOTINHISTORY'))
|
||||
}
|
||||
|
||||
extract()
|
||||
})
|
||||
|
||||
function extract () {
|
||||
var child = childProcess.spawn('git', ['log', '-E', '--format=%H==SPLIT==%B==END==', range])
|
||||
var stdout = ''
|
||||
var err = ''
|
||||
|
||||
child.stdout.on('data', function (data) {
|
||||
stdout += data
|
||||
})
|
||||
|
||||
child.stderr.on('data', function (data) {
|
||||
err += data
|
||||
})
|
||||
|
||||
child.on('close', function (code) {
|
||||
if (err || code) return cb(err)
|
||||
|
||||
cb(null, String(stdout).split('==END==\n')
|
||||
.filter(function (raw) {
|
||||
return !!raw.trim()
|
||||
})
|
||||
.map(function (raw) {
|
||||
var data = raw.split('==SPLIT==')
|
||||
return {
|
||||
hash: data[0],
|
||||
message: data[1]
|
||||
}
|
||||
})
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
const execa = require('execa');
|
||||
const log = require('npmlog');
|
||||
const SemanticReleaseError = require('@semantic-release/error');
|
||||
|
||||
module.exports = async ({lastRelease, options}) => {
|
||||
let stdout;
|
||||
if (lastRelease.gitHead) {
|
||||
try {
|
||||
({stdout} = await execa('git', ['branch', '--no-color', '--contains', lastRelease.gitHead]));
|
||||
} catch (err) {
|
||||
throw notInHistoryError(lastRelease.gitHead, options.branch);
|
||||
}
|
||||
const branches = stdout
|
||||
.split('\n')
|
||||
.map(branch => branch.replace('*', '').trim())
|
||||
.filter(branch => !!branch);
|
||||
|
||||
if (!branches.includes(options.branch)) {
|
||||
throw notInHistoryError(lastRelease.gitHead, options.branch, branches);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
({stdout} = await execa('git', [
|
||||
'log',
|
||||
'--format=%H==SPLIT==%B==END==',
|
||||
`${lastRelease.gitHead ? lastRelease.gitHead + '..' : ''}HEAD`,
|
||||
]));
|
||||
} catch (err) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return String(stdout)
|
||||
.split('==END==')
|
||||
.filter(raw => !!raw.trim())
|
||||
.map(raw => {
|
||||
const [hash, message] = raw.trim().split('==SPLIT==');
|
||||
return {hash, message};
|
||||
});
|
||||
};
|
||||
|
||||
function notInHistoryError(gitHead, branch, branches) {
|
||||
log.error(
|
||||
'commits',
|
||||
`
|
||||
The commit the last release of this package was derived from is not in the direct history of the "${branch}" branch.
|
||||
This means semantic-release can not extract the commits between now and then.
|
||||
This is usually caused by force pushing, releasing from an unrelated branch, or using an already existing package name.
|
||||
You can recover from this error by publishing manually or restoring the commit "${gitHead}".
|
||||
${branches && branches.length
|
||||
? `\nHere is a list of branches that still contain the commit in question: \n * ${branches.join('\n * ')}`
|
||||
: ''}
|
||||
`
|
||||
);
|
||||
return new SemanticReleaseError('Commit not in history', 'ENOTINHISTORY');
|
||||
}
|
||||
+9
-10
@@ -1,12 +1,11 @@
|
||||
module.exports = function (pkg, conf) {
|
||||
if (pkg.publishConfig && pkg.publishConfig.registry) return pkg.publishConfig.registry
|
||||
module.exports = ({publishConfig, name}, conf) => {
|
||||
if (publishConfig && publishConfig.registry) {
|
||||
return publishConfig.registry;
|
||||
}
|
||||
|
||||
if (pkg.name[0] !== '@') return conf.get('registry') || 'https://registry.npmjs.org/'
|
||||
if (name[0] !== '@') {
|
||||
return conf.get('registry') || 'https://registry.npmjs.org/';
|
||||
}
|
||||
|
||||
var scope = pkg.name.split('/')[0]
|
||||
var scopedRegistry = conf.get(scope + '/registry')
|
||||
|
||||
if (scopedRegistry) return scopedRegistry
|
||||
|
||||
return conf.get('registry') || 'https://registry.npmjs.org/'
|
||||
}
|
||||
return conf.get(`${name.split('/')[0]}/registry`) || conf.get('registry') || 'https://registry.npmjs.org/';
|
||||
};
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
const {promisify} = require('util');
|
||||
const SemanticReleaseError = require('@semantic-release/error');
|
||||
|
||||
module.exports = async config => {
|
||||
const {plugins, lastRelease} = config;
|
||||
const type = await promisify(plugins.analyzeCommits)(config);
|
||||
|
||||
if (!type) {
|
||||
throw new SemanticReleaseError('There are no relevant changes, so no new version is released.', 'ENOCHANGE');
|
||||
}
|
||||
if (!lastRelease.version) return 'initial';
|
||||
|
||||
return type;
|
||||
};
|
||||
@@ -1,4 +1,3 @@
|
||||
/* istanbul ignore next */
|
||||
module.exports = function (config, options, cb) {
|
||||
cb(null)
|
||||
}
|
||||
module.exports = (config, options, cb) => {
|
||||
cb(null);
|
||||
};
|
||||
|
||||
+32
-32
@@ -1,42 +1,42 @@
|
||||
var relative = require('require-relative')
|
||||
var series = require('run-series')
|
||||
const {promisify} = require('util');
|
||||
const relative = require('require-relative');
|
||||
const pSeries = require('p-series');
|
||||
|
||||
var exports = module.exports = function (options) {
|
||||
var plugins = {
|
||||
analyzeCommits: exports.normalize(options.analyzeCommits, '@semantic-release/commit-analyzer'),
|
||||
generateNotes: exports.normalize(options.generateNotes, '@semantic-release/release-notes-generator'),
|
||||
getLastRelease: exports.normalize(options.getLastRelease, '@semantic-release/last-release-npm')
|
||||
}
|
||||
|
||||
;['verifyConditions', 'verifyRelease'].forEach(function (plugin) {
|
||||
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] = exports.normalize(
|
||||
plugins[plugin] = normalize(
|
||||
options[plugin],
|
||||
plugin === 'verifyConditions'
|
||||
? '@semantic-release/condition-travis'
|
||||
: './plugin-noop'
|
||||
)
|
||||
return
|
||||
plugin === 'verifyConditions' ? '@semantic-release/condition-travis' : './plugin-noop'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
plugins[plugin] = function (pluginOptions, cb) {
|
||||
var tasks = options[plugin].map(function (step) {
|
||||
return exports.normalize(step, './plugin-noop').bind(null, pluginOptions)
|
||||
})
|
||||
plugins[plugin] = async pluginOptions => {
|
||||
return pSeries(
|
||||
options[plugin].map(step => {
|
||||
return () => promisify(normalize(step, './plugin-noop'))(pluginOptions);
|
||||
})
|
||||
);
|
||||
};
|
||||
});
|
||||
|
||||
series(tasks, cb)
|
||||
}
|
||||
})
|
||||
return plugins;
|
||||
};
|
||||
|
||||
return plugins
|
||||
}
|
||||
const normalize = (pluginConfig, fallback) => {
|
||||
if (typeof pluginConfig === 'string') return relative(pluginConfig).bind(null, {});
|
||||
|
||||
exports.normalize = function (pluginConfig, fallback) {
|
||||
if (typeof pluginConfig === 'string') return relative(pluginConfig).bind(null, {})
|
||||
|
||||
if (pluginConfig && (typeof pluginConfig.path === 'string')) {
|
||||
return relative(pluginConfig.path).bind(null, pluginConfig)
|
||||
if (pluginConfig && typeof pluginConfig.path === 'string') {
|
||||
return relative(pluginConfig.path).bind(null, pluginConfig);
|
||||
}
|
||||
|
||||
return require(fallback).bind(null, pluginConfig)
|
||||
}
|
||||
return require(fallback).bind(null, pluginConfig);
|
||||
};
|
||||
|
||||
module.exports.normalize = normalize;
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
var SemanticReleaseError = require('@semantic-release/error')
|
||||
|
||||
module.exports = function (config, cb) {
|
||||
var plugins = config.plugins
|
||||
var lastRelease = config.lastRelease
|
||||
|
||||
plugins.analyzeCommits(config, function (err, type) {
|
||||
if (err) return cb(err)
|
||||
|
||||
if (!type) {
|
||||
return cb(new SemanticReleaseError(
|
||||
'There are no relevant changes, so no new version is released.',
|
||||
'ENOCHANGE'
|
||||
))
|
||||
}
|
||||
|
||||
if (!lastRelease.version) return cb(null, 'initial')
|
||||
|
||||
cb(null, type)
|
||||
})
|
||||
}
|
||||
+14
-29
@@ -1,40 +1,25 @@
|
||||
var SemanticReleaseError = require('@semantic-release/error')
|
||||
const SemanticReleaseError = require('@semantic-release/error');
|
||||
|
||||
module.exports = function (config) {
|
||||
var pkg = config.pkg
|
||||
var options = config.options
|
||||
var env = config.env
|
||||
var errors = []
|
||||
module.exports = ({pkg, options, env}) => {
|
||||
const errors = [];
|
||||
|
||||
if (!pkg.name) {
|
||||
errors.push(new SemanticReleaseError(
|
||||
'No "name" found in package.json.',
|
||||
'ENOPKGNAME'
|
||||
))
|
||||
errors.push(new SemanticReleaseError('No "name" found in package.json.', 'ENOPKGNAME'));
|
||||
}
|
||||
|
||||
if (!pkg.repository || !pkg.repository.url) {
|
||||
errors.push(new SemanticReleaseError(
|
||||
'No "repository" found in package.json.',
|
||||
'ENOPKGREPO'
|
||||
))
|
||||
errors.push(new SemanticReleaseError('No "repository" found in package.json.', 'ENOPKGREPO'));
|
||||
}
|
||||
|
||||
if (options.debug) return errors
|
||||
if (!options.debug) {
|
||||
if (!options.githubToken) {
|
||||
errors.push(new SemanticReleaseError('No github token specified.', 'ENOGHTOKEN'));
|
||||
}
|
||||
|
||||
if (!options.githubToken) {
|
||||
errors.push(new SemanticReleaseError(
|
||||
'No github token specified.',
|
||||
'ENOGHTOKEN'
|
||||
))
|
||||
if (!(env.NPM_TOKEN || (env.NPM_OLD_TOKEN && env.NPM_EMAIL))) {
|
||||
errors.push(new SemanticReleaseError('No npm token specified.', 'ENONPMTOKEN'));
|
||||
}
|
||||
}
|
||||
|
||||
if (!(env.NPM_TOKEN || (env.NPM_OLD_TOKEN && env.NPM_EMAIL))) {
|
||||
errors.push(new SemanticReleaseError(
|
||||
'No npm token specified.',
|
||||
'ENONPMTOKEN'
|
||||
))
|
||||
}
|
||||
|
||||
return errors
|
||||
}
|
||||
return errors;
|
||||
};
|
||||
|
||||
+31
-64
@@ -1,71 +1,38 @@
|
||||
var url = require('url')
|
||||
const {promisify} = require('util');
|
||||
const url = require('url');
|
||||
const gitHead = require('git-head');
|
||||
const GitHubApi = require('github');
|
||||
const parseSlug = require('parse-github-repo-url');
|
||||
|
||||
var gitHead = require('git-head')
|
||||
var GitHubApi = require('github')
|
||||
var parseSlug = require('parse-github-repo-url')
|
||||
module.exports = async config => {
|
||||
const {pkg, options: {branch, debug, githubUrl, githubToken, githubApiPathPrefix}, plugins} = config;
|
||||
const [owner, repo] = parseSlug(pkg.repository.url);
|
||||
const name = `v${pkg.version}`;
|
||||
const tag = {owner, repo, ref: `refs/tags/${name}`, sha: await promisify(gitHead)()};
|
||||
const body = await promisify(plugins.generateNotes)(config);
|
||||
const release = {owner, repo, tag_name: name, name, target_commitish: branch, draft: !!debug, body};
|
||||
|
||||
module.exports = function (config, cb) {
|
||||
var pkg = config.pkg
|
||||
var options = config.options
|
||||
var plugins = config.plugins
|
||||
var ghConfig = options.githubUrl ? url.parse(options.githubUrl) : {}
|
||||
if (debug && !githubToken) {
|
||||
return {published: false, release};
|
||||
}
|
||||
|
||||
var github = new GitHubApi({
|
||||
port: ghConfig.port,
|
||||
protocol: (ghConfig.protocol || '').split(':')[0] || null,
|
||||
host: ghConfig.hostname,
|
||||
pathPrefix: options.githubApiPathPrefix || null
|
||||
})
|
||||
const {port, protocol, hostname} = githubUrl ? url.parse(githubUrl) : {};
|
||||
const github = new GitHubApi({
|
||||
port,
|
||||
protocol: (protocol || '').split(':')[0] || null,
|
||||
host: hostname,
|
||||
pathPrefix: githubApiPathPrefix || null,
|
||||
});
|
||||
|
||||
plugins.generateNotes(config, function (err, log) {
|
||||
if (err) return cb(err)
|
||||
github.authenticate({type: 'token', token: githubToken});
|
||||
|
||||
gitHead(function (err, hash) {
|
||||
if (err) return cb(err)
|
||||
if (debug) {
|
||||
await github.repos.createRelease(release);
|
||||
return {published: true, release};
|
||||
}
|
||||
|
||||
var ghRepo = parseSlug(pkg.repository.url)
|
||||
var tag = {
|
||||
owner: ghRepo[0],
|
||||
repo: ghRepo[1],
|
||||
ref: 'refs/tags/v' + pkg.version,
|
||||
sha: hash
|
||||
}
|
||||
var release = {
|
||||
owner: ghRepo[0],
|
||||
repo: ghRepo[1],
|
||||
tag_name: 'v' + pkg.version,
|
||||
name: 'v' + pkg.version,
|
||||
target_commitish: options.branch,
|
||||
draft: !!options.debug,
|
||||
body: log
|
||||
}
|
||||
await github.gitdata.createReference(tag);
|
||||
await github.repos.createRelease(release);
|
||||
|
||||
if (options.debug && !options.githubToken) {
|
||||
return cb(null, false, release)
|
||||
}
|
||||
|
||||
github.authenticate({
|
||||
type: 'token',
|
||||
token: options.githubToken
|
||||
})
|
||||
|
||||
if (options.debug) {
|
||||
return github.repos.createRelease(release, function (err) {
|
||||
if (err) return cb(err)
|
||||
|
||||
cb(null, true, release)
|
||||
})
|
||||
}
|
||||
|
||||
github.gitdata.createReference(tag, function (err) {
|
||||
if (err) return cb(err)
|
||||
|
||||
github.repos.createRelease(release, function (err) {
|
||||
if (err) return cb(err)
|
||||
|
||||
cb(null, true, release)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
return {published: true, release};
|
||||
};
|
||||
|
||||
+18
-40
@@ -1,45 +1,23 @@
|
||||
var _ = require('lodash')
|
||||
var auto = require('run-auto')
|
||||
var semver = require('semver')
|
||||
const {promisify} = require('util');
|
||||
const {assign} = require('lodash');
|
||||
const semver = require('semver');
|
||||
|
||||
var getCommits = require('./lib/commits')
|
||||
var getType = require('./lib/type')
|
||||
const getCommits = require('./lib/get-commits');
|
||||
const getReleaseType = require('./lib/get-release-type');
|
||||
|
||||
module.exports = function (config, cb) {
|
||||
var plugins = config.plugins
|
||||
module.exports = async config => {
|
||||
const {getLastRelease, verifyRelease} = config.plugins;
|
||||
|
||||
auto({
|
||||
lastRelease: plugins.getLastRelease.bind(null, config),
|
||||
commits: ['lastRelease', function (results, cb) {
|
||||
getCommits(_.assign({
|
||||
lastRelease: results.lastRelease
|
||||
}, config),
|
||||
cb)
|
||||
}],
|
||||
type: ['commits', 'lastRelease', function (results, cb) {
|
||||
getType(_.assign({
|
||||
commits: results.commits,
|
||||
lastRelease: results.lastRelease
|
||||
}, config),
|
||||
cb)
|
||||
}]
|
||||
}, function (err, results) {
|
||||
if (err) return cb(err)
|
||||
const lastRelease = await promisify(getLastRelease)(config);
|
||||
const commits = await getCommits(assign({lastRelease}, config));
|
||||
const type = await getReleaseType(assign({commits, lastRelease}, config));
|
||||
|
||||
var nextRelease = {
|
||||
type: results.type,
|
||||
version: results.type === 'initial'
|
||||
? '1.0.0'
|
||||
: semver.inc(results.lastRelease.version, results.type)
|
||||
}
|
||||
const nextRelease = {
|
||||
type: type,
|
||||
version: type === 'initial' ? '1.0.0' : semver.inc(lastRelease.version, type),
|
||||
};
|
||||
|
||||
plugins.verifyRelease(_.assign({
|
||||
commits: results.commits,
|
||||
lastRelease: results.lastRelease,
|
||||
nextRelease: nextRelease
|
||||
}, config), function (err) {
|
||||
if (err) return cb(err)
|
||||
cb(null, nextRelease)
|
||||
})
|
||||
})
|
||||
}
|
||||
await promisify(verifyRelease)(assign({commits, lastRelease, nextRelease}, config));
|
||||
|
||||
return nextRelease;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user