codekingpro/portable-devtools
115k
1// called with all the options already set to their defaults
2
3const retrieveTag = require('./retrieve-tag.js')
4const semver = require('semver')
5const enforceClean = require('./enforce-clean.js')
6const writeJson = require('./write-json.js')
7const readJson = require('./read-json.js')
8const git = require('@npmcli/git')
9const commit = require('./commit.js')
10const tag = require('./tag.js')
11const { log } = require('proc-log')
12
13const runScript = require('@npmcli/run-script')
14
15module.exports = async (newversion, opts) => {
16 const {
17 path,
18 allowSameVersion,
19 gitTagVersion,
20 ignoreScripts,
21 preid,
22 pkg,
23 } = opts
24
25 const { valid, clean, inc } = semver
26 const current = pkg.version || '0.0.0'
27 const currentClean = clean(current)
28
29 let newV
30 if (valid(newversion, { loose: true })) {
31 newV = clean(newversion, { loose: true })
32 } else if (newversion === 'from-git') {
33 newV = await retrieveTag(opts)
34 } else {
35 newV = inc(currentClean, newversion, { loose: true }, preid)
36 }
37
38 if (!newV) {
39 throw Object.assign(new Error('Invalid version: ' + newversion), {
40 current,
41 requested: newversion,
42 })
43 }
44
45 if (newV === currentClean && !allowSameVersion) {
46 throw Object.assign(new Error('Version not changed'), {
47 current,
48 requested: newversion,
49 newVersion: newV,
50 })
51 }
52
53 const isGitDir = newversion === 'from-git' || await git.is(opts)
54
55 // ok! now we know the new version, and the old version is in pkg
56
57 // - check if git dir is clean
58 // returns false if we should not keep doing git stuff
59 const doGit = gitTagVersion && isGitDir && await enforceClean(opts)
60
61 if (!ignoreScripts) {
62 await runScript({
63 ...opts,
64 pkg,
65 stdio: 'inherit',
66 event: 'preversion',
67 env: {
68 npm_old_version: current,
69 npm_new_version: newV,
70 },
71 })
72 }
73
74 // - update the files
75 pkg.version = newV
76 delete pkg._id
77 await writeJson(`${path}/package.json`, pkg)
78
79 // try to update shrinkwrap, but ok if this fails
80 const locks = [`${path}/package-lock.json`, `${path}/npm-shrinkwrap.json`]
81 const haveLocks = []
82 for (const lock of locks) {
83 try {
84 const sw = await readJson(lock)
85 sw.version = newV
86 if (sw.packages && sw.packages['']) {
87 sw.packages[''].version = newV
88 }
89 await writeJson(lock, sw)
90 haveLocks.push(lock)
91 } catch {
92 // ignore errors
93 }
94 }
95
96 if (!ignoreScripts) {
97 await runScript({
98 ...opts,
99 pkg,
100 stdio: 'inherit',
101 event: 'version',
102 env: {
103 npm_old_version: current,
104 npm_new_version: newV,
105 },
106 })
107 }
108
109 if (doGit) {
110 // - git add, git commit, git tag
111 await git.spawn(['add', `${path}/package.json`], opts)
112 // sometimes people .gitignore their lockfiles
113 for (const lock of haveLocks) {
114 await git.spawn(['add', lock], opts).catch(() => {})
115 }
116 await commit(newV, opts)
117 await tag(newV, opts)
118 } else {
119 log.verbose('version', 'Not tagging: not in a git repo or no git cmd')
120 }
121
122 if (!ignoreScripts) {
123 await runScript({
124 ...opts,
125 pkg,
126 stdio: 'inherit',
127 event: 'postversion',
128 env: {
129 npm_old_version: current,
130 npm_new_version: newV,
131 },
132 })
133 }
134
135 return newV
136}
137 