From 01267047b3e8e9287c0b56722fbe63d946acd76d Mon Sep 17 00:00:00 2001 From: Pierre Vanduynslager Date: Thu, 3 Oct 2019 00:26:14 -0400 Subject: [PATCH 1/2] feat: allow to configure the registry via `NPM_CONFIG_REGISTRY` --- README.md | 4 +++- lib/get-registry.js | 14 +++++++------- test/get-registry.test.js | 19 ++++++++++++++----- 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 13db8d53..c4b23afc 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,9 @@ Use either `NPM_TOKEN` for token authentication or `NPM_USERNAME`, `NPM_PASSWORD The plugin uses the [`npm` CLI](https://github.com/npm/cli) which will read the configuration from [`.npmrc`](https://docs.npmjs.com/files/npmrc). See [`npm config`](https://docs.npmjs.com/misc/config) for the option list. -The [`registry`](https://docs.npmjs.com/misc/registry) and [`dist-tag`](https://docs.npmjs.com/cli/dist-tag) can be configured in the `package.json` and will take precedence over the configuration in `.npmrc`: +The [`registry`](https://docs.npmjs.com/misc/registry) can be configured via the npm environment variable `NPM_CONFIG_REGISTRY` and will take precedence over the configuration in `.npmrc`. + +The [`registry`](https://docs.npmjs.com/misc/registry) and [`dist-tag`](https://docs.npmjs.com/cli/dist-tag) can be configured in the `package.json` and will take precedence over the configuration in `.npmrc` and `NPM_CONFIG_REGISTRY`: ```json { "publishConfig": { diff --git a/lib/get-registry.js b/lib/get-registry.js index 5a25e4e5..d3e7e2be 100644 --- a/lib/get-registry.js +++ b/lib/get-registry.js @@ -2,10 +2,10 @@ const path = require('path'); const rc = require('rc'); const getRegistryUrl = require('registry-auth-token/registry-url'); -module.exports = ({publishConfig: {registry} = {}, name}, {cwd}) => - registry - ? registry - : getRegistryUrl( - name.split('/')[0], - rc('npm', {registry: 'https://registry.npmjs.org/'}, {config: path.resolve(cwd, '.npmrc')}) - ); +module.exports = ({publishConfig: {registry} = {}, name}, {cwd, env}) => + registry || + env.NPM_CONFIG_REGISTRY || + getRegistryUrl( + name.split('/')[0], + rc('npm', {registry: 'https://registry.npmjs.org/'}, {config: path.resolve(cwd, '.npmrc')}) + ); diff --git a/test/get-registry.test.js b/test/get-registry.test.js index fa542be2..e5520660 100644 --- a/test/get-registry.test.js +++ b/test/get-registry.test.js @@ -6,15 +6,15 @@ import getRegistry from '../lib/get-registry'; test('Get default registry', t => { const cwd = tempy.directory(); - t.is(getRegistry({name: 'package-name'}, {cwd}), 'https://registry.npmjs.org/'); - t.is(getRegistry({name: 'package-name', publishConfig: {}}, {cwd}), 'https://registry.npmjs.org/'); + t.is(getRegistry({name: 'package-name'}, {cwd, env: {}}), 'https://registry.npmjs.org/'); + t.is(getRegistry({name: 'package-name', publishConfig: {}}, {cwd, env: {}}), 'https://registry.npmjs.org/'); }); test('Get the registry configured in ".npmrc" and normalize trailing slash', async t => { const cwd = tempy.directory(); await appendFile(path.resolve(cwd, '.npmrc'), 'registry = https://custom1.registry.com'); - t.is(getRegistry({name: 'package-name'}, {cwd}), 'https://custom1.registry.com/'); + t.is(getRegistry({name: 'package-name'}, {cwd, env: {}}), 'https://custom1.registry.com/'); }); test('Get the registry configured from "publishConfig"', async t => { @@ -22,14 +22,23 @@ test('Get the registry configured from "publishConfig"', async t => { await appendFile(path.resolve(cwd, '.npmrc'), 'registry = https://custom2.registry.com'); t.is( - getRegistry({name: 'package-name', publishConfig: {registry: 'https://custom3.registry.com/'}}, {cwd}), + getRegistry({name: 'package-name', publishConfig: {registry: 'https://custom3.registry.com/'}}, {cwd, env: {}}), 'https://custom3.registry.com/' ); }); +test('Get the registry configured in "NPM_CONFIG_REGISTRY"', t => { + const cwd = tempy.directory(); + + t.is( + getRegistry({name: 'package-name'}, {cwd, env: {NPM_CONFIG_REGISTRY: 'https://custom1.registry.com/'}}), + 'https://custom1.registry.com/' + ); +}); + test('Get the registry configured in ".npmrc" for scoped package', async t => { const cwd = tempy.directory(); await appendFile(path.resolve(cwd, '.npmrc'), '@scope:registry = https://custom3.registry.com'); - t.is(getRegistry({name: '@scope/package-name'}, {cwd}), 'https://custom3.registry.com/'); + t.is(getRegistry({name: '@scope/package-name'}, {cwd, env: {}}), 'https://custom3.registry.com/'); }); From 8726effc8ba5946ab3fc94391e9b5db7fe39320b Mon Sep 17 00:00:00 2001 From: Pierre Vanduynslager Date: Fri, 4 Oct 2019 17:20:38 -0400 Subject: [PATCH 2/2] feat: preserve local `.npmrc` file --- index.js | 14 +++++---- lib/get-release-info.js | 4 ++- lib/prepare.js | 9 ++++-- lib/publish.js | 6 ++-- lib/set-npmrc-auth.js | 20 +++++++++---- lib/verify-auth.js | 6 ++-- package.json | 4 +-- test/get-release-info.test.js | 30 ++++++++++++------- test/integration.test.js | 20 +------------ test/prepare.test.js | 18 ++++++++++++ test/set-npmrc-auth.test.js | 55 +++++++++++++++++++++++------------ 11 files changed, 115 insertions(+), 71 deletions(-) diff --git a/index.js b/index.js index 5200dc18..e560dc86 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,6 @@ const {defaultTo, castArray} = require('lodash'); const AggregateError = require('aggregate-error'); +const tempy = require('tempy'); const setLegacyToken = require('./lib/set-legacy-token'); const getPkg = require('./lib/get-pkg'); const verifyNpmConfig = require('./lib/verify-config'); @@ -9,6 +10,7 @@ const publishNpm = require('./lib/publish'); let verified; let prepared; +const npmrc = tempy.file({name: '.npmrc'}); async function verifyConditions(pluginConfig, context) { // If the npm publish plugin is used and has `npmPublish`, `tarballDir` or `pkgRoot` configured, validate them now in order to prevent any release if the configuration is wrong @@ -30,7 +32,7 @@ async function verifyConditions(pluginConfig, context) { // Verify the npm authentication only if `npmPublish` is not false and `pkg.private` is not `true` if (pluginConfig.npmPublish !== false && pkg.private !== true) { - await verifyNpmAuth(pluginConfig, pkg, context); + await verifyNpmAuth(npmrc, pkg, context); } } catch (error) { errors.push(...error); @@ -52,7 +54,7 @@ async function prepare(pluginConfig, context) { // Reload package.json in case a previous external step updated it const pkg = await getPkg(pluginConfig, context); if (!verified && pluginConfig.npmPublish !== false && pkg.private !== true) { - await verifyNpmAuth(pluginConfig, pkg, context); + await verifyNpmAuth(npmrc, pkg, context); } } catch (error) { errors.push(...error); @@ -62,7 +64,7 @@ async function prepare(pluginConfig, context) { throw new AggregateError(errors); } - await prepareNpm(pluginConfig, context); + await prepareNpm(npmrc, pluginConfig, context); prepared = true; } @@ -76,7 +78,7 @@ async function publish(pluginConfig, context) { // Reload package.json in case a previous external step updated it pkg = await getPkg(pluginConfig, context); if (!verified && pluginConfig.npmPublish !== false && pkg.private !== true) { - await verifyNpmAuth(pluginConfig, pkg, context); + await verifyNpmAuth(npmrc, pkg, context); } } catch (error) { errors.push(...error); @@ -87,10 +89,10 @@ async function publish(pluginConfig, context) { } if (!prepared) { - await prepareNpm(pluginConfig, context); + await prepareNpm(npmrc, pluginConfig, context); } - return publishNpm(pluginConfig, pkg, context); + return publishNpm(npmrc, pluginConfig, pkg, context); } module.exports = {verifyConditions, prepare, publish}; diff --git a/lib/get-release-info.js b/lib/get-release-info.js index dd3ef5f1..144167ce 100644 --- a/lib/get-release-info.js +++ b/lib/get-release-info.js @@ -2,11 +2,13 @@ const execa = require('execa'); const normalizeUrl = require('normalize-url'); module.exports = async ( + npmrc, {name, publishConfig: {tag} = {}}, {cwd, env: {DEFAULT_NPM_REGISTRY = 'https://registry.npmjs.org/', ...env}}, registry ) => { - const distTag = tag || (await execa('npm', ['config', 'get', 'tag'], {cwd, env})).stdout || 'latest'; + const distTag = + tag || (await execa('npm', ['config', 'get', 'tag', '--userconfig', npmrc], {cwd, env})).stdout || 'latest'; return { name: `npm package (@${distTag} dist-tag)`, diff --git a/lib/prepare.js b/lib/prepare.js index 18db3347..254adab4 100644 --- a/lib/prepare.js +++ b/lib/prepare.js @@ -2,12 +2,15 @@ const path = require('path'); const {move} = require('fs-extra'); const execa = require('execa'); -module.exports = async ({tarballDir, pkgRoot}, {cwd, env, stdout, stderr, nextRelease: {version}, logger}) => { +module.exports = async (npmrc, {tarballDir, pkgRoot}, {cwd, env, stdout, stderr, nextRelease: {version}, logger}) => { const basePath = pkgRoot ? path.resolve(cwd, pkgRoot) : cwd; logger.log('Write version %s to package.json in %s', version, basePath); - const versionResult = execa('npm', ['version', version, '--no-git-tag-version'], {cwd: basePath, env}); + const versionResult = execa('npm', ['version', version, '--userconfig', npmrc, '--no-git-tag-version'], { + cwd: basePath, + env, + }); versionResult.stdout.pipe( stdout, {end: false} @@ -21,7 +24,7 @@ module.exports = async ({tarballDir, pkgRoot}, {cwd, env, stdout, stderr, nextRe if (tarballDir) { logger.log('Creating npm package version %s', version); - const packResult = execa('npm', ['pack', basePath], {cwd, env}); + const packResult = execa('npm', ['pack', basePath, '--userconfig', npmrc], {cwd, env}); packResult.stdout.pipe( stdout, {end: false} diff --git a/lib/publish.js b/lib/publish.js index a824f1e0..51e6cd7d 100644 --- a/lib/publish.js +++ b/lib/publish.js @@ -3,7 +3,7 @@ const execa = require('execa'); const getRegistry = require('./get-registry'); const getReleaseInfo = require('./get-release-info'); -module.exports = async ({npmPublish, pkgRoot}, pkg, context) => { +module.exports = async (npmrc, {npmPublish, pkgRoot}, pkg, context) => { const { cwd, env, @@ -18,7 +18,7 @@ module.exports = async ({npmPublish, pkgRoot}, pkg, context) => { const registry = getRegistry(pkg, context); logger.log('Publishing version %s to npm registry', version); - const result = execa('npm', ['publish', basePath, '--registry', registry], {cwd, env}); + const result = execa('npm', ['publish', basePath, '--userconfig', npmrc, '--registry', registry], {cwd, env}); result.stdout.pipe( stdout, {end: false} @@ -30,7 +30,7 @@ module.exports = async ({npmPublish, pkgRoot}, pkg, context) => { await result; logger.log(`Published ${pkg.name}@${pkg.version} on ${registry}`); - return getReleaseInfo(pkg, context, registry); + return getReleaseInfo(npmrc, pkg, context, registry); } logger.log( diff --git a/lib/set-npmrc-auth.js b/lib/set-npmrc-auth.js index 40f65c92..0ffde7ed 100644 --- a/lib/set-npmrc-auth.js +++ b/lib/set-npmrc-auth.js @@ -1,27 +1,37 @@ const path = require('path'); const rc = require('rc'); -const {appendFile} = require('fs-extra'); +const {outputFile, copy, readFile} = require('fs-extra'); const getAuthToken = require('registry-auth-token'); const nerfDart = require('nerf-dart'); const AggregateError = require('aggregate-error'); const getError = require('./get-error'); +const readFileIfExists = async path => { + try { + return await readFile(path); + } catch (_) { + return ''; + } +}; + module.exports = async ( + npmrc, registry, {cwd, env: {NPM_TOKEN, NPM_CONFIG_USERCONFIG, NPM_USERNAME, NPM_PASSWORD, NPM_EMAIL}, logger} ) => { logger.log('Verify authentication for registry %s', registry); const config = NPM_CONFIG_USERCONFIG || path.resolve(cwd, '.npmrc'); if (getAuthToken(registry, {npmrc: rc('npm', {registry: 'https://registry.npmjs.org/'}, {config})})) { + await copy(config, npmrc); return; } if (NPM_USERNAME && NPM_PASSWORD && NPM_EMAIL) { - await appendFile(config, `\n_auth = \${LEGACY_TOKEN}\nemail = \${NPM_EMAIL}`); - logger.log(`Wrote NPM_USERNAME, NPM_PASSWORD and NPM_EMAIL to ${config}`); + await outputFile(npmrc, `${await readFileIfExists(config)}\n_auth = \${LEGACY_TOKEN}\nemail = \${NPM_EMAIL}`); + logger.log(`Wrote NPM_USERNAME, NPM_PASSWORD and NPM_EMAIL to ${npmrc}`); } else if (NPM_TOKEN) { - await appendFile(config, `\n${nerfDart(registry)}:_authToken = \${NPM_TOKEN}`); - logger.log(`Wrote NPM_TOKEN to ${config}`); + await outputFile(npmrc, `${await readFileIfExists(config)}\n${nerfDart(registry)}:_authToken = \${NPM_TOKEN}`); + logger.log(`Wrote NPM_TOKEN to ${npmrc}`); } else { throw new AggregateError([getError('ENONPMTOKEN', {registry})]); } diff --git a/lib/verify-auth.js b/lib/verify-auth.js index 9eb3386d..fe8c60bf 100644 --- a/lib/verify-auth.js +++ b/lib/verify-auth.js @@ -5,18 +5,18 @@ const getError = require('./get-error'); const getRegistry = require('./get-registry'); const setNpmrcAuth = require('./set-npmrc-auth'); -module.exports = async (pluginConfig, pkg, context) => { +module.exports = async (npmrc, pkg, context) => { const { cwd, env: {DEFAULT_NPM_REGISTRY = 'https://registry.npmjs.org/', ...env}, } = context; const registry = getRegistry(pkg, context); - await setNpmrcAuth(registry, context); + await setNpmrcAuth(npmrc, registry, context); if (normalizeUrl(registry) === normalizeUrl(DEFAULT_NPM_REGISTRY)) { try { - await execa('npm', ['whoami', '--registry', registry], {cwd, env}); + await execa('npm', ['whoami', '--userconfig', npmrc, '--registry', registry], {cwd, env}); } catch (_) { throw new AggregateError([getError('EINVALIDNPMTOKEN', {registry})]); } diff --git a/package.json b/package.json index 19230f52..52238505 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,8 @@ "npm": "^6.10.3", "rc": "^1.2.8", "read-pkg": "^5.0.0", - "registry-auth-token": "^4.0.0" + "registry-auth-token": "^4.0.0", + "tempy": "^0.3.0" }, "devDependencies": { "ava": "^2.0.0", @@ -44,7 +45,6 @@ "semantic-release": "^15.0.0", "sinon": "^7.1.1", "stream-buffers": "^3.0.2", - "tempy": "^0.3.0", "xo": "^0.25.0" }, "engines": { diff --git a/test/get-release-info.test.js b/test/get-release-info.test.js index 575307a1..eae496d0 100644 --- a/test/get-release-info.test.js +++ b/test/get-release-info.test.js @@ -1,4 +1,3 @@ -import path from 'path'; import test from 'ava'; import {writeFile} from 'fs-extra'; import tempy from 'tempy'; @@ -15,8 +14,9 @@ test.beforeEach(() => { test('Default registry and tag', async t => { const cwd = tempy.directory(); + const npmrc = tempy.file({name: '.npmrc'}); - t.deepEqual(await getReleaseInfo({name: 'module'}, {cwd, env: {}}, 'https://registry.npmjs.org/'), { + t.deepEqual(await getReleaseInfo(npmrc, {name: 'module'}, {cwd, env: {}}, 'https://registry.npmjs.org/'), { name: 'npm package (@latest dist-tag)', url: 'https://www.npmjs.com/package/module', }); @@ -24,8 +24,9 @@ test('Default registry and tag', async t => { test('Default registry, tag and scoped module', async t => { const cwd = tempy.directory(); + const npmrc = tempy.file({name: '.npmrc'}); - t.deepEqual(await getReleaseInfo({name: '@scope/module'}, {cwd, env: {}}, 'https://registry.npmjs.org/'), { + t.deepEqual(await getReleaseInfo(npmrc, {name: '@scope/module'}, {cwd, env: {}}, 'https://registry.npmjs.org/'), { name: 'npm package (@latest dist-tag)', url: 'https://www.npmjs.com/package/@scope/module', }); @@ -33,8 +34,9 @@ test('Default registry, tag and scoped module', async t => { test('Custom registry, tag and scoped module', async t => { const cwd = tempy.directory(); + const npmrc = tempy.file({name: '.npmrc'}); - t.deepEqual(await getReleaseInfo({name: '@scope/module'}, {cwd, env: {}}, 'https://custom.registry.org/'), { + t.deepEqual(await getReleaseInfo(npmrc, {name: '@scope/module'}, {cwd, env: {}}, 'https://custom.registry.org/'), { name: 'npm package (@latest dist-tag)', url: undefined, }); @@ -42,10 +44,11 @@ test('Custom registry, tag and scoped module', async t => { test('Default registry and tag from .npmrc', async t => { const cwd = tempy.directory(); - await writeFile(path.resolve(cwd, '.npmrc'), 'tag=npmrc'); + const npmrc = tempy.file({name: '.npmrc'}); + await writeFile(npmrc, 'tag=npmrc'); t.deepEqual( - await getReleaseInfo({name: 'module', publishConfig: {}}, {cwd, env: {}}, 'https://registry.npmjs.org/'), + await getReleaseInfo(npmrc, {name: 'module', publishConfig: {}}, {cwd, env: {}}, 'https://registry.npmjs.org/'), { name: 'npm package (@npmrc dist-tag)', url: 'https://www.npmjs.com/package/module', @@ -55,22 +58,29 @@ test('Default registry and tag from .npmrc', async t => { test('Default registry and tag from package.json', async t => { const cwd = tempy.directory(); + const npmrc = tempy.file({name: '.npmrc'}); - await writeFile(path.resolve(cwd, '.npmrc'), 'tag=npmrc'); + await writeFile(npmrc, 'tag=npmrc'); t.deepEqual( - await getReleaseInfo({name: 'module', publishConfig: {tag: 'pkg'}}, {cwd, env: {}}, 'https://registry.npmjs.org/'), + await getReleaseInfo( + npmrc, + {name: 'module', publishConfig: {tag: 'pkg'}}, + {cwd, env: {}}, + 'https://registry.npmjs.org/' + ), {name: 'npm package (@pkg dist-tag)', url: 'https://www.npmjs.com/package/module'} ); }); test('Default tag', async t => { const cwd = tempy.directory(); + const npmrc = tempy.file({name: '.npmrc'}); - await writeFile(path.resolve(cwd, '.npmrc'), 'tag='); + await writeFile(npmrc, 'tag='); t.deepEqual( - await getReleaseInfo({name: 'module', publishConfig: {}}, {cwd, env: {}}, 'https://registry.npmjs.org/'), + await getReleaseInfo(npmrc, {name: 'module', publishConfig: {}}, {cwd, env: {}}, 'https://registry.npmjs.org/'), { name: 'npm package (@latest dist-tag)', url: 'https://www.npmjs.com/package/module', diff --git a/test/integration.test.js b/test/integration.test.js index 2e810f91..d70baaba 100644 --- a/test/integration.test.js +++ b/test/integration.test.js @@ -1,6 +1,6 @@ import path from 'path'; import test from 'ava'; -import {outputJson, readJson, readFile, pathExists} from 'fs-extra'; +import {outputJson, readJson, pathExists} from 'fs-extra'; import execa from 'execa'; import {spy} from 'sinon'; import tempy from 'tempy'; @@ -110,9 +110,6 @@ test('Throws error if NPM token is invalid', async t => { t.is(error.name, 'SemanticReleaseError'); t.is(error.code, 'EINVALIDNPMTOKEN'); t.is(error.message, 'Invalid npm token.'); - - const npmrc = (await readFile(path.resolve(cwd, '.npmrc'))).toString(); - t.regex(npmrc, /:_authToken/); }); test('Skip Token validation if the registry configured is not the default one', async t => { @@ -126,9 +123,6 @@ test('Skip Token validation if the registry configured is not the default one', {cwd, env, options: {}, stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger} ) ); - - const npmrc = (await readFile(path.resolve(cwd, '.npmrc'))).toString(); - t.regex(npmrc, /:_authToken/); }); test('Verify npm auth and package', async t => { @@ -148,10 +142,6 @@ test('Verify npm auth and package', async t => { } ) ); - - const npmrc = (await readFile(path.resolve(cwd, '.npmrc'))).toString(); - t.regex(npmrc, /_auth =/); - t.regex(npmrc, /email =/); }); test('Verify npm auth and package from a sub-directory', async t => { @@ -171,10 +161,6 @@ test('Verify npm auth and package from a sub-directory', async t => { } ) ); - - const npmrc = (await readFile(path.resolve(cwd, '.npmrc'))).toString(); - t.regex(npmrc, /_auth =/); - t.regex(npmrc, /email =/); }); test('Verify npm auth and package with "npm_config_registry" env var set by yarn', async t => { @@ -194,10 +180,6 @@ test('Verify npm auth and package with "npm_config_registry" env var set by yarn } ) ); - - const npmrc = (await readFile(path.resolve(cwd, '.npmrc'))).toString(); - t.regex(npmrc, /_auth =/); - t.regex(npmrc, /email =/); }); test('Throw SemanticReleaseError Array if config option are not valid in verifyConditions', async t => { diff --git a/test/prepare.test.js b/test/prepare.test.js index 361d11e0..1cca2576 100644 --- a/test/prepare.test.js +++ b/test/prepare.test.js @@ -16,10 +16,12 @@ test.beforeEach(t => { test('Updade package.json', async t => { const cwd = tempy.directory(); + const npmrc = tempy.file({name: '.npmrc'}); const packagePath = path.resolve(cwd, 'package.json'); await outputJson(packagePath, {version: '0.0.0-dev'}); await prepare( + npmrc, {}, { cwd, @@ -40,6 +42,7 @@ test('Updade package.json', async t => { test('Updade package.json and npm-shrinkwrap.json', async t => { const cwd = tempy.directory(); + const npmrc = tempy.file({name: '.npmrc'}); const packagePath = path.resolve(cwd, 'package.json'); const shrinkwrapPath = path.resolve(cwd, 'npm-shrinkwrap.json'); await outputJson(packagePath, {version: '0.0.0-dev'}); @@ -47,6 +50,7 @@ test('Updade package.json and npm-shrinkwrap.json', async t => { await execa('npm', ['shrinkwrap'], {cwd}); await prepare( + npmrc, {}, { cwd, @@ -67,6 +71,7 @@ test('Updade package.json and npm-shrinkwrap.json', async t => { test('Updade package.json and package-lock.json', async t => { const cwd = tempy.directory(); + const npmrc = tempy.file({name: '.npmrc'}); const packagePath = path.resolve(cwd, 'package.json'); const packageLockPath = path.resolve(cwd, 'package-lock.json'); await outputJson(packagePath, {version: '0.0.0-dev'}); @@ -75,6 +80,7 @@ test('Updade package.json and package-lock.json', async t => { await execa('npm', ['install'], {cwd}); await prepare( + npmrc, {}, { cwd, @@ -95,6 +101,7 @@ test('Updade package.json and package-lock.json', async t => { test('Updade package.json and npm-shrinkwrap.json in a sub-directory', async t => { const cwd = tempy.directory(); + const npmrc = tempy.file({name: '.npmrc'}); const pkgRoot = 'dist'; const packagePath = path.resolve(cwd, pkgRoot, 'package.json'); const shrinkwrapPath = path.resolve(cwd, pkgRoot, 'npm-shrinkwrap.json'); @@ -103,6 +110,7 @@ test('Updade package.json and npm-shrinkwrap.json in a sub-directory', async t = await execa('npm', ['shrinkwrap'], {cwd: path.resolve(cwd, pkgRoot)}); await prepare( + npmrc, {pkgRoot}, { cwd, @@ -123,6 +131,7 @@ test('Updade package.json and npm-shrinkwrap.json in a sub-directory', async t = test('Updade package.json and package-lock.json in a sub-directory', async t => { const cwd = tempy.directory(); + const npmrc = tempy.file({name: '.npmrc'}); const pkgRoot = 'dist'; const packagePath = path.resolve(cwd, pkgRoot, 'package.json'); const packageLockPath = path.resolve(cwd, pkgRoot, 'package-lock.json'); @@ -132,6 +141,7 @@ test('Updade package.json and package-lock.json in a sub-directory', async t => await execa('npm', ['install'], {cwd: path.resolve(cwd, pkgRoot)}); await prepare( + npmrc, {pkgRoot}, { cwd, @@ -152,10 +162,12 @@ test('Updade package.json and package-lock.json in a sub-directory', async t => test('Preserve indentation and newline', async t => { const cwd = tempy.directory(); + const npmrc = tempy.file({name: '.npmrc'}); const packagePath = path.resolve(cwd, 'package.json'); await outputFile(packagePath, `{\r\n "name": "package-name",\r\n "version": "0.0.0-dev"\r\n}\r\n`); await prepare( + npmrc, {}, { cwd, @@ -179,10 +191,12 @@ test('Preserve indentation and newline', async t => { test('Use default indentation and newline if it cannot be detected', async t => { const cwd = tempy.directory(); + const npmrc = tempy.file({name: '.npmrc'}); const packagePath = path.resolve(cwd, 'package.json'); await outputFile(packagePath, `{"name": "package-name","version": "0.0.0-dev"}`); await prepare( + npmrc, {}, { cwd, @@ -203,11 +217,13 @@ test('Use default indentation and newline if it cannot be detected', async t => test('Create the package in the "tarballDir" directory', async t => { const cwd = tempy.directory(); + const npmrc = tempy.file({name: '.npmrc'}); const packagePath = path.resolve(cwd, 'package.json'); const pkg = {name: 'my-pkg', version: '0.0.0-dev'}; await outputJson(packagePath, pkg); await prepare( + npmrc, {tarballDir: 'tarball'}, { cwd, @@ -229,11 +245,13 @@ test('Create the package in the "tarballDir" directory', async t => { test('Only move the created tarball if the "tarballDir" directory is not the CWD', async t => { const cwd = tempy.directory(); + const npmrc = tempy.file({name: '.npmrc'}); const packagePath = path.resolve(cwd, 'package.json'); const pkg = {name: 'my-pkg', version: '0.0.0-dev'}; await outputJson(packagePath, pkg); await prepare( + npmrc, {tarballDir: '.'}, { cwd, diff --git a/test/set-npmrc-auth.test.js b/test/set-npmrc-auth.test.js index 239c0173..da1705e0 100644 --- a/test/set-npmrc-auth.test.js +++ b/test/set-npmrc-auth.test.js @@ -13,56 +13,62 @@ test.beforeEach(t => { test('Set auth with "NPM_TOKEN"', async t => { const cwd = tempy.directory(); + const npmrc = tempy.file({name: '.npmrc'}); const env = {NPM_TOKEN: 'npm_token'}; - await setNpmrcAuth('http://custom.registry.com', {cwd, env, logger: t.context.logger}); + await setNpmrcAuth(npmrc, 'http://custom.registry.com', {cwd, env, logger: t.context.logger}); - const npmrc = (await readFile(path.resolve(cwd, '.npmrc'))).toString(); - t.regex(npmrc, /\/\/custom.registry.com\/:_authToken = \$\{NPM_TOKEN\}/); - t.deepEqual(t.context.log.args[1], [`Wrote NPM_TOKEN to ${path.resolve(cwd, '.npmrc')}`]); + t.regex((await readFile(npmrc)).toString(), /\/\/custom.registry.com\/:_authToken = \$\{NPM_TOKEN\}/); + t.deepEqual(t.context.log.args[1], [`Wrote NPM_TOKEN to ${npmrc}`]); }); test('Set auth with "NPM_USERNAME", "NPM_PASSWORD" and "NPM_EMAIL"', async t => { const cwd = tempy.directory(); + const npmrc = tempy.file({name: '.npmrc'}); const env = {NPM_USERNAME: 'npm_username', NPM_PASSWORD: 'npm_pasword', NPM_EMAIL: 'npm_email'}; - await setNpmrcAuth('http://custom.registry.com', {cwd, env, logger: t.context.logger}); + await setNpmrcAuth(npmrc, 'http://custom.registry.com', {cwd, env, logger: t.context.logger}); - const npmrc = (await readFile(path.resolve(cwd, '.npmrc'))).toString(); - t.is(npmrc, `\n_auth = \${LEGACY_TOKEN}\nemail = \${NPM_EMAIL}`); - t.deepEqual(t.context.log.args[1], [ - `Wrote NPM_USERNAME, NPM_PASSWORD and NPM_EMAIL to ${path.resolve(cwd, '.npmrc')}`, - ]); + t.is((await readFile(npmrc)).toString(), `\n_auth = \${LEGACY_TOKEN}\nemail = \${NPM_EMAIL}`); + t.deepEqual(t.context.log.args[1], [`Wrote NPM_USERNAME, NPM_PASSWORD and NPM_EMAIL to ${npmrc}`]); }); -test('Do not modify ".npmrc" if auth is already configured', async t => { +test('Copy ".npmrc" if auth is already configured', async t => { const cwd = tempy.directory(); + const npmrc = tempy.file({name: '.npmrc'}); await appendFile(path.resolve(cwd, '.npmrc'), `//custom.registry.com/:_authToken = \${NPM_TOKEN}`); - await setNpmrcAuth('http://custom.registry.com', {cwd, env: {}, logger: t.context.logger}); + await setNpmrcAuth(npmrc, 'http://custom.registry.com', {cwd, env: {}, logger: t.context.logger}); + t.is((await readFile(npmrc)).toString(), `//custom.registry.com/:_authToken = \${NPM_TOKEN}`); t.is(t.context.log.callCount, 1); }); -test('Do not modify ".npmrc" if auth is already configured for a scoped package', async t => { +test('Copy ".npmrc" if auth is already configured for a scoped package', async t => { const cwd = tempy.directory(); + const npmrc = tempy.file({name: '.npmrc'}); await appendFile( path.resolve(cwd, '.npmrc'), `@scope:registry=http://custom.registry.com\n//custom.registry.com/:_authToken = \${NPM_TOKEN}` ); - await setNpmrcAuth('http://custom.registry.com', {cwd, env: {}, logger: t.context.logger}); + await setNpmrcAuth(npmrc, 'http://custom.registry.com', {cwd, env: {}, logger: t.context.logger}); + t.is( + (await readFile(npmrc)).toString(), + `@scope:registry=http://custom.registry.com\n//custom.registry.com/:_authToken = \${NPM_TOKEN}` + ); t.is(t.context.log.callCount, 1); }); test('Throw error if "NPM_TOKEN" is missing', async t => { const cwd = tempy.directory(); + const npmrc = tempy.file({name: '.npmrc'}); const [error] = await t.throwsAsync( - setNpmrcAuth('http://custom.registry.com', {cwd, env: {}, logger: t.context.logger}) + setNpmrcAuth(npmrc, 'http://custom.registry.com', {cwd, env: {}, logger: t.context.logger}) ); t.is(error.name, 'SemanticReleaseError'); @@ -72,23 +78,28 @@ test('Throw error if "NPM_TOKEN" is missing', async t => { test('Emulate npm config resolution if "NPM_CONFIG_USERCONFIG" is set', async t => { const cwd = tempy.directory(); + const npmrc = tempy.file({name: '.npmrc'}); await appendFile(path.resolve(cwd, '.custom-npmrc'), `//custom.registry.com/:_authToken = \${NPM_TOKEN}`); - await setNpmrcAuth('http://custom.registry.com', { + await setNpmrcAuth(npmrc, 'http://custom.registry.com', { cwd, env: {NPM_CONFIG_USERCONFIG: path.resolve(cwd, '.custom-npmrc')}, logger: t.context.logger, }); + t.is((await readFile(npmrc)).toString(), `//custom.registry.com/:_authToken = \${NPM_TOKEN}`); t.is(t.context.log.callCount, 1); }); test('Throw error if "NPM_USERNAME" is missing', async t => { const cwd = tempy.directory(); + const npmrc = tempy.file({name: '.npmrc'}); const env = {NPM_PASSWORD: 'npm_pasword', NPM_EMAIL: 'npm_email'}; - const [error] = await t.throwsAsync(setNpmrcAuth('http://custom.registry.com', {cwd, env, logger: t.context.logger})); + const [error] = await t.throwsAsync( + setNpmrcAuth(npmrc, 'http://custom.registry.com', {cwd, env, logger: t.context.logger}) + ); t.is(error.name, 'SemanticReleaseError'); t.is(error.message, 'No npm token specified.'); @@ -97,9 +108,12 @@ test('Throw error if "NPM_USERNAME" is missing', async t => { test('Throw error if "NPM_PASSWORD" is missing', async t => { const cwd = tempy.directory(); + const npmrc = tempy.file({name: '.npmrc'}); const env = {NPM_USERNAME: 'npm_username', NPM_EMAIL: 'npm_email'}; - const [error] = await t.throwsAsync(setNpmrcAuth('http://custom.registry.com', {cwd, env, logger: t.context.logger})); + const [error] = await t.throwsAsync( + setNpmrcAuth(npmrc, 'http://custom.registry.com', {cwd, env, logger: t.context.logger}) + ); t.is(error.name, 'SemanticReleaseError'); t.is(error.message, 'No npm token specified.'); @@ -108,9 +122,12 @@ test('Throw error if "NPM_PASSWORD" is missing', async t => { test('Throw error if "NPM_EMAIL" is missing', async t => { const cwd = tempy.directory(); + const npmrc = tempy.file({name: '.npmrc'}); const env = {NPM_USERNAME: 'npm_username', NPM_PASSWORD: 'npm_password'}; - const [error] = await t.throwsAsync(setNpmrcAuth('http://custom.registry.com', {cwd, env, logger: t.context.logger})); + const [error] = await t.throwsAsync( + setNpmrcAuth(npmrc, 'http://custom.registry.com', {cwd, env, logger: t.context.logger}) + ); t.is(error.name, 'SemanticReleaseError'); t.is(error.message, 'No npm token specified.');