Skip to content

Commit

Permalink
Merge branch 'master' into beta
Browse files Browse the repository at this point in the history
  • Loading branch information
pvdlg committed Oct 28, 2019
2 parents b1780c1 + de677ea commit 851106c
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 41 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ services:
node_js:
- 12
- 10
- 8.15 # minimal supported node version
- 8.16 # minimal supported node version

# Trigger a push build on release and greenkeeper branches + PRs build on every branches
# Avoid double build on PRs (See https://github.com/travis-ci/travis-ci/issues/1147)
Expand Down
26 changes: 12 additions & 14 deletions lib/set-npmrc-auth.js
Original file line number Diff line number Diff line change
@@ -1,36 +1,34 @@
const path = require('path');
const rc = require('rc');
const {outputFile, copy, readFile} = require('fs-extra');
const {outputFile, 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);
const {configs, ...rcConfig} = rc(
'npm',
{registry: 'https://registry.npmjs.org/'},
{config: NPM_CONFIG_USERCONFIG || path.resolve(cwd, '.npmrc')}
);
const currentConfig = configs ? (await Promise.all(configs.map(config => readFile(config)))).join('\n') : '';

if (getAuthToken(registry, {npmrc: rcConfig})) {
await outputFile(npmrc, currentConfig);
return;
}

