Skip to content

Commit

Permalink
feat: use get-github-auth-token for gh auth tokens
Browse files Browse the repository at this point in the history
  • Loading branch information
JoshuaKGoldberg committed May 26, 2024
1 parent 018b3b2 commit 613d187
Show file tree
Hide file tree
Showing 9 changed files with 50 additions and 50 deletions.
13 changes: 6 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,18 @@

## CLI

`prune-github-notifications` can be run on the CLI with an auth token for _notifications_ access specified as a `GH_TOKEN` environment variable:
`prune-github-notifications` can be run on the CLI with an auth token for _notifications_ access:

```shell
GH_TOKEN=$(gh auth token) npx prune-github-notifications
npx prune-github-notifications
```

### CLI Options
[`get-github-auth-token`](https://github.com/JoshuaKGoldberg/get-github-auth-token) is used to retrieve a GitHub auth token from `process.env.GH_TOKEN` or executing `gh auth token`.

Only `auth` is required, and only if a `GH_TOKEN` isn't available.
### CLI Options

| Option | Type | Default | Description |
| ------------- | ---------- | -------------------------------- | ------------------------------------------------------------- |
| `--auth` | `string` | `process.env.GH_TOKEN` | GitHub authentication token with _notifications_ access. |
| `--bandwidth` | `number` | `6` | Maximum parallel requests to start at once. |
| `--reason` | `string[]` | `["subscribed"]` | Notification reason(s) to filter to. |
| `--title` | `string` | `"^chore\(deps\): update .+ to"` | Notification title regular expression to filter to. |
Expand All @@ -38,13 +37,13 @@ Only `auth` is required, and only if a `GH_TOKEN` isn't available.
For example, providing all options on the CLI:

```shell
npx prune-github-notifications --auth $(gh auth token) --bandwidth 10 --reason subscribed --title "^chore.+ update .+ to"
npx prune-github-notifications --bandwidth 10 --reason subscribed --title "^chore.+ update .+ to"
```

Running in watch mode to clear notifications every ten seconds:

```shell
npx prune-github-notifications --auth $(gh auth token) --watch 10
npx prune-github-notifications --watch 10
```

## Node.js API
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
},
"dependencies": {
"chalk": "^5.3.0",
"get-github-auth-token": "^0.1.0",
"octokit": "^3.1.2",
"throttled-queue": "^2.1.4",
"zod": "^3.22.4"
Expand Down Expand Up @@ -76,7 +77,6 @@
"vitest": "^1.3.1",
"yaml-eslint-parser": "^1.2.2"
},
"packageManager": "pnpm@9.0.6",
"engines": {
"node": ">=20"
},
Expand Down
11 changes: 11 additions & 0 deletions pnpm-lock.yaml

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

24 changes: 0 additions & 24 deletions src/cli.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,28 +21,8 @@ vi.mock("./runInWatch.js", () => ({
}));

