From f48e7e3cb81d5e29904feaea26d5b128beab630d Mon Sep 17 00:00:00 2001 From: Ke Wu Date: Mon, 13 Feb 2023 11:46:05 +0800 Subject: [PATCH] feat: installation lifecycle scripts (#448) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: 天玎 --- lib/download/npm.js | 3 +- lib/format_install_options.js | 4 +- lib/global_install.js | 4 +- lib/install_package.js | 12 +- lib/lifecycle_scripts.js | 86 +++++++++++++++ lib/local_install.js | 121 +++------------------ lib/postinstall.js | 44 -------- lib/postuninstall.js | 17 --- lib/preinstall.js | 22 ---- lib/prepare.js | 20 ---- lib/prepublish.js | 20 ---- lib/preuninstall.js | 23 ---- lib/uninstall.js | 4 - lib/utils.js | 8 +- package.json | 5 +- test/fixtures/npm_package_env/package.json | 4 +- test/fixtures/postinstall/package.json | 3 +- test/fixtures/same-bin-name/package.json | 5 +- test/installGlobal.test.js | 1 - test/installLocal.test.js | 10 +- test/postInstallError.test.js | 6 +- test/postinstall.test.js | 22 ---- test/runscript-with-egg-doctools.test.js | 4 +- test/runscript-with-mocha.test.js | 4 +- 24 files changed, 138 insertions(+), 314 deletions(-) create mode 100644 lib/lifecycle_scripts.js delete mode 100644 lib/postinstall.js delete mode 100644 lib/postuninstall.js delete mode 100644 lib/preinstall.js delete mode 100644 lib/prepare.js delete mode 100644 lib/prepublish.js delete mode 100644 lib/preuninstall.js diff --git a/lib/download/npm.js b/lib/download/npm.js index cd4d351b..0efc03c7 100644 --- a/lib/download/npm.js +++ b/lib/download/npm.js @@ -13,7 +13,6 @@ const chalk = require('chalk'); const moment = require('moment'); const os = require('os'); const semver = require('semver'); -const utility = require('utility'); const { family: getLibcFamily } = require('detect-libc'); const get = require('../get'); const utils = require('../utils'); @@ -153,7 +152,7 @@ async function _getCacheInfo(fullname, globalOptions) { if (!globalOptions.cacheDir) { return info; } - const hash = utility.md5(info.pkgUrl); + const hash = crypto.createHash('md5').update(info.pkgUrl).digest('hex'); const parentDir = path.join(globalOptions.cacheDir, 'manifests', hash[0], hash[1], hash[2]); // { etag, age, headers, manifests } info.cacheFile = path.join(parentDir, `${hash}.json`); diff --git a/lib/format_install_options.js b/lib/format_install_options.js index bf9a0fdc..3be03e52 100644 --- a/lib/format_install_options.js +++ b/lib/format_install_options.js @@ -20,8 +20,8 @@ module.exports = function formatInstallOptions(options) { // close EventEmitter memory leak warning options.events.setMaxListeners(0); options.events.await = awaitEvent; - - options.postInstallTasks = []; + options.runscriptCount = 0; + options.runscriptTime = 0; // [ // {package: pkg, parentDir: 'parentDir', packageDir: 'packageDir'}, // ... diff --git a/lib/global_install.js b/lib/global_install.js index 13b56270..d2f16038 100644 --- a/lib/global_install.js +++ b/lib/global_install.js @@ -3,8 +3,8 @@ */ const path = require('path'); -const utility = require('utility'); const fs = require('fs/promises'); +const crypto = require('crypto'); const chalk = require('chalk'); const npa = require('./npa'); const installLocal = require('./local_install'); @@ -31,7 +31,7 @@ module.exports = async (options, context) => { } = pkg; let name = alias || pkgName; if (!name) { - name = utility.md5(version); + name = crypto.createHash('md5').update(version).digest('hex'); } // compatibility: delete old store dir diff --git a/lib/install_package.js b/lib/install_package.js index 47fd60e8..332f778f 100644 --- a/lib/install_package.js +++ b/lib/install_package.js @@ -3,10 +3,9 @@ const path = require('path'); const chalk = require('chalk'); const semver = require('semver'); const pMap = require('p-map'); +const os = require('os'); const download = require('./download'); const utils = require('./utils'); -const postinstall = require('./postinstall'); -const preinstall = require('./preinstall'); const npa = require('./npa'); const bin = require('./bin'); const link = require('./link'); @@ -15,6 +14,7 @@ const resolve = require('./download/npm').resolve; const { REGISTRY_TYPES, } = require('./npa_types'); +const { runLifecycleScripts } = require('./lifecycle_scripts'); module.exports = install; @@ -51,7 +51,7 @@ async function _install(parentDir, pkg, ancestors, options, context) { options.progresses.installTasks, pkg.name, pkg.version, parentDir); if (options.spinner) { - options.spinner.text = `[${options.progresses.finishedInstallTasks}/${options.progresses.installTasks}] Installing ${pkg.name}@${pkg.version}`; + options.spinner.text = `[${options.progresses.finishedInstallTasks}/${options.progresses.installTasks}] Installing ${pkg.name}@${pkg.version}${os.EOL}`; } let p = npa(pkg.name ? `${pkg.name}@${pkg.version}` : pkg.version, { where: options.root, nested: context.nested }); const displayName = p.displayName = utils.getDisplayName(pkg, ancestors); @@ -214,7 +214,6 @@ async function _install(parentDir, pkg, ancestors, options, context) { } } - await preinstall(realPkg, realPkgDir, displayName, options); // link bundleDependencies' bin // npminstall fsevents const bundledDependencies = await getBundleDependencies(realPkg, realPkgDir); @@ -292,7 +291,6 @@ async function _install(parentDir, pkg, ancestors, options, context) { } // FIXME: run postinstall before link may cause incompatible error. see // arborist/reify.js#steps._build, npm runs postinstall after unpacking. - await postinstall(realPkg, realPkgDir, pkg.optional, displayName, options); } catch (err) { // delete donefile when install error, make sure this package won't be skipped during next installation. try { @@ -316,6 +314,10 @@ async function _install(parentDir, pkg, ancestors, options, context) { realPkg.version, realPkgDir); + if (!options.ignoreScripts) { + await runLifecycleScripts(realPkg, realPkgDir, pkg, displayName, options); + } + return { exists: false, dir: realPkgDir, diff --git a/lib/lifecycle_scripts.js b/lib/lifecycle_scripts.js new file mode 100644 index 00000000..56a3c534 --- /dev/null +++ b/lib/lifecycle_scripts.js @@ -0,0 +1,86 @@ +const chalk = require('chalk'); +const path = require('path'); +const os = require('os'); +const npa = require('npm-package-arg'); +const ms = require('ms'); +const { LOCAL_TYPES } = require('./npa_types'); +const utils = require('./utils'); + +// scripts that should run in root package and linked package +exports.DEFAULT_ROOT_SCRIPTS = [ + 'preinstall', + 'install', + 'postinstall', + 'prepublish', + 'preprepare', + 'prepare', + 'postprepare', +]; + +// scripts that should run in dependencies +exports.DEFAULT_DEP_SCRIPTS = [ + 'preinstall', + 'install', + 'postinstall', +]; + +exports.runLifecycleScripts = async function runLifecycleScripts(pkg, root, originPkg, displayName, options) { + const scripts = pkg.scripts || {}; + + // https://docs.npmjs.com/misc/scripts#default-values + // "install": "node-gyp rebuild" + // If there is a binding.gyp file in the root of your package, + // npm will default the install command to compile using node-gyp. + if (!scripts.install && (await utils.exists(path.join(root, 'binding.gyp')))) { + options.console.warn( + '[npminstall:runscript] %s found binding.gyp file, auto run "node-gyp rebuild", root: %j', + displayName, root + ); + scripts.install = 'node-gyp rebuild'; + } + + let scriptList = exports.DEFAULT_DEP_SCRIPTS; + + if (root === options.root || LOCAL_TYPES.includes(npa(`${originPkg.name}@${originPkg.version}`).type)) { + scriptList = exports.DEFAULT_ROOT_SCRIPTS; + } + + for (const script of scriptList) { + const cmd = scripts[script]; + if (!cmd) { + continue; + } + + console.info( + '> %s %s %s %s> %s', + displayName, + script, + root, + os.EOL, + cmd + ); + const startTime = Date.now(); + try { + await utils.runScript(root, cmd, options); + } catch (error) { + options.console.warn('[npminstall:runscript:error] %s run %s %s error: %s', chalk.red(displayName), script, cmd, error); + // If post install execute error, make sure this package won't be skipped during next installation. + try { + await utils.unsetInstallDone(root); + } catch (e) { + options.console.warn(chalk.yellow(`unsetInstallDone: ${root} error: ${e}, ignore it`)); + } + if (originPkg.optional) { + options.console.warn(chalk.red('%s optional error: %s'), displayName, error.stack); + continue; + } + error.message = `run ${script} error, please remove node_modules before retry!\n${error.message}`; + throw error; + } finally { + const ts = Date.now() - startTime; + console.info('> %s %s, finished in %s', displayName, script, ms(ts)); + options.runscriptCount += 1; + options.runscriptTime += ts; + } + } +}; diff --git a/lib/local_install.js b/lib/local_install.js index 50f6c1b6..8ca374a2 100644 --- a/lib/local_install.js +++ b/lib/local_install.js @@ -15,15 +15,12 @@ const { writeFileSync } = require('fs'); const moment = require('moment'); const util = require('util'); const utils = require('./utils'); -const postinstall = require('./postinstall'); -const preinstall = require('./preinstall'); -const prepublish = require('./prepublish'); -const prepare = require('./prepare'); const installPackage = require('./install_package'); const dependencies = require('./dependencies'); const createResolution = require('./resolution'); const formatInstallOptions = require('./format_install_options'); const Context = require('./context'); +const { runLifecycleScripts } = require('./lifecycle_scripts'); /** * npm install @@ -102,8 +99,6 @@ module.exports = async (options, context = new Context()) => { } }; -exports.runPostInstallTasks = runPostInstallTasks; - async function _install(options, context) { const rootPkgFile = path.join(options.root, 'package.json'); const rootPkg = await utils.readJSON(rootPkgFile); @@ -133,10 +128,6 @@ async function _install(options, context) { } } - // trigger root project's preinstall hook only when executing a full installation. - // e.g. calling npminstall with no arguments - if (options.installRoot) await preinstall(rootPkg, options.root, displayName, options); - context.nested.update(pkgs.map(pkg => `${pkg.name}@${pkg.version}`), rootPkg.name && rootPkg.version ? displayName : 'root'); const nodeModulesDir = path.join(options.targetDir, 'node_modules'); await utils.mkdirp(nodeModulesDir); @@ -151,7 +142,6 @@ async function _install(options, context) { // multi-thread installation await pMap(pkgs, mapper, 10); options.downloadFinished = Date.now(); - options.spinner && options.spinner.succeed(`Installed ${pkgs.length} packages on ${options.root}`); if (!options.disableFallbackStore) { // link every packages' latest version to /node_modules/.store/node_modules, fallback for peerDeps @@ -173,18 +163,9 @@ async function _install(options, context) { } } - // run postinstall script if exist - if (options.installRoot) await postinstall(rootPkg, options.root, false, displayName, options); - // run dependencies' postinstall scripts - await runPostInstallTasks(options); - - // local install trigger prepublish / prepare when no packages and non-production mode - // prepare is run after prepublish - // see: - // - https://docs.npmjs.com/misc/scripts - // - https://github.com/npm/npm/issues/3059#issuecomment-32057292 - if (options.installRoot && !options.production) await prepublish(rootPkg, options.root, options); - if (options.installRoot && !options.production) await prepare(rootPkg, options.root, options); + if (options.installRoot && !options.ignoreScripts) { + await runLifecycleScripts(rootPkg, options.root, { optional: false }, displayName, options); + } // link peerDependencies if not match the version in target directory await linkPeer(options); @@ -201,6 +182,16 @@ async function _install(options, context) { // record dependencies tree resolved from npm recordDependenciesTree(options); + if (!options.ignoreScripts && options.runscriptCount > 0) { + const runscriptInfo = util.format('Run %s script(s) in %s.', options.runscriptCount, ms(options.runscriptTime)); + if (options.spinner) { + options.spinner.succeed(runscriptInfo); + } else { + console.info(runscriptInfo); + } + } + + options.spinner?.succeed(`Installed ${pkgs.length} packages on ${options.root}`); // print install finished finishInstall(options); @@ -398,90 +389,6 @@ async function linkLatestVersion(pkg, storeDir, options, isFallback = false) { pkg.name, pkg.version, linkDir, relative); } -async function runPostInstallTasks(options) { - let count = 0; - const total = options.postInstallTasks.length; - if (total && options.ignoreScripts) { - options.console.warn(chalk.yellow('ignore all post install scripts')); - return; - } - - if (total) { - options.console.log(chalk.yellow(`execute post install ${total} scripts...`)); - } - - for (const task of options.postInstallTasks) { - count++; - const pkg = task.pkg; - const root = task.root; - const displayName = task.displayName; - const installScript = pkg.scripts.install; - const postinstallScript = pkg.scripts.postinstall; - try { - if (installScript) { - options.console.warn( - '%s %s run %j, root: %j', - chalk.yellow(`[${count}/${total}] scripts.install`), - chalk.gray(displayName), - installScript, - root - ); - const start = Date.now(); - try { - await utils.runScript(root, installScript, options); - } catch (err) { - options.console.warn('[npminstall:runscript:error] %s scripts.install run %j error: %s', - chalk.red(displayName), installScript, err); - throw err; - } - options.console.warn( - '%s %s finished in %s', - chalk.yellow(`[${count}/${total}] scripts.install`), - chalk.gray(displayName), - ms(Date.now() - start) - ); - } - if (postinstallScript) { - options.console.warn( - '%s %s run %j, root: %j', - chalk.yellow(`[${count}/${total}] scripts.postinstall`), - chalk.gray(displayName), - postinstallScript, - root - ); - const start = Date.now(); - try { - await utils.runScript(root, postinstallScript, options); - } catch (err) { - options.console.warn('[npminstall:runscript:error] %s scripts.postinstall run %j error: %s', - chalk.red(displayName), postinstallScript, err); - throw err; - } - options.console.warn( - '%s %s finished in %s', - chalk.yellow(`[${count}/${total}] scripts.postinstall`), - chalk.gray(displayName), - ms(Date.now() - start) - ); - } - } catch (err) { - // If post install execute error, make sure this package won't be skipped during next installation. - try { - await utils.unsetInstallDone(root); - } catch (e) { - options.console.warn(chalk.yellow(`unsetInstallDone: ${root} error: ${e}, ignore it`)); - } - if (task.optional) { - console.warn(chalk.red('%s optional error: %s'), displayName, err.stack); - continue; - } - err.message = `post install error, please remove node_modules before retry!\n${err.message}`; - throw err; - } - } - options.spinner && options.spinner.succeed(`Run ${options.postInstallTasks.length} scripts`); -} - function printPendingMessages(options) { for (const item of options.pendingMessages) { if (options.console[item[0]] && options.console[item[0]] !== debug) { diff --git a/lib/postinstall.js b/lib/postinstall.js deleted file mode 100644 index a9cc6c29..00000000 --- a/lib/postinstall.js +++ /dev/null @@ -1,44 +0,0 @@ -const chalk = require('chalk'); -const path = require('path'); -const utils = require('./utils'); - -module.exports = postinstall; - -// @see https://docs.npmjs.com/misc/scripts -// npminstall will collect all install & postinstall scripts, -// and run these scripts until all dependencies installed -// node-gyp rebuild don't dependent on other packages, so we can run it immediately -async function postinstall(pkg, root, optional, displayName, options) { - const scripts = pkg.scripts || {}; - - // https://docs.npmjs.com/misc/scripts#default-values - // "install": "node-gyp rebuild" - // If there is a binding.gyp file in the root of your package, - // npm will default the install command to compile using node-gyp. - if (!scripts.install && (await utils.exists(path.join(root, 'binding.gyp')))) { - options.console.warn( - '[npminstall:runscript] %s found binding.gyp file, auto run "node-gyp rebuild", root: %j', - chalk.gray(displayName), root - ); - const cmd = 'node-gyp rebuild'; - try { - await utils.runScript(root, cmd, options); - } catch (err) { - options.console.warn('[npminstall:runscript:error] %s has binding.gyp file, run %j error: %s', - chalk.red(displayName), cmd, err); - throw err; - } - } - - if (scripts.install || scripts.postinstall) { - if (options.postInstallTasks.some(task => task.root === root)) { - return; - } - options.postInstallTasks.push({ - pkg, - root, - optional, - displayName, - }); - } -} diff --git a/lib/postuninstall.js b/lib/postuninstall.js deleted file mode 100644 index 6fabd021..00000000 --- a/lib/postuninstall.js +++ /dev/null @@ -1,17 +0,0 @@ -const chalk = require('chalk'); -const runScript = require('./utils').runScript; - -module.exports = postuninstall; - -// @see https://docs.npmjs.com/misc/scripts -async function postuninstall(pkg, root, options) { - const scripts = pkg.scripts || {}; - if (scripts.postuninstall) { - options.console.warn(chalk.yellow('[npminstall:runscript] [%s@%s]%s scripts.postuninstall: %j, root: %j'), - pkg.name, pkg.version, options.ignoreScripts ? ' ignore' : '', scripts.postuninstall, options.root); - if (!options.ignoreScripts) { - // root is removed - await runScript(options.root, scripts.postuninstall, options); - } - } -} diff --git a/lib/preinstall.js b/lib/preinstall.js deleted file mode 100644 index 0264cd00..00000000 --- a/lib/preinstall.js +++ /dev/null @@ -1,22 +0,0 @@ -const chalk = require('chalk'); -const runScript = require('./utils').runScript; - -module.exports = preinstall; - -// @see https://docs.npmjs.com/misc/scripts -async function preinstall(pkg, root, displayName, options) { - const scripts = pkg.scripts || {}; - if (scripts.preinstall) { - options.console.warn( - '[npminstall:runscript] %s %s %s %j, root: %j', - chalk.yellow('scripts.preinstall'), - chalk.gray(displayName), - chalk.yellow(options.ignoreScripts ? ' ignore' : ''), - scripts.preinstall, - root - ); - if (!options.ignoreScripts) { - await runScript(root, scripts.preinstall, options); - } - } -} diff --git a/lib/prepare.js b/lib/prepare.js deleted file mode 100644 index 3c5e052e..00000000 --- a/lib/prepare.js +++ /dev/null @@ -1,20 +0,0 @@ -const chalk = require('chalk'); -const runScript = require('./utils').runScript; - -module.exports = prepare; - -// @see https://docs.npmjs.com/misc/scripts -// Run BEFORE the package is pack or publish. (Also run on local npm install without any arguments.) -async function prepare(pkg, root, options) { - const scripts = pkg.scripts || {}; - if (scripts.prepare) { - options.console.warn( - '[npminstall:runscript] %s %s %j, root: %j', - chalk.yellow('scripts.prepare'), - chalk.gray(`${pkg.name}@${pkg.version}`), - scripts.prepare, - root - ); - await runScript(root, scripts.prepare, options); - } -} diff --git a/lib/prepublish.js b/lib/prepublish.js deleted file mode 100644 index 24f41f24..00000000 --- a/lib/prepublish.js +++ /dev/null @@ -1,20 +0,0 @@ -const chalk = require('chalk'); -const runScript = require('./utils').runScript; - -module.exports = prepublish; - -// @see https://docs.npmjs.com/misc/scripts -// Run BEFORE the package is published. (Also run on local npm install without any arguments.) -async function prepublish(pkg, root, options) { - const scripts = pkg.scripts || {}; - if (scripts.prepublish) { - options.console.warn( - '[npminstall:runscript] %s %s %j, root: %j', - chalk.yellow('scripts.prepublish'), - chalk.gray(`${pkg.name}@${pkg.version}`), - scripts.prepublish, - root - ); - await runScript(root, scripts.prepublish, options); - } -} diff --git a/lib/preuninstall.js b/lib/preuninstall.js deleted file mode 100644 index 1fb011d7..00000000 --- a/lib/preuninstall.js +++ /dev/null @@ -1,23 +0,0 @@ -const chalk = require('chalk'); -const runScript = require('./utils').runScript; - -module.exports = preuninstall; - -// @see https://docs.npmjs.com/misc/scripts -async function preuninstall(pkg, root, options) { - const scripts = pkg.scripts || {}; - if (scripts.preuninstall) { - options.console.warn(chalk.yellow('[npminstall:runscript] [%s@%s]%s scripts.preuninstall: %j'), - pkg.name, pkg.version, options.ignoreScripts ? ' ignore' : '', scripts.preuninstall); - if (!options.ignoreScripts) { - await runScript(root, scripts.preuninstall, options); - } - } - if (scripts.uninstall) { - options.console.warn(chalk.yellow('[npminstall:runscript] [%s@%s]%s scripts.uninstall: %j'), - pkg.name, pkg.version, options.ignoreScripts ? ' ignore' : '', scripts.uninstall); - if (!options.ignoreScripts) { - await runScript(root, scripts.uninstall, options); - } - } -} diff --git a/lib/uninstall.js b/lib/uninstall.js index 3dc8ec4b..563a717c 100644 --- a/lib/uninstall.js +++ b/lib/uninstall.js @@ -1,8 +1,6 @@ const path = require('path'); const chalk = require('chalk'); const utils = require('./utils'); -const preUninstall = require('./preuninstall'); -const postUninstall = require('./postuninstall'); module.exports = async options => { const pkgs = options.pkgs; @@ -22,13 +20,11 @@ module.exports = async options => { async function uninstall(pkg, options) { const pkgRoot = path.join(options.targetDir, 'node_modules', pkg.name); const pkgInfo = await utils.readJSON(path.join(pkgRoot, 'package.json')); - await preUninstall(pkgInfo, pkgRoot, options); await utils.rimraf(pkgRoot); const pkgFile = path.resolve(options.targetDir, 'package.json'); if (await utils.exists(pkgFile)) { await utils.pruneJSON(pkgFile, pkg.name); } - await postUninstall(pkgInfo, pkgRoot, options); const rootPrefix = options.workspaceRoot || options.root; options.console.log('%s %s %s', chalk.red('-'), diff --git a/lib/utils.js b/lib/utils.js index 237700e0..2d35a28b 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -11,13 +11,12 @@ const zlib = require('zlib'); const chalk = require('chalk'); const globby = require('globby'); const tar = require('tar'); -const runscript = require('runscript'); +const { command } = require('execa'); const homedir = require('node-homedir'); const fse = require('fs-extra'); const destroy = require('destroy'); const normalizeData = require('normalize-package-data'); const semver = require('semver'); -const utility = require('utility'); const globalConfig = require('./config'); const get = require('./get'); @@ -178,7 +177,7 @@ exports.formatPackageUrl = (registry, name) => { if (name[0] === '@') { // dont encodeURIComponent @ char, it will be 405 // https://registry.npmjs.com/%40rstacruz%2Ftap-spec/%3E%3D4.1.1 - name = '@' + utility.encodeURIComponent(name.substring(1)); + name = '@' + encodeURIComponent(name.substring(1)); } const parsed = url.parse(registry); if (parsed.pathname.endsWith('/')) { @@ -260,10 +259,11 @@ exports.runScript = async (pkgDir, script, options) => { } try { - return await runscript(script, { + return await command(script, { cwd: pkgDir, env, stdio: 'inherit', + shell: true, }); } catch (err) { if (ignoreError) { diff --git a/package.json b/package.json index 955eb63e..009d1480 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,7 @@ "chalk": "^2.4.2", "destroy": "^1.0.4", "detect-libc": "^2.0.1", + "execa": "^5.1.1", "fs-extra": "^7.0.1", "globby": "^11.1.0", "minimatch": "^3.0.4", @@ -51,11 +52,9 @@ "p-map": "^2.1.0", "pacote": "^15.0.0", "rc": "^1.2.8", - "runscript": "^1.3.0", "semver": "^7.0.0", "tar": "^6.0.0", - "urllib": "^3.0.3", - "utility": "^1.16.1" + "urllib": "^3.0.3" }, "devDependencies": { "assert-file": "^1.0.0", diff --git a/test/fixtures/npm_package_env/package.json b/test/fixtures/npm_package_env/package.json index 8ff2b5f3..b048d748 100644 --- a/test/fixtures/npm_package_env/package.json +++ b/test/fixtures/npm_package_env/package.json @@ -11,7 +11,9 @@ "engines": { "node": "~0.10.0 || ~0.12.0 || ^4.2.0", "foo": { - "bar": [ 1111 ] + "bar": [ + 1111 + ] } }, "greenkeeper": { diff --git a/test/fixtures/postinstall/package.json b/test/fixtures/postinstall/package.json index ceee670e..a9bf2693 100644 --- a/test/fixtures/postinstall/package.json +++ b/test/fixtures/postinstall/package.json @@ -11,6 +11,5 @@ "dependencies": { "utility": "1.6.0", "a-dep-b": "*" - }, - "__npminstall_done": false + } } diff --git a/test/fixtures/same-bin-name/package.json b/test/fixtures/same-bin-name/package.json index 828c1036..427824d7 100644 --- a/test/fixtures/same-bin-name/package.json +++ b/test/fixtures/same-bin-name/package.json @@ -1,4 +1,7 @@ { "name": "same-bin-name", - "version": "1.0.0" + "version": "1.0.0", + "dependencies": { + "webpack-parallel-uglify-plugin": "^1.0.0" + } } diff --git a/test/installGlobal.test.js b/test/installGlobal.test.js index c3cf3d27..45c550fc 100644 --- a/test/installGlobal.test.js +++ b/test/installGlobal.test.js @@ -89,7 +89,6 @@ describe('test/installGlobal.test.js', () => { .end(); assert(await exists(path.join(binDir, 'egg-bin'))); - assert(await exists(path.join(binDir, 'mocha'))); assert(await exists(path.join(libDir, 'node_modules/egg-bin'))); assert((await fs.stat(path.join(libDir, 'node_modules/egg-bin'))).isDirectory()); }); diff --git a/test/installLocal.test.js b/test/installLocal.test.js index b8ec92a0..cd978526 100644 --- a/test/installLocal.test.js +++ b/test/installLocal.test.js @@ -18,7 +18,7 @@ describe('test/installLocal.test.js', () => { await npminstall({ root, pkgs: [ - { name: null, version: 'file:pkg' }, + { name: 'test', version: 'file:pkg' }, ], }); const pkg = await helper.readJSON(path.join(root, 'node_modules/pkg/package.json')); @@ -30,7 +30,7 @@ describe('test/installLocal.test.js', () => { await npminstall({ root, pkgs: [ - { name: null, version: 'file:pkg' }, + { name: 'test', version: 'file:pkg' }, ], }); const pkg = await helper.readJSON(path.join(root, 'node_modules/pkg/package.json')); @@ -41,7 +41,7 @@ describe('test/installLocal.test.js', () => { await npminstall({ root, pkgs: [ - { name: null, version: './pkg' }, + { name: 'test', version: './pkg' }, ], }); const pkg = await helper.readJSON(path.join(root, 'node_modules/pkg/package.json')); @@ -55,7 +55,7 @@ describe('test/installLocal.test.js', () => { await npminstall({ root, pkgs: [ - { name: null, version: 'file:pkg-link' }, + { name: 'test', version: 'file:pkg-link' }, ], }); const pkg = await helper.readJSON(path.join(root, 'node_modules/pkg/package.json')); @@ -212,7 +212,7 @@ describe('test/installLocal.test.js', () => { await npminstall({ root, pkgs: [ - { name: null, version: 'file:pkg' }, + { name: 'test', version: 'file:pkg' }, ], }); let pkg = await helper.readJSON(path.join(root, 'node_modules/pkg/package.json')); diff --git a/test/postInstallError.test.js b/test/postInstallError.test.js index dd29d2bc..b53a58e5 100644 --- a/test/postInstallError.test.js +++ b/test/postInstallError.test.js @@ -21,7 +21,7 @@ describe('test/postInstallError.test.js', () => { ], }); } catch (err) { - assert(err.message.indexOf('post install error, please remove node_modules before retry!') >= 0); + assert(err.message.indexOf('run postinstall error, please remove node_modules before retry!') >= 0); throwError = true; } assert.equal(throwError, true); @@ -34,8 +34,8 @@ describe('test/postInstallError.test.js', () => { await coffee.fork(helper.npminstall, [ '--production' ], { cwd }) .debug() .expect('code', 0) - .expect('stderr', /httpsync@\* optional error: .*Error: Run ".*?build\.sh" error/) - .expect('stderr', /scripts.install httpsync@\* run "sh build.sh"/) + .expect('stderr', /httpsync@\* optional error: .*Error: Command failed with exit code \d+\: sh build\.sh/) + .expect('stderr', /httpsync@\* run install sh build.sh/) .expect('stdout', /All packages installed/) .end(); }); diff --git a/test/postinstall.test.js b/test/postinstall.test.js index 687d9863..d52cc380 100644 --- a/test/postinstall.test.js +++ b/test/postinstall.test.js @@ -35,28 +35,6 @@ describe('test/postinstall.test.js', () => { // prepare pass assert.equal(fs.readFileSync(path.join(root, 'node_modules', '.prepare.txt'), 'utf8'), 'success: prepare'); }); - - it('should not run prepublish with production mode', async () => { - await npminstall({ - root, - production: true, - }); - const pkg = await readJSON(path.join(root, 'node_modules', 'utility', 'package.json')); - assert.equal(pkg.name, 'utility'); - assert.equal(pkg.version, '1.6.0'); - - // postinstall pass - assert.equal(fs.readFileSync(path.join(root, 'node_modules', '.postinstall.txt'), 'utf8'), 'success: postinstall'); - - // prepublish pass - let hasFile = false; - try { - hasFile = !!fs.statSync(path.join(root, 'node_modules', '.prepublish.txt')); - } catch (err) { - // empty - } - assert.equal(hasFile, false); - }); }); if (semver.satisfies(process.version, '< 13.0.0')) { diff --git a/test/runscript-with-egg-doctools.test.js b/test/runscript-with-egg-doctools.test.js index e652ca97..4757f1bd 100644 --- a/test/runscript-with-egg-doctools.test.js +++ b/test/runscript-with-egg-doctools.test.js @@ -1,6 +1,6 @@ const assert = require('assert'); const path = require('path'); -const runScript = require('runscript'); +const { command } = require('execa'); const readJSON = require('../lib/utils').readJSON; const npminstall = require('./npminstall'); const helper = require('./helper'); @@ -20,7 +20,7 @@ describe('test/runscript-with-egg-doctools.test.js', () => { assert(pkg.name === 'egg-doctools'); const bin = path.join(root, 'node_modules', '.bin', 'doctools'); - const stdio = await runScript(`${bin} -V`, { stdio: 'pipe' }); + const stdio = await command(`${bin} -V`, { stdio: 'pipe' }); assert(stdio.stdout.toString().trim() === '2.9.0'); }); }); diff --git a/test/runscript-with-mocha.test.js b/test/runscript-with-mocha.test.js index a5d6b8ba..fddcd4da 100644 --- a/test/runscript-with-mocha.test.js +++ b/test/runscript-with-mocha.test.js @@ -1,7 +1,7 @@ const assert = require('assert'); const path = require('path'); const fs = require('fs/promises'); -const runScript = require('runscript'); +const { command } = require('execa'); const readJSON = require('../lib/utils').readJSON; const npminstall = require('./npminstall'); const helper = require('./helper'); @@ -24,7 +24,7 @@ describe('test/runscript-with-mocha.test.js', () => { if (process.platform === 'win32') { mochaBin = `${mochaBin}.cmd`; } - const stdio = await runScript(`${mochaBin} -V`, { stdio: 'pipe' }); + const stdio = await command(`${mochaBin} -V`, { stdio: 'pipe' }); assert(stdio.stdout.toString().trim() === '3.5.3'); const names = await fs.readdir(path.join(root, 'node_modules', '.bin')); console.log(names);