Skip to content

Commit de677ea

Browse files
committed
fix: preserve config in both home and local .npmrc
1 parent 7db019f commit de677ea

File tree

2 files changed

+98
-35
lines changed

2 files changed

+98
-35
lines changed

lib/set-npmrc-auth.js

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,34 @@
11
const path = require('path');
22
const rc = require('rc');
3-
const {outputFile, copy, readFile} = require('fs-extra');
3+
const {outputFile, readFile} = require('fs-extra');
44
const getAuthToken = require('registry-auth-token');
55
const nerfDart = require('nerf-dart');
66
const AggregateError = require('aggregate-error');
77
const getError = require('./get-error');
88

9-
const readFileIfExists = async path => {
10-
try {
11-
return await readFile(path);
12-
} catch (_) {
13-
return '';
14-
}
15-
};
16-
179
module.exports = async (
1810
npmrc,
1911
registry,
2012
{cwd, env: {NPM_TOKEN, NPM_CONFIG_USERCONFIG, NPM_USERNAME, NPM_PASSWORD, NPM_EMAIL}, logger}
2113
) => {
2214
logger.log('Verify authentication for registry %s', registry);
23-
const config = NPM_CONFIG_USERCONFIG || path.resolve(cwd, '.npmrc');
24-
if (getAuthToken(registry, {npmrc: rc('npm', {registry: 'https://registry.npmjs.org/'}, {config})})) {
25-
await copy(config, npmrc);
15+
const {configs, ...rcConfig} = rc(
16+
'npm',
17+
{registry: 'https://registry.npmjs.org/'},
18+
{config: NPM_CONFIG_USERCONFIG || path.resolve(cwd, '.npmrc')}
19+
);
20+
const currentConfig = configs ? (await Promise.all(configs.map(config => readFile(config)))).join('\n') : '';
21+
22+
if (getAuthToken(registry, {npmrc: rcConfig})) {
23+
await outputFile(npmrc, currentConfig);
2624
return;
2725
}
2826

2927
if (NPM_USERNAME && NPM_PASSWORD && NPM_EMAIL) {
30-
await outputFile(npmrc, `${await readFileIfExists(config)}\n_auth = \${LEGACY_TOKEN}\nemail = \${NPM_EMAIL}`);
28+
await outputFile(npmrc, `${currentConfig}\n_auth = \${LEGACY_TOKEN}\nemail = \${NPM_EMAIL}`);
3129
logger.log(`Wrote NPM_USERNAME, NPM_PASSWORD and NPM_EMAIL to ${npmrc}`);
3230
} else if (NPM_TOKEN) {
33-
await outputFile(npmrc, `${await readFileIfExists(config)}\n${nerfDart(registry)}:_authToken = \${NPM_TOKEN}`);
31+
await outputFile(npmrc, `${currentConfig}\n${nerfDart(registry)}:_authToken = \${NPM_TOKEN}`);
3432
logger.log(`Wrote NPM_TOKEN to ${npmrc}`);
3533
} else {
3634
throw new AggregateError([getError('ENONPMTOKEN', {registry})]);

test/set-npmrc-auth.test.js

Lines changed: 86 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,86 +3,145 @@ import test from 'ava';
33
import {readFile, appendFile} from 'fs-extra';
44
import {stub} from 'sinon';
55
import tempy from 'tempy';
6-
import setNpmrcAuth from '../lib/set-npmrc-auth';
6+
import clearModule from 'clear-module';
7+
8+
const {HOME} = process.env;
9+
const cwd = process.cwd();
710

811
test.beforeEach(t => {
912
// Stub the logger
1013
t.context.log = stub();
1114
t.context.logger = {log: t.context.log};
15+
16+
clearModule('rc');
17+
clearModule('../lib/set-npmrc-auth');
18+
});
19+
20+
test.afterEach.always(() => {
21+
process.env.HOME = HOME;
22+
process.chdir(cwd);
1223
});
1324

14-
test('Set auth with "NPM_TOKEN"', async t => {
25+
test.serial('Set auth with "NPM_TOKEN"', async t => {
26+
process.env.HOME = tempy.directory();
1527
const cwd = tempy.directory();
28+
process.chdir(cwd);
1629
const npmrc = tempy.file({name: '.npmrc'});
1730
const env = {NPM_TOKEN: 'npm_token'};
1831

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

2134
t.regex((await readFile(npmrc)).toString(), /\/\/custom.registry.com\/:_authToken = \$\{NPM_TOKEN\}/);
2235
t.deepEqual(t.context.log.args[1], [`Wrote NPM_TOKEN to ${npmrc}`]);
2336
});
2437

25-
test('Set auth with "NPM_USERNAME", "NPM_PASSWORD" and "NPM_EMAIL"', async t => {
38+
test.serial('Set auth with "NPM_USERNAME", "NPM_PASSWORD" and "NPM_EMAIL"', async t => {
39+
process.env.HOME = tempy.directory();
2640
const cwd = tempy.directory();
41+
process.chdir(cwd);
2742
const npmrc = tempy.file({name: '.npmrc'});
2843
const env = {NPM_USERNAME: 'npm_username', NPM_PASSWORD: 'npm_pasword', NPM_EMAIL: 'npm_email'};
2944

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

3247
t.is((await readFile(npmrc)).toString(), `\n_auth = \${LEGACY_TOKEN}\nemail = \${NPM_EMAIL}`);
3348
t.deepEqual(t.context.log.args[1], [`Wrote NPM_USERNAME, NPM_PASSWORD and NPM_EMAIL to ${npmrc}`]);
3449
});
3550

36-
test('Copy ".npmrc" if auth is already configured', async t => {
51+
test.serial('Preserve home ".npmrc"', async t => {
52+
process.env.HOME = tempy.directory();
53+
const cwd = tempy.directory();
54+
process.chdir(cwd);
55+
const npmrc = tempy.file({name: '.npmrc'});
56+
const env = {NPM_TOKEN: 'npm_token'};
57+
58+
await appendFile(path.resolve(process.env.HOME, '.npmrc'), 'home_config = test');
59+
60+
await require('../lib/set-npmrc-auth')(npmrc, 'http://custom.registry.com', {cwd, env, logger: t.context.logger});
61+
62+
t.is((await readFile(npmrc)).toString(), `home_config = test\n//custom.registry.com/:_authToken = \${NPM_TOKEN}`);
63+
t.deepEqual(t.context.log.args[1], [`Wrote NPM_TOKEN to ${npmrc}`]);
64+
});
65+
66+
test.serial('Preserve home and local ".npmrc"', async t => {
67+
process.env.HOME = tempy.directory();
3768
const cwd = tempy.directory();
69+
process.chdir(cwd);
70+
const npmrc = tempy.file({name: '.npmrc'});
71+
const env = {NPM_TOKEN: 'npm_token'};
72+
73+
await appendFile(path.resolve(cwd, '.npmrc'), 'cwd_config = test');
74+
await appendFile(path.resolve(process.env.HOME, '.npmrc'), 'home_config = test');
75+
76+
await require('../lib/set-npmrc-auth')(npmrc, 'http://custom.registry.com', {cwd, env, logger: t.context.logger});
77+
78+
t.is(
79+
(await readFile(npmrc)).toString(),
80+
`home_config = test\ncwd_config = test\n//custom.registry.com/:_authToken = \${NPM_TOKEN}`
81+
);
82+
t.deepEqual(t.context.log.args[1], [`Wrote NPM_TOKEN to ${npmrc}`]);
83+
});
84+
85+
test.serial('Preserve all ".npmrc" if auth is already configured', async t => {
86+
process.env.HOME = tempy.directory();
87+
const cwd = tempy.directory();
88+
process.chdir(cwd);
3889
const npmrc = tempy.file({name: '.npmrc'});
3990

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

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

44-
t.is((await readFile(npmrc)).toString(), `//custom.registry.com/:_authToken = \${NPM_TOKEN}`);
96+
t.is((await readFile(npmrc)).toString(), `home_config = test\n//custom.registry.com/:_authToken = \${NPM_TOKEN}`);
4597
t.is(t.context.log.callCount, 1);
4698
});
4799

48-
test('Copy ".npmrc" if auth is already configured for a scoped package', async t => {
100+
test.serial('Preserve ".npmrc" if auth is already configured for a scoped package', async t => {
101+
process.env.HOME = tempy.directory();
49102
const cwd = tempy.directory();
103+
process.chdir(cwd);
50104
const npmrc = tempy.file({name: '.npmrc'});
51105

52106
await appendFile(
53107
path.resolve(cwd, '.npmrc'),
54108
`@scope:registry=http://custom.registry.com\n//custom.registry.com/:_authToken = \${NPM_TOKEN}`
55109
);
110+
await appendFile(path.resolve(process.env.HOME, '.npmrc'), 'home_config = test');
56111

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

59114
t.is(
60115
(await readFile(npmrc)).toString(),
61-
`@scope:registry=http://custom.registry.com\n//custom.registry.com/:_authToken = \${NPM_TOKEN}`
116+
`home_config = test\n@scope:registry=http://custom.registry.com\n//custom.registry.com/:_authToken = \${NPM_TOKEN}`
62117
);
63118
t.is(t.context.log.callCount, 1);
64119
});
65120

66-
test('Throw error if "NPM_TOKEN" is missing', async t => {
121+
test.serial('Throw error if "NPM_TOKEN" is missing', async t => {
122+
process.env.HOME = tempy.directory();
67123
const cwd = tempy.directory();
124+
process.chdir(cwd);
68125
const npmrc = tempy.file({name: '.npmrc'});
69126

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

74131
t.is(error.name, 'SemanticReleaseError');
75132
t.is(error.message, 'No npm token specified.');
76133
t.is(error.code, 'ENONPMTOKEN');
77134
});
78135

79-
test('Emulate npm config resolution if "NPM_CONFIG_USERCONFIG" is set', async t => {
136+
test.serial('Emulate npm config resolution if "NPM_CONFIG_USERCONFIG" is set', async t => {
137+
process.env.HOME = tempy.directory();
80138
const cwd = tempy.directory();
139+
process.chdir(cwd);
81140
const npmrc = tempy.file({name: '.npmrc'});
82141

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

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

95-
test('Throw error if "NPM_USERNAME" is missing', async t => {
154+
test.serial('Throw error if "NPM_USERNAME" is missing', async t => {
155+
process.env.HOME = tempy.directory();
96156
const cwd = tempy.directory();
157+
process.chdir(cwd);
97158
const npmrc = tempy.file({name: '.npmrc'});
98159
const env = {NPM_PASSWORD: 'npm_pasword', NPM_EMAIL: 'npm_email'};
99160

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

104165
t.is(error.name, 'SemanticReleaseError');
105166
t.is(error.message, 'No npm token specified.');
106167
t.is(error.code, 'ENONPMTOKEN');
107168
});
108169

109-
test('Throw error if "NPM_PASSWORD" is missing', async t => {
170+
test.serial('Throw error if "NPM_PASSWORD" is missing', async t => {
171+
process.env.HOME = tempy.directory();
110172
const cwd = tempy.directory();
173+
process.chdir(cwd);
111174
const npmrc = tempy.file({name: '.npmrc'});
112175
const env = {NPM_USERNAME: 'npm_username', NPM_EMAIL: 'npm_email'};
113176

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

118181
t.is(error.name, 'SemanticReleaseError');
119182
t.is(error.message, 'No npm token specified.');
120183
t.is(error.code, 'ENONPMTOKEN');
121184
});
122185

123-
test('Throw error if "NPM_EMAIL" is missing', async t => {
186+
test.serial('Throw error if "NPM_EMAIL" is missing', async t => {
187+
process.env.HOME = tempy.directory();
124188
const cwd = tempy.directory();
189+
process.chdir(cwd);
125190
const npmrc = tempy.file({name: '.npmrc'});
126191
const env = {NPM_USERNAME: 'npm_username', NPM_PASSWORD: 'npm_password'};
127192

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

132197
t.is(error.name, 'SemanticReleaseError');

0 commit comments

Comments
 (0)