Use parseEnv instead of dotenv and avoid side effects (#1947) · changesets/changesets@492b0ca · GitHub
Skip to content

Commit 492b0ca

Browse files
bluwyAndarist
andauthored
Use parseEnv instead of dotenv and avoid side effects (#1947)
Co-authored-by: Mateusz Burzyński <mateuszburzynski@gmail.com>
1 parent 8e9afd1 commit 492b0ca

6 files changed

Lines changed: 71 additions & 41 deletions

File tree

‎.changeset/late-animals-drive.md‎

Lines changed: 5 additions & 0 deletions

‎.changeset/tricky-spies-hunt.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@changesets/get-github-info": patch
3+
---
4+
5+
Automatically load `GITHUB_` environment variables from `.env` file

‎packages/changelog-github/src/index.ts‎

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1+
import { parseEnv } from "node:util";
2+
import fs from "node:fs/promises";
3+
import path from "node:path";
14
import type { ChangelogFunctions } from "@changesets/types";
2-
import { config } from "dotenv";
35
import { getInfo, getInfoFromPullRequest } from "@changesets/get-github-info";
46

5-
config();
6-
77
// "match what you skip, capture what you want": the left alternative
88
// consumes markdown links so the right alternative only matches bare refs
99
function linkifyIssueRefs(
@@ -17,9 +17,28 @@ function linkifyIssueRefs(
1717
);
1818
}
1919

20-
function readEnv() {
20+
async function readEnvFile() {
21+
const envFile = path.resolve(process.cwd(), ".env");
22+
let content: string | undefined;
23+
try {
24+
content = await fs.readFile(envFile, "utf-8");
25+
} catch {
26+
return {};
27+
}
28+
return parseEnv(content);
29+
}
30+
31+
let cachedEnv: ReturnType<typeof readEnvFile> | undefined;
32+
function readEnvFileCached() {
33+
cachedEnv ??= readEnvFile();
34+
return cachedEnv;
35+
}
36+
37+
async function readEnv() {
2138
const GITHUB_SERVER_URL =
22-
process.env.GITHUB_SERVER_URL || "https://github.com";
39+
process.env.GITHUB_SERVER_URL ||
40+
(await readEnvFileCached()).GITHUB_SERVER_URL ||
41+
"https://github.com";
2342
return { GITHUB_SERVER_URL };
2443
}
2544

@@ -59,7 +78,7 @@ const changelogFunctions: ChangelogFunctions = {
5978
return [changesetLink, ...updatedDepenenciesList].join("\n");
6079
},
6180
getReleaseLine: async (changeset, type, options) => {
62-
const { GITHUB_SERVER_URL } = readEnv();
81+
const { GITHUB_SERVER_URL } = await readEnv();
6382
if (!options || !options.repo) {
6483
throw new Error(
6584
'Please provide a repo to this changelog generator like this:\n"changelog": ["@changesets/changelog-github", { "repo": "org/repo" }]',

‎packages/get-github-info/README.md‎

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,25 +9,11 @@
99

1010
> Note: This assumes you already have changesets setup.
1111
12-
To use `@changesets/get-github-info`, you'll need to install it and you'll probably also want `dotenv` to provide a GitHub personal access token via a `.env` file.
12+
You can use `@changesets/get-github-info` like this if you have a [custom changelog formatter](https://github.com/changesets/changesets/blob/main/docs/modifying-changelog-format.md).
1313

14-
```bash
15-
yarn add --dev @changesets/get-github-info dotenv
16-
```
17-
18-
or
19-
20-
```bash
21-
npm install --save-dev @changesets/get-github-info dotenv
22-
```
23-
24-
Then you can use it in your `.changeset/config.js` like this.
25-
26-
```jsx
27-
import dotenv from "dotenv";
14+
```js
2815
import { getInfo } from "@changesets/get-github-info";
2916

30-
dotenv.config();
3117
// ...
3218

3319
const getReleaseLine = async (changeset, type) => {
@@ -53,7 +39,7 @@ const getReleaseLine = async (changeset, type) => {
5339
// ...
5440
```
5541

56-
You'll need to [get a GitHub personal access token](https://github.com/settings/tokens/new?scopes=read:user,repo:status&description=changesets) with `read:user` and `repo:status` permissions, and add it to a `.env` file.
42+
You'll need to [get a GitHub personal access token](https://github.com/settings/tokens/new?scopes=read:user,repo:status&description=changesets) with `read:user` and `repo:status` permissions, and add it to a `.env` file (it'll be loaded automatically).
5743

5844
```bash
5945
GITHUB_TOKEN=token_here

‎packages/get-github-info/src/index.ts‎

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,36 @@
11
import DataLoader from "dataloader";
2+
import { parseEnv } from "node:util";
3+
import fs from "node:fs/promises";
4+
import path from "node:path";
25

3-
function readEnv() {
6+
async function readEnvFile() {
7+
const envFile = path.resolve(process.cwd(), ".env");
8+
let content: string | undefined;
9+
try {
10+
content = await fs.readFile(envFile, "utf-8");
11+
} catch {
12+
return {};
13+
}
14+
return parseEnv(content);
15+
}
16+
17+
let cachedEnv: ReturnType<typeof readEnvFile> | undefined;
18+
function readEnvFileCached() {
19+
cachedEnv ??= readEnvFile();
20+
return cachedEnv;
21+
}
22+
23+
async function readEnv() {
424
const GITHUB_GRAPHQL_URL =
5-
process.env.GITHUB_GRAPHQL_URL || "https://api.github.com/graphql";
25+
process.env.GITHUB_GRAPHQL_URL ||
26+
(await readEnvFileCached()).GITHUB_GRAPHQL_URL ||
27+
"https://api.github.com/graphql";
628
const GITHUB_SERVER_URL =
7-
process.env.GITHUB_SERVER_URL || "https://github.com";
8-
const GITHUB_TOKEN = process.env.GITHUB_TOKEN;
29+
process.env.GITHUB_SERVER_URL ||
30+
(await readEnvFileCached()).GITHUB_SERVER_URL ||
31+
"https://github.com";
32+
const GITHUB_TOKEN =
33+
process.env.GITHUB_TOKEN || (await readEnvFileCached()).GITHUB_TOKEN;
934
return { GITHUB_GRAPHQL_URL, GITHUB_SERVER_URL, GITHUB_TOKEN };
1035
}
1136

@@ -33,9 +58,7 @@ function makeQuery(repos: ReposWithCommitsAndPRsToFetch) {
3358
${repos[repo]
3459
.map((data) =>
3560
data.kind === "commit"
36-
? `a${data.commit}: object(expression: ${JSON.stringify(
37-
data.commit,
38-
)}) {
61+
? `a${data.commit}: object(expression: ${JSON.stringify(data.commit)}) {
3962
... on Commit {
4063
commitUrl
4164
associatedPullRequests(first: 50) {
@@ -86,7 +109,8 @@ function makeQuery(repos: ReposWithCommitsAndPRsToFetch) {
86109
// getReleaseLine will be called a large number of times but it'll be called at the same time
87110
// so instead of doing a bunch of network requests, we can do a single one.
88111
const GHDataLoader = new DataLoader(async (requests: RequestData[]) => {
89-
const { GITHUB_GRAPHQL_URL, GITHUB_SERVER_URL, GITHUB_TOKEN } = readEnv();
112+
const { GITHUB_GRAPHQL_URL, GITHUB_SERVER_URL, GITHUB_TOKEN } =
113+
await readEnv();
90114
if (!GITHUB_TOKEN) {
91115
throw new Error(
92116
`Please create a GitHub personal access token at ${GITHUB_SERVER_URL}/settings/tokens/new?scopes=read:user,repo:status&description=changesets-${new Date()
@@ -129,11 +153,7 @@ const GHDataLoader = new DataLoader(async (requests: RequestData[]) => {
129153

130154
if (data.errors) {
131155
throw new Error(
132-
`Fetched data from GitHub returned errors\n${JSON.stringify(
133-
data.errors,
134-
null,
135-
2,
136-
)}`,
156+
`Fetched data from GitHub returned errors\n${JSON.stringify(data.errors, null, 2)}`,
137157
);
138158
}
139159

‎yarn.lock‎

Lines changed: 0 additions & 5 deletions

0 commit comments

Comments
 (0)