diff --git a/lib/verify-auth.js b/lib/verify-auth.js index d4605632..00f4ba44 100644 --- a/lib/verify-auth.js +++ b/lib/verify-auth.js @@ -5,6 +5,8 @@ const getError = require('./get-error'); const getRegistry = require('./get-registry'); const setNpmrcAuth = require('./set-npmrc-auth'); +const memo = {}; + module.exports = async (npmrc, pkg, context) => { const { cwd, @@ -17,12 +19,20 @@ module.exports = async (npmrc, pkg, context) => { await setNpmrcAuth(npmrc, registry, context); if (normalizeUrl(registry) === normalizeUrl(DEFAULT_NPM_REGISTRY)) { + const key = npmrc + registry; + if (memo[key]) { + return memo[key]; + } + try { const whoamiResult = execa('npm', ['whoami', '--userconfig', npmrc, '--registry', registry], {cwd, env}); whoamiResult.stdout.pipe(stdout, {end: false}); whoamiResult.stderr.pipe(stderr, {end: false}); + + memo[key] = whoamiResult; await whoamiResult; } catch { + memo[key] = undefined; throw new AggregateError([getError('EINVALIDNPMTOKEN', {registry})]); } } diff --git a/test/verify-auth.test.js b/test/verify-auth.test.js new file mode 100644 index 00000000..ea9fd469 --- /dev/null +++ b/test/verify-auth.test.js @@ -0,0 +1,43 @@ +const test = require('ava'); +const {stub} = require('sinon'); +const tempy = require('tempy'); + +const getRegistryPath = require.resolve('../lib/get-registry'); +const verifyAuthPath = require.resolve('../lib/verify-auth'); +const setNmprcAuthPath = require.resolve('../lib/set-npmrc-auth'); +const execaPath = require.resolve('execa'); + +const resetModuleCache = () => { + require.cache[getRegistryPath] = undefined; + require.cache[verifyAuthPath] = undefined; + require.cache[setNmprcAuthPath] = undefined; + require.cache[execaPath] = undefined; +}; + +test.before(resetModuleCache); +test.after(resetModuleCache); + +test('Verify `npm-whoami` calls memoization', async (t) => { + const pkg = {}; + const context = {cwd: tempy.directory(), env: {}}; + const fakeExeca = stub().returns({stdout: {pipe() {}}, stderr: {pipe() {}}}); + + require.cache[getRegistryPath] = {id: getRegistryPath, exports: () => 'https://registry.npmjs.org/'}; + require.cache[setNmprcAuthPath] = {id: setNmprcAuthPath, exports: () => {}}; + require.cache[execaPath] = {id: execaPath, exports: fakeExeca}; + + const verifyAuth = require('../lib/verify-auth'); + + await verifyAuth('foo', pkg, context); + await verifyAuth('foo', pkg, context); + await verifyAuth('foo', pkg, context); + + t.assert(fakeExeca.calledOnce); + + fakeExeca.resetHistory(); + + await verifyAuth('foo', pkg, context); + await verifyAuth('bar', pkg, context); + + t.assert(fakeExeca.calledTwice); +});