Skip to content

Commit f910480

Browse files
committed
fix(npm): Fix NPM_TOKEN usage again
This is a retake on #130. Although npm/cli#8 claims to have support for `npm_config_//registry.npmjs.org/:_authToken=` usage, my tests and the reports on the internet says this still doesn't work, even with the latest npm (7.0.15 at the time). The only way to pass the token is to have the `authToken` line in an `.npmrc` file. The quick&dirty way would have been to create one in the project directory but that may collide with a potentially pre-existing project `.npmrc`. Trying to merge these seems more trouble than it is worth: https://github.com/actions/setup-node/blob/59e61b89511ed136a0b17773f07c349fa5c01e8b/src/authutil.ts (even worse as you'd need to revert these changes after the fact) The "better" solution I found is: 1. Create a temporary file as your npmrc 2. Put the token/registry line there 3. Tell npm to use that file as the user config 4. Use the `npm_config_userconfig` for the above to support yarn too This may still fail for yarn, see yarnpkg/yarn#4568.
1 parent e798120 commit f910480

File tree

1 file changed

+36
-13
lines changed

1 file changed

+36
-13
lines changed

src/targets/npm.ts

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ import {
1212
BaseArtifactProvider,
1313
RemoteArtifact,
1414
} from '../artifact_providers/base';
15+
import { withTempFile } from 'src/utils/files';
16+
import { fstat, writeFileSync } from 'fs';
17+
import { fileURLToPath } from 'url';
1518

1619
const logger = loggerRaw.withScope('[npm]');
1720

@@ -24,6 +27,8 @@ export const YARN_BIN = process.env.YARN_BIN || 'yarn';
2427
const NPM_MIN_MAJOR = 5;
2528
const NPM_MIN_MINOR = 6;
2629

30+
const NPM_TOKEN_ENV_VAR = 'NPM_TOKEN';
31+
2732
/** A regular expression used to find the package tarball */
2833
const DEFAULT_PACKAGE_REGEX = /^.*\d\.\d.*\.tgz$/;
2934

@@ -43,6 +48,8 @@ export interface NpmTargetOptions extends TargetConfig {
4348
useOtp?: boolean;
4449
/** Do we use Yarn instead of NPM? */
4550
useYarn: boolean;
51+
/** Value of NPM_TOKEN so we can pass it to npm executable */
52+
token: string;
4653
}
4754

4855
/** Options for running the NPM publish command */
@@ -125,8 +132,14 @@ export class NpmTarget extends BaseTarget {
125132
* Extracts NPM target options from the raw configuration
126133
*/
127134
protected getNpmConfig(): NpmTargetOptions {
135+
const token = process.env.NPM_TOKEN;
136+
if (!token) {
137+
throw new Error('NPM target: NPM_TOKEN not found in the environment');
138+
}
139+
128140
const npmConfig: NpmTargetOptions = {
129141
useYarn: !!process.env.USE_YARN || !hasExecutable(NPM_BIN),
142+
token,
130143
};
131144
if (this.config.access) {
132145
if (Object.values(NpmPackageAccess).includes(this.config.access)) {
@@ -180,22 +193,32 @@ export class NpmTarget extends BaseTarget {
180193
args.push('--tag=next');
181194
}
182195

183-
// Pass OTP if configured
184-
const spawnOptions: SpawnOptions = {};
185-
if (options.otp) {
186-
spawnOptions.env = {
187-
...process.env,
188-
NPM_CONFIG_OTP: options.otp,
189-
};
190-
}
196+
let result;
197+
await withTempFile(filePath => {
198+
// Pass OTP if configured
199+
const spawnOptions: SpawnOptions = {};
200+
spawnOptions.env = { ...process.env };
201+
if (options.otp) {
202+
spawnOptions.env.NPM_CONFIG_OTP = options.otp;
203+
}
204+
spawnOptions.env[NPM_TOKEN_ENV_VAR] = this.npmConfig.token;
205+
// WARNING: This may fail for Yarn: https://github.com/yarnpkg/yarn/issues/4568
206+
spawnOptions.env.npm_config_userconfig = filePath;
207+
writeFileSync(
208+
filePath,
209+
`//registry.npmjs.org/:_authToken=\${${NPM_TOKEN_ENV_VAR}}`
210+
);
191211

192-
// The path has to be pushed always as the last arg
193-
args.push(path);
212+
// The path has to be pushed always as the last arg
213+
args.push(path);
194214

195-
// Disable output buffering because NPM/Yarn can ask us for one-time passwords
196-
return spawnProcess(bin, args, spawnOptions, {
197-
showStdout: true,
215+
// Disable output buffering because NPM/Yarn can ask us for one-time passwords
216+
result = spawnProcess(bin, args, spawnOptions, {
217+
showStdout: true,
218+
});
198219
});
220+
221+
return result;
199222
}
200223

201224
/**

0 commit comments

Comments
 (0)