()
| 38 | ] |
| 39 | |
| 40 | async exec () { |
| 41 | if (this.npm.global) { |
| 42 | throw Object.assign(new Error('`npm ci` does not work for global packages'), { |
| 43 | code: 'ECIGLOBAL', |
| 44 | }) |
| 45 | } |
| 46 | |
| 47 | const dryRun = this.npm.config.get('dry-run') |
| 48 | const ignoreScripts = this.npm.config.get('ignore-scripts') |
| 49 | const where = this.npm.prefix |
| 50 | const Arborist = require('@npmcli/arborist') |
| 51 | const { policy: allowScriptsPolicy } = await resolveAllowScripts(this.npm) |
| 52 | const opts = { |
| 53 | ...this.npm.flatOptions, |
| 54 | packageLock: true, // npm ci should never skip lock files |
| 55 | path: where, |
| 56 | save: false, // npm ci should never modify the lockfile or package.json |
| 57 | workspaces: this.workspaceNames, |
| 58 | allowScripts: allowScriptsPolicy, |
| 59 | } |
| 60 | |
| 61 | // generate an inventory from the virtual tree in the lockfile |
| 62 | const virtualArb = new Arborist(opts) |
| 63 | try { |
| 64 | await virtualArb.loadVirtual() |
| 65 | } catch (err) { |
| 66 | log.verbose('loadVirtual', err.stack) |
| 67 | const msg = |
| 68 | 'The `npm ci` command can only install with an existing package-lock.json or\n' + |
| 69 | 'npm-shrinkwrap.json with lockfileVersion >= 1. Run an install with npm@5 or\n' + |
| 70 | 'later to generate a package-lock.json file, then try again.' |
| 71 | throw this.usageError(msg) |
| 72 | } |
| 73 | const virtualInventory = new Map(virtualArb.virtualTree.inventory) |
| 74 | |
| 75 | // Now we make our real Arborist. |
| 76 | // We need a new one because the virtual tree fromt the lockfile can have extraneous dependencies in it that won't install on this platform |
| 77 | const arb = new Arborist(opts) |
| 78 | await arb.buildIdealTree() |
| 79 | await strictAllowScriptsPreflight({ arb, npm: this.npm, idealTreeOpts: opts }) |
| 80 | |
| 81 | // Verifies that the packages from the ideal tree will match the same versions that are present in the virtual tree (lock file). |
| 82 | const errors = validateLockfile(virtualInventory, arb.idealTree.inventory) |
| 83 | if (errors.length) { |
| 84 | throw this.usageError( |
| 85 | '`npm ci` can only install packages when your package.json and package-lock.json or npm-shrinkwrap.json are in sync. ' + |
| 86 | 'Please update your lock file with `npm install` before continuing.\n\n' + |
| 87 | errors.join('\n') |
| 88 | ) |
| 89 | } |
| 90 | |
| 91 | if (!dryRun) { |
| 92 | const workspacePaths = await getWorkspaces([], { |
| 93 | path: this.npm.localPrefix, |
| 94 | includeWorkspaceRoot: true, |
| 95 | }) |
| 96 | |
| 97 | // Only remove node_modules after we've successfully loaded the virtual tree and validated the lockfile |
nothing calls this directly
no test coverage detected