describe("pruneGitHubNotificationsCLI", () => {
it("throws an error when auth is not available", async () => {
await expect(async () => {
await pruneGitHubNotificationsCLI([]);
}).rejects.toMatchInlineSnapshot(`
[ZodError: [
{
"code": "invalid_type",
"expected": "string",
"received": "undefined",
"path": [
"auth"
],
"message": "--auth is required if a GH_TOKEN environment variable is not specified."
}
]]
`);
});

it("passes parsed arguments to pruneGitHubNotifications when they're valid and watch mode is not enabled", async () => {
await pruneGitHubNotificationsCLI([
"--auth",
"abc_def",
"--bandwidth",
"123",
"--reason",
Expand All @@ -54,7 +34,6 @@ describe("pruneGitHubNotificationsCLI", () => {
]);

expect(mockPruneGitHubNotifications).toHaveBeenCalledWith({
auth: "abc_def",
bandwidth: 123,
filters: {
reason: new Set(["abc", "def"]),
Expand All @@ -66,8 +45,6 @@ describe("pruneGitHubNotificationsCLI", () => {

it("passes parsed arguments to runInWatch when they're valid and watch mode is enabled", async () => {
await pruneGitHubNotificationsCLI([
"--auth",
"abc_def",
"--bandwidth",
"123",
"--reason",
Expand All @@ -81,7 +58,6 @@ describe("pruneGitHubNotificationsCLI", () => {
]);

expect(mockPruneGitHubNotifications).toHaveBeenCalledWith({
auth: "abc_def",
bandwidth: 123,
filters: {
reason: new Set(["abc", "def"]),
Expand Down
7 changes: 1 addition & 6 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,6 @@ import { pruneGitHubNotifications } from "./pruneGitHubNotifications.js";
import { runInWatch } from "./runInWatch.js";

const schema = z.object({
auth: z.string({
required_error:
"--auth is required if a GH_TOKEN environment variable is not specified.",
}),
bandwidth: z.coerce.number().optional(),
reason: z
.array(z.string())
Expand Down Expand Up @@ -46,11 +42,10 @@ export async function pruneGitHubNotificationsCLI(args: string[]) {
tokens: true,
});

const { auth, bandwidth, reason, title, watch } = schema.parse(values);
const { bandwidth, reason, title, watch } = schema.parse(values);

const action = async () =>
await pruneGitHubNotifications({
auth,
bandwidth,
filters: {
reason,
Expand Down
30 changes: 25 additions & 5 deletions src/pruneGitHubNotifications.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@ import { describe, expect, it, vi } from "vitest";

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

const mockGetGitHubAuthToken = vi.fn();

vi.mock("get-github-auth-token", () => ({
get getGitHubAuthToken() {
return mockGetGitHubAuthToken;
},
}));

const mockRequest = vi.fn().mockResolvedValue({
data: [
{
Expand Down Expand Up @@ -43,15 +51,23 @@ vi.mock("octokit", () => ({

describe("pruneGitHubNotifications", () => {
it("throws an error when auth is not available", async () => {
mockGetGitHubAuthToken.mockResolvedValue({
error: "Oh no!",
succeeded: false,
});

await expect(async () => {
await pruneGitHubNotifications();
}).rejects.toMatchInlineSnapshot(
`[Error: Please provide an auth token (process.env.GH_TOKEN).]`,
);
}).rejects.toMatchInlineSnapshot(`[Error: Oh no!]`);
});

it("unsubscribes from threads based on default filters when no filters are provided", async () => {
await pruneGitHubNotifications({ auth: "abc123" });
mockGetGitHubAuthToken.mockResolvedValue({
succeeded: true,
token: "abc123",
});

await pruneGitHubNotifications();

expect(mockRequest.mock.calls).toMatchInlineSnapshot(`
[
Expand Down Expand Up @@ -86,8 +102,12 @@ describe("pruneGitHubNotifications", () => {
});

it("unsubscribes from threads based on custom filters when custom filters are provided", async () => {
mockGetGitHubAuthToken.mockResolvedValue({
succeeded: true,
token: "abc123",
});

await pruneGitHubNotifications({
auth: "abc123",
filters: { reason: new Set(["other-reason"]), title: /other title/ },
});

Expand Down
10 changes: 5 additions & 5 deletions src/pruneGitHubNotifications.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { getGitHubAuthToken } from "get-github-auth-token";
import { Octokit } from "octokit";
import throttledQueue from "throttled-queue";

Expand All @@ -15,16 +16,15 @@ type ThrottledQueue = (
) => <Return = unknown>(fn: () => Promise<Return> | Return) => Promise<Return>;

export async function pruneGitHubNotifications({
auth,
bandwidth = defaultOptions.bandwidth,
filters,
}: PruneGitHubNotificationsOptions = {}): Promise<PruneGitHubNotificationsResult> {
auth ??= process.env.GH_TOKEN;
if (!auth) {
throw new Error(`Please provide an auth token (process.env.GH_TOKEN).`);
const auth = await getGitHubAuthToken();
if (!auth.succeeded) {
throw new Error(auth.error);
}

const octokit = new Octokit({ auth });
const octokit = new Octokit({ auth: auth.token });
const notifications = await octokit.request("GET /notifications", {
headers: {
"X-GitHub-Api-Version": "2022-11-28",
Expand Down
2 changes: 1 addition & 1 deletion src/runInWatch.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { runInWatch } from "./runInWatch.js";
const mockLog = vi.fn();
const mockSetTimeout = vi.fn();

describe("pruneGitHubNotificationsCLI", () => {
describe("runInWatch", () => {
beforeEach(() => {
console.log = mockLog;
globalThis.setTimeout = mockSetTimeout as unknown as typeof setTimeout;
Expand Down
1 change: 0 additions & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
export interface PruneGitHubNotificationsOptions {
auth?: string;
bandwidth?: number;
filters?: Partial<FilterOptions>;
}
Expand Down

0 comments on commit 613d187

Please sign in to comment.