From 8565d9dc138a1c4f75154b3242f603434712af6a Mon Sep 17 00:00:00 2001 From: Pierre Vanduynslager Date: Thu, 23 Nov 2017 21:31:02 -0500 Subject: [PATCH] feat: Read package.json file instead using the one passed by semantic-release --- index.js | 12 +++++-- lib/get-pkg.js | 16 ++++++++++ lib/verify-pkg.js | 7 ----- lib/verify.js | 2 -- package.json | 3 +- test/get-pkg.test.js | 49 +++++++++++++++++++++++++++++ test/integration.test.js | 28 +++++++++-------- test/set-npmrc-auth.test.js | 2 +- test/update-package-version.test.js | 2 +- test/verify-pkg.test.js | 14 --------- 10 files changed, 93 insertions(+), 42 deletions(-) create mode 100644 lib/get-pkg.js delete mode 100644 lib/verify-pkg.js create mode 100644 test/get-pkg.test.js delete mode 100644 test/verify-pkg.test.js diff --git a/index.js b/index.js index 11bf57f1..10d44f38 100644 --- a/index.js +++ b/index.js @@ -1,15 +1,19 @@ +const getPkg = require('./lib/get-pkg'); const verifyNpm = require('./lib/verify'); const publishNpm = require('./lib/publish'); const getLastReleaseNpm = require('./lib/get-last-release'); let verified; -async function verifyConditions(pluginConfig, {pkg, logger}) { +async function verifyConditions(pluginConfig, {logger}) { + const pkg = await getPkg(); await verifyNpm(pkg, logger); verified = true; } -async function getLastRelease(pluginConfig, {pkg, logger}) { +async function getLastRelease(pluginConfig, {logger}) { + // Reload package.json in case a previous external step updated it + const pkg = await getPkg(); if (!verified) { await verifyNpm(pkg, logger); verified = true; @@ -17,7 +21,9 @@ async function getLastRelease(pluginConfig, {pkg, logger}) { return getLastReleaseNpm(pkg, logger); } -async function publish(pluginConfig, {pkg, nextRelease: {version}, logger}) { +async function publish(pluginConfig, {nextRelease: {version}, logger}) { + // Reload package.json in case a previous external step updated it + const pkg = await getPkg(); if (!verified) { await verifyNpm(pkg, logger); verified = true; diff --git a/lib/get-pkg.js b/lib/get-pkg.js new file mode 100644 index 00000000..dfb4ec85 --- /dev/null +++ b/lib/get-pkg.js @@ -0,0 +1,16 @@ +const readPkgUp = require('read-pkg-up'); +const SemanticReleaseError = require('@semantic-release/error'); + +module.exports = async () => { + const {pkg} = await readPkgUp(); + + if (!pkg) { + throw new SemanticReleaseError('A package.json file is required to release on npm.', 'ENOPKG'); + } + + if (!pkg.name) { + throw new SemanticReleaseError('No "name" found in package.json.', 'ENOPKGNAME'); + } + + return pkg; +}; diff --git a/lib/verify-pkg.js b/lib/verify-pkg.js deleted file mode 100644 index 96d182cc..00000000 --- a/lib/verify-pkg.js +++ /dev/null @@ -1,7 +0,0 @@ -const SemanticReleaseError = require('@semantic-release/error'); - -module.exports = ({name}) => { - if (!name) { - throw new SemanticReleaseError('No "name" found in package.json.', 'ENOPKGNAME'); - } -}; diff --git a/lib/verify.js b/lib/verify.js index f89a940d..9e3e8125 100644 --- a/lib/verify.js +++ b/lib/verify.js @@ -1,10 +1,8 @@ const execa = require('execa'); const SemanticReleaseError = require('@semantic-release/error'); -const verifyPkg = require('./verify-pkg'); const setNpmrcAuth = require('./set-npmrc-auth'); module.exports = async (pkg, logger) => { - verifyPkg(pkg); await setNpmrcAuth(pkg, logger); try { await execa('npm', ['whoami']); diff --git a/package.json b/package.json index f49f7df7..65e60f0d 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "nerf-dart": "^1.0.0", "npm-conf": "^1.1.3", "npm-registry-client": "^8.5.0", + "read-pkg-up": "^3.0.0", "registry-auth-token": "^3.3.1" }, "devDependencies": { @@ -39,7 +40,7 @@ "nock": "^9.1.0", "nyc": "^11.2.1", "prettier": "~1.8.2", - "semantic-release": "^9.1.1", + "semantic-release": "^10.0.0", "sinon": "^4.1.2", "tempy": "^0.2.1", "xo": "^0.18.2" diff --git a/test/get-pkg.test.js b/test/get-pkg.test.js new file mode 100644 index 00000000..9711fa9e --- /dev/null +++ b/test/get-pkg.test.js @@ -0,0 +1,49 @@ +import test from 'ava'; +import {writeJson, writeFile} from 'fs-extra'; +import tempy from 'tempy'; +import getPkg from '../lib/get-pkg'; + +test.beforeEach(t => { + // Save the current working diretory + t.context.cwd = process.cwd(); + // Change current working directory to a temp directory + process.chdir(tempy.directory()); +}); + +test.afterEach.always(t => { + // Restore the current working directory + process.chdir(t.context.cwd); +}); + +test.serial('Verify name and return parsed package.json', async t => { + const pkg = {name: 'package', version: '0.0.0'}; + await writeJson('./package.json', pkg); + + const result = await getPkg(); + t.is(pkg.name, result.name); + t.is(pkg.version, result.version); +}); + +test.serial('Throw error if missing package.json', async t => { + const error = await t.throws(getPkg()); + + t.is(error.name, 'SemanticReleaseError'); + t.is(error.code, 'ENOPKG'); +}); + +test.serial('Throw error if missing package name', async t => { + await writeJson('./package.json', {version: '0.0.0'}); + + const error = await t.throws(getPkg()); + + t.is(error.name, 'SemanticReleaseError'); + t.is(error.code, 'ENOPKGNAME'); +}); + +test.serial('Throw error if package.json is malformed', async t => { + await writeFile('./package.json', "{name: 'package',}"); + + const error = await t.throws(getPkg()); + + t.is(error.name, 'JSONError'); +}); diff --git a/test/integration.test.js b/test/integration.test.js index f2de84cf..2ded23f7 100644 --- a/test/integration.test.js +++ b/test/integration.test.js @@ -66,9 +66,9 @@ test.after.always(async () => { test.serial('Throws error if NPM token is invalid', async t => { process.env.NPM_TOKEN = 'wrong_token'; - const error = await t.throws( - t.context.m.verifyConditions({}, {pkg: {name: 'invalid-token'}, logger: t.context.logger}) - ); + const pkg = {name: 'published', version: '1.0.0', publishConfig: {registry: npmRegistry.url}}; + await writeJson('./package.json', pkg); + const error = await t.throws(t.context.m.verifyConditions({}, {logger: t.context.logger})); t.true(error instanceof SemanticReleaseError); t.is(error.code, 'EINVALIDNPMTOKEN'); @@ -81,7 +81,8 @@ test.serial('Throws error if NPM token is invalid', async t => { test.serial('Verify npm auth and package', async t => { Object.assign(process.env, npmRegistry.authEnv); const pkg = {name: 'valid-token', publishConfig: {registry: npmRegistry.url}}; - await t.notThrows(t.context.m.verifyConditions({}, {pkg, logger: t.context.logger})); + await writeJson('./package.json', pkg); + await t.notThrows(t.context.m.verifyConditions({}, {logger: t.context.logger})); const npmrc = (await readFile('.npmrc')).toString(); t.regex(npmrc, /_auth =/); @@ -91,7 +92,8 @@ test.serial('Verify npm auth and package', async t => { test.serial('Return nothing if no version if published', async t => { Object.assign(process.env, npmRegistry.authEnv); const pkg = {name: 'not-published', publishConfig: {registry: npmRegistry.url}}; - const nextRelease = await t.context.m.getLastRelease({}, {pkg, logger: t.context.logger}); + await writeJson('./package.json', pkg); + const nextRelease = await t.context.m.getLastRelease({}, {logger: t.context.logger}); t.deepEqual(nextRelease, {}); }); @@ -110,7 +112,7 @@ test.serial('Return last version published', async t => { await execa('npm', ['publish']); - const nextRelease = await t.context.m.getLastRelease({}, {pkg, logger: t.context.logger}); + const nextRelease = await t.context.m.getLastRelease({}, {logger: t.context.logger}); t.is(nextRelease.version, '1.0.0'); }); @@ -133,7 +135,7 @@ test.serial('Return last version published on a dist-tag', async t => { // Publish version 1.1.0 on next await execa('npm', ['publish', '--tag=next']); - const nextRelease = await t.context.m.getLastRelease({}, {pkg, logger: t.context.logger}); + const nextRelease = await t.context.m.getLastRelease({}, {logger: t.context.logger}); t.is(nextRelease.version, '1.1.0'); }); @@ -152,7 +154,7 @@ test.serial('Return nothing for an unpublished package', async t => { await execa('npm', ['publish']); await execa('npm', ['unpublish', 'unpublished', '--force']); - const nextRelease = await t.context.m.getLastRelease({}, {pkg, logger: t.context.logger}); + const nextRelease = await t.context.m.getLastRelease({}, {logger: t.context.logger}); t.deepEqual(nextRelease, {}); }); @@ -161,7 +163,7 @@ test.serial('Publish a package', async t => { const pkg = {name: 'publish', version: '1.0.0', publishConfig: {registry: npmRegistry.url}}; await writeJson('./package.json', pkg); - await t.context.m.publish({}, {pkg, logger: t.context.logger, nextRelease: {version: '1.0.0'}}); + await t.context.m.publish({}, {logger: t.context.logger, nextRelease: {version: '1.0.0'}}); t.is((await execa('npm', ['view', 'publish', 'version'])).stdout, '1.0.0'); }); @@ -171,13 +173,13 @@ test.serial('Verify token and set up auth only on the fist call', async t => { const pkg = {name: 'test-module', version: '0.0.0-dev', publishConfig: {registry: npmRegistry.url}}; await writeJson('./package.json', pkg); - await t.notThrows(t.context.m.verifyConditions({}, {pkg, logger: t.context.logger})); + await t.notThrows(t.context.m.verifyConditions({}, {logger: t.context.logger})); - let nextRelease = await t.context.m.getLastRelease({}, {pkg, logger: t.context.logger}); + let nextRelease = await t.context.m.getLastRelease({}, {logger: t.context.logger}); t.deepEqual(nextRelease, {}); - await t.context.m.publish({}, {pkg, logger: t.context.logger, nextRelease: {version: '1.0.0'}}); + await t.context.m.publish({}, {logger: t.context.logger, nextRelease: {version: '1.0.0'}}); - nextRelease = await t.context.m.getLastRelease({}, {pkg, logger: t.context.logger}); + nextRelease = await t.context.m.getLastRelease({}, {logger: t.context.logger}); t.is(nextRelease.version, '1.0.0'); }); diff --git a/test/set-npmrc-auth.test.js b/test/set-npmrc-auth.test.js index ab8fa23e..1bbcf1e9 100644 --- a/test/set-npmrc-auth.test.js +++ b/test/set-npmrc-auth.test.js @@ -27,7 +27,7 @@ test.beforeEach(t => { }); test.afterEach.always(t => { - // Clear `rc` from the npm cache as it cache the relative path of .npmrc files, preventing to load a new file after changing current working directory + // Clear `rc` from the npm cache as it cache the relative path of .npmrc files, preventing to load a new file after changing current working directory. See https://github.com/dominictarr/rc/issues/101 clearModule('rc'); // Restore process.env process.env = Object.assign({}, t.context.env); diff --git a/test/update-package-version.test.js b/test/update-package-version.test.js index 0b635a2a..87e58215 100644 --- a/test/update-package-version.test.js +++ b/test/update-package-version.test.js @@ -1,5 +1,5 @@ -import {writeJson, readJson} from 'fs-extra'; import test from 'ava'; +import {writeJson, readJson} from 'fs-extra'; import tempy from 'tempy'; import execa from 'execa'; import {stub} from 'sinon'; diff --git a/test/verify-pkg.test.js b/test/verify-pkg.test.js deleted file mode 100644 index edd325b0..00000000 --- a/test/verify-pkg.test.js +++ /dev/null @@ -1,14 +0,0 @@ -import test from 'ava'; -import SemanticReleaseError from '@semantic-release/error'; -import verify from '../lib/verify-pkg'; - -test('Verify name and repository', t => { - t.notThrows(() => verify({name: 'package'})); -}); - -test('Return error for missing package name', t => { - const error = t.throws(() => verify({repository: {url: 'http://github.com/whats/up.git'}})); - - t.true(error instanceof SemanticReleaseError); - t.is(error.code, 'ENOPKGNAME'); -});