Welcome to mirror list, hosted at ThFree Co, Russian Federation.

publish.js « lib « npm « deps - github.com/nodejs/node.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 3e8df0076efa223284ae9bc61fafe424a5986ba9 (plain)
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
137
138
139
140
const util = require('util')
const log = require('npmlog')
const semver = require('semver')
const pack = require('libnpmpack')
const libpub = require('libnpmpublish').publish
const runScript = require('@npmcli/run-script')
const pacote = require('pacote')
const npa = require('npm-package-arg')
const npmFetch = require('npm-registry-fetch')

const npm = require('./npm.js')
const output = require('./utils/output.js')
const otplease = require('./utils/otplease.js')
const { getContents, logTar } = require('./utils/tar.js')

// this is the only case in the CLI where we use the old full slow
// 'read-package-json' module, because we want to pull in all the
// defaults and metadata, like git sha's and default scripts and all that.
const readJson = util.promisify(require('read-package-json'))

const completion = require('./utils/completion/none.js')
const usageUtil = require('./utils/usage.js')
const usage = usageUtil('publish',
  'npm publish [<folder>] [--tag <tag>] [--access <public|restricted>] [--dry-run]' +
  '\n\nPublishes \'.\' if no argument supplied' +
  '\nSets tag `latest` if no --tag specified')

const cmd = (args, cb) => publish(args).then(() => cb()).catch(cb)

const publish = async args => {
  if (args.length === 0)
    args = ['.']
  if (args.length !== 1)
    throw usage

  log.verbose('publish', args)

  const opts = { ...npm.flatOptions }
  const { json, defaultTag } = opts

  if (semver.validRange(defaultTag))
    throw new Error('Tag name must not be a valid SemVer range: ' + defaultTag.trim())

  const tarball = await publish_(args[0], opts)
  const silent = log.level === 'silent'
  if (!silent && json)
    output(JSON.stringify(tarball, null, 2))
  else if (!silent)
    output(`+ ${tarball.id}`)

  return tarball
}

// if it's a directory, read it from the file system
// otherwise, get the full metadata from whatever it is
const getManifest = (spec, opts) =>
  spec.type === 'directory' ? readJson(`${spec.fetchSpec}/package.json`)
  : pacote.manifest(spec, { ...opts, fullMetadata: true })

// for historical reasons, publishConfig in package.json can contain
// ANY config keys that npm supports in .npmrc files and elsewhere.
// We *may* want to revisit this at some point, and have a minimal set
// that's a SemVer-major change that ought to get a RFC written on it.
const { flatten } = require('./utils/flat-options.js')
const publishConfigToOpts = publishConfig =>
  // create a new object that inherits from the config stack
  // then squash the css-case into camelCase opts, like we do
  flatten(Object.assign(Object.create(npm.config.list[0]), publishConfig))

const publish_ = async (arg, opts) => {
  const { unicode, dryRun, json } = opts
  // you can publish name@version, ./foo.tgz, etc.
  // even though the default is the 'file:.' cwd.
  const spec = npa(arg)

  let manifest = await getManifest(spec, opts)

  if (manifest.publishConfig)
    Object.assign(opts, publishConfigToOpts(manifest.publishConfig))

  // only run scripts for directory type publishes
  if (spec.type === 'directory') {
    await runScript({
      event: 'prepublishOnly',
      path: spec.fetchSpec,
      stdio: 'inherit',
      pkg: manifest,
      banner: log.level !== 'silent',
    })
  }

  const tarballData = await pack(spec, opts)
  const pkgContents = await getContents(manifest, tarballData)

  // The purpose of re-reading the manifest is in case it changed,
  // so that we send the latest and greatest thing to the registry
  // note that publishConfig might have changed as well!
  manifest = await getManifest(spec, opts)
  if (manifest.publishConfig)
    Object.assign(opts, publishConfigToOpts(manifest.publishConfig))

  // note that logTar calls npmlog.notice(), so if we ARE in silent mode,
  // this will do nothing, but we still want it in the debuglog if it fails.
  if (!json)
    logTar(pkgContents, { log, unicode })

  if (!dryRun) {
    const resolved = npa.resolve(manifest.name, manifest.version)
    const registry = npmFetch.pickRegistry(resolved, opts)
    const creds = npm.config.getCredentialsByURI(registry)
    if (!creds.token && !creds.username) {
      throw Object.assign(new Error('This command requires you to be logged in.'), {
        code: 'ENEEDAUTH',
      })
    }
    await otplease(opts, opts => libpub(manifest, tarballData, opts))
  }

  if (spec.type === 'directory') {
    await runScript({
      event: 'publish',
      path: spec.fetchSpec,
      stdio: 'inherit',
      pkg: manifest,
      banner: log.level !== 'silent',
    })

    await runScript({
      event: 'postpublish',
      path: spec.fetchSpec,
      stdio: 'inherit',
      pkg: manifest,
      banner: log.level !== 'silent',
    })
  }

  return pkgContents
}

module.exports = Object.assign(cmd, { usage, completion })