• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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