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