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

fix: infer author email from package.json if available #2108

Merged
merged 1 commit into from
Apr 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ export const base = createBase({
getEmailFromCodeOfConduct,
getEmailFromGit,
getEmailFromNpm,
getPackageAuthor,
),
);

Expand Down
6 changes: 3 additions & 3 deletions src/options/readAuthor.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@ import { readAuthor } from "./readAuthor.js";

describe(readAuthor, () => {
it("returns package author when it exists", async () => {
const author = "test-author";
const name = "test-author";
const getNpmDefaults = vi.fn();

const actual = await readAuthor(
() => Promise.resolve({ author }),
() => Promise.resolve({ name }),
getNpmDefaults,
undefined,
);

expect(actual).toBe(author);
expect(actual).toBe(name);
expect(getNpmDefaults).not.toHaveBeenCalled();
});

Expand Down
6 changes: 4 additions & 2 deletions src/options/readAuthor.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { PackageAuthor } from "./readPackageAuthor.js";

export async function readAuthor(
getPackageAuthor: () => Promise<{ author?: string }>,
getPackageAuthor: () => Promise<PackageAuthor>,
getNpmDefaults: () => Promise<undefined | { name?: string }>,
owner: string | undefined,
) {
return (
(await getPackageAuthor()).author ?? (await getNpmDefaults())?.name ?? owner
(await getPackageAuthor()).name ?? (await getNpmDefaults())?.name ?? owner
);
}
4 changes: 3 additions & 1 deletion src/options/readEmailFromNpm.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { UserInfo } from "npm-user";

import { PackageAuthor } from "./readPackageAuthor.js";

export async function readEmailFromNpm(
getNpmDefaults: () => Promise<undefined | UserInfo>,
getPackageAuthor: () => Promise<{ email: string | undefined }>,
getPackageAuthor: () => Promise<PackageAuthor>,
) {
return (await getNpmDefaults())?.email ?? (await getPackageAuthor()).email;
}
16 changes: 16 additions & 0 deletions src/options/readEmails.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ describe(readEmails, () => {
() => Promise.resolve(undefined),
() => Promise.resolve(undefined),
() => Promise.resolve(undefined),
() => Promise.resolve({}),
);

expect(actual).toBeUndefined();
Expand All @@ -22,6 +23,7 @@ describe(readEmails, () => {
() => Promise.resolve(emailCoC),
() => Promise.resolve(undefined),
() => Promise.resolve(undefined),
() => Promise.resolve({}),
);

expect(actual).toEqual({ github: emailCoC, npm: emailCoC });
Expand All @@ -32,6 +34,7 @@ describe(readEmails, () => {
() => Promise.resolve(undefined),
() => Promise.resolve(undefined),
() => Promise.resolve(emailNpm),
() => Promise.resolve({}),
);

expect(actual).toEqual({ github: emailNpm, npm: emailNpm });
Expand All @@ -42,6 +45,7 @@ describe(readEmails, () => {
() => Promise.resolve(emailCoC),
() => Promise.resolve(undefined),
() => Promise.resolve(emailNpm),
() => Promise.resolve({}),
);

expect(actual).toEqual({ github: emailCoC, npm: emailNpm });
Expand All @@ -52,8 +56,20 @@ describe(readEmails, () => {
() => Promise.resolve(undefined),
() => Promise.resolve(emailGit),
() => Promise.resolve(emailNpm),
() => Promise.resolve({}),
);

expect(actual).toEqual({ github: emailGit, npm: emailNpm });
});

it("resolves package author email as the github and npm emails when only the package author email exists", async () => {
const actual = await readEmails(
() => Promise.resolve(undefined),
() => Promise.resolve(undefined),
() => Promise.resolve(undefined),
() => Promise.resolve({ email: emailNpm }),
);

expect(actual).toEqual({ github: emailNpm, npm: emailNpm });
});
});
6 changes: 5 additions & 1 deletion src/options/readEmails.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import { PackageAuthor } from "./readPackageAuthor.js";

export async function readEmails(
getEmailFromCodeOfConduct: () => Promise<string | undefined>,
getEmailFromGit: () => Promise<string | undefined>,
getEmailFromNpm: () => Promise<string | undefined>,
getPackageAuthor: () => Promise<PackageAuthor>,
) {
const github =
(await getEmailFromCodeOfConduct()) ?? (await getEmailFromGit());
const npm = (await getEmailFromNpm()) ?? github;
const npm =
(await getPackageAuthor()).email ?? (await getEmailFromNpm()) ?? github;

return npm ? { github: github || npm, npm } : undefined;
}
22 changes: 11 additions & 11 deletions src/options/readOwner.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,44 +7,44 @@ describe(readOwner, () => {
const take = vi.fn();
const organization = "test-organization";
const getGitDefaults = vi.fn().mockResolvedValueOnce({ organization });
const getPackageDataFull = vi.fn();
const getPackageAuthor = vi.fn();

const actual = await readOwner(take, getGitDefaults, getPackageDataFull);
const actual = await readOwner(take, getGitDefaults, getPackageAuthor);

expect(actual).toBe(organization);
expect(take).not.toHaveBeenCalled();
expect(getPackageDataFull).not.toHaveBeenCalled();
expect(getPackageAuthor).not.toHaveBeenCalled();
});

it("returns package data author when only it exists", async () => {
const take = vi.fn();
const author = "test-author";
const name = "test-author";
const getGitDefaults = vi.fn();
const getPackageDataFull = vi.fn().mockResolvedValueOnce({ author });
const getPackageAuthor = vi.fn().mockResolvedValueOnce({ name });

const actual = await readOwner(take, getGitDefaults, getPackageDataFull);
const actual = await readOwner(take, getGitDefaults, getPackageAuthor);

expect(actual).toBe(author);
expect(actual).toBe(name);
expect(take).not.toHaveBeenCalled();
});

it("returns the gh config value when only it resolves", async () => {
const user = "test-user";
const take = vi.fn().mockResolvedValueOnce({ stdout: user });
const getGitDefaults = vi.fn();
const getPackageDataFull = vi.fn().mockResolvedValueOnce({});
const getPackageAuthor = vi.fn().mockResolvedValueOnce({});

const actual = await readOwner(take, getGitDefaults, getPackageDataFull);
const actual = await readOwner(take, getGitDefaults, getPackageAuthor);

expect(actual).toBe(user);
});

it("returns undefined when no values exist", async () => {
const take = vi.fn().mockResolvedValueOnce({});
const getGitDefaults = vi.fn();
const getPackageDataFull = vi.fn().mockResolvedValueOnce({});
const getPackageAuthor = vi.fn().mockResolvedValueOnce({});

const actual = await readOwner(take, getGitDefaults, getPackageDataFull);
const actual = await readOwner(take, getGitDefaults, getPackageAuthor);

expect(actual).toBe(undefined);
});
Expand Down
6 changes: 4 additions & 2 deletions src/options/readOwner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@ import { TakeInput } from "bingo";
import { GitUrl } from "git-url-parse";
import { inputFromScript } from "input-from-script";

import { PackageAuthor } from "./readPackageAuthor.js";

export async function readOwner(
take: TakeInput,
getGitDefaults: () => Promise<GitUrl | undefined>,
getPackageAuthor: () => Promise<{ author?: string }>,
getPackageAuthor: () => Promise<PackageAuthor>,
) {
return (
(await getGitDefaults())?.organization ??
(await getPackageAuthor()).author ??
(await getPackageAuthor()).name ??
(
await take(inputFromScript, {
command: "gh config get user -h github.com",
Expand Down
8 changes: 4 additions & 4 deletions src/options/readPackageAuthor.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@ import { readPackageAuthor } from "./readPackageAuthor.js";
describe(readPackageAuthor, () => {
it.each([
[{}, {}],
[{ author: "abc123" }, { author: "abc123" }],
[{ name: "abc123" }, { author: "abc123" }],
[
{ author: "abc123", email: "[email protected]" },
{ email: "[email protected]", name: "abc123" },
{ author: "abc123 <[email protected]>" },
],
[
{ author: "abc123", email: "[email protected]" },
{ email: "[email protected]", name: "abc123" },
{ author: "abc123 <[email protected]>" },
],
[
{ author: "abc123", email: "[email protected]" },
{ email: "[email protected]", name: "abc123" },
{ author: { email: "[email protected]", name: "abc123" } },
],
])("returns %s when given %s", async (expected, packageDataFull) => {
Expand Down
30 changes: 15 additions & 15 deletions src/options/readPackageAuthor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,24 @@ import parse from "parse-author";

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

export interface PackageAuthor {
email?: string | undefined;
name?: string | undefined;
}

export async function readPackageAuthor(
getPackageDataFull: () => Promise<PartialPackageData>,
) {
): Promise<PackageAuthor> {
const packageData = await getPackageDataFull();
let packageAuthor: string | undefined;
let packageEmail: string | undefined;

if (typeof packageData.author === "string") {
const parsedAuthor = parse(packageData.author);
packageAuthor = parsedAuthor.name;
packageEmail = parsedAuthor.email;
} else if (packageData.author) {
packageAuthor = packageData.author.name;
packageEmail = packageData.author.email;
}
switch (typeof packageData.author) {
case "object":
return packageData.author;

return {
author: packageAuthor,
email: packageEmail,
};
case "string":
return parse(packageData.author);

default:
return {};
}
}
2 changes: 1 addition & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export interface AllContributorsData {
}

export interface PartialPackageData {
author?: string | { email: string; name: string };
author?: string | { email?: string; name?: string };
bin?: Record<string, string> | string;
dependencies?: Record<string, string>;
description?: string;
Expand Down