Skip to content

Commit

Permalink
feat: add findEmails utility function
Browse files Browse the repository at this point in the history
  • Loading branch information
reifiedbeans committed Jul 4, 2024
1 parent 941d684 commit 85b7172
Show file tree
Hide file tree
Showing 11 changed files with 1,092 additions and 68 deletions.
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/dist
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,6 @@ node_modules

# ESLint
.eslintcache

# Build output
/dist
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
/dist
.eslintcache
pnpm-lock.yaml
18 changes: 17 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,30 @@
[![npm](https://img.shields.io/npm/v/find-gh-commit-emails/latest)](https://www.npmjs.com/package/find-gh-commit-emails)
[![license: MIT](https://img.shields.io/npm/l/find-gh-commit-emails)](https://github.com/reifiedbeans/find-gh-commit-emails/blob/main/LICENSE)

A script to search for emails used by a given GitHub user.
Utilities for finding emails used by a given GitHub user.

## Usage

This package provides an executable that can be invoked directly.

```shell
npx find-gh-commit-emails <username>
```

A utility function is also provided for use in Node.js applications.

```javascript
import { findEmails } from "find-gh-commit-emails";

const username = "<username>";
const token = "[token]";
const options = {
includeCommitter: true,
};

const emailMap = await findEmails(username, token, options);
```

## License

Licensed under the [MIT License](https://github.com/reifiedbeans/find-gh-commit-emails/blob/main/LICENSE).
22 changes: 22 additions & 0 deletions bin/cli.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/usr/bin/env node
import { program } from "@commander-js/extra-typings";
import { findEmails } from "../lib/index.ts";

program
.name("find-gh-commit-emails")
.description(
"Search for emails used by a given GitHub user. " +
"Setting the GITHUB_TOKEN environment variable to a valid GitHub personal " +
"access token will enable searching in non-public repositories.",
)
.argument("username", "GitHub username to find emails for")
.option("--include-committer", "include committer email in results", false)
.configureHelp({ helpWidth: 80 })
.showHelpAfterError()
.action(async (username, opts) => {
const token = process.env["GITHUB_TOKEN"];
const emailsMap = await findEmails(username, token, opts);
console.log(JSON.stringify(emailsMap, null, 2));
});

program.parse(process.argv);
58 changes: 0 additions & 58 deletions index.js

This file was deleted.

51 changes: 51 additions & 0 deletions lib/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { Octokit } from "octokit";

interface Options {
readonly includeCommitter?: boolean;
}

/**
* Find emails for a GitHub user
* @param username a GitHub username
* @param token a GitHub token
* @param opts additional options
*/
export async function findEmails(
username: string,
token?: string,
opts?: Options,
) {
const github = new Octokit({ auth: token });

const commitData = await github.paginate("GET /search/commits", {
q: `author:${username}`,
});

const emailMap = new Map<string, Set<string>>();

for (const entry of commitData) {
const repo = entry.repository.full_name;
const emails = [entry.commit.author.email];

if (opts?.includeCommitter && entry.commit.committer?.email) {
emails.push(entry.commit.committer.email);
}

for (const email of emails) {
let repos = emailMap.get(email);
if (!repos) {
repos = new Set();
emailMap.set(email, repos);
}
repos.add(repo);
}
}

const object: { [key: string]: string[] } = {};
for (const [email, repos] of emailMap) {
Object.assign(object, {
[email]: Array.from(repos),
});
}
return object;
}
19 changes: 12 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,26 @@
"license": "MIT",
"type": "module",
"files": [
"index.js"
"dist"
],
"main": "dist/lib/index.js",
"types": "dist/lib/index.d.ts",
"bin": {
"find-gh-commit-emails": "index.js"
"find-gh-commit-emails": "dist/bin/cli.js"
},
"engines": {
"node": ">=18"
},
"scripts": {
"build": "tsup",
"format": "prettier --write .",
"format:check": "prettier --check .",
"lint": "eslint --cache --max-warnings=0 .",
"lint:fix": "eslint --fix --cache --max-warnings=0 .",
"prepack": "npm-run-all lint format:check"
"lint": "tsc && eslint --cache --max-warnings=0 .",
"lint:fix": "tsc && eslint --fix --cache --max-warnings=0 .",
"prepack": "npm-run-all build lint format:check"
},
"dependencies": {
"commander": "^12.1.0",
"@commander-js/extra-typings": "^12.1.0",
"octokit": "^4.0.2"
},
"devDependencies": {
Expand All @@ -36,7 +39,9 @@
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0",
"npm-run-all": "^4.1.5",
"prettier": "^3.3.2"
"prettier": "^3.3.2",
"tsup": "^8.1.0",
"typescript": "^5.5.3"
},
"publishConfig": {
"access": "public"
Expand Down
Loading

0 comments on commit 85b7172

Please sign in to comment.