Skip to content

Commit

Permalink
fix: skip npm auth verification if npmPublish is false
Browse files Browse the repository at this point in the history
  • Loading branch information
pvdlg authored and gr2m committed Dec 21, 2017
1 parent 49e2e2b commit 4cd5cd7
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 23 deletions.
30 changes: 20 additions & 10 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
const {castArray} = require('lodash');
const setLegacyToken = require('./lib/set-legacy-token');
const getPkg = require('./lib/get-pkg');
const verifyNpm = require('./lib/verify');
const verifyNpmConfig = require('./lib/verify-config');
const verifyNpmAuth = require('./lib/verify-auth');
const publishNpm = require('./lib/publish');
const getLastReleaseNpm = require('./lib/get-last-release');

let verified;

async function verifyConditions(pluginConfig, {options, logger}) {
async function verifyConditions(pluginConfig, {options: {publish, getLastRelease}, logger}) {
// 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
if (options.publish) {
const publishPlugin = castArray(options.publish).find(
config => config.path && config.path === '@semantic-release/npm'
);
if (publish) {
const publishPlugin = castArray(publish).find(config => config.path && config.path === '@semantic-release/npm');
if (publishPlugin && publishPlugin.npmPublish) {
pluginConfig.npmPublish = publishPlugin.npmPublish;
}
Expand All @@ -23,9 +22,18 @@ async function verifyConditions(pluginConfig, {options, logger}) {
pluginConfig.pkgRoot = publishPlugin.pkgRoot;
}
}
setLegacyToken();

const pkg = await getPkg(pluginConfig.pkgRoot);
await verifyNpm(pluginConfig, pkg, logger);
await verifyNpmConfig(pluginConfig, pkg, logger);

// Verify the npm authentication only if `npmPublish` is not false and if the npm plugin is used as `getLastRelease`
if (
pluginConfig.npmPublish !== false ||
(getLastRelease && (getLastRelease === '@semantic-release/npm' || getLastRelease.path === '@semantic-release/npm'))
) {
setLegacyToken();
await verifyNpmAuth(pluginConfig, pkg, logger);
}
verified = true;
}

Expand All @@ -42,7 +50,8 @@ async function getLastRelease(pluginConfig, {options, logger}) {
pluginConfig.pkgRoot = publishPlugin.pkgRoot;
}
}
await verifyNpm(pluginConfig, pkg, logger);
await verifyNpmConfig(pluginConfig, pkg, logger);
await verifyNpmAuth(pluginConfig, pkg, logger);
verified = true;
}
return getLastReleaseNpm(pkg, logger);
Expand All @@ -53,7 +62,8 @@ async function publish(pluginConfig, {nextRelease: {version}, logger}) {
// Reload package.json in case a previous external step updated it
const pkg = await getPkg(pluginConfig.pkgRoot);
if (!verified) {
await verifyNpm(pluginConfig, pkg, logger);
await verifyNpmConfig(pluginConfig, pkg, logger);
await verifyNpmAuth(pluginConfig, pkg, logger);
verified = true;
}
await publishNpm(pluginConfig, pkg, version, logger);
Expand Down
14 changes: 14 additions & 0 deletions lib/verify-auth.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const execa = require('execa');
const SemanticReleaseError = require('@semantic-release/error');
const getRegistry = require('./get-registry');
const setNpmrcAuth = require('./set-npmrc-auth');

module.exports = async (pluginConfig, pkg, logger) => {
const registry = await getRegistry(pkg.publishConfig, pkg.name);
await setNpmrcAuth(registry, logger);
try {
await execa('npm', ['whoami', '--registry', registry]);
} catch (err) {
throw new SemanticReleaseError('Invalid npm token.', 'EINVALIDNPMTOKEN');
}
};
13 changes: 1 addition & 12 deletions lib/verify.js → lib/verify-config.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
const {isString, isUndefined, isBoolean} = require('lodash');
const execa = require('execa');
const SemanticReleaseError = require('@semantic-release/error');
const getRegistry = require('./get-registry');
const setNpmrcAuth = require('./set-npmrc-auth');

module.exports = async ({npmPublish, tarballDir, pkgRoot}, pkg, logger) => {
module.exports = async ({npmPublish, tarballDir, pkgRoot}) => {
if (!isUndefined(npmPublish) && !isBoolean(npmPublish)) {
throw new SemanticReleaseError('The "npmPublish" options, if defined, must be a Boolean.', 'EINVALIDNPMPUBLISH');
}
Expand All @@ -16,12 +13,4 @@ module.exports = async ({npmPublish, tarballDir, pkgRoot}, pkg, logger) => {
if (!isUndefined(pkgRoot) && !isString(pkgRoot)) {
throw new SemanticReleaseError('The "pkgRoot" options, if defined, must be a String.', 'EINVALIDPKGROOT');
}

const registry = await getRegistry(pkg.publishConfig, pkg.name);
await setNpmrcAuth(registry, logger);
try {
await execa('npm', ['whoami', '--registry', registry]);
} catch (err) {
throw new SemanticReleaseError('Invalid npm token.', 'EINVALIDNPMTOKEN');
}
};
51 changes: 51 additions & 0 deletions test/integration.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,13 @@ test.after.always(async () => {
await npmRegistry.stop();
});

test.serial('Skip npm auth verification if "npmPublish" is false', async t => {
process.env.NPM_TOKEN = 'wrong_token';
const pkg = {name: 'published', version: '1.0.0', publishConfig: {registry: npmRegistry.url}};
await outputJson('./package.json', pkg);
await t.notThrows(t.context.m.verifyConditions({npmPublish: false}, {options: {}, logger: t.context.logger}));
});

test.serial('Throws error if NPM token is invalid', async t => {
process.env.NPM_TOKEN = 'wrong_token';
const pkg = {name: 'published', version: '1.0.0', publishConfig: {registry: npmRegistry.url}};
Expand All @@ -62,6 +69,50 @@ test.serial('Throws error if NPM token is invalid', async t => {
t.regex(npmrc, /:_authToken/);
});

test.serial(
'Throws error if NPM token is invalid if "npmPublish" is false and npm plugin used for "getLastRelease"',
async t => {
process.env.NPM_TOKEN = 'wrong_token';
const pkg = {name: 'published', version: '1.0.0', publishConfig: {registry: npmRegistry.url}};
await outputJson('./package.json', pkg);
const error = await t.throws(
t.context.m.verifyConditions(
{npmPublish: false},
{options: {getLastRelease: '@semantic-release/npm'}, logger: t.context.logger}
)
);

t.true(error instanceof SemanticReleaseError);
t.is(error.code, 'EINVALIDNPMTOKEN');
t.is(error.message, 'Invalid npm token.');

const npmrc = (await readFile('.npmrc')).toString();
t.regex(npmrc, /:_authToken/);
}
);

test.serial(
'Throws error if NPM token is invalid if "npmPublish" is false and npm plugin used for "getLastRelease" as an object',
async t => {
process.env.NPM_TOKEN = 'wrong_token';
const pkg = {name: 'published', version: '1.0.0', publishConfig: {registry: npmRegistry.url}};
await outputJson('./package.json', pkg);
const error = await t.throws(
t.context.m.verifyConditions(
{npmPublish: false},
{options: {getLastRelease: {path: '@semantic-release/npm'}}, logger: t.context.logger}
)
);

t.true(error instanceof SemanticReleaseError);
t.is(error.code, 'EINVALIDNPMTOKEN');
t.is(error.message, 'Invalid npm token.');

const npmrc = (await readFile('.npmrc')).toString();
t.regex(npmrc, /:_authToken/);
}
);

test.serial('Verify npm auth and package', async t => {
Object.assign(process.env, npmRegistry.authEnv);
const pkg = {name: 'valid-token', publishConfig: {registry: npmRegistry.url}};
Expand Down
6 changes: 5 additions & 1 deletion test/verify.test.js → test/verify-config.test.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import test from 'ava';
import {stub} from 'sinon';
import verify from '../lib/verify';
import verify from '../lib/verify-config';

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

test('Verify "npmPublish", "tarballDir" and "pkgRoot" options', async t => {
await t.notThrows(verify({npmPublish: true, tarballDir: 'release', pkgRoot: 'dist'}, {}, t.context.logger));
});

test('Throw SemanticReleaseError if "npmPublish" option is not a Boolean', async t => {
const npmPublish = 42;
const error = await t.throws(verify({npmPublish}, {}, t.context.logger));
Expand Down

0 comments on commit 4cd5cd7

Please sign in to comment.