1 // npm version <newver>
3 module.exports = version
5 var semver = require('semver')
6 var path = require('path')
7 var fs = require('graceful-fs')
8 var writeFileAtomic = require('write-file-atomic')
9 var chain = require('slide').chain
10 var log = require('npmlog')
11 var npm = require('./npm.js')
12 var git = require('./utils/git.js')
13 var assert = require('assert')
14 var lifecycle = require('./utils/lifecycle.js')
16 version.usage = 'npm version [<newversion> | major | minor | patch | premajor | preminor | prepatch | prerelease]' +
17 '\n(run in package dir)\n' +
18 "'npm -v' or 'npm --version' to print npm version " +
19 '(' + npm.version + ')\n' +
20 "'npm view <pkg> version' to view a package's " +
21 'published version\n' +
22 "'npm ls' to inspect current package/dependency versions"
24 function version (args, silent, cb_) {
25 if (typeof cb_ !== 'function') {
29 if (args.length > 1) return cb_(version.usage)
31 var packagePath = path.join(npm.localPrefix, 'package.json')
32 fs.readFile(packagePath, function (er, data) {
33 if (data) data = data.toString()
35 data = JSON.parse(data)
41 if (!args.length) return dump(data, cb_)
44 log.error('version', 'No valid package.json found')
48 var newVersion = semver.valid(args[0])
49 if (!newVersion) newVersion = semver.inc(data.version, args[0])
50 if (!newVersion) return cb_(version.usage)
51 if (data.version === newVersion) return cb_(new Error('Version not changed'))
52 data.version = newVersion
53 var lifecycleData = Object.create(data)
54 lifecycleData._id = data.name + '@' + newVersion
57 var where = npm.prefix
59 [checkGit, localData],
60 [lifecycle, lifecycleData, 'preversion', where],
61 [updatePackage, newVersion, silent],
62 [lifecycle, lifecycleData, 'version', where],
63 [commit, localData, newVersion],
64 [lifecycle, lifecycleData, 'postversion', where] ],
69 function readPackage (cb) {
70 var packagePath = path.join(npm.localPrefix, 'package.json')
71 fs.readFile(packagePath, function (er, data) {
72 if (er) return cb(new Error(er))
73 if (data) data = data.toString()
75 data = JSON.parse(data)
84 function updatePackage (newVersion, silent, cb_) {
86 if (!er && !silent) console.log('v' + newVersion)
90 readPackage(function (er, data) {
91 if (er) return cb(new Error(er))
92 data.version = newVersion
93 write(data, 'package.json', cb)
97 function commit (localData, newVersion, cb) {
98 updateShrinkwrap(newVersion, function (er, hasShrinkwrap) {
99 if (er || !localData.hasGit) return cb(er)
100 _commit(newVersion, hasShrinkwrap, cb)
104 function updateShrinkwrap (newVersion, cb) {
105 fs.readFile(path.join(npm.localPrefix, 'npm-shrinkwrap.json'), function (er, data) {
106 if (er && er.code === 'ENOENT') return cb(null, false)
109 data = data.toString()
110 data = JSON.parse(data)
112 log.error('version', 'Bad npm-shrinkwrap.json data')
116 data.version = newVersion
117 write(data, 'npm-shrinkwrap.json', function (er) {
119 log.error('version', 'Bad npm-shrinkwrap.json data')
127 function dump (data, cb) {
130 if (data && data.name && data.version) v[data.name] = data.version
132 Object.keys(process.versions).sort().forEach(function (k) {
133 v[k] = process.versions[k]
136 if (npm.config.get('json')) v = JSON.stringify(v, null, 2)
142 function checkGit (localData, cb) {
143 fs.stat(path.join(npm.localPrefix, '.git'), function (er, s) {
144 var doGit = !er && npm.config.get('git-tag-version')
146 if (er) log.verbose('version', 'error checking for .git', er)
147 log.verbose('version', 'not tagging in git')
148 return cb(null, false)
153 [ 'status', '--porcelain' ],
154 { env: process.env },
155 function (er, stdout) {
156 if (er && er.code === 'ENOGIT') {
159 'This is a Git checkout, but the git command was not found.',
160 'npm could not create a Git tag for this release!'
162 return cb(null, false)
165 var lines = stdout.trim().split('\n').filter(function (line) {
166 return line.trim() && !line.match(/^\?\? /)
167 }).map(function (line) {
170 if (lines.length && !npm.config.get('force')) {
172 'Git working directory not clean.\n' + lines.join('\n')
175 localData.hasGit = true
182 function _commit (version, hasShrinkwrap, cb) {
183 var packagePath = path.join(npm.localPrefix, 'package.json')
184 var options = { env: process.env }
185 var message = npm.config.get('message').replace(/%s/g, version)
186 var sign = npm.config.get('sign-git-tag')
187 var flag = sign ? '-sm' : '-am'
190 git.chainableExec([ 'add', packagePath ], options),
191 hasShrinkwrap && git.chainableExec([ 'add', 'npm-shrinkwrap.json' ], options),
192 git.chainableExec([ 'commit', '-m', message ], options),
193 git.chainableExec([ 'tag', npm.config.get('tag-version-prefix') + version, flag, message ], options)
199 function write (data, file, cb) {
200 assert(data && typeof data === 'object', 'must pass data to version write')
201 assert(typeof file === 'string', 'must pass filename to write to version write')
203 log.verbose('version.write', 'data', data, 'to', file)
205 path.join(npm.localPrefix, file),
206 new Buffer(JSON.stringify(data, null, 2) + '\n'),