@capgo/standard-version
Version:
replacement for `npm version` with automatic CHANGELOG generation
173 lines (156 loc) • 5.01 kB
JavaScript
const chalk = require('chalk')
const checkpoint = require('../checkpoint')
const conventionalRecommendedBump = require('conventional-recommended-bump')
const figures = require('figures')
const fs = require('fs')
const DotGitignore = require('dotgitignore')
const path = require('path')
const presetLoader = require('../preset-loader')
const runLifecycleScript = require('../run-lifecycle-script')
const semver = require('semver')
const writeFile = require('../write-file')
const { resolveUpdaterObjectFromArgument } = require('../updaters')
let configsToUpdate = {}
async function Bump (args, version) {
// reset the cache of updated config files each
// time we perform the version bump step.
configsToUpdate = {}
if (args.skip.bump) return version
let newVersion = version
await runLifecycleScript(args, 'prerelease')
const stdout = await runLifecycleScript(args, 'prebump')
if (stdout && stdout.trim().length) args.releaseAs = stdout.trim()
const release = await bumpVersion(args.releaseAs, version, args)
if (!args.firstRelease) {
const releaseType = getReleaseType(args.prerelease, release.releaseType, version)
newVersion = semver.valid(releaseType) || semver.inc(version, releaseType, args.prerelease)
updateConfigs(args, newVersion)
} else {
checkpoint(args, 'skip version bump on first release', [], chalk.red(figures.cross))
}
await runLifecycleScript(args, 'postbump')
return newVersion
}
Bump.getUpdatedConfigs = function () {
return configsToUpdate
}
function getReleaseType (prerelease, expectedReleaseType, currentVersion) {
if (isString(prerelease)) {
if (isInPrerelease(currentVersion)) {
if (shouldContinuePrerelease(currentVersion, expectedReleaseType) ||
getTypePriority(getCurrentActiveType(currentVersion)) > getTypePriority(expectedReleaseType)
) {
return 'prerelease'
}
}
return 'pre' + expectedReleaseType
} else {
return expectedReleaseType
}
}
function isString (val) {
return typeof val === 'string'
}
/**
* if a version is currently in pre-release state,
* and if it current in-pre-release type is same as expect type,
* it should continue the pre-release with the same type
*
* @param version
* @param expectType
* @return {boolean}
*/
function shouldContinuePrerelease (version, expectType) {
return getCurrentActiveType(version) === expectType
}
function isInPrerelease (version) {
return Array.isArray(semver.prerelease(version))
}
const TypeList = ['major', 'minor', 'patch'].reverse()
/**
* extract the in-pre-release type in target version
*
* @param version
* @return {string}
*/
function getCurrentActiveType (version) {
const typelist = TypeList
for (let i = 0; i < typelist.length; i++) {
if (semver[typelist[i]](version)) {
return typelist[i]
}
}
}
/**
* calculate the priority of release type,
* major - 2, minor - 1, patch - 0
*
* @param type
* @return {number}
*/
function getTypePriority (type) {
return TypeList.indexOf(type)
}
function bumpVersion (releaseAs, currentVersion, args) {
return new Promise((resolve, reject) => {
if (releaseAs) {
return resolve({
releaseType: releaseAs
})
} else {
const presetOptions = presetLoader(args)
if (typeof presetOptions === 'object') {
if (semver.lt(currentVersion, '1.0.0')) presetOptions.preMajor = true
}
conventionalRecommendedBump({
debug: args.verbose && console.info.bind(console, 'conventional-recommended-bump'),
preset: presetOptions,
path: args.path,
tagPrefix: args.tagPrefix,
lernaPackage: args.lernaPackage
}, function (err, release) {
if (err) return reject(err)
else return resolve(release)
})
}
})
}
/**
* attempt to update the version number in provided `bumpFiles`
* @param args config object
* @param newVersion version number to update to.
* @return void
*/
function updateConfigs (args, newVersion) {
const dotgit = DotGitignore()
args.bumpFiles.forEach(function (bumpFile) {
const updater = resolveUpdaterObjectFromArgument(bumpFile)
if (!updater) {
return
}
const configPath = path.resolve(process.cwd(), updater.filename)
try {
if (dotgit.ignore(configPath)) return
const stat = fs.lstatSync(configPath)
if (!stat.isFile()) return
const contents = fs.readFileSync(configPath, 'utf8')
checkpoint(
args,
'bumping version in ' + updater.filename + ' from %s to %s',
[updater.updater.readVersion(contents), newVersion]
)
writeFile(
args,
configPath,
updater.updater.writeVersion(contents, newVersion)
)
// flag any config files that we modify the version # for
// as having been updated.
configsToUpdate[updater.filename] = true
} catch (err) {
if (err.code !== 'ENOENT') console.warn(err.message)
}
})
}
module.exports = Bump