Skip to content

Commit e1e1667

Browse files
committed
fix: parsing of .npmrc file
1 parent 8090f2a commit e1e1667

6 files changed

Lines changed: 186 additions & 38 deletions

File tree

dist/index.js

Lines changed: 14 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,14 @@
2727
"@changesets/read": "^0.4.6",
2828
"@manypkg/get-packages": "^1.1.1",
2929
"@types/fs-extra": "^8.0.0",
30+
"@types/ini": "1.3.31",
3031
"@types/jest": "^24.0.18",
3132
"@types/node": "^12.7.1",
3233
"@types/semver": "^6.0.2",
3334
"babel-jest": "^24.9.0",
3435
"fs-extra": "^8.1.0",
3536
"husky": "^3.0.3",
37+
"ini": "^2.0.0",
3638
"jest": "^24.9.0",
3739
"mdast-util-to-string": "^1.0.6",
3840
"remark-parse": "^7.0.1",

src/index.ts

Lines changed: 3 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import * as core from "@actions/core";
22
import fs from "fs-extra";
3+
import * as ini from "ini";
34
import * as gitUtils from "./gitUtils";
5+
import * as npmUtils from "./npmUtils";
46
import { runPublish, runVersion } from "./run";
57
import readChangesetState from "./readChangesetState";
68

@@ -42,34 +44,7 @@ const getOptionalInput = (name: string) => core.getInput(name) || undefined;
4244
"No changesets found, attempting to publish any unpublished packages to npm"
4345
);
4446

45-
let userNpmrcPath = `${process.env.HOME}/.npmrc`;
46-
if (fs.existsSync(userNpmrcPath)) {
47-
console.log("Found existing user .npmrc file");
48-
const userNpmrcContent = await fs.readFile(userNpmrcPath, "utf8");
49-
const authLine = userNpmrcContent.split("\n").find((line) => {
50-
// check based on https://github.com/npm/cli/blob/8f8f71e4dd5ee66b3b17888faad5a7bf6c657eed/test/lib/adduser.js#L103-L105
51-
return /^\/\/registry\.npmjs\.org\/:[_-]authToken=/i.test(line);
52-
});
53-
if (authLine) {
54-
console.log(
55-
"Found existing auth token for the npm registry in the user .npmrc file"
56-
);
57-
} else {
58-
console.log(
59-
"Didn't find existing auth token for the npm registry in the user .npmrc file, creating one"
60-
);
61-
fs.appendFileSync(
62-
userNpmrcPath,
63-
`\n//registry.npmjs.org/:_authToken=${process.env.NPM_TOKEN}\n`
64-
);
65-
}
66-
} else {
67-
console.log("No user .npmrc file found, creating one");
68-
fs.writeFileSync(
69-
userNpmrcPath,
70-
`//registry.npmjs.org/:_authToken=${process.env.NPM_TOKEN}\n`
71-
);
72-
}
47+
npmUtils.prepareNpmConfig();
7348

