1 |
|
2 |
|
3 | module.exports = version
|
4 |
|
5 | var 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 |
|
16 | version.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 |
|
24 | function 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 |
|
42 |
|
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 |
|
67 | function 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 |
|
91 | function 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 |
|
106 | function 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 |
|
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 |
|
146 | function 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 |
|
164 | function 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 | }
|