diff --git a/README.md b/README.md index 5ae65e2b..c2dfa530 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,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/index.js b/index.js index ceaf2f15..32b36ef3 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'); @@ -10,6 +11,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 @@ -31,7 +33,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); @@ -53,7 +55,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); @@ -63,7 +65,7 @@ async function prepare(pluginConfig, context) { throw new AggregateError(errors); } - await prepareNpm(pluginConfig, context); + await prepareNpm(npmrc, pluginConfig, context); prepared = true; } @@ -77,7 +79,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); @@ -88,10 +90,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); } async function addChannel(pluginConfig, context) { @@ -104,7 +106,7 @@ async function addChannel(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); @@ -114,7 +116,7 @@ async function addChannel(pluginConfig, context) { throw new AggregateError(errors); } - return addChannelNpm(pluginConfig, pkg, context); + return addChannelNpm(npmrc, pluginConfig, pkg, context); } module.exports = {verifyConditions, prepare, publish, addChannel}; diff --git a/lib/add-channel.js b/lib/add-channel.js index 566f24b8..0ed55d2d 100644 --- a/lib/add-channel.js +++ b/lib/add-channel.js @@ -3,7 +3,7 @@ const getRegistry = require('./get-registry'); const getChannel = require('./get-channel'); const getReleaseInfo = require('./get-release-info'); -module.exports = async ({npmPublish}, pkg, context) => { +module.exports = async (npmrc, {npmPublish}, pkg, context) => { const { cwd, env, @@ -18,10 +18,14 @@ module.exports = async ({npmPublish}, pkg, context) => { const distTag = getChannel(channel); logger.log(`Adding version ${version} to npm registry on dist-tag ${distTag}`); - const result = execa('npm', ['dist-tag', 'add', `${pkg.name}@${version}`, distTag, '--registry', registry], { - cwd, - env, - }); + const result = execa( + 'npm', + ['dist-tag', 'add', `${pkg.name}@${version}`, distTag, '--userconfig', npmrc, '--registry', registry], + { + cwd, + env, + } + ); result.stdout.pipe( stdout, {end: false} 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/lib/prepare.js b/lib/prepare.js index d2910c6f..bf6f2cde 100644 --- a/lib/prepare.js +++ b/lib/prepare.js @@ -2,15 +2,19 @@ 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', '--allow-same-version'], { - cwd: basePath, - env, - }); + const versionResult = execa( + 'npm', + ['version', version, '--userconfig', npmrc, '--no-git-tag-version', '--allow-same-version'], + { + cwd: basePath, + env, + } + ); versionResult.stdout.pipe( stdout, {end: false} @@ -24,7 +28,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 25982e70..7fdc46aa 100644 --- a/lib/publish.js +++ b/lib/publish.js @@ -4,7 +4,7 @@ const getRegistry = require('./get-registry'); const getChannel = require('./get-channel'); const getReleaseInfo = require('./get-release-info'); -module.exports = async ({npmPublish, pkgRoot}, pkg, context) => { +module.exports = async (npmrc, {npmPublish, pkgRoot}, pkg, context) => { const { cwd, env, @@ -20,7 +20,11 @@ module.exports = async ({npmPublish, pkgRoot}, pkg, context) => { const distTag = getChannel(channel); logger.log(`Publishing version ${version} to npm registry on dist-tag ${distTag}`); - const result = execa('npm', ['publish', basePath, '--tag', distTag, '--registry', registry], {cwd, env}); + const result = execa( + 'npm', + ['publish', basePath, '--userconfig', npmrc, '--tag', distTag, '--registry', registry], + {cwd, env} + ); result.stdout.pipe( stdout, {end: false} 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 b6a7a7a7..24c7a714 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,8 @@ "rc": "^1.2.8", "read-pkg": "^5.0.0", "registry-auth-token": "^4.0.0", - "semver": "^5.5.0" + "semver": "^5.5.0", + "tempy": "^0.3.0" }, "devDependencies": { "ava": "^2.0.0", @@ -45,7 +46,6 @@ "semantic-release": "^16.0.0-beta", "sinon": "^7.1.1", "stream-buffers": "^3.0.2", - "tempy": "^0.3.0", "xo": "^0.25.0" }, "engines": { 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/'); }); diff --git a/test/integration.test.js b/test/integration.test.js index 2737ebfc..bb2caf0a 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.');