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