From e36a56bb89652e5cd177f9be2e963dd5e4701123 Mon Sep 17 00:00:00 2001 From: Pierre Vanduynslager Date: Tue, 19 Dec 2017 20:10:06 -0500 Subject: [PATCH] feat: add `pkgRoot` option to publish a sub-directory --- README.md | 37 ++++++-- index.js | 21 +++-- lib/get-pkg.js | 24 ++--- lib/publish.js | 9 +- lib/update-package-version.js | 19 ++-- lib/verify.js | 6 +- package.json | 2 +- test/get-pkg.test.js | 15 +++- test/integration.test.js | 131 ++++++++++++++++++++++------ test/update-package-version.test.js | 39 +++++++-- test/verify.test.js | 8 ++ 11 files changed, 240 insertions(+), 71 deletions(-) diff --git a/README.md b/README.md index 9958b75a..a91bb55f 100644 --- a/README.md +++ b/README.md @@ -39,10 +39,13 @@ Use either `NPM_TOKEN` for token authentication or `NPM_USERNAME`, `NPM_PASSWORD ### Options -| Options | Description | Default | -| ------------ | ---------------------------------------------------------------------------------------------------------------------- | ------- | -| `npmPublish` | Whether to publish the `npm` package to the registry. If `false` the `package.json` version will still be updated. | `true` | -| `tarballDir` | Directory path in which to generate the the package tarball. If `false` the tarball is not be kept on the file system. | `false` | +| Options | Description | Default | +|--------------|---------------------------------------------------------------------------------------------------------------------|---------| +| `npmPublish` | Whether to publish the `npm` package to the registry. If `false` the `package.json` version will still be updated. | `true` | +| `pkgRoot` | Directory path to publish. | `.` | +| `tarballDir` | Directory path in which to write the the package tarball. If `false` the tarball is not be kept on the file system. | `false` | + +**Note**: The `pkgRoot` directory must contains a `package.json`. The version will be updated only in the `package.json` and `npm-shrinkwrap.json` within the `pkgRoot` directory. ### Npm configuration @@ -74,7 +77,7 @@ Each individual plugin can be disabled, replaced or used with other plugins in t } ``` -The `npmPublish` and `tarballDir` option can be used to skip the publishing to the `npm` registry and instead, release the package tarball with another plugin. For example with the [github](https://github.com/semantic-release/github): +The `npmPublish` and `tarballDir` option can be used to skip the publishing to the `npm` registry and instead, release the package tarball with another plugin. For example with the [github](https://github.com/semantic-release/github) plugin: ```json { @@ -95,3 +98,27 @@ The `npmPublish` and `tarballDir` option can be used to skip the publishing to t } } ``` + +When publishing from a sub-directory with the `pkgRoot` option, the `package.json` and `npm-shrinkwrap.json` updated with the new version can be moved to another directory with a `postpublish` [npm script](https://docs.npmjs.com/misc/scripts). For example with the [git](https://github.com/semantic-release/git) plugin: + +```json +{ + "release": { + "verifyConditions": ["@semantic-release/conditions-travis", "@semantic-release/npm", "@semantic-release/git"], + "getLastRelease": "@semantic-release/npm", + "publish": [ + { + "path": "@semantic-release/npm", + "pkgRoot": "dist" + }, + { + "path": "@semantic-release/git", + "assets": ["package.json", "npm-shrinkwrap.json"] + }, + ] + }, + "scripts": { + "postpublish": "cp -r dist/package.json . && cp -r dist/npm-shrinkwrap.json ." + } +} +``` diff --git a/index.js b/index.js index 1e118115..dac2ee89 100644 --- a/index.js +++ b/index.js @@ -8,7 +8,7 @@ const getLastReleaseNpm = require('./lib/get-last-release'); let verified; async function verifyConditions(pluginConfig, {options, logger}) { - // If the npm publish plugin is used and has `npmPublish` or `tarballDir` configured, validate them now in order to prevent any release if the configuration is wrong + // 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' @@ -19,18 +19,29 @@ async function verifyConditions(pluginConfig, {options, logger}) { if (publishPlugin && publishPlugin.tarballDir) { pluginConfig.tarballDir = publishPlugin.tarballDir; } + if (publishPlugin && publishPlugin.pkgRoot) { + pluginConfig.pkgRoot = publishPlugin.pkgRoot; + } } setLegacyToken(); - const pkg = await getPkg(); + const pkg = await getPkg(pluginConfig.pkgRoot); await verifyNpm(pluginConfig, pkg, logger); verified = true; } -async function getLastRelease(pluginConfig, {logger}) { +async function getLastRelease(pluginConfig, {options, logger}) { setLegacyToken(); // Reload package.json in case a previous external step updated it - const pkg = await getPkg(); + const pkg = await getPkg(pluginConfig.pkgRoot); if (!verified) { + if (options.publish) { + const publishPlugin = castArray(options.publish).find( + config => config.path && config.path === '@semantic-release/npm' + ); + if (publishPlugin && publishPlugin.pkgRoot) { + pluginConfig.pkgRoot = publishPlugin.pkgRoot; + } + } await verifyNpm(pluginConfig, pkg, logger); verified = true; } @@ -40,7 +51,7 @@ async function getLastRelease(pluginConfig, {logger}) { async function publish(pluginConfig, {nextRelease: {version}, logger}) { setLegacyToken(); // Reload package.json in case a previous external step updated it - const pkg = await getPkg(); + const pkg = await getPkg(pluginConfig.pkgRoot); if (!verified) { await verifyNpm(pluginConfig, pkg, logger); verified = true; diff --git a/lib/get-pkg.js b/lib/get-pkg.js index dfb4ec85..e7a3a918 100644 --- a/lib/get-pkg.js +++ b/lib/get-pkg.js @@ -1,16 +1,18 @@ -const readPkgUp = require('read-pkg-up'); +const readPkg = require('read-pkg'); const SemanticReleaseError = require('@semantic-release/error'); -module.exports = async () => { - const {pkg} = await readPkgUp(); +module.exports = async pkgRoot => { + try { + const pkg = await readPkg(pkgRoot); + if (!pkg.name) { + throw new SemanticReleaseError('No "name" found in package.json.', 'ENOPKGNAME'); + } - if (!pkg) { - throw new SemanticReleaseError('A package.json file is required to release on npm.', 'ENOPKG'); + return pkg; + } catch (err) { + if (err.code === 'ENOENT') { + throw new SemanticReleaseError('A package.json file is required to release on npm.', 'ENOPKG'); + } + throw err; } - - if (!pkg.name) { - throw new SemanticReleaseError('No "name" found in package.json.', 'ENOPKGNAME'); - } - - return pkg; }; diff --git a/lib/publish.js b/lib/publish.js index 324b7cdb..dc8d7d88 100644 --- a/lib/publish.js +++ b/lib/publish.js @@ -4,19 +4,20 @@ const execa = require('execa'); const getRegistry = require('./get-registry'); const updatePackageVersion = require('./update-package-version'); -module.exports = async ({npmPublish, tarballDir}, {publishConfig, name}, version, logger) => { +module.exports = async ({npmPublish, tarballDir, pkgRoot}, {publishConfig, name}, version, logger) => { + const basePath = pkgRoot || '.'; const registry = await getRegistry(publishConfig, name); - await updatePackageVersion(version, logger); + await updatePackageVersion(version, basePath, logger); if (tarballDir) { logger.log('Creating npm package version %s', version); - const tarball = await execa.stdout('npm', ['pack']); + const tarball = await execa.stdout('npm', ['pack', `./${basePath}`]); await move(tarball, path.join(tarballDir.trim(), tarball)); } if (npmPublish !== false) { logger.log('Publishing version %s to npm registry', version); - const shell = await execa('npm', ['publish', '--registry', registry]); + const shell = await execa('npm', ['publish', `./${basePath}`, '--registry', registry]); process.stdout.write(shell.stdout); } }; diff --git a/lib/update-package-version.js b/lib/update-package-version.js index 821909a1..cc713618 100644 --- a/lib/update-package-version.js +++ b/lib/update-package-version.js @@ -1,15 +1,18 @@ +const path = require('path'); const {readFile, writeFile, pathExists} = require('fs-extra'); -module.exports = async (version, logger) => { - const pkg = (await readFile('./package.json')).toString(); +module.exports = async (version, basePath, logger) => { + const packagePath = path.join(basePath, 'package.json'); + const shrinkwrapPath = path.join(basePath, 'npm-shrinkwrap.json'); + const pkg = (await readFile(packagePath)).toString(); - await writeFile('./package.json', replaceVersion(pkg, version)); - logger.log('Wrote version %s to package.json', version); + await writeFile(packagePath, replaceVersion(pkg, version)); + logger.log('Wrote version %s to %s', version, packagePath); - if (await pathExists('./npm-shrinkwrap.json')) { - const shrinkwrap = (await readFile('./npm-shrinkwrap.json')).toString(); - await writeFile('./npm-shrinkwrap.json', replaceVersion(shrinkwrap, version)); - logger.log('Wrote version %s to npm-shrinkwrap.json', version); + if (await pathExists(shrinkwrapPath)) { + const shrinkwrap = (await readFile(shrinkwrapPath)).toString(); + await writeFile(shrinkwrapPath, replaceVersion(shrinkwrap, version)); + logger.log('Wrote version %s to %s', version, shrinkwrapPath); } }; diff --git a/lib/verify.js b/lib/verify.js index 99f4d441..d585734c 100644 --- a/lib/verify.js +++ b/lib/verify.js @@ -4,7 +4,7 @@ const SemanticReleaseError = require('@semantic-release/error'); const getRegistry = require('./get-registry'); const setNpmrcAuth = require('./set-npmrc-auth'); -module.exports = async ({npmPublish, tarballDir}, pkg, logger) => { +module.exports = async ({npmPublish, tarballDir, pkgRoot}, pkg, logger) => { if (!isUndefined(npmPublish) && !isBoolean(npmPublish)) { throw new SemanticReleaseError('The "npmPublish" options, if defined, must be a Boolean.', 'EINVALIDNPMPUBLISH'); } @@ -13,6 +13,10 @@ module.exports = async ({npmPublish, tarballDir}, pkg, logger) => { throw new SemanticReleaseError('The "tarballDir" options, if defined, must be a String.', 'EINVALIDTARBALLDIR'); } + 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 { diff --git a/package.json b/package.json index 85604e09..cd344c7c 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "nerf-dart": "^1.0.0", "npm-conf": "^1.1.3", "npm-registry-client": "^8.5.0", - "read-pkg-up": "^3.0.0", + "read-pkg": "^3.0.0", "registry-auth-token": "^3.3.1" }, "devDependencies": { diff --git a/test/get-pkg.test.js b/test/get-pkg.test.js index 03b0f2ee..4e72cd96 100644 --- a/test/get-pkg.test.js +++ b/test/get-pkg.test.js @@ -1,5 +1,5 @@ import test from 'ava'; -import {writeJson, writeFile} from 'fs-extra'; +import {outputJson, writeFile} from 'fs-extra'; import tempy from 'tempy'; import getPkg from '../lib/get-pkg'; @@ -18,13 +18,22 @@ test.afterEach.always(() => { test.serial('Verify name and return parsed package.json', async t => { const pkg = {name: 'package', version: '0.0.0'}; - await writeJson('./package.json', pkg); + await outputJson('./package.json', pkg); const result = await getPkg(); t.is(pkg.name, result.name); t.is(pkg.version, result.version); }); +test.serial('Verify name and return parsed package.json from a sub-directory', async t => { + const pkg = {name: 'package', version: '0.0.0'}; + await outputJson('./dist/package.json', pkg); + + const result = await getPkg('dist'); + 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()); @@ -33,7 +42,7 @@ test.serial('Throw error if missing package.json', async t => { }); test.serial('Throw error if missing package name', async t => { - await writeJson('./package.json', {version: '0.0.0'}); + await outputJson('./package.json', {version: '0.0.0'}); const error = await t.throws(getPkg()); diff --git a/test/integration.test.js b/test/integration.test.js index ccc36370..52ffa399 100644 --- a/test/integration.test.js +++ b/test/integration.test.js @@ -1,5 +1,5 @@ import test from 'ava'; -import {writeJson, readJson, readFile, appendFile, pathExists} from 'fs-extra'; +import {outputJson, readJson, readFile, appendFile, pathExists} from 'fs-extra'; import execa from 'execa'; import {stub} from 'sinon'; import tempy from 'tempy'; @@ -51,7 +51,7 @@ test.after.always(async () => { 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}}; - await writeJson('./package.json', pkg); + await outputJson('./package.json', pkg); const error = await t.throws(t.context.m.verifyConditions({}, {options: {}, logger: t.context.logger})); t.true(error instanceof SemanticReleaseError); @@ -65,7 +65,7 @@ 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 writeJson('./package.json', pkg); + await outputJson('./package.json', pkg); await t.notThrows(t.context.m.verifyConditions({}, {options: {}, logger: t.context.logger})); const npmrc = (await readFile('.npmrc')).toString(); @@ -73,11 +73,22 @@ test.serial('Verify npm auth and package', async t => { t.regex(npmrc, /email =/); }); +test.serial('Verify npm auth and package from a sub-directory', async t => { + Object.assign(process.env, npmRegistry.authEnv); + const pkg = {name: 'valid-token', publishConfig: {registry: npmRegistry.url}}; + await outputJson('./dist/package.json', pkg); + await t.notThrows(t.context.m.verifyConditions({pkgRoot: 'dist'}, {options: {}, logger: t.context.logger})); + + const npmrc = (await readFile('.npmrc')).toString(); + t.regex(npmrc, /_auth =/); + t.regex(npmrc, /email =/); +}); + test.serial('Verify npm auth and package with "npm_config_registry" env var set by yarn', async t => { Object.assign(process.env, npmRegistry.authEnv); process.env.npm_config_registry = 'https://registry.yarnpkg.com'; // eslint-disable-line camelcase const pkg = {name: 'valid-token', publishConfig: {registry: npmRegistry.url}}; - await writeJson('./package.json', pkg); + await outputJson('./package.json', pkg); await t.notThrows(t.context.m.verifyConditions({}, {options: {}, logger: t.context.logger})); const npmrc = (await readFile('.npmrc')).toString(); @@ -88,8 +99,8 @@ test.serial('Verify npm auth and package with "npm_config_registry" env var set 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}}; - await writeJson('./package.json', pkg); - const nextRelease = await t.context.m.getLastRelease({}, {logger: t.context.logger}); + await outputJson('./package.json', pkg); + const nextRelease = await t.context.m.getLastRelease({}, {options: {}, logger: t.context.logger}); t.falsy(nextRelease); }); @@ -97,7 +108,7 @@ test.serial('Return nothing if no version if published', async t => { test.serial('Return last version published', async t => { Object.assign(process.env, npmRegistry.authEnv); const pkg = {name: 'published', version: '1.0.0', publishConfig: {registry: npmRegistry.url}}; - await writeJson('./package.json', pkg); + await outputJson('./package.json', pkg); await appendFile( './.npmrc', @@ -108,14 +119,18 @@ test.serial('Return last version published', async t => { await execa('npm', ['publish']); - const nextRelease = await t.context.m.getLastRelease({}, {logger: t.context.logger}); + const nextRelease = await t.context.m.getLastRelease({}, {options: {}, logger: t.context.logger}); t.is(nextRelease.version, '1.0.0'); }); test.serial('Return last version published on a dist-tag', async t => { Object.assign(process.env, npmRegistry.authEnv); - const pkg = {name: 'published-next', version: '1.0.0', publishConfig: {registry: npmRegistry.url, tag: 'next'}}; - await writeJson('./package.json', pkg); + const pkg = { + name: 'published-next', + version: '1.0.0', + publishConfig: {options: {}, registry: npmRegistry.url, tag: 'next'}, + }; + await outputJson('./package.json', pkg); await appendFile( './.npmrc', @@ -127,18 +142,18 @@ test.serial('Return last version published on a dist-tag', async t => { // Publish version 1.0.0 on latest and next await execa('npm', ['publish', '--tag=next']); pkg.version = '1.1.0'; - await writeJson('./package.json', pkg); + await outputJson('./package.json', pkg); // Publish version 1.1.0 on next await execa('npm', ['publish', '--tag=next']); - const nextRelease = await t.context.m.getLastRelease({}, {logger: t.context.logger}); + const nextRelease = await t.context.m.getLastRelease({}, {options: {}, logger: t.context.logger}); t.is(nextRelease.version, '1.1.0'); }); test.serial('Return nothing for an unpublished package', async t => { Object.assign(process.env, npmRegistry.authEnv); const pkg = {name: 'unpublished', version: '1.0.0', publishConfig: {registry: npmRegistry.url}}; - await writeJson('./package.json', pkg); + await outputJson('./package.json', pkg); await appendFile( './.npmrc', @@ -150,13 +165,34 @@ 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({}, {logger: t.context.logger}); + const nextRelease = await t.context.m.getLastRelease( + {}, + {options: {publish: ['@semantic-release/npm']}, logger: t.context.logger} + ); t.falsy(nextRelease); }); -test('Throw SemanticReleaseError if publish "npmPublish" option is not a Boolean', async t => { +test('Throw SemanticReleaseError if publish "pkgRoot" option in getLastRelease is not a String', async t => { + const pkg = {name: 'invalid-pkgRoot', publishConfig: {registry: npmRegistry.url}}; + await outputJson('./dist/package.json', pkg); + const pkgRoot = 42; + const error = await t.throws( + t.context.m.getLastRelease( + {}, + { + options: {publish: ['@semantic-release/github', {path: '@semantic-release/npm', pkgRoot}]}, + logger: t.context.logger, + } + ) + ); + + t.is(error.name, 'SemanticReleaseError'); + t.is(error.code, 'EINVALIDPKGROOT'); +}); + +test('Throw SemanticReleaseError if publish "npmPublish" option in verifyConditions is not a Boolean', async t => { const pkg = {name: 'invalid-npmPublish', publishConfig: {registry: npmRegistry.url}}; - await writeJson('./package.json', pkg); + await outputJson('./package.json', pkg); const npmPublish = 42; const error = await t.throws( t.context.m.verifyConditions( @@ -172,9 +208,9 @@ test('Throw SemanticReleaseError if publish "npmPublish" option is not a Boolean t.is(error.code, 'EINVALIDNPMPUBLISH'); }); -test('Throw SemanticReleaseError if publish "tarballDir" option is not a String', async t => { +test('Throw SemanticReleaseError if publish "tarballDir" option in verifyConditions is not a String', async t => { const pkg = {name: 'invalid-tarballDir', publishConfig: {registry: npmRegistry.url}}; - await writeJson('./package.json', pkg); + await outputJson('./package.json', pkg); const tarballDir = 42; const error = await t.throws( t.context.m.verifyConditions( @@ -190,10 +226,28 @@ test('Throw SemanticReleaseError if publish "tarballDir" option is not a String' t.is(error.code, 'EINVALIDTARBALLDIR'); }); +test('Throw SemanticReleaseError if publish "pkgRoot" option in verifyConditions is not a String', async t => { + const pkg = {name: 'invalid-pkgRoot', publishConfig: {registry: npmRegistry.url}}; + await outputJson('./dist/package.json', pkg); + const pkgRoot = 42; + const error = await t.throws( + t.context.m.verifyConditions( + {}, + { + options: {publish: ['@semantic-release/github', {path: '@semantic-release/npm', pkgRoot}]}, + logger: t.context.logger, + } + ) + ); + + t.is(error.name, 'SemanticReleaseError'); + t.is(error.code, 'EINVALIDPKGROOT'); +}); + test.serial('Publish the package', async t => { Object.assign(process.env, npmRegistry.authEnv); const pkg = {name: 'publish', version: '0.0.0', publishConfig: {registry: npmRegistry.url}}; - await writeJson('./package.json', pkg); + await outputJson('./package.json', pkg); await t.context.m.publish({}, {logger: t.context.logger, nextRelease: {version: '1.0.0'}}); @@ -202,33 +256,60 @@ test.serial('Publish the package', async t => { t.is((await execa('npm', ['view', pkg.name, 'version'])).stdout, '1.0.0'); }); +test.serial('Publish the package from a sub-directory', async t => { + Object.assign(process.env, npmRegistry.authEnv); + const pkg = {name: 'publish-sub-dir', version: '0.0.0', publishConfig: {registry: npmRegistry.url}}; + await outputJson('./dist/package.json', pkg); + + await t.context.m.publish({pkgRoot: 'dist'}, {logger: t.context.logger, nextRelease: {version: '1.0.0'}}); + + t.is((await readJson('./dist/package.json')).version, '1.0.0'); + t.false(await pathExists(`./${pkg.name}-1.0.0.tgz`)); + t.is((await execa('npm', ['view', pkg.name, 'version'])).stdout, '1.0.0'); +}); + test.serial('Create the package and skip publish', async t => { Object.assign(process.env, npmRegistry.authEnv); const pkg = {name: 'skip-publish', version: '0.0.0', publishConfig: {registry: npmRegistry.url}}; - await writeJson('./package.json', pkg); + await outputJson('./package.json', pkg); await t.context.m.publish( - {npmPublish: false, tarballDir: 'dist'}, + {npmPublish: false, tarballDir: 'tarball'}, {logger: t.context.logger, nextRelease: {version: '1.0.0'}} ); t.is((await readJson('./package.json')).version, '1.0.0'); - t.true(await pathExists(`./dist/${pkg.name}-1.0.0.tgz`)); + t.true(await pathExists(`./tarball/${pkg.name}-1.0.0.tgz`)); + await t.throws(execa('npm', ['view', pkg.name, 'version'])); +}); + +test.serial('Create the package and skip publish from a sub-directory', async t => { + Object.assign(process.env, npmRegistry.authEnv); + const pkg = {name: 'skip-publish-sub-dir', version: '0.0.0', publishConfig: {registry: npmRegistry.url}}; + await outputJson('./dist/package.json', pkg); + + await t.context.m.publish( + {npmPublish: false, tarballDir: './tarball', pkgRoot: './dist'}, + {logger: t.context.logger, nextRelease: {version: '1.0.0'}} + ); + + t.is((await readJson('./dist/package.json')).version, '1.0.0'); + t.true(await pathExists(`./tarball/${pkg.name}-1.0.0.tgz`)); await t.throws(execa('npm', ['view', pkg.name, 'version'])); }); test.serial('Verify token and set up auth only on the fist call', async t => { Object.assign(process.env, npmRegistry.authEnv); const pkg = {name: 'test-module', version: '0.0.0-dev', publishConfig: {registry: npmRegistry.url}}; - await writeJson('./package.json', pkg); + await outputJson('./package.json', pkg); await t.notThrows(t.context.m.verifyConditions({}, {options: {}, logger: t.context.logger})); - let nextRelease = await t.context.m.getLastRelease({}, {logger: t.context.logger}); + let nextRelease = await t.context.m.getLastRelease({}, {options: {}, logger: t.context.logger}); t.falsy(nextRelease); await t.context.m.publish({}, {logger: t.context.logger, nextRelease: {version: '1.0.0'}}); - nextRelease = await t.context.m.getLastRelease({}, {logger: t.context.logger}); + nextRelease = await t.context.m.getLastRelease({}, {options: {}, logger: t.context.logger}); t.is(nextRelease.version, '1.0.0'); }); diff --git a/test/update-package-version.test.js b/test/update-package-version.test.js index 4f67cc75..ac167b0e 100644 --- a/test/update-package-version.test.js +++ b/test/update-package-version.test.js @@ -1,5 +1,5 @@ import test from 'ava'; -import {writeFile, readFile} from 'fs-extra'; +import {outputFile, readFile} from 'fs-extra'; import tempy from 'tempy'; import execa from 'execa'; import {stub} from 'sinon'; @@ -34,15 +34,15 @@ test.serial('Updade package.json', async t => { `; // Create package.json in repository root - await writeFile('./package.json', pkg); + await outputFile('./package.json', pkg); - await updatePackageVersion('1.0.0', t.context.logger); + await updatePackageVersion('1.0.0', '.', t.context.logger); // Verify package.json has been updated t.is((await readFile('./package.json')).toString(), pkg.replace('0.0.0-dev', '1.0.0')); // Verify the logger has been called with the version updated - t.deepEqual(t.context.log.args[0], ['Wrote version %s to package.json', '1.0.0']); + t.deepEqual(t.context.log.args[0], ['Wrote version %s to %s', '1.0.0', 'package.json']); }); test.serial('Updade package.json and npm-shrinkwrap.json', async t => { @@ -54,17 +54,40 @@ test.serial('Updade package.json and npm-shrinkwrap.json', async t => { "version": "0.0.0-dev" }`; // Create package.json in repository root - await writeFile('./package.json', pkg); + await outputFile('./package.json', pkg); // Create a npm-shrinkwrap.json file await execa('npm', ['shrinkwrap']); const shrinkwrap = (await readFile('./npm-shrinkwrap.json')).toString(); - await updatePackageVersion('1.0.0', t.context.logger); + await updatePackageVersion('1.0.0', '.', t.context.logger); // Verify package.json and npm-shrinkwrap.json have been updated t.is((await readFile('./package.json')).toString(), pkg.replace('0.0.0-dev', '1.0.0')); t.is((await readFile('./npm-shrinkwrap.json')).toString(), shrinkwrap.replace('0.0.0-dev', '1.0.0')); // Verify the logger has been called with the version updated - t.deepEqual(t.context.log.args[0], ['Wrote version %s to package.json', '1.0.0']); - t.deepEqual(t.context.log.args[1], ['Wrote version %s to npm-shrinkwrap.json', '1.0.0']); + t.deepEqual(t.context.log.args[0], ['Wrote version %s to %s', '1.0.0', 'package.json']); + t.deepEqual(t.context.log.args[1], ['Wrote version %s to %s', '1.0.0', 'npm-shrinkwrap.json']); +}); + +test.serial('Updade package.json and npm-shrinkwrap.json in a sub-directory', async t => { + const pkg = `{ + "name": "test","description":"pacakage description","version":"0.0.0-dev" + }`; + + // Create package.json in repository root + await outputFile('./dist/package.json', pkg); + process.chdir('dist'); + // Create a npm-shrinkwrap.json file + await execa('npm', ['shrinkwrap']); + process.chdir('..'); + const shrinkwrap = (await readFile('./dist/npm-shrinkwrap.json')).toString(); + + await updatePackageVersion('1.0.0', 'dist', t.context.logger); + + // Verify package.json and npm-shrinkwrap.json have been updated + t.is((await readFile('./dist/package.json')).toString(), pkg.replace('0.0.0-dev', '1.0.0')); + t.is((await readFile('./dist/npm-shrinkwrap.json')).toString(), shrinkwrap.replace('0.0.0-dev', '1.0.0')); + // Verify the logger has been called with the version updated + t.deepEqual(t.context.log.args[0], ['Wrote version %s to %s', '1.0.0', 'dist/package.json']); + t.deepEqual(t.context.log.args[1], ['Wrote version %s to %s', '1.0.0', 'dist/npm-shrinkwrap.json']); }); diff --git a/test/verify.test.js b/test/verify.test.js index ad4d91f5..faa03ee2 100644 --- a/test/verify.test.js +++ b/test/verify.test.js @@ -23,3 +23,11 @@ test('Throw SemanticReleaseError if "tarballDir" option is not a String', async t.is(error.name, 'SemanticReleaseError'); t.is(error.code, 'EINVALIDTARBALLDIR'); }); + +test('Throw SemanticReleaseError if "pkgRoot" option is not a String', async t => { + const pkgRoot = 42; + const error = await t.throws(verify({pkgRoot}, {}, t.context.logger)); + + t.is(error.name, 'SemanticReleaseError'); + t.is(error.code, 'EINVALIDPKGROOT'); +});