7449
const result = await runPublish({
7550
script: publishScript,

src/npmUtils.test.ts

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
import fs from "fs";
2+
import path from "path";
3+
import * as ini from "ini";
4+
import fixtures from "fixturez";
5+
import { prepareNpmConfig } from "./npmUtils";
6+
7+
const f = fixtures(__dirname);
8+
const authToken = "npm_abc";
9+
10+
describe("prepareNpmConfig", () => {
11+
let tmpDir: string;
12+
let npmrcPath: string;
13+
14+
beforeEach(() => {
15+
tmpDir = f.temp();
16+
npmrcPath = path.join(tmpDir, ".npmrc");
17+
});
18+
19+
describe("when .npmrc exists", () => {
20+
describe("when authToken is defined", () => {
21+
beforeEach(() => {
22+
fs.writeFileSync(
23+
npmrcPath,
24+
ini.stringify({
25+
email: "npm@company.com",
26+
"//registry.npmjs.org/:_authToken": authToken,
27+
})
28+
);
29+
});
30+
test("should not change the .npmrc file", () => {
31+
prepareNpmConfig({ HOME: tmpDir });
32+
33+
const npmConfig = ini.parse(fs.readFileSync(npmrcPath, "utf-8"));
34+
expect(npmConfig).toMatchInlineSnapshot(`
35+
Object {
36+
"//registry.npmjs.org/:_authToken": "npm_abc",
37+
"email": "npm@company.com",
38+
}
39+
`);
40+
});
41+
});
42+
describe("when authToken is not defined", () => {
43+
beforeEach(() => {
44+
fs.writeFileSync(
45+
npmrcPath,
46+
ini.stringify({
47+
email: "npm@company.com",
48+
})
49+
);
50+
});
51+
describe("when NPM_TOKEN environment variable is not defined", () => {
52+
test("it should throw an error", () => {
53+
expect(() =>
54+
prepareNpmConfig({
55+
HOME: tmpDir,
56+
NPM_TOKEN: undefined,
57+
})
58+
).toThrowErrorMatchingInlineSnapshot(
59+
`"Missing NPM authToken. Please make sure you have the \`NPM_TOKEN\` environment variable defined."`
60+
);
61+
});
62+
});
63+
test("should inject NPM_TOKEN value in .npmrc file", () => {
64+
prepareNpmConfig({
65+
HOME: tmpDir,
66+
NPM_TOKEN: authToken,
67+
});
68+
69+
const npmConfig = ini.parse(fs.readFileSync(npmrcPath, "utf-8"));
70+
expect(npmConfig).toMatchInlineSnapshot(`
71+
Object {
72+
"//registry.npmjs.org/:_authToken": "npm_abc",
73+
"email": "npm@company.com",
74+
}
75+
`);
76+
});
77+
});
78+
});
79+
80+
describe("when .npmrc does not exist", () => {
81+
describe("when NPM_TOKEN environment variable is not defined", () => {
82+
test("it should throw an error", () => {
83+
expect(() =>
84+
prepareNpmConfig({
85+
HOME: tmpDir,
86+
NPM_TOKEN: undefined,
87+
})
88+
).toThrowErrorMatchingInlineSnapshot(
89+
`"Missing NPM authToken. Please make sure you have the \`NPM_TOKEN\` environment variable defined."`
90+
);
91+
});
92+
});
93+
test("should create a new .npmrc config", () => {
94+
prepareNpmConfig({
95+
HOME: tmpDir,
96+
NPM_TOKEN: authToken,
97+
});
98+
99+
const npmConfig = ini.parse(fs.readFileSync(npmrcPath, "utf-8"));
100+
expect(npmConfig).toMatchInlineSnapshot(`
101+
Object {
102+
"//registry.npmjs.org/:_authToken": "npm_abc",
103+
}
104+
`);
105+
});
106+
});
107+
});

src/npmUtils.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import fs from "fs";
2+
import * as ini from "ini";
3+
4+
export const prepareNpmConfig = (
5+
// Allow to inject a custom object, useful in tests.
6+
processEnv = process.env
7+
) => {
8+
const userNpmrcPath = `${processEnv.HOME}/.npmrc`;
9+
10+
if (fs.existsSync(userNpmrcPath)) {
11+
console.log(`Found existing user .npmrc file at ${userNpmrcPath}`);
12+
13+
// Parse the `.npmrc` content using the `npm/ini` package.
14+
const npmConfig = ini.parse(fs.readFileSync(userNpmrcPath, "utf-8"));
15+
16+
let hasAuthToken = false;
17+
for (const [key, value] of Object.entries(npmConfig)) {
18+
if (/\/\/(.*)authToken$/.test(key) && Boolean(value)) {
19+
console.log("The .npmrc file has an authToken");
20+
hasAuthToken = true;
21+
}
22+
}
23+
24+
if (!hasAuthToken) {
25+
console.log(
26+
"The .npmrc file does not have an authToken defined, creating one using the `NPM_TOKEN` environment variable"
27+
);
28+
if (!processEnv.NPM_TOKEN) {
29+
throw new Error(
30+
"Missing NPM authToken. Please make sure you have the `NPM_TOKEN` environment variable defined."
31+
);
32+
}
33+
npmConfig["//registry.npmjs.org/:_authToken"] = processEnv.NPM_TOKEN;
34+
fs.writeFileSync(userNpmrcPath, ini.stringify(npmConfig));
35+
}
36+
} else {
37+
console.log("No user .npmrc file found, creating one");
38+
if (!processEnv.NPM_TOKEN) {
39+
throw new Error(
40+
"Missing NPM authToken. Please make sure you have the `NPM_TOKEN` environment variable defined."
41+
);
42+
}
43+
fs.writeFileSync(
44+
userNpmrcPath,
45+
ini.stringify({
46+
"//registry.npmjs.org/:_authToken": processEnv.NPM_TOKEN,
47+
})
48+
);
49+
}
50+
};

yarn.lock

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2265,6 +2265,11 @@
22652265
dependencies:
22662266
"@types/node" "*"
22672267

2268+
"@types/ini@1.3.31":
2269+
version "1.3.31"
2270+
resolved "https://registry.yarnpkg.com/@types/ini/-/ini-1.3.31.tgz#c78541a187bd88d5c73e990711c9d85214800d1b"
2271+
integrity sha512-8ecxxaG4AlVEM1k9+BsziMw8UsX0qy3jYI1ad/71RrDZ+rdL6aZB0wLfAuflQiDhkD5o4yJ0uPK3OSUic3fG0w==
2272+
22682273
"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0":
22692274
version "2.0.1"
22702275
resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz#42995b446db9a48a11a07ec083499a860e9138ff"
@@ -4940,6 +4945,11 @@ ini@^1.3.4, ini@~1.3.0:
49404945
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
49414946
integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==
49424947

4948+
ini@^2.0.0:
4949+
version "2.0.0"
4950+
resolved "https://registry.yarnpkg.com/ini/-/ini-2.0.0.tgz#e5fd556ecdd5726be978fa1001862eacb0a94bc5"
4951+
integrity sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==
4952+
49434953
invariant@^2.2.2, invariant@^2.2.4:
49444954
version "2.2.4"
49454955
resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"

0 commit comments

Comments
 (0)