Skip to content

Commit

Permalink
feat: main two places, process.env.GH_TOKEN and gh auth token
Browse files Browse the repository at this point in the history
  • Loading branch information
JoshuaKGoldberg committed May 26, 2024
1 parent 1be4165 commit 1653257
Show file tree
Hide file tree
Showing 10 changed files with 140 additions and 64 deletions.
15 changes: 13 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,22 @@ npm i get-github-auth-token
```

```ts
import { greet } from "get-github-auth-token";
import { getGitHubAuthToken } from "get-github-auth-token";

greet("Hello, world! 💖");
const auth = await getGitHubAuthToken("Hello, world! 💖");

if (auth.succeeded) {
console.log("Token:", auth.token);
} else {
console.error("Oh no:", auth.error);
}
```

`getGitHubAuthToken` attempts to find a GitHub auth token from the following places, in order:

1. `process.env.GH_TOKEN`
2. Executing `gh auth token` as a child process

## Contributors

<!-- spellchecker: disable -->
Expand Down
6 changes: 6 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@ export default tseslint.config(

// These on-by-default rules work well for this repo if configured
"@typescript-eslint/no-unused-vars": ["error", { caughtErrors: "all" }],
"@typescript-eslint/prefer-nullish-coalescing": [
"error",
{
ignorePrimitives: { string: true },
},
],
"perfectionist/sort-objects": [
"error",
{
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"@eslint/js": "9.3.0",
"@release-it/conventional-changelog": "8.0.1",
"@types/eslint-plugin-markdown": "2.0.2",
"@types/node": "^20.12.12",
"@vitest/coverage-v8": "1.6.0",
"console-fail-test": "0.2.3",
"cspell": "8.8.3",
Expand Down
4 changes: 4 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

78 changes: 78 additions & 0 deletions src/getGitHubAuthToken.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { beforeEach, describe, expect, it, vi } from "vitest";

import { getGitHubAuthToken } from "./getGitHubAuthToken.js";

const mockExec = vi.fn();

vi.mock("node:util", () => ({
get promisify() {
return () => mockExec;
},
}));

describe("getGitHubAuthToken", () => {
beforeEach(() => {
process.env.GH_TOKEN = "";
});

it("returns GH_TOKEN when it exists and is truthy", async () => {
const GH_TOKEN = "gho_abc123";

process.env.GH_TOKEN = GH_TOKEN;

const actual = await getGitHubAuthToken();

expect(actual).toEqual({ succeeded: true, token: GH_TOKEN });
expect(mockExec).not.toHaveBeenCalled();
});

it("returns the token when gh auth token prints a token", async () => {
const stdout = "gho_abc123";

mockExec.mockResolvedValue({ stdout });

const actual = await getGitHubAuthToken();

expect(actual).toEqual({ succeeded: true, token: stdout });
});

it("returns the gh error when gh auth token and gh error", async () => {
const stderr = "Oh no!";

mockExec.mockResolvedValueOnce({ stderr: "auth token issue" });
mockExec.mockResolvedValueOnce({ stderr });

const actual = await getGitHubAuthToken();

expect(actual).toEqual({
error: `Could not run \`gh\`: ${stderr}`,
succeeded: false,
});
});

it("returns the gh auth token error when only gh auth token errors", async () => {
const stderr = "Oh no!";

mockExec.mockResolvedValueOnce({ stderr });
mockExec.mockResolvedValueOnce({ stdout: "" });

const actual = await getGitHubAuthToken();

expect(actual).toEqual({
error: stderr,
succeeded: false,
});
});

it("returns undefined when both gh and gh auth token print nothing", async () => {
mockExec.mockResolvedValueOnce({ stderr: "", stdout: "" });
mockExec.mockResolvedValueOnce({ stderr: "", stdout: "" });

const actual = await getGitHubAuthToken();

expect(actual).toEqual({
error: undefined,
succeeded: false,
});
});
});
27 changes: 27 additions & 0 deletions src/getGitHubAuthToken.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import * as cp from "node:child_process";
import * as util from "node:util";

import { GitHubAuthToken } from "./types.js";

export async function getGitHubAuthToken(): Promise<GitHubAuthToken> {
if (process.env.GH_TOKEN) {
return { succeeded: true, token: process.env.GH_TOKEN };
}

const exec = util.promisify(cp.exec);
const token = await exec("gh auth token");

if (token?.stdout) {

Check failure on line 14 in src/getGitHubAuthToken.ts

View workflow job for this annotation

GitHub Actions / lint

Unnecessary optional chain on a non-nullish value
return { succeeded: true, token: token.stdout };
}

const help = await exec("gh");

return {
error:
(help.stderr && `Could not run \`gh\`: ${help.stderr}`) ||
token?.stderr ||

Check failure on line 23 in src/getGitHubAuthToken.ts

View workflow job for this annotation

GitHub Actions / lint

Unnecessary optional chain on a non-nullish value
undefined,
succeeded: false,
};
}
44 changes: 0 additions & 44 deletions src/greet.test.ts

This file was deleted.

13 changes: 0 additions & 13 deletions src/greet.ts

This file was deleted.

2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export * from "./greet.js";
export * from "./getGitHubAuthToken.js";
export * from "./types.js";
14 changes: 10 additions & 4 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
export interface GreetOptions {
logger?: (message: string) => void;
message: string;
times?: number;
export interface GitHubAuthTokenFailure {
error: string | undefined;
succeeded: false;
}

export interface GitHubAuthTokenSuccess {
succeeded: true;
token: string;
}

export type GitHubAuthToken = GitHubAuthTokenFailure | GitHubAuthTokenSuccess;

0 comments on commit 1653257

Please sign in to comment.