Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: lookup Github username if token is available #155

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ coverage
dist
types
.conf*
.env
111 changes: 111 additions & 0 deletions src/author.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import { upperFirst } from "scule";
import { ResolvedChangelogConfig } from "./config";
import { GitCommit } from "./git";
import { getGithubLoginByCommit } from "./github";

export interface GithubAuthor {
commits: string[];
github?: string;
email: Set<string>;
name: string;
}

export async function resolveAuthorInfo(
config: ResolvedChangelogConfig,
info: GithubAuthor
JohnCampionJr marked this conversation as resolved.
Show resolved Hide resolved
) {
if (info.github) {
return info;
}

try {
for (const email of info.email) {
const { user } = await fetch(`https://ungh.cc/users/find/${email}`)
.then((r) => r.json())
.catch(() => ({ user: null }));
if (user) {
info.github = user.username;
break;
}
}
} catch {}

if (info.github) {
return info;
}

// token not provided, skip github resolving
if (!config.tokens.github) {
return info;
}

if (info.commits.length > 0) {
try {
info.github = await getGithubLoginByCommit(config, info.commits[0]);
JohnCampionJr marked this conversation as resolved.
Show resolved Hide resolved
} catch {}
}

return info;
}

export async function resolveAuthors(
commits: GitCommit[],
config: ResolvedChangelogConfig
) {
JohnCampionJr marked this conversation as resolved.
Show resolved Hide resolved
const _authors = new Map<string, GithubAuthor>();
for (const commit of commits) {
if (!commit.author) {
continue;
}
const name = formatName(commit.author.name);
if (!name || name.includes("[bot]")) {
continue;
}
if (
config.excludeAuthors &&
config.excludeAuthors.some(
(v) => name.includes(v) || commit.author.email?.includes(v)
)
) {
continue;
}
if (_authors.has(name)) {
const entry = _authors.get(name);
entry.email.add(commit.author.email);
entry.commits.push(commit.shortHash);
} else {
_authors.set(name, {
name,
email: new Set([commit.author.email]),
commits: [commit.shortHash],
});
}
}

// Try to map authors to github usernames
const authors = [..._authors.values()];
const resolved = await Promise.all(
authors.map((info) => resolveAuthorInfo(config, info))
JohnCampionJr marked this conversation as resolved.
Show resolved Hide resolved
);

// check for duplicate logins
const loginSet = new Set<string>();
return resolved.filter((i) => {
if (i.github && loginSet.has(i.github)) {
return false;
}
if (i.github) {
loginSet.add(i.github);
}
return true;
});
}

// --- Internal utils ---

function formatName(name = "") {
return name
.split(" ")
.map((p) => upperFirst(p.trim()))
.join(" ");
}
12 changes: 12 additions & 0 deletions src/github.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,18 @@ export async function listGithubReleases(
});
}

export async function getGithubLoginByCommit(
config: ResolvedChangelogConfig,
commit: string
): Promise<string> {
const data = await githubFetch(
config,
`/repos/${config.repo.repo}/commits/${commit}`,
{}
);
return data?.author?.login;
}

export async function getGithubReleaseByTag(
config: ResolvedChangelogConfig,
tag: string
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ export * from "./markdown";
export * from "./config";
export * from "./semver";
export * from "./repo";
export * from "./author";
52 changes: 2 additions & 50 deletions src/markdown.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { upperFirst } from "scule";
import { convert } from "convert-gitmoji";
import { fetch } from "node-fetch-native";
import type { ResolvedChangelogConfig } from "./config";
import type { GitCommit, Reference } from "./git";
import { formatReference, formatCompareChanges } from "./repo";
import { resolveAuthors } from "./author";

export async function generateMarkDown(
commits: GitCommit[],
Expand Down Expand Up @@ -42,48 +42,7 @@ export async function generateMarkDown(
markdown.push("", "#### ⚠️ Breaking Changes", "", ...breakingChanges);
}

const _authors = new Map<string, { email: Set<string>; github?: string }>();
for (const commit of commits) {
if (!commit.author) {
continue;
}
const name = formatName(commit.author.name);
if (!name || name.includes("[bot]")) {
continue;
}
if (
config.excludeAuthors &&
config.excludeAuthors.some(
(v) => name.includes(v) || commit.author.email?.includes(v)
)
) {
continue;
}
if (_authors.has(name)) {
const entry = _authors.get(name);
entry.email.add(commit.author.email);
} else {
_authors.set(name, { email: new Set([commit.author.email]) });
}
}

// Try to map authors to github usernames
await Promise.all(
[..._authors.keys()].map(async (authorName) => {
const meta = _authors.get(authorName);
for (const email of meta.email) {
const { user } = await fetch(`https://ungh.cc/users/find/${email}`)
.then((r) => r.json())
.catch(() => ({ user: null }));
if (user) {
meta.github = user.username;
break;
}
}
})
);

const authors = [..._authors.entries()].map((e) => ({ name: e[0], ...e[1] }));
const authors = await resolveAuthors(commits, config);

if (authors.length > 0) {
markdown.push(
Expand Down Expand Up @@ -169,13 +128,6 @@ function formatReferences(
// return title.length <= 3 ? title.toUpperCase() : upperFirst(title)
// }

function formatName(name = "") {
return name
.split(" ")
.map((p) => upperFirst(p.trim()))
.join(" ");
}

function groupBy(items: any[], key: string) {
const groups = {};
for (const item of items) {
Expand Down
Loading