From d825e901eceea4cf8d860e35238dc30008eb4da4 Mon Sep 17 00:00:00 2001 From: isaacs Date: Wed, 9 Dec 2020 14:17:36 -0800 Subject: [PATCH] ci: run install scripts for root project `npm ci` should run all the same preinstall/install/postinstall/prepare scripts for the root project just like `npm install`. Fixes: #1905 PR-URL: https://github.com/npm/cli/pull/2316 Credit: @isaacs Close: #2316 Reviewed-by: @ruyadorno --- lib/ci.js | 23 +++++++++++++++++++++++ test/lib/ci.js | 19 ++++++++++++++++++- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/lib/ci.js b/lib/ci.js index 1255fbc2646fd..2917899c82551 100644 --- a/lib/ci.js +++ b/lib/ci.js @@ -2,6 +2,7 @@ const util = require('util') const Arborist = require('@npmcli/arborist') const rimraf = util.promisify(require('rimraf')) const reifyFinish = require('./utils/reify-finish.js') +const runScript = require('@npmcli/run-script') const log = require('npmlog') const npm = require('./npm.js') @@ -20,6 +21,7 @@ const ci = async () => { } const where = npm.prefix + const { scriptShell } = npm.flatOptions const arb = new Arborist({ ...npm.flatOptions, path: where }) await Promise.all([ @@ -35,6 +37,27 @@ const ci = async () => { ]) // npm ci should never modify the lockfile or package.json await arb.reify({ ...npm.flatOptions, save: false }) + + // run the same set of scripts that `npm install` runs. + const scripts = [ + 'preinstall', + 'install', + 'postinstall', + 'prepublish', // XXX should we remove this finally?? + 'preprepare', + 'prepare', + 'postprepare', + ] + for (const event of scripts) { + await runScript({ + path: where, + args: [], + scriptShell, + stdio: 'inherit', + stdioString: true, + event, + }) + } await reifyFinish(arb) } diff --git a/test/lib/ci.js b/test/lib/ci.js index 8ddb8f8aad23c..c32fb83279a41 100644 --- a/test/lib/ci.js +++ b/test/lib/ci.js @@ -6,7 +6,16 @@ const { test } = require('tap') const requireInject = require('require-inject') -test('should use Arborist', (t) => { +test('should use Arborist and run-script', (t) => { + const scripts = [ + 'preinstall', + 'install', + 'postinstall', + 'prepublish', // XXX should we remove this finally?? + 'preprepare', + 'prepare', + 'postprepare', + ] const ci = requireInject('../../lib/ci.js', { '../../lib/npm.js': { prefix: 'foo', @@ -15,6 +24,9 @@ test('should use Arborist', (t) => { }, }, '../../lib/utils/reify-finish.js': async () => {}, + '@npmcli/run-script': opts => { + t.match(opts, { event: scripts.shift() }) + }, '@npmcli/arborist': function (args) { t.ok(args, 'gets options object') this.loadVirtual = () => { @@ -40,6 +52,7 @@ test('should use Arborist', (t) => { ci(null, er => { if (er) throw er + t.strictSame(scripts, [], 'called all scripts') t.end() }) }) @@ -53,6 +66,7 @@ test('should pass flatOptions to Arborist.reify', (t) => { }, }, '../../lib/utils/reify-finish.js': async () => {}, + '@npmcli/run-script': opts => {}, '@npmcli/arborist': function () { this.loadVirtual = () => Promise.resolve(true) this.reify = async (options) => { @@ -80,6 +94,7 @@ test('should throw if package-lock.json or npm-shrinkwrap missing', (t) => { global: false, }, }, + '@npmcli/run-script': opts => {}, '../../lib/utils/reify-finish.js': async () => {}, npmlog: { verbose: () => { @@ -102,6 +117,7 @@ test('should throw ECIGLOBAL', (t) => { global: true, }, }, + '@npmcli/run-script': opts => {}, '../../lib/utils/reify-finish.js': async () => {}, }) ci(null, (err, res) => { @@ -125,6 +141,7 @@ test('should remove existing node_modules before installing', (t) => { global: false, }, }, + '@npmcli/run-script': opts => {}, '../../lib/utils/reify-finish.js': async () => {}, '@npmcli/arborist': function () { this.loadVirtual = () => Promise.resolve(true)