Repository: semantic-release/npm
Pull request #188 (2019-08-21 17:47:36)

Port changes in master to beta


Patch:
diff --git a/.travis.yml b/.travis.yml
index 9b5b8bf..dc0b69f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -4,8 +4,9 @@ services:
   - docker
 
 node_js:
+  - 12
   - 10
-  - 8
+  - 8.3 # 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)
diff --git a/lib/prepare.js b/lib/prepare.js
index 9bc65c5..d2910c6 100644
--- a/lib/prepare.js
+++ b/lib/prepare.js
@@ -35,6 +35,13 @@ module.exports = async ({tarballDir, pkgRoot}, {cwd, env, stdout, stderr, nextRe
     );
 
     const tarball = (await packResult).stdout.split('\n').pop();
-    await move(path.resolve(cwd, tarball), path.resolve(cwd, tarballDir.trim(), tarball));
+    const tarballSource = path.resolve(cwd, tarball);
+    const tarballDestination = path.resolve(cwd, tarballDir.trim(), tarball);
+
+    // Only move the tarball if we need to
+    // Fixes: https://github.com/semantic-release/npm/issues/169
+    if (tarballSource !== tarballDestination) {
+      await move(tarballSource, tarballDestination);
+    }
   }
 };
diff --git a/lib/set-npmrc-auth.js b/lib/set-npmrc-auth.js
index da31684..40f65c9 100644
--- a/lib/set-npmrc-auth.js
+++ b/lib/set-npmrc-auth.js
@@ -6,9 +6,12 @@ const nerfDart = require('nerf-dart');
 const AggregateError = require('aggregate-error');
 const getError = require('./get-error');
 
