refactor: use one config object instead of passing arguments to plugins on their own
This commit does a lot but it's all connected and tries to make everything more extensible and future proof.
1. CLI arguments and options from the "package.json" are no longer treated as two different things. You can now pass options either way.
BREAKING CHANGE: cli arguments are now normalized to camelCase, so e.g. `options['github-url']` is now `options.githubUrl`
2. Plugins no longer receive config they need one by one, but in one huge object. This way it's easier to pass more info in the future w/o breaking existing plugins that rely on the position of the callback in the arguments array.
BREAKING CHANGE: Plugins now need to read their passed options from one huge config object.
Old:
```js
module.exports = function (pluginConfig, foo, bar, cb) {…}
```
New:
```js
// ES5
module.exports = function(pluginConfig, config, cb) {
var foo = config.foo
var bar = config.bar
…
}
// ES6
module.exports = function (pluginConfig, {foo, bar}, cb) {…}
```
This commit is contained in:
+49
-40
@@ -1,27 +1,35 @@
|
||||
const { readFileSync, writeFileSync } = require('fs')
|
||||
const path = require('path')
|
||||
|
||||
const _ = require('lodash')
|
||||
const log = require('npmlog')
|
||||
const nopt = require('nopt')
|
||||
const npmconf = require('npmconf')
|
||||
|
||||
const PREFIX = 'semantic-release'
|
||||
const env = process.env
|
||||
const options = _.defaults(nopt({
|
||||
const pkg = JSON.parse(readFileSync('./package.json'))
|
||||
const knownOptions = {
|
||||
branch: String,
|
||||
debug: Boolean,
|
||||
'github-token': String,
|
||||
'github-url': String
|
||||
}, {
|
||||
token: 'github-token',
|
||||
dry: 'debug'
|
||||
}), {
|
||||
debug: !env.CI,
|
||||
'github-token': env.GH_TOKEN || env.GITHUB_TOKEN,
|
||||
'github-url': env.GH_URL
|
||||
})
|
||||
const PREFIX = 'semantic-release'
|
||||
|
||||
const pkg = JSON.parse(readFileSync('./package.json'))
|
||||
const plugins = require('./lib/plugins')(pkg.release || {})
|
||||
'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) => _.camelCase(key)),
|
||||
pkg.release,
|
||||
{
|
||||
branch: 'master',
|
||||
debug: !env.CI,
|
||||
githubToken: env.GH_TOKEN || env.GITHUB_TOKEN,
|
||||
githubUrl: env.GH_URL
|
||||
}
|
||||
)
|
||||
const plugins = require('./lib/plugins')(options)
|
||||
|
||||
npmconf.load({}, (err, conf) => {
|
||||
if (err) {
|
||||
@@ -29,28 +37,41 @@ npmconf.load({}, (err, conf) => {
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
log.level = conf.get('loglevel')
|
||||
let npm = {
|
||||
auth: {
|
||||
token: env.NPM_TOKEN
|
||||
},
|
||||
loglevel: conf.get('loglevel'),
|
||||
registry: conf.get('registry'),
|
||||
tag: (pkg.publishConfig || {}).tag || conf.get('tag') || 'latest'
|
||||
}
|
||||
|
||||
log.verbose(PREFIX, 'argv:', options)
|
||||
log.verbose(PREFIX, 'options:', pkg.release || 'no options')
|
||||
log.verbose(PREFIX, 'Verifying pkg, options and env.')
|
||||
if (npm.registry[npm.registry.length - 1] !== '/') npm.registry += '/'
|
||||
|
||||
const errors = require('./lib/verify')(pkg, options, env)
|
||||
log.level = npm.loglevel
|
||||
|
||||
const config = {PREFIX, log, env, pkg, options, plugins, npm}
|
||||
|
||||
log.verbose(PREFIX, 'options:', _.assign({
|
||||
githubToken: options.githubToken ? '***' : undefined
|
||||
}), options)
|
||||
log.verbose(PREFIX, 'Verifying config.')
|
||||
|
||||
const errors = require('./lib/verify')(config)
|
||||
errors.forEach((err) => log.error(PREFIX, `${err.message} ${err.code}`))
|
||||
if (errors.length) process.exit(1)
|
||||
|
||||
if (!options.argv.cooked.length || options.argv.cooked[0] === 'pre') {
|
||||
if (options.argv.remain[0] === 'pre') {
|
||||
log.verbose(PREFIX, 'Running pre-script.')
|
||||
log.verbose(PREFIX, 'Veriying conditions.')
|
||||
|
||||
plugins.verifyConditions(pkg, options, env, (err) => {
|
||||
plugins.verifyConditions(config, (err) => {
|
||||
if (err) {
|
||||
log[options.debug ? 'warn' : 'error'](PREFIX, err.message)
|
||||
if (!options.debug) process.exit(1)
|
||||
}
|
||||
|
||||
const registry = conf.get('registry')
|
||||
const nerfDart = require('./lib/nerf-dart')(registry)
|
||||
const nerfDart = require('./lib/nerf-dart')(npm.registry)
|
||||
let wroteNpmRc = false
|
||||
|
||||
if (env.NPM_TOKEN) {
|
||||
@@ -69,19 +90,7 @@ npmconf.load({}, (err, conf) => {
|
||||
|
||||
if (wroteNpmRc) log.verbose(PREFIX, 'Wrote authToken to .npmrc.')
|
||||
|
||||
const npmConfig = {
|
||||
auth: {
|
||||
token: env.NPM_TOKEN
|
||||
},
|
||||
loglevel: log.level,
|
||||
registry: registry + (registry[registry.length - 1] !== '/' ? '/' : ''),
|
||||
tag: (pkg.publishConfig || {}).tag || conf.get('tag') || 'latest'
|
||||
}
|
||||
|
||||
require('./pre')(pkg,
|
||||
npmConfig,
|
||||
plugins,
|
||||
(err, release) => {
|
||||
require('./pre')(config, (err, release) => {
|
||||
if (err) {
|
||||
log.error(PREFIX, 'Failed to determine new version.')
|
||||
|
||||
@@ -91,7 +100,7 @@ npmconf.load({}, (err, conf) => {
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const message = `Determined version ${release.version} as "${npmConfig.tag}".`
|
||||
const message = `Determined version ${release.version} as "${npm.tag}".`
|
||||
|
||||
log.verbose(PREFIX, message)
|
||||
|
||||
@@ -108,10 +117,10 @@ npmconf.load({}, (err, conf) => {
|
||||
})
|
||||
})
|
||||
})
|
||||
} else if (options.argv.cooked[0] === 'post') {
|
||||
} else if (options.argv.remain[0] === 'post') {
|
||||
log.verbose(PREFIX, 'Running post-script.')
|
||||
|
||||
require('./post')(pkg, options, plugins, (err, published, release) => {
|
||||
require('./post')(config, (err, published, release) => {
|
||||
if (err) {
|
||||
log.error(PREFIX, 'Failed to publish release notes.', err)
|
||||
process.exit(1)
|
||||
@@ -120,6 +129,6 @@ npmconf.load({}, (err, conf) => {
|
||||
log.verbose(PREFIX, `${published ? 'Published' : 'Generated'} release notes.`, release)
|
||||
})
|
||||
} else {
|
||||
log.error(PREFIX, `Command "${options.argv.cooked[0]}" not recognized. User either "pre" or "post"`)
|
||||
log.error(PREFIX, `Command "${options.argv.remain[0]}" not recognized. User either "pre" or "post"`)
|
||||
}
|
||||
})
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
const { exec } = require('child_process')
|
||||
|
||||
module.exports = function (lastRelease, cb) {
|
||||
module.exports = function ({lastRelease}, cb) {
|
||||
const from = lastRelease.gitHead
|
||||
const range = (from ? from + '..' : '') + 'HEAD'
|
||||
|
||||
|
||||
@@ -3,24 +3,24 @@ const SemanticReleaseError = require('@semantic-release/error')
|
||||
const npmlog = require('npmlog')
|
||||
const RegClient = require('npm-registry-client')
|
||||
|
||||
module.exports = function (pkg, npmConfig, cb) {
|
||||
npmlog.level = npmConfig.loglevel || 'error'
|
||||
module.exports = function ({pkg, npm}, cb) {
|
||||
npmlog.level = npm.loglevel || 'error'
|
||||
const client = new RegClient({log: npmlog})
|
||||
|
||||
client.get(`${npmConfig.registry}${pkg.name}`, {
|
||||
auth: npmConfig.auth
|
||||
client.get(`${npm.registry}${pkg.name}`, {
|
||||
auth: npm.auth
|
||||
}, (err, data) => {
|
||||
if (err && err.statusCode === 404) return cb(null, {})
|
||||
if (err) return cb(err)
|
||||
|
||||
const version = data['dist-tags'][npmConfig.tag]
|
||||
const version = data['dist-tags'][npm.tag]
|
||||
|
||||
if (!version) return cb(new SemanticReleaseError(`There is no release with the dist-tag "${npmConfig.tag}" yet. Tag a version first.`, 'ENODISTTAG'))
|
||||
if (!version) return cb(new SemanticReleaseError(`There is no release with the dist-tag "${npm.tag}" yet. Tag a version first.`, 'ENODISTTAG'))
|
||||
|
||||
cb(null, {
|
||||
version,
|
||||
gitHead: data.versions[version].gitHead,
|
||||
tag: npmConfig.tag
|
||||
tag: npm.tag
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* istanbul ignore next */
|
||||
module.exports = function (options, release, cb) {
|
||||
module.exports = function (config, options, cb) {
|
||||
cb(null)
|
||||
}
|
||||
|
||||
+10
-10
@@ -1,20 +1,20 @@
|
||||
const relative = require('require-relative')
|
||||
|
||||
let exports = module.exports = function (source) {
|
||||
let exports = module.exports = function (options) {
|
||||
return {
|
||||
analyzeCommits: exports.normalize(source.analyzeCommits, '@semantic-release/commit-analyzer'),
|
||||
generateNotes: exports.normalize(source.generateNotes, '@semantic-release/release-notes-generator'),
|
||||
verifyConditions: exports.normalize(source.verifyConditions, '@semantic-release/condition-travis'),
|
||||
verifyRelease: exports.normalize(source.verifyRelease, './plugin-noop')
|
||||
analyzeCommits: exports.normalize(options.analyzeCommits, '@semantic-release/commit-analyzer'),
|
||||
generateNotes: exports.normalize(options.generateNotes, '@semantic-release/release-notes-generator'),
|
||||
verifyConditions: exports.normalize(options.verifyConditions, '@semantic-release/condition-travis'),
|
||||
verifyRelease: exports.normalize(options.verifyRelease, './plugin-noop')
|
||||
}
|
||||
}
|
||||
|
||||
exports.normalize = function (plugin, fallback) {
|
||||
if (typeof plugin === 'string') return relative(plugin).bind(null, {})
|
||||
exports.normalize = function (pluginConfig, fallback) {
|
||||
if (typeof pluginConfig === 'string') return relative(pluginConfig).bind(null, {})
|
||||
|
||||
if (plugin && (typeof plugin.path === 'string')) {
|
||||
return relative(plugin.path).bind(null, plugin)
|
||||
if (pluginConfig && (typeof pluginConfig.path === 'string')) {
|
||||
return relative(pluginConfig.path).bind(null, pluginConfig)
|
||||
}
|
||||
|
||||
return require(fallback).bind(null, plugin)
|
||||
return require(fallback).bind(null, pluginConfig)
|
||||
}
|
||||
|
||||
+4
-2
@@ -1,7 +1,9 @@
|
||||
const SemanticReleaseError = require('@semantic-release/error')
|
||||
|
||||
module.exports = function (plugins, commits, lastRelease, cb) {
|
||||
plugins.analyzeCommits(commits, (err, type) => {
|
||||
module.exports = function (config, cb) {
|
||||
const { plugins, lastRelease } = config
|
||||
|
||||
plugins.analyzeCommits(config, (err, type) => {
|
||||
if (err) return cb(err)
|
||||
|
||||
if (!type) {
|
||||
|
||||
+2
-2
@@ -2,7 +2,7 @@ const parseSlug = require('parse-github-repo-url')
|
||||
|
||||
const SemanticReleaseError = require('@semantic-release/error')
|
||||
|
||||
module.exports = function (pkg, options, env) {
|
||||
module.exports = function ({pkg, options, env}) {
|
||||
let errors = []
|
||||
|
||||
if (!pkg.name) {
|
||||
@@ -26,7 +26,7 @@ module.exports = function (pkg, options, env) {
|
||||
|
||||
if (options.debug) return errors
|
||||
|
||||
if (!options['github-token']) {
|
||||
if (!options.githubToken) {
|
||||
errors.push(new SemanticReleaseError(
|
||||
'No github token specified.',
|
||||
'ENOGHTOKEN'
|
||||
|
||||
+10
-9
@@ -4,17 +4,18 @@ const gitHead = require('git-head')
|
||||
const GitHubApi = require('github')
|
||||
const parseSlug = require('parse-github-repo-url')
|
||||
|
||||
module.exports = function (pkg, argv, plugins, cb) {
|
||||
const config = argv['github-url'] ? url.parse(argv['github-url']) : {}
|
||||
module.exports = function (config, cb) {
|
||||
const { pkg, options, plugins } = config
|
||||
const ghConfig = options.githubUrl ? url.parse(options.githubUrl) : {}
|
||||
|
||||
const github = new GitHubApi({
|
||||
version: '3.0.0',
|
||||
port: config.port,
|
||||
protocol: (config.protocol || '').split(':')[0] || null,
|
||||
host: config.hostname
|
||||
port: ghConfig.port,
|
||||
protocol: (ghConfig.protocol || '').split(':')[0] || null,
|
||||
host: ghConfig.hostname
|
||||
})
|
||||
|
||||
plugins.generateNotes(pkg, (err, log) => {
|
||||
plugins.generateNotes(config, (err, log) => {
|
||||
if (err) return cb(err)
|
||||
|
||||
gitHead((err, hash) => {
|
||||
@@ -27,17 +28,17 @@ module.exports = function (pkg, argv, plugins, cb) {
|
||||
name: `v${pkg.version}`,
|
||||
tag_name: `v${pkg.version}`,
|
||||
target_commitish: hash,
|
||||
draft: !!argv.debug,
|
||||
draft: !!options.debug,
|
||||
body: log
|
||||
}
|
||||
|
||||
if (argv.debug && !argv['github-token']) {
|
||||
if (options.debug && !options.githubToken) {
|
||||
return cb(null, false, release)
|
||||
}
|
||||
|
||||
github.authenticate({
|
||||
type: 'oauth',
|
||||
token: argv['github-token']
|
||||
token: options.githubToken
|
||||
})
|
||||
|
||||
github.releases.createRelease(release, (err) => {
|
||||
|
||||
+18
-7
@@ -1,3 +1,4 @@
|
||||
const _ = require('lodash')
|
||||
const auto = require('run-auto')
|
||||
const semver = require('semver')
|
||||
|
||||
@@ -5,28 +6,38 @@ const getLastRelease = require('./lib/last-release')
|
||||
const getCommits = require('./lib/commits')
|
||||
const getType = require('./lib/type')
|
||||
|
||||
module.exports = function (pkg, npmConfig, plugins, cb) {
|
||||
module.exports = function (config, cb) {
|
||||
const {plugins} = config
|
||||
auto({
|
||||
lastRelease: getLastRelease.bind(null, pkg, npmConfig),
|
||||
lastRelease: getLastRelease.bind(null, config),
|
||||
commits: ['lastRelease', (cb, results) => {
|
||||
getCommits(results.lastRelease, cb)
|
||||
getCommits(_.assign({
|
||||
lastRelease: results.lastRelease
|
||||
}, config),
|
||||
cb)
|
||||
}],
|
||||
type: ['commits', 'lastRelease', (cb, results) => {
|
||||
getType(plugins, results.commits, results.lastRelease, cb)
|
||||
getType(_.assign({
|
||||
commits: results.commits,
|
||||
lastRelease: results.lastRelease
|
||||
}, config),
|
||||
cb)
|
||||
}]
|
||||
}, (err, results) => {
|
||||
if (err) return cb(err)
|
||||
|
||||
const nextRelease = {
|
||||
type: results.type,
|
||||
commits: results.commits,
|
||||
lastVersion: results.lastRelease.version,
|
||||
version: results.type === 'initial' ?
|
||||
'1.0.0' :
|
||||
semver.inc(results.lastRelease.version, results.type)
|
||||
}
|
||||
|
||||
plugins.verifyRelease(nextRelease, (err) => {
|
||||
plugins.verifyRelease(_.assign({
|
||||
commits: results.commits,
|
||||
lastRelease: results.lastRelease,
|
||||
nextRelease
|
||||
}, config), (err) => {
|
||||
if (err) return cb(err)
|
||||
cb(null, nextRelease)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user