Conditionally append NPM_TOKEN to .npmrc (#545)

* fix: conditionally append NPM_TOKEN to .npmrc for trusted publishing support

The .npmrc generation now intelligently handles both traditional NPM token
authentication and trusted publishing scenarios:

- Only appends auth token to .npmrc when NPM_TOKEN is defined (not undefined)
- Uses strict comparison (!== undefined) instead of truthy checks
- Provides informative logging when no NPM_TOKEN is present
- Maintains full backward compatibility with existing workflows

This fixes issues with trusted publishing where OIDC tokens from GitHub
Actions are used instead of NPM_TOKEN, preventing 'undefined' from being
written to the registry auth configuration.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Update src/index.ts

Co-authored-by: Mateusz Burzyński <mateuszburzynski@gmail.com>

* simplify

* tweak changeset

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Mateusz Burzyński <mateuszburzynski@gmail.com>
This commit is contained in:
Ryan Bas
2026-01-27 23:14:11 +01:00
committed by GitHub
co-authored by Claude Mateusz Burzyński
parent 5e0dfa5699
commit 54220dd92c
2 changed files with 33 additions and 19 deletions
+5
View File
@@ -0,0 +1,5 @@
---
"@changesets/action": patch
---
The `.npmrc` generation now intelligently handles both traditional NPM token authentication and trusted publishing scenarios by only appending the auth token when `NPM_TOKEN` is defined. This prevents 'undefined' from being written to the registry configuration when using OIDC tokens from GitHub Actions trusted publishing.
+28 -19
View File
@@ -67,32 +67,41 @@ const getOptionalInput = (name: string) => core.getInput(name) || undefined;
"No changesets found. Attempting to publish any unpublished packages to npm" "No changesets found. Attempting to publish any unpublished packages to npm"
); );
let userNpmrcPath = `${process.env.HOME}/.npmrc`; if (process.env.NPM_TOKEN) {
if (await fileExists(userNpmrcPath)) { const userNpmrcPath = `${process.env.HOME}/.npmrc`;
core.info("Found existing user .npmrc file");
const userNpmrcContent = await fs.readFile(userNpmrcPath, "utf8"); if (await fileExists(userNpmrcPath)) {
const authLine = userNpmrcContent.split("\n").find((line) => { core.info("Found existing user .npmrc file");
// check based on https://github.com/npm/cli/blob/8f8f71e4dd5ee66b3b17888faad5a7bf6c657eed/test/lib/adduser.js#L103-L105 const userNpmrcContent = await fs.readFile(userNpmrcPath, "utf8");
return /^\s*\/\/registry\.npmjs\.org\/:[_-]authToken=/i.test(line); const authLine = userNpmrcContent.split("\n").find((line) => {
}); // check based on https://github.com/npm/cli/blob/8f8f71e4dd5ee66b3b17888faad5a7bf6c657eed/test/lib/adduser.js#L103-L105
if (authLine) { return /^\s*\/\/registry\.npmjs\.org\/:[_-]authToken=/i.test(line);
core.info( });
"Found existing auth token for the npm registry in the user .npmrc file" if (authLine) {
); core.info(
"Found existing auth token for the npm registry in the user .npmrc file"
);
} else {
core.info(
"Didn't find existing auth token for the npm registry in the user .npmrc file, creating one"
);
await fs.appendFile(
userNpmrcPath,
`\n//registry.npmjs.org/:_authToken=${process.env.NPM_TOKEN}\n`
);
}
} else { } else {
core.info( core.info(
"Didn't find existing auth token for the npm registry in the user .npmrc file, creating one" "No user .npmrc file found, creating one with NPM_TOKEN used as auth token"
); );
await fs.appendFile( await fs.writeFile(
userNpmrcPath, userNpmrcPath,
`\n//registry.npmjs.org/:_authToken=${process.env.NPM_TOKEN}\n` `//registry.npmjs.org/:_authToken=${process.env.NPM_TOKEN}\n`
); );
} }
} else { } else {
core.info("No user .npmrc file found, creating one"); core.info(
await fs.writeFile( "No NPM_TOKEN found - assuming trusted publishing or npm is already authenticated"
userNpmrcPath,
`//registry.npmjs.org/:_authToken=${process.env.NPM_TOKEN}\n`
); );
} }