-module.exports = async (registry, {cwd, env: {NPM_TOKEN, NPM_USERNAME, NPM_PASSWORD, NPM_EMAIL}, logger}) => {
+module.exports = async (
+  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 = path.resolve(cwd, '.npmrc');
+  const config = NPM_CONFIG_USERCONFIG || path.resolve(cwd, '.npmrc');
   if (getAuthToken(registry, {npmrc: rc('npm', {registry: 'https://registry.npmjs.org/'}, {config})})) {
     return;
   }
diff --git a/package.json b/package.json
index 4130a57..9ee369e 100644
--- a/package.json
+++ b/package.json
@@ -3,50 +3,49 @@
   "description": "semantic-release plugin to publish a npm package",
   "version": "0.0.0-development",
   "author": "Pierre Vanduynslager (https://twitter.com/@pvdlg_)",
+  "ava": {
+    "files": [
+      "test/**/*.test.js"
+    ],
+    "helpers": [
+      "test/helpers/**/*"
+    ]
+  },
   "bugs": {
     "url": "https://github.com/semantic-release/npm/issues"
   },
-  "config": {
-    "commitizen": {
-      "path": "cz-conventional-changelog"
-    }
-  },
   "contributors": [
     "Stephan Bönnemann <stephan@boennemann.me> (http://boennemann.me)",
     "Gregor Martynus (https://twitter.com/gr2m)"
   ],
   "dependencies": {
     "@semantic-release/error": "^2.2.0",
-    "aggregate-error": "^2.0.0",
-    "execa": "^1.0.0",
-    "fs-extra": "^7.0.0",
-    "lodash": "^4.17.4",
+    "aggregate-error": "^3.0.0",
+    "execa": "^2.0.2",
+    "fs-extra": "^8.0.0",
+    "lodash": "^4.17.15",
     "nerf-dart": "^1.0.0",
     "normalize-url": "^4.0.0",
-    "npm": "6.5.0",
+    "npm": "^6.10.3",
     "rc": "^1.2.8",
-    "read-pkg": "^4.0.0",
-    "registry-auth-token": "^3.3.1",
+    "read-pkg": "^5.0.0",
+    "registry-auth-token": "^4.0.0",
     "semver": "^5.5.0"
   },
   "devDependencies": {
-    "ava": "^1.0.1",
-    "clear-module": "^3.0.0",
+    "ava": "^2.0.0",
+    "clear-module": "^4.0.0",
     "codecov": "^3.0.0",
-    "commitizen": "^3.0.0",
-    "cz-conventional-changelog": "^2.0.0",
     "delay": "^4.0.0",
     "dockerode": "^2.5.3",
-    "file-url": "^2.0.2",
-    "get-stream": "^4.0.0",
+    "get-stream": "^5.0.0",
     "got": "^9.0.0",
-    "nock": "^10.0.0",
-    "nyc": "^13.1.0",
-    "p-retry": "^3.0.0",
+    "nyc": "^14.0.0",
+    "p-retry": "^4.0.0",
     "semantic-release": "^16.0.0-beta",
     "sinon": "^7.1.1",
     "stream-buffers": "^3.0.2",
-    "tempy": "^0.2.1",
+    "tempy": "^0.3.0",
     "xo": "^0.24.0"
   },
   "engines": {
@@ -93,7 +92,6 @@
     "url": "https://github.com/semantic-release/npm.git"
   },
   "scripts": {
-    "cm": "git-cz",
     "codecov": "codecov -f coverage/coverage-final.json",
     "lint": "xo",
     "pretest": "npm run lint",


Test patch:
diff --git a/test/integration.test.js b/test/integration.test.js
index e6c6c0f..84662c5 100644
--- a/test/integration.test.js
+++ b/test/integration.test.js
@@ -257,7 +257,7 @@ test('Publish the package', async t => {
   t.deepEqual(result, {name: 'npm package (@latest dist-tag)', url: undefined, channel: 'latest'});
   t.is((await readJson(path.resolve(cwd, 'package.json'))).version, '1.0.0');
   t.false(await pathExists(path.resolve(cwd, `${pkg.name}-1.0.0.tgz`)));
-  t.is(await execa.stdout('npm', ['view', pkg.name, 'version'], {cwd, env: testEnv}), '1.0.0');
+  t.is((await execa('npm', ['view', pkg.name, 'version'], {cwd, env: testEnv})).stdout, '1.0.0');
 });
 
 test('Publish the package on a dist-tag', async t => {
@@ -286,7 +286,7 @@ test('Publish the package on a dist-tag', async t => {
   });
   t.is((await readJson(path.resolve(cwd, 'package.json'))).version, '1.0.0');
   t.false(await pathExists(path.resolve(cwd, `${pkg.name}-1.0.0.tgz`)));
-  t.is(await execa.stdout('npm', ['view', pkg.name, 'version'], {cwd, env: testEnv}), '1.0.0');
+  t.is((await execa('npm', ['view', pkg.name, 'version'], {cwd, env: testEnv})).stdout, '1.0.0');
 });
 
 test('Publish the package from a sub-directory', async t => {
@@ -311,7 +311,7 @@ test('Publish the package from a sub-directory', async t => {
   t.deepEqual(result, {name: 'npm package (@latest dist-tag)', url: undefined, channel: 'latest'});
   t.is((await readJson(path.resolve(cwd, 'dist/package.json'))).version, '1.0.0');
   t.false(await pathExists(path.resolve(cwd, `${pkg.name}-1.0.0.tgz`)));
-  t.is(await execa.stdout('npm', ['view', pkg.name, 'version'], {cwd, env: testEnv}), '1.0.0');
+  t.is((await execa('npm', ['view', pkg.name, 'version'], {cwd, env: testEnv})).stdout, '1.0.0');
 });
 
 test('Create the package and skip publish ("npmPublish" is false)', async t => {
@@ -573,7 +573,7 @@ test('Publish the package and add to default dist-tag', async t => {
   );
 
   t.deepEqual(result, {name: 'npm package (@latest dist-tag)', url: undefined, channel: 'latest'});
-  t.is(await execa.stdout('npm', ['view', pkg.name, 'dist-tags.latest'], {cwd, env}), '1.0.0');
+  t.is((await execa('npm', ['view', pkg.name, 'dist-tags.latest'], {cwd, env})).stdout, '1.0.0');
 });
 
 test('Publish the package and add to lts dist-tag', async t => {
@@ -610,7 +610,7 @@ test('Publish the package and add to lts dist-tag', async t => {
 
   t.deepEqual(result, {name: 'npm package (@release-1.x dist-tag)', url: undefined, channel: 'release-1.x'});
   t.is(
-    await execa.stdout('npm', ['view', pkg.name, 'dist-tags'], {cwd, env}),
+    (await execa('npm', ['view', pkg.name, 'dist-tags'], {cwd, env})).stdout,
     "{ latest: '1.0.0', 'release-1.x': '1.0.0' }"
   );
 });
@@ -763,7 +763,7 @@ test('Verify token and set up auth only on the fist call, then prepare on prepar
     }
   );
   t.deepEqual(result, {name: 'npm package (@next dist-tag)', url: undefined, channel: 'next'});
-  t.is(await execa.stdout('npm', ['view', pkg.name, 'dist-tags.next'], {cwd, env}), '1.0.0');
+  t.is((await execa('npm', ['view', pkg.name, 'dist-tags.next'], {cwd, env})).stdout, '1.0.0');
 
   result = await t.context.m.addChannel(
     {},
@@ -779,5 +779,5 @@ test('Verify token and set up auth only on the fist call, then prepare on prepar
   );
 
   t.deepEqual(result, {name: 'npm package (@latest dist-tag)', url: undefined, channel: 'latest'});
-  t.is(await execa.stdout('npm', ['view', pkg.name, 'dist-tags.latest'], {cwd, env}), '1.0.0');
+  t.is((await execa('npm', ['view', pkg.name, 'dist-tags.latest'], {cwd, env})).stdout, '1.0.0');
 });
diff --git a/test/prepare.test.js b/test/prepare.test.js
index 3407357..361d11e 100644
--- a/test/prepare.test.js
+++ b/test/prepare.test.js
@@ -1,6 +1,6 @@
 import path from 'path';
 import test from 'ava';
-import {outputJson, readJson, outputFile, readFile, pathExists} from 'fs-extra';
+import {outputJson, readJson, outputFile, readFile, pathExists, appendFile} from 'fs-extra';
 import tempy from 'tempy';
 import execa from 'execa';
 import {stub} from 'sinon';
@@ -70,6 +70,7 @@ test('Updade package.json and package-lock.json', async t => {
   const packagePath = path.resolve(cwd, 'package.json');
   const packageLockPath = path.resolve(cwd, 'package-lock.json');
   await outputJson(packagePath, {version: '0.0.0-dev'});
+  await appendFile(path.resolve(cwd, '.npmrc'), 'package-lock = true');
   // Create a package-lock.json file
   await execa('npm', ['install'], {cwd});
 
@@ -126,6 +127,7 @@ test('Updade package.json and package-lock.json in a sub-directory', async t =>
   const packagePath = path.resolve(cwd, pkgRoot, 'package.json');
   const packageLockPath = path.resolve(cwd, pkgRoot, 'package-lock.json');
   await outputJson(packagePath, {version: '0.0.0-dev'});
+  await appendFile(path.resolve(cwd, pkgRoot, '.npmrc'), 'package-lock = true');
   // Create a package-lock.json file
   await execa('npm', ['install'], {cwd: path.resolve(cwd, pkgRoot)});
 
@@ -224,3 +226,29 @@ test('Create the package in the "tarballDir" directory', async t => {
   // Verify the logger has been called with the version updated
   t.deepEqual(t.context.log.args[0], ['Write version %s to package.json in %s', '1.0.0', cwd]);
 });
+
+test('Only move the created tarball if the "tarballDir" directory is not the CWD', async t => {
+  const cwd = tempy.directory();
+  const packagePath = path.resolve(cwd, 'package.json');
+  const pkg = {name: 'my-pkg', version: '0.0.0-dev'};
+  await outputJson(packagePath, pkg);
+
+  await prepare(
+    {tarballDir: '.'},
+    {
+      cwd,
+      env: {},
+      stdout: t.context.stdout,
+      stderr: t.context.stderr,
+      nextRelease: {version: '1.0.0'},
+      logger: t.context.logger,
+    }
+  );
+
+  // Verify package.json has been updated
+  t.is((await readJson(packagePath)).version, '1.0.0');
+
+  t.true(await pathExists(path.resolve(cwd, `${pkg.name}-1.0.0.tgz`)));
+  // Verify the logger has been called with the version updated
+  t.deepEqual(t.context.log.args[0], ['Write version %s to package.json in %s', '1.0.0', cwd]);
+});
diff --git a/test/set-npmrc-auth.test.js b/test/set-npmrc-auth.test.js
index 380790d..239c017 100644
--- a/test/set-npmrc-auth.test.js
+++ b/test/set-npmrc-auth.test.js
@@ -70,6 +70,20 @@ test('Throw error if "NPM_TOKEN" is missing', async t => {
   t.is(error.code, 'ENONPMTOKEN');
 });
 
+test('Emulate npm config resolution if "NPM_CONFIG_USERCONFIG" is set', async t => {
+  const cwd = tempy.directory();
+
+  await appendFile(path.resolve(cwd, '.custom-npmrc'), `//custom.registry.com/:_authToken = \${NPM_TOKEN}`);
+
+  await setNpmrcAuth('http://custom.registry.com', {
+    cwd,
+    env: {NPM_CONFIG_USERCONFIG: path.resolve(cwd, '.custom-npmrc')},
+    logger: t.context.logger,
+  });
+
+  t.is(t.context.log.callCount, 1);
+});
+
 test('Throw error if "NPM_USERNAME" is missing', async t => {
   const cwd = tempy.directory();
   const env = {NPM_PASSWORD: 'npm_pasword', NPM_EMAIL: 'npm_email'};