UNPKG

5.26 kBJavaScriptView Raw
1// npm version <newver>
2
3module.exports = version
4
5var semver = require("semver")
6 , path = require("path")
7 , fs = require("graceful-fs")
8 , writeFileAtomic = require("write-file-atomic")
9 , chain = require("slide").chain
10 , log = require("npmlog")
11 , pkgyaml = require("package-yaml")
12 , npm = require("./npm.js")
13 , git = require("./utils/git.js")
14 , assert = require("assert")
15
16version.usage = "npm version [<newversion> | major | minor | micro | prerelease | preminor | premajor ]\n"
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"
23
24function version (args, silent, cb_) {
25 if (typeof cb_ !== "function") cb_ = silent, silent = false
26 if (args.length > 1) return cb_(version.usage)
27
28 pkgyaml.read(npm.localPrefix, function (er, data) {
29 function cb (er) {
30 if (!er && !silent) console.log("v" + data.version)
31 cb_(er)
32 }
33
34 if (!args.length) return dump(data, cb_)
35
36 if (er) {
37 log.error("version", "No package.json found")
38 return cb_(er)
39 }
40
41 // adding "micro" as an alias for patch, because "patch" is ambiguous
42 // see https://github.com/mojombo/semver/issues/160
43 if (args[0] === 'micro') args[0] = 'patch'
44
45 var newVersion = semver.valid(args[0])
46 if (!newVersion) newVersion = semver.inc(data.version, args[0])
47 if (!newVersion) return cb_(version.usage)
48 if (data.version === newVersion) return cb_(new Error("Version not changed"))
49 data.version = newVersion
50
51 checkGit(function (er, hasGit) {
52 if (er) return cb_(er)
53
54 write(data, null, function (er) {
55 if (er) return cb_(er)
56
57 updateShrinkwrap(newVersion, function (er, hasShrinkwrap) {
58 if (er || !hasGit) return cb(er)
59
60 commit(data.version, hasShrinkwrap, cb)
61 })
62 })
63 })
64 })
65}
66
67function updateShrinkwrap (newVersion, cb) {
68 fs.readFile(path.join(npm.localPrefix, "npm-shrinkwrap.json"), function (er, data) {
69 if (er && er.code === "ENOENT") return cb(null, false)
70
71 try {
72 data = data.toString()
73 data = JSON.parse(data)
74 }
75 catch (er) {
76 log.error("version", "Bad npm-shrinkwrap.json data")
77 return cb(er)
78 }
79
80 data.version = newVersion
81 write(data, "npm-shrinkwrap.json", function (er) {
82 if (er) {
83 log.error("version", "Bad npm-shrinkwrap.json data")
84 return cb(er)
85 }
86 cb(null, true)
87 })
88 })
89}
90
91function dump (data, cb) {
92 var v = {}
93
94 if (data && data.name && data.version) v[data.name] = data.version
95 v.npm = npm.version
96 Object.keys(process.versions).sort().forEach(function (k) {
97 v[k] = process.versions[k]
98 })
99
100 if (npm.config.get("json")) v = JSON.stringify(v, null, 2)
101
102 console.log(v)
103 cb()
104}
105
106function checkGit (cb) {
107 fs.stat(path.join(npm.localPrefix, ".git"), function (er, s) {
108 var doGit = !er && s.isDirectory() && npm.config.get("git-tag-version")
109 if (!doGit) {
110 if (er) log.verbose("version", "error checking for .git", er)
111 log.verbose("version", "not tagging in git")
112 return cb(null, false)
113 }
114
115 // check for git
116 git.whichAndExec(
117 [ "status", "--porcelain" ],
118 { env : process.env },
119 function (er, stdout) {
120 if (er && er.code === "ENOGIT") {
121 log.warn(
122 "version",
123 "This is a Git checkout, but the git command was not found.",
124 "npm could not create a Git tag for this release!"
125 )
126 return cb(null, false)
127 }
128
129 var lines = stdout.trim().split("\n").filter(function (line) {
130 if (line.match(/^\?\? /)) return false
131 if (line.match(/^. /)) return false
132 return !!line.trim()
133 }).map(function (line) {
134 return line.trim()
135 })
136 if (lines.length) return cb(new Error(
137 "Git working directory not clean.\n"+lines.join("\n")
138 ))
139
140 cb(null, true)
141 }
142 )
143 })
144}
145
146function commit (version, hasShrinkwrap, cb) {
147 var options = { env : process.env }
148 var message = npm.config.get("message").replace(/%s/g, version)
149 var sign = npm.config.get("sign-git-tag")
150 var flag = sign ? "-sm" : "-am"
151 pkgyaml.stat(npm.localPrefix, function(er, stat) {
152 chain(
153 [
154 git.chainableExec([ "add", stat.file ], options),
155 hasShrinkwrap && git.chainableExec([ "add", "npm-shrinkwrap.json" ] , options),
156 git.chainableExec([ "commit", "-m", message ], options),
157 git.chainableExec([ "tag", "v" + version, flag, message ], options)
158 ],
159 cb
160 )
161 })
162}
163
164function write (data, file, cb) {
165 assert(data && typeof data === "object", "must pass data to version write")
166 assert(typeof file === "string" || file == null, "must pass filename to write to version write")
167
168 log.verbose("version.write", "data", data, "to", file)
169 if (file == null) {
170 return pkgyaml.write(npm.localPrefix, data, cb)
171 }
172 writeFileAtomic(
173 path.join(npm.localPrefix, file),
174 new Buffer(JSON.stringify(data, null, 2) + "\n"),
175 cb
176 )
177}