if (NPM_USERNAME && NPM_PASSWORD && NPM_EMAIL) {
await outputFile(npmrc, `${await readFileIfExists(config)}\n_auth = \${LEGACY_TOKEN}\nemail = \${NPM_EMAIL}`);
await outputFile(npmrc, `${currentConfig}\n_auth = \${LEGACY_TOKEN}\nemail = \${NPM_EMAIL}`);
logger.log(`Wrote NPM_USERNAME, NPM_PASSWORD and NPM_EMAIL to ${npmrc}`);
} else if (NPM_TOKEN) {
await outputFile(npmrc, `${await readFileIfExists(config)}\n${nerfDart(registry)}:_authToken = \${NPM_TOKEN}`);
await outputFile(npmrc, `${currentConfig}\n${nerfDart(registry)}:_authToken = \${NPM_TOKEN}`);
logger.log(`Wrote NPM_TOKEN to ${npmrc}`);
} else {
throw new AggregateError([getError('ENONPMTOKEN', {registry})]);
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"dependencies": {
"@semantic-release/error": "^2.2.0",
"aggregate-error": "^3.0.0",
"execa": "^3.0.0",
"execa": "^3.2.0",
"fs-extra": "^8.0.0",
"lodash": "^4.17.15",
"nerf-dart": "^1.0.0",
Expand Down Expand Up @@ -49,7 +49,7 @@
"xo": "^0.25.0"
},
"engines": {
"node": ">=8.15"
"node": ">=8.16"
},
"files": [
"lib",
Expand Down
107 changes: 86 additions & 21 deletions test/set-npmrc-auth.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,86 +3,145 @@ import test from 'ava';
import {readFile, appendFile} from 'fs-extra';
import {stub} from 'sinon';
import tempy from 'tempy';
import setNpmrcAuth from '../lib/set-npmrc-auth';
import clearModule from 'clear-module';

const {HOME} = process.env;
const cwd = process.cwd();

test.beforeEach(t => {
// Stub the logger
t.context.log = stub();
t.context.logger = {log: t.context.log};

clearModule('rc');
clearModule('../lib/set-npmrc-auth');
});

test.afterEach.always(() => {
process.env.HOME = HOME;
process.chdir(cwd);
});

test('Set auth with "NPM_TOKEN"', async t => {
test.serial('Set auth with "NPM_TOKEN"', async t => {
process.env.HOME = tempy.directory();
const cwd = tempy.directory();
process.chdir(cwd);
const npmrc = tempy.file({name: '.npmrc'});
const env = {NPM_TOKEN: 'npm_token'};

await setNpmrcAuth(npmrc, 'http://custom.registry.com', {cwd, env, logger: t.context.logger});
await require('../lib/set-npmrc-auth')(npmrc, 'http://custom.registry.com', {cwd, env, logger: t.context.logger});

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 => {
test.serial('Set auth with "NPM_USERNAME", "NPM_PASSWORD" and "NPM_EMAIL"', async t => {
process.env.HOME = tempy.directory();
const cwd = tempy.directory();
process.chdir(cwd);
const npmrc = tempy.file({name: '.npmrc'});
const env = {NPM_USERNAME: 'npm_username', NPM_PASSWORD: 'npm_pasword', NPM_EMAIL: 'npm_email'};

await setNpmrcAuth(npmrc, 'http://custom.registry.com', {cwd, env, logger: t.context.logger});
await require('../lib/set-npmrc-auth')(npmrc, 'http://custom.registry.com', {cwd, env, logger: t.context.logger});

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('Copy ".npmrc" if auth is already configured', async t => {
test.serial('Preserve home ".npmrc"', async t => {
process.env.HOME = tempy.directory();
const cwd = tempy.directory();
process.chdir(cwd);
const npmrc = tempy.file({name: '.npmrc'});
const env = {NPM_TOKEN: 'npm_token'};

await appendFile(path.resolve(process.env.HOME, '.npmrc'), 'home_config = test');

await require('../lib/set-npmrc-auth')(npmrc, 'http://custom.registry.com', {cwd, env, logger: t.context.logger});

t.is((await readFile(npmrc)).toString(), `home_config = test\n//custom.registry.com/:_authToken = \${NPM_TOKEN}`);
t.deepEqual(t.context.log.args[1], [`Wrote NPM_TOKEN to ${npmrc}`]);
});

test.serial('Preserve home and local ".npmrc"', async t => {
process.env.HOME = tempy.directory();
const cwd = tempy.directory();
process.chdir(cwd);
const npmrc = tempy.file({name: '.npmrc'});
const env = {NPM_TOKEN: 'npm_token'};

await appendFile(path.resolve(cwd, '.npmrc'), 'cwd_config = test');
await appendFile(path.resolve(process.env.HOME, '.npmrc'), 'home_config = test');

await require('../lib/set-npmrc-auth')(npmrc, 'http://custom.registry.com', {cwd, env, logger: t.context.logger});

t.is(
(await readFile(npmrc)).toString(),
`home_config = test\ncwd_config = test\n//custom.registry.com/:_authToken = \${NPM_TOKEN}`
);
t.deepEqual(t.context.log.args[1], [`Wrote NPM_TOKEN to ${npmrc}`]);
});

test.serial('Preserve all ".npmrc" if auth is already configured', async t => {
process.env.HOME = tempy.directory();
const cwd = tempy.directory();
process.chdir(cwd);
const npmrc = tempy.file({name: '.npmrc'});

await appendFile(path.resolve(cwd, '.npmrc'), `//custom.registry.com/:_authToken = \${NPM_TOKEN}`);
await appendFile(path.resolve(process.env.HOME, '.npmrc'), 'home_config = test');

await setNpmrcAuth(npmrc, 'http://custom.registry.com', {cwd, env: {}, logger: t.context.logger});
await require('../lib/set-npmrc-auth')(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((await readFile(npmrc)).toString(), `home_config = test\n//custom.registry.com/:_authToken = \${NPM_TOKEN}`);
t.is(t.context.log.callCount, 1);
});

test('Copy ".npmrc" if auth is already configured for a scoped package', async t => {
test.serial('Preserve ".npmrc" if auth is already configured for a scoped package', async t => {
process.env.HOME = tempy.directory();
const cwd = tempy.directory();
process.chdir(cwd);
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 appendFile(path.resolve(process.env.HOME, '.npmrc'), 'home_config = test');

await setNpmrcAuth(npmrc, 'http://custom.registry.com', {cwd, env: {}, logger: t.context.logger});
await require('../lib/set-npmrc-auth')(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}`
`home_config = test\n@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 => {
test.serial('Throw error if "NPM_TOKEN" is missing', async t => {
process.env.HOME = tempy.directory();
const cwd = tempy.directory();
process.chdir(cwd);
const npmrc = tempy.file({name: '.npmrc'});

const [error] = await t.throwsAsync(
setNpmrcAuth(npmrc, 'http://custom.registry.com', {cwd, env: {}, logger: t.context.logger})
require('../lib/set-npmrc-auth')(npmrc, 'http://custom.registry.com', {cwd, env: {}, logger: t.context.logger})
);

t.is(error.name, 'SemanticReleaseError');
t.is(error.message, 'No npm token specified.');
t.is(error.code, 'ENONPMTOKEN');
});

test('Emulate npm config resolution if "NPM_CONFIG_USERCONFIG" is set', async t => {
test.serial('Emulate npm config resolution if "NPM_CONFIG_USERCONFIG" is set', async t => {
process.env.HOME = tempy.directory();
const cwd = tempy.directory();
process.chdir(cwd);
const npmrc = tempy.file({name: '.npmrc'});

await appendFile(path.resolve(cwd, '.custom-npmrc'), `//custom.registry.com/:_authToken = \${NPM_TOKEN}`);

await setNpmrcAuth(npmrc, 'http://custom.registry.com', {
await require('../lib/set-npmrc-auth')(npmrc, 'http://custom.registry.com', {
cwd,
env: {NPM_CONFIG_USERCONFIG: path.resolve(cwd, '.custom-npmrc')},
logger: t.context.logger,
Expand All @@ -92,41 +151,47 @@ test('Emulate npm config resolution if "NPM_CONFIG_USERCONFIG" is set', async t
t.is(t.context.log.callCount, 1);
});

test('Throw error if "NPM_USERNAME" is missing', async t => {
test.serial('Throw error if "NPM_USERNAME" is missing', async t => {
process.env.HOME = tempy.directory();
const cwd = tempy.directory();
process.chdir(cwd);
const npmrc = tempy.file({name: '.npmrc'});
const env = {NPM_PASSWORD: 'npm_pasword', NPM_EMAIL: 'npm_email'};

const [error] = await t.throwsAsync(
setNpmrcAuth(npmrc, 'http://custom.registry.com', {cwd, env, logger: t.context.logger})
require('../lib/set-npmrc-auth')(npmrc, 'http://custom.registry.com', {cwd, env, logger: t.context.logger})
);

t.is(error.name, 'SemanticReleaseError');
t.is(error.message, 'No npm token specified.');
t.is(error.code, 'ENONPMTOKEN');
});

test('Throw error if "NPM_PASSWORD" is missing', async t => {
test.serial('Throw error if "NPM_PASSWORD" is missing', async t => {
process.env.HOME = tempy.directory();
const cwd = tempy.directory();
process.chdir(cwd);
const npmrc = tempy.file({name: '.npmrc'});
const env = {NPM_USERNAME: 'npm_username', NPM_EMAIL: 'npm_email'};

const [error] = await t.throwsAsync(
setNpmrcAuth(npmrc, 'http://custom.registry.com', {cwd, env, logger: t.context.logger})
require('../lib/set-npmrc-auth')(npmrc, 'http://custom.registry.com', {cwd, env, logger: t.context.logger})
);

t.is(error.name, 'SemanticReleaseError');
t.is(error.message, 'No npm token specified.');
t.is(error.code, 'ENONPMTOKEN');
});

test('Throw error if "NPM_EMAIL" is missing', async t => {
test.serial('Throw error if "NPM_EMAIL" is missing', async t => {
process.env.HOME = tempy.directory();
const cwd = tempy.directory();
process.chdir(cwd);
const npmrc = tempy.file({name: '.npmrc'});
const env = {NPM_USERNAME: 'npm_username', NPM_PASSWORD: 'npm_password'};

const [error] = await t.throwsAsync(
setNpmrcAuth(npmrc, 'http://custom.registry.com', {cwd, env, logger: t.context.logger})
require('../lib/set-npmrc-auth')(npmrc, 'http://custom.registry.com', {cwd, env, logger: t.context.logger})
);

t.is(error.name, 'SemanticReleaseError');
Expand Down
9 changes: 6 additions & 3 deletions test/verify-config.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,27 @@ test('Verify "npmPublish", "tarballDir" and "pkgRoot" options', async t => {

test('Return SemanticReleaseError if "npmPublish" option is not a Boolean', async t => {
const npmPublish = 42;
const [error] = await verify({npmPublish}, {}, t.context.logger);
const [error, ...errors] = await verify({npmPublish}, {}, t.context.logger);

t.is(errors.length, 0);
t.is(error.name, 'SemanticReleaseError');
t.is(error.code, 'EINVALIDNPMPUBLISH');
});

test('Return SemanticReleaseError if "tarballDir" option is not a String', async t => {
const tarballDir = 42;
const [error] = await verify({tarballDir}, {}, t.context.logger);
const [error, ...errors] = await verify({tarballDir}, {}, t.context.logger);

t.is(errors.length, 0);
t.is(error.name, 'SemanticReleaseError');
t.is(error.code, 'EINVALIDTARBALLDIR');
});

test('Return SemanticReleaseError if "pkgRoot" option is not a String', async t => {
const pkgRoot = 42;
const [error] = await verify({pkgRoot}, {}, t.context.logger);
const [error, ...errors] = await verify({pkgRoot}, {}, t.context.logger);

t.is(errors.length, 0);
t.is(error.name, 'SemanticReleaseError');
t.is(error.code, 'EINVALIDPKGROOT');
});
Expand Down

0 comments on commit 851106c

Please sign in to comment.