| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355 | 'use strict'const BB = require('bluebird')const assert = require('assert')const chain = require('slide').chainconst detectIndent = require('detect-indent')const detectNewline = require('detect-newline')const fs = require('graceful-fs')const readFile = BB.promisify(require('graceful-fs').readFile)const git = require('./utils/git.js')const lifecycle = require('./utils/lifecycle.js')const log = require('npmlog')const npm = require('./npm.js')const output = require('./utils/output.js')const parseJSON = require('./utils/parse-json.js')const path = require('path')const semver = require('semver')const stringifyPackage = require('stringify-package')const writeFileAtomic = require('write-file-atomic')version.usage = 'npm version [<newversion> | major | minor | patch | premajor | preminor | prepatch | prerelease [--preid=<prerelease-id>] | from-git]' +                '\n(run in package dir)\n' +                "'npm -v' or 'npm --version' to print npm version " +                '(' + npm.version + ')\n' +                "'npm view <pkg> version' to view a package's " +                'published version\n' +                "'npm ls' to inspect current package/dependency versions"// npm version <newver>module.exports = versionfunction version (args, silent, cb_) {  if (typeof cb_ !== 'function') {    cb_ = silent    silent = false  }  if (args.length > 1) return cb_(version.usage)  readPackage(function (er, data, indent, newline) {    if (!args.length) return dump(data, cb_)    if (er) {      log.error('version', 'No valid package.json found')      return cb_(er)    }    if (args[0] === 'from-git') {      retrieveTagVersion(silent, data, cb_)    } else {      var newVersion = semver.valid(args[0])      if (!newVersion) newVersion = semver.inc(data.version, args[0], npm.config.get('preid'))      if (!newVersion) return cb_(version.usage)      persistVersion(newVersion, silent, data, cb_)    }  })}function retrieveTagVersion (silent, data, cb_) {  chain([    verifyGit,    parseLastGitTag  ], function (er, results) {    if (er) return cb_(er)    var localData = {      hasGit: true,      existingTag: true    }    var version = results[results.length - 1]    persistVersion(version, silent, data, localData, cb_)  })}function parseLastGitTag (cb) {  var options = { env: process.env }  git.whichAndExec(['describe', '--abbrev=0'], options, function (er, stdout) {    if (er) {      if (er.message.indexOf('No names found') !== -1) return cb(new Error('No tags found'))      return cb(er)    }    var tag = stdout.trim()    var prefix = npm.config.get('tag-version-prefix')    // Strip the prefix from the start of the tag:    if (tag.indexOf(prefix) === 0) tag = tag.slice(prefix.length)    var version = semver.valid(tag)    if (!version) return cb(new Error(tag + ' is not a valid version'))    cb(null, version)  })}function persistVersion (newVersion, silent, data, localData, cb_) {  if (typeof localData === 'function') {    cb_ = localData    localData = {}  }  if (!npm.config.get('allow-same-version') && data.version === newVersion) {    return cb_(new Error('Version not changed, might want --allow-same-version'))  }  data.version = newVersion  var lifecycleData = Object.create(data)  lifecycleData._id = data.name + '@' + newVersion  var where = npm.prefix  chain([    !localData.hasGit && [checkGit, localData],    [lifecycle, lifecycleData, 'preversion', where],    [updatePackage, newVersion, silent],    [lifecycle, lifecycleData, 'version', where],    [commit, localData, newVersion],    [lifecycle, lifecycleData, 'postversion', where]  ], cb_)}function readPackage (cb) {  var packagePath = path.join(npm.localPrefix, 'package.json')  fs.readFile(packagePath, 'utf8', function (er, data) {    if (er) return cb(new Error(er))    var indent    var newline    try {      indent = detectIndent(data).indent      newline = detectNewline(data)      data = JSON.parse(data)    } catch (e) {      er = e      data = null    }    cb(er, data, indent, newline)  })}function updatePackage (newVersion, silent, cb_) {  function cb (er) {    if (!er && !silent) output('v' + newVersion)    cb_(er)  }  readPackage(function (er, data, indent, newline) {    if (er) return cb(new Error(er))    data.version = newVersion    write(data, 'package.json', indent, newline, cb)  })}function commit (localData, newVersion, cb) {  updateShrinkwrap(newVersion, function (er, hasShrinkwrap, hasLock) {    if (er || !localData.hasGit) return cb(er)    localData.hasShrinkwrap = hasShrinkwrap    localData.hasPackageLock = hasLock    _commit(newVersion, localData, cb)  })}const SHRINKWRAP = 'npm-shrinkwrap.json'const PKGLOCK = 'package-lock.json'function readLockfile (name) {  return readFile(    path.join(npm.localPrefix, name), 'utf8'  ).catch({code: 'ENOENT'}, () => null)}function updateShrinkwrap (newVersion, cb) {  BB.join(    readLockfile(SHRINKWRAP),    readLockfile(PKGLOCK),    (shrinkwrap, lockfile) => {      if (!shrinkwrap && !lockfile) {        return cb(null, false, false)      }      const file = shrinkwrap ? SHRINKWRAP : PKGLOCK      let data      let indent      let newline      try {        data = parseJSON(shrinkwrap || lockfile)        indent = detectIndent(shrinkwrap || lockfile).indent        newline = detectNewline(shrinkwrap || lockfile)      } catch (err) {        log.error('version', `Bad ${file} data.`)        return cb(err)      }      data.version = newVersion      write(data, file, indent, newline, (err) => {        if (err) {          log.error('version', `Failed to update version in ${file}`)          return cb(err)        } else {          return cb(null, !!shrinkwrap, !!lockfile)        }      })    }  )}function dump (data, cb) {  var v = {}  if (data && data.name && data.version) v[data.name] = data.version  v.npm = npm.version  Object.keys(process.versions).sort().forEach(function (k) {    v[k] = process.versions[k]  })  if (npm.config.get('json')) v = JSON.stringify(v, null, 2)  output(v)  cb()}function statGitFolder (cb) {  fs.stat(path.join(npm.localPrefix, '.git'), cb)}function callGitStatus (cb) {  git.whichAndExec(    [ 'status', '--porcelain' ],    { env: process.env },    cb  )}function cleanStatusLines (stdout) {  var lines = stdout.trim().split('\n').filter(function (line) {    return line.trim() && !line.match(/^\?\? /)  }).map(function (line) {    return line.trim()  })  return lines}function verifyGit (cb) {  function checkStatus (er) {    if (er) return cb(er)    callGitStatus(checkStdout)  }  function checkStdout (er, stdout) {    if (er) return cb(er)    var lines = cleanStatusLines(stdout)    if (lines.length > 0) {      return cb(new Error(        'Git working directory not clean.\n' + lines.join('\n')      ))    }    cb()  }  statGitFolder(checkStatus)}function checkGit (localData, cb) {  statGitFolder(function (er) {    var doGit = !er && npm.config.get('git-tag-version')    if (!doGit) {      if (er && npm.config.get('git-tag-version')) log.verbose('version', 'error checking for .git', er)      log.verbose('version', 'not tagging in git')      return cb(null, false)    }    // check for git    callGitStatus(function (er, stdout) {      if (er && er.code === 'ENOGIT') {        log.warn(          'version',          'This is a Git checkout, but the git command was not found.',          'npm could not create a Git tag for this release!'        )        return cb(null, false)      }      var lines = cleanStatusLines(stdout)      if (lines.length && !npm.config.get('force')) {        return cb(new Error(          'Git working directory not clean.\n' + lines.join('\n')        ))      }      localData.hasGit = true      cb(null, true)    })  })}module.exports.buildCommitArgs = buildCommitArgsfunction buildCommitArgs (args) {  const add = []  args = args || []  if (args[0] === 'commit') args.shift()  if (!npm.config.get('commit-hooks')) add.push('-n')  if (npm.config.get('allow-same-version')) add.push('--allow-empty')  return ['commit', ...add, ...args]}module.exports.buildTagFlags = buildTagFlagsfunction buildTagFlags () {  return '-'.concat(    npm.config.get('sign-git-tag') ? 's' : '',    npm.config.get('allow-same-version') ? 'f' : '',    'm'  )}function _commit (version, localData, cb) {  const options = { env: process.env }  const message = npm.config.get('message').replace(/%s/g, version)  const signCommit = npm.config.get('sign-git-commit')  const commitArgs = buildCommitArgs([    'commit',    ...(signCommit ? ['-S', '-m'] : ['-m']),    message  ])  stagePackageFiles(localData, options).then(() => {    return git.exec(commitArgs, options)  }).then(() => {    if (!localData.existingTag) {      return git.exec([        'tag', npm.config.get('tag-version-prefix') + version,        buildTagFlags(), message      ], options)    }  }).nodeify(cb)}function stagePackageFiles (localData, options) {  return addLocalFile('package.json', options, false).then(() => {    if (localData.hasShrinkwrap) {      return addLocalFile('npm-shrinkwrap.json', options, true)    } else if (localData.hasPackageLock) {      return addLocalFile('package-lock.json', options, true)    }  })}function addLocalFile (file, options, ignoreFailure) {  const p = git.exec(['add', path.join(npm.localPrefix, file)], options)  return ignoreFailure    ? p.catch(() => {})    : p}function write (data, file, indent, newline, cb) {  assert(data && typeof data === 'object', 'must pass data to version write')  assert(typeof file === 'string', 'must pass filename to write to version write')  log.verbose('version.write', 'data', data, 'to', file)  writeFileAtomic(    path.join(npm.localPrefix, file),    stringifyPackage(data, indent, newline),    cb  )}
 |