diff --git a/command.js b/command.js index afe65fe8d..40d7d7e93 100755 --- a/command.js +++ b/command.js @@ -126,6 +126,11 @@ const yargs = require('yargs') default: defaults.npmPublishHint, describe: 'Customized publishing hint' }) + .option('noBumpWhenEmptyChanges', { + type: 'boolean', + default: false, + describe: 'Avoid bumping files and generating changelog if there are no changes.' + }) .check((argv) => { if (typeof argv.scripts !== 'object' || Array.isArray(argv.scripts)) { throw Error('scripts must be an object') diff --git a/index.js b/index.js index 8941e654a..cb88fc915 100755 --- a/index.js +++ b/index.js @@ -82,6 +82,7 @@ module.exports = async function standardVersion (argv) { } const newVersion = await bump(args, version) + if (!newVersion) return await changelog(args, newVersion) await commit(args, newVersion) await tag(newVersion, pkg ? pkg.private : false, args) diff --git a/lib/lifecycles/bump.js b/lib/lifecycles/bump.js index da72199f6..10f912550 100644 --- a/lib/lifecycles/bump.js +++ b/lib/lifecycles/bump.js @@ -12,8 +12,45 @@ const runLifecycleScript = require('../run-lifecycle-script') const semver = require('semver') const writeFile = require('../write-file') const { resolveUpdaterObjectFromArgument } = require('../updaters') +const addBangNotes = require('conventional-changelog-conventionalcommits/add-bang-notes') let configsToUpdate = {} +function _whatBump (config, commits) { + let level = 2 + let breakings = 0 + let features = 0 + let fix = 0 + + commits.forEach(commit => { + addBangNotes(commit) + if (commit.notes.length > 0) { + breakings += commit.notes.length + level = 0 + } else if (commit.type === 'feat' || commit.type === 'feature') { + features += 1 + if (level === 2) { + level = 1 + } + } + if (commit.type === 'fix') { + fix += 1 + } + }) + + if (config.preMajor && level < 2) { + level++ + } + + if (!breakings && !features && !fix) return {} + + return { + level, + reason: breakings === 1 + ? `There is ${breakings} BREAKING CHANGE and ${features} features` + : `There are ${breakings} BREAKING CHANGES and ${features} features` + } +} + async function Bump (args, version) { // reset the cache of updated config files each // time we perform the version bump step. @@ -25,6 +62,14 @@ async function Bump (args, version) { const stdout = await runLifecycleScript(args, 'prebump') if (stdout && stdout.trim().length) args.releaseAs = stdout.trim() const release = await bumpVersion(args.releaseAs, version, args) + if (!Object.keys(release).length) { + checkpoint( + args, + 'no commits found, so not bumping version', + [] + ) + return null + } if (!args.firstRelease) { const releaseType = getReleaseType(args.prerelease, release.releaseType, version) const releaseTypeAsVersion = releaseType === 'pre' + release.releaseType ? semver.valid(release.releaseType + '-' + args.prerelease + '.0') : semver.valid(releaseType) @@ -108,7 +153,8 @@ function getTypePriority (type) { } function bumpVersion (releaseAs, currentVersion, args) { - return new Promise((resolve, reject) => { + // eslint-disable-next-line no-async-promise-executor + return new Promise(async (resolve, reject) => { if (releaseAs) { return resolve({ releaseType: releaseAs @@ -123,7 +169,12 @@ function bumpVersion (releaseAs, currentVersion, args) { preset: presetOptions, path: args.path, tagPrefix: args.tagPrefix, - lernaPackage: args.lernaPackage + lernaPackage: args.lernaPackage, + ...args.noBumpWhenEmptyChanges && { + whatBump (commits) { + return _whatBump(presetOptions, commits) + } + } }, args.parserOpts, function (err, release) { if (err) return reject(err) else return resolve(release)