Skip to content

Commit 551737a

Browse files
fix: correct remaining --auto mismatches (#1612)
## PR Checklist - [x] Addresses an existing open issue: fixes #934; fixes #1157; fixes #1613 - [x] That issue was marked as [`status: accepting prs`](https://github.com/JoshuaKGoldberg/create-typescript-app/issues?q=is%3Aopen+is%3Aissue+label%3A%22status%3A+accepting+prs%22) - [x] Steps in [CONTRIBUTING.md](https://github.com/JoshuaKGoldberg/create-typescript-app/blob/main/.github/CONTRIBUTING.md) were taken ## Overview Fills in a lot of logic around defaults that was previously not hooked up. `--auto` now completely works as expected in this repository. 💖
1 parent ebc96fa commit 551737a

12 files changed

+288
-102
lines changed

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
},
99
"license": "MIT",
1010
"author": {
11-
"name": "Josh Goldberg",
11+
"name": "Josh Goldberg",
1212
"email": "[email protected]"
1313
},
1414
"type": "module",

script/migrate-test-e2e.ts

+1-18
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ import * as fs from "node:fs/promises";
44
import { rimraf } from "rimraf";
55
import { assert, describe, expect, test } from "vitest";
66

7-
import packageData from "../package.json" assert { type: "json" };
8-
97
const filesExpectedToBeChanged = [
108
"README.md",
119
"knip.json",
@@ -21,21 +19,6 @@ const filesThatMightBeChanged = new Set([
2119
"script/__snapshots__/migrate-test-e2e.ts.snap",
2220
]);
2321

24-
const {
25-
author: { email: emailNpm, name: authorName },
26-
description,
27-
name: repository,
28-
} = packageData;
29-
const emailGithub = "[email protected]";
30-
const bin = "./bin/index.js";
31-
const guide =
32-
"https://www.joshuakgoldberg.com/blog/contributing-to-a-create-typescript-app-repository";
33-
const guideTitle = "Contributing to a create-typescript-app Repository";
34-
const logo = "./docs/create-typescript-app.png";
35-
const logoAlt = `Project logo: the TypeScript blue square with rounded corners, but a plus sign instead of 'TS'`;
36-
const owner = "JoshuaKGoldberg";
37-
const title = "Create TypeScript App";
38-
3922
await rimraf("coverage*");
4023

4124
const originalReadme = (await fs.readFile("README.md")).toString();
@@ -46,7 +29,7 @@ const originalSnapshots = (
4629

4730
await $({
4831
stdio: "inherit",
49-
})`c8 -o ./coverage -r html -r lcov --src src node ${bin} --base everything --author ${authorName} --mode migrate --bin ${bin} --description ${description} --email-github ${emailGithub} --email-npm ${emailNpm} --guide ${guide} --guide-title ${guideTitle} --logo ${logo} --logo-alt ${logoAlt} --owner ${owner} --title ${title} --repository ${repository} --skip-all-contributors-api --skip-github-api --skip-install`;
32+
})`c8 -o ./coverage -r html -r lcov --src src node ./bin/index.js --auto --mode migrate --skip-all-contributors-api --skip-github-api --skip-install`;
5033

5134
// All Contributors seems to not be using Prettier to format files...
5235
await fs.writeFile(

src/shared/options/createOptionDefaults/index.test.ts

+63-16
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { describe, expect, it, vi } from "vitest";
1+
import { beforeEach, describe, expect, it, vi } from "vitest";
22

33
import { createOptionDefaults } from "./index.js";
44

@@ -34,6 +34,14 @@ vi.mock("../../packages.js", () => ({
3434
},
3535
}));
3636

37+
const mockReadGitHubEmail = vi.fn();
38+
39+
vi.mock("./readGitHubEmail.js", () => ({
40+
get readGitHubEmail() {
41+
return mockReadGitHubEmail;
42+
},
43+
}));
44+
3745
describe("createOptionDefaults", () => {
3846
describe("bin", () => {
3947
it("returns undefined when package data does not have a bin", async () => {
@@ -56,24 +64,29 @@ describe("createOptionDefaults", () => {
5664
});
5765

5866
describe("email", () => {
67+
beforeEach(() => {
68+
mockNpmUser.mockImplementation((username: string) => ({
69+
email: `npm-${username}@test.com`,
70+
}));
71+
});
72+
5973
it("returns the npm whoami email from npm when only an npm exists", async () => {
6074
mock$.mockImplementation(([command]: string[]) =>
61-
command === "npm whoami" ? { stdout: "npm-username" } : undefined,
75+
command === "npm whoami" ? { stdout: "username" } : undefined,
6276
);
63-
mockNpmUser.mockImplementation((username: string) => ({
64-
email: `test@${username}.com`,
65-
}));
77+
mockReadGitHubEmail.mockResolvedValueOnce(undefined);
6678

6779
const actual = await createOptionDefaults().email();
6880

6981
expect(actual).toEqual({
70-
github: "test@npm-username.com",
71-
npm: "test@npm-username.com",
82+
github: "npm-username@test.com",
83+
npm: "npm-username@test.com",
7284
});
7385
});
7486

7587
it("returns the npm whoami email from npm when only a package author email exists", async () => {
7688
mock$.mockResolvedValue({ stdout: "" });
89+
mockReadGitHubEmail.mockResolvedValueOnce(undefined);
7790
mockReadPackageData.mockResolvedValue({
7891
author: {
7992
@@ -88,41 +101,75 @@ describe("createOptionDefaults", () => {
88101
});
89102
});
90103

104+
it("returns the github email when only a github email exists", async () => {
105+
mock$.mockResolvedValue({ stdout: "" });
106+
mockReadPackageData.mockResolvedValueOnce({});
107+
mockReadGitHubEmail.mockResolvedValueOnce("[email protected]");
108+
109+
const actual = await createOptionDefaults().email();
110+
111+
expect(actual).toEqual({
112+
github: "[email protected]",
113+
114+
});
115+
});
116+
91117
it("returns the git user email when only a git user email exists", async () => {
92118
mock$.mockImplementation(([command]: string[]) =>
93119
command === "git config --get user.email"
94-
? { stdout: "test@git.com" }
120+
? { stdout: "git@test.com" }
95121
: undefined,
96122
);
123+
mockReadGitHubEmail.mockResolvedValueOnce(undefined);
124+
mockReadPackageData.mockResolvedValue({});
125+
126+
const actual = await createOptionDefaults().email();
127+
128+
expect(actual).toEqual({
129+
github: "[email protected]",
130+
131+
});
132+
});
133+
134+
it("returns both the git user email and the npm user email when only those two exist", async () => {
135+
mock$.mockImplementation(([command]: string[]) => ({
136+
stdout:
137+
command === "git config --get user.email"
138+
139+
: "username",
140+
}));
141+
mockReadGitHubEmail.mockResolvedValueOnce(undefined);
97142
mockReadPackageData.mockResolvedValue({});
98143

99144
const actual = await createOptionDefaults().email();
100145

101146
expect(actual).toEqual({
102-
github: "test@git.com",
103-
npm: "test@git.com",
147+
github: "git@test.com",
148+
npm: "npm-username@test.com",
104149
});
105150
});
106151

107-
it("returns both the git user email and the npm user email when both exist", async () => {
152+
it("returns all three emails when they all exist", async () => {
108153
mock$.mockImplementation(([command]: string[]) => ({
109154
stdout:
110155
command === "git config --get user.email"
111-
? "test@git.com"
112-
: "npm-username",
156+
? "git@test.com"
157+
: "username",
113158
}));
159+
mockReadGitHubEmail.mockResolvedValueOnce("[email protected]");
114160
mockReadPackageData.mockResolvedValue({});
115161

116162
const actual = await createOptionDefaults().email();
117163

118164
expect(actual).toEqual({
119-
github: "test@git.com",
120-
npm: "test@npm-username.com",
165+
github: "github@test.com",
166+
npm: "npm-username@test.com",
121167
});
122168
});
123169

124-
it("returns undefined when neither git nor npm emails exist", async () => {
170+
it("returns undefined when none of the emails exist", async () => {
125171
mock$.mockResolvedValue({ stdout: "" });
172+
mockReadGitHubEmail.mockResolvedValueOnce(undefined);
126173
mockReadPackageData.mockResolvedValue({});
127174

128175
const actual = await createOptionDefaults().email();

src/shared/options/createOptionDefaults/index.ts

+13-6
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { PromptedOptions } from "../../types.js";
1212
import { parsePackageAuthor } from "./parsePackageAuthor.js";
1313
import { readDefaultsFromDevelopment } from "./readDefaultsFromDevelopment.js";
1414
import { readDefaultsFromReadme } from "./readDefaultsFromReadme.js";
15+
import { readGitHubEmail } from "./readGitHubEmail.js";
1516

1617
export function createOptionDefaults(promptedOptions?: PromptedOptions) {
1718
const gitDefaults = tryCatchLazyValueAsync(async () =>
@@ -29,19 +30,25 @@ export function createOptionDefaults(promptedOptions?: PromptedOptions) {
2930
);
3031

3132
return {
32-
author: async () => (await packageAuthor()).author ?? npmDefaults.name,
33+
author: async () =>
34+
(await packageAuthor()).author ?? (await npmDefaults())?.name,
3335
bin: async () => (await packageData()).bin,
3436
description: async () => (await packageData()).description,
3537
email: async () => {
36-
const gitEmail = await tryCatchAsync(
37-
async () => (await $`git config --get user.email`).stdout,
38-
);
38+
const githubEmail =
39+
(await readGitHubEmail()) ??
40+
(await tryCatchAsync(
41+
async () => (await $`git config --get user.email`).stdout,
42+
));
3943
const npmEmail =
4044
(await npmDefaults())?.email ?? (await packageAuthor()).email;
4145

4246
/* eslint-disable @typescript-eslint/no-non-null-assertion */
43-
return gitEmail || npmEmail
44-
? { github: (gitEmail || npmEmail)!, npm: (npmEmail || gitEmail)! }
47+
return githubEmail || npmEmail
48+
? {
49+
github: (githubEmail || npmEmail)!,
50+
npm: (npmEmail || githubEmail)!,
51+
}
4552
: undefined;
4653
/* eslint-enable @typescript-eslint/no-non-null-assertion */
4754
},

src/shared/options/createOptionDefaults/readDefaultsFromDevelopment.test.ts

+5-28
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ describe("readDefaultsFromDevelopment", () => {
2020
expect(guide).toBeUndefined();
2121
});
2222

23-
it("reads guide when it exists", async () => {
23+
it("reads the href and title when the tag exists", async () => {
2424
mockReadFileSafe.mockResolvedValue(`# Development
2525
2626
> If you'd like a more guided walkthrough, see [Contributing to a create-typescript-app Repository](https://www.joshuakgoldberg.com/blog/contributing-to-a-create-typescript-app-repository).
@@ -29,33 +29,10 @@ describe("readDefaultsFromDevelopment", () => {
2929

3030
const guide = await readDefaultsFromDevelopment().guide();
3131

32-
expect(guide).toBe(
33-
"https://www.joshuakgoldberg.com/blog/contributing-to-a-create-typescript-app-repository",
34-
);
35-
});
36-
});
37-
38-
describe("guideTitle", () => {
39-
it("defaults to undefined when .github/DEVELOPMENT.md cannot be found", async () => {
40-
mockReadFileSafe.mockResolvedValue("");
41-
42-
const guideTitle = await readDefaultsFromDevelopment().guideTitle();
43-
44-
expect(guideTitle).toBeUndefined();
45-
});
46-
47-
it("reads guideTitle when it exists", async () => {
48-
mockReadFileSafe.mockResolvedValue(`# Development
49-
50-
> If you'd like a more guided walkthrough, see [Contributing to a create-typescript-app Repository](https://www.joshuakgoldberg.com/blog/contributing-to-a-create-typescript-app-repository).
51-
> It'll walk you through the common activities you'll need to contribute.
52-
`);
53-
54-
const guideTitle = await readDefaultsFromDevelopment().guideTitle();
55-
56-
expect(guideTitle).toBe(
57-
"Contributing to a create-typescript-app Repository",
58-
);
32+
expect(guide).toEqual({
33+
href: "https://www.joshuakgoldberg.com/blog/contributing-to-a-create-typescript-app-repository",
34+
title: "Contributing to a create-typescript-app Repository",
35+
});
5936
});
6037
});
6138
});

src/shared/options/createOptionDefaults/readDefaultsFromDevelopment.ts

+13-11
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,20 @@ import lazyValue from "lazy-value";
33
import { readFileSafe } from "../../readFileSafe.js";
44

55
export function readDefaultsFromDevelopment() {
6-
const development = lazyValue(
7-
async () => await readFileSafe(".github/DEVELOPMENT.md", ""),
8-
);
6+
return {
7+
guide: lazyValue(async () => {
8+
const tag = /> .*guided walkthrough, see \[((?!\[).+)\]\((.+)\)/i.exec(
9+
await readFileSafe(".github/DEVELOPMENT.md", ""),
10+
);
911

10-
const guideTag = lazyValue(async () =>
11-
/> .*guided walkthrough, see \[((?!\[).+)\]\((.+)\)/i.exec(
12-
await development(),
13-
),
14-
);
12+
if (!tag) {
13+
return undefined;
14+
}
1515

16-
return {
17-
guide: async () => (await guideTag())?.[2],
18-
guideTitle: async () => (await guideTag())?.[1],
16+
return {
17+
href: tag[2],
18+
title: tag[1],
19+
};
20+
}),
1921
};
2022
}

0 commit comments

Comments
 (0)