Skip to content

Commit 6f58d7f

Browse files
JoshuaKGoldbergjohnnyreillyAslemammad
authored
docs: overhaul for scripts and their end-to-end tests (#1187)
## PR Checklist - [x] Addresses an existing open issue: fixes #1141; fixes #1186 - [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 Adds some inline comments to end-to-end tests, as well as a more full description of what to do with migration snapshots in development docs. Also simplifies the migration test error to suggest looking at the docs. Touches a little bit on what #1045 requests around more clear and standardized token docs. Co-authored-by: John Reilly <[email protected]> Co-authored-by: Mohammad Bagher Abiyat <[email protected]>
1 parent 0b2d425 commit 6f58d7f

15 files changed

+269
-54
lines changed

Diff for: .github/DEVELOPMENT.md

+52-2
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,8 @@ Each follows roughly the same general flow:
119119
120120
### The Creation Script
121121

122+
> 📝 See [`docs/Creation.md`](../docs/Creation.md) for user documentation on the creation script.
123+
122124
This template's "creation" script is located in `src/create/`.
123125
You can run it locally with `node bin/index.js --mode create`.
124126
Note that files need to be built with `pnpm run build` beforehand.
@@ -142,6 +144,8 @@ See `.github/workflows/test-create.yml`.
142144

143145
### The Initialization Script
144146

147+
> 📝 See [`docs/Initialization.md`](../docs/Initialization.md) for user documentation on the initialization script.
148+
145149
This template's "initialization" script is located in `src/initialize/`.
146150
You can run it locally with `pnpm run initialize`.
147151
It uses [`tsx`](https://github.com/esbuild-kit/tsx) so you don't need to build files before running.
@@ -172,6 +176,8 @@ See `.github/workflows/test-initialize.yml`.
172176

173177
### The Migration Script
174178

179+
> 📝 See [`docs/Migration.md`](../docs/Migration.md) for user documentation on the migration script.
180+
175181
This template's "migration" script is located in `src/migrate/`.
176182
Note that files need to be built with `pnpm run build` beforehand.
177183

@@ -194,6 +200,9 @@ node ../create-typescript-app/bin/migrate.js
194200

195201
#### Testing the Migration Script
196202

203+
> 💡 Seeing `Oh no! Running the migrate script unexpectedly modified:` errors?
204+
> _[Unexpected File Modifications](#unexpected-file-modifications)_ covers that below.
205+
197206
You can run the end-to-end test for migrating locally on the command-line:
198207

199208
```shell
@@ -210,5 +219,46 @@ The `pnpm run test:migrate` script is run in CI to ensure that templating change
210219
See `.github/workflows/test-migrate.yml`.
211220

212221
> Tip: if the migration test is failing in CI and you don't see any errors, try [downloading the full logs](https://docs.github.com/en/actions/monitoring-and-troubleshooting-workflows/using-workflow-run-logs#downloading-logs).
213-
> There'll likely be a list of changed files under a message like _`Oh no! Running the migrate script modified some files:`_.
214-
> You can also try running the test script locally.
222+
223+
##### Migration Snapshot Failures
224+
225+
The migration test uses the [Vitest file snapshot](https://vitest.dev/guide/snapshot#file-snapshots) in `script/__snapshots__/migrate-test-e2e.js.snap` to store expected differences to this repository after running the migration script.
226+
The end-to-end migration test will fail any changes that don't keep the same differences in that snapshot.
227+
228+
You can update the snapshot file by:
229+
230+
1. Committing any changes to your local repository
231+
2. Running `pnpm i` and `pnpm build` if any updates have been made to the `package.json` or `src/` files, respectively
232+
3. Running `pnpm run test:migrate -u` to update the snapshot
233+
234+
At this point there will be some files changed:
235+
236+
- `script/__snapshots__/migrate-test-e2e.js.snap` will have updates if any files mismatched templates
237+
- The actual updated files on disk will be there too
238+
239+
If the snapshot file changes are what you expected, then you can commit them.
240+
The rest of the file changes can be reverted.
241+
242+
> [🚀 Feature: Add a way to apply known file changes after migration #1184](https://github.com/JoshuaKGoldberg/create-typescript-app/issues/1184) tracks turning the test snapshot into a feature.
243+
244+
##### Unexpected File Modifications
245+
246+
The migration test also asserts that no files were unexpectedly changed.
247+
If you see a failure like:
248+
249+
```plaintext
250+
Oh no! Running the migrate script unexpectedly modified:
251+
- ...
252+
```
253+
254+
...then that means the file generated from templates differs from what's checked into the repository.
255+
This is most often caused by changes to templates not being applied to checked-in files too.
256+
257+
Templates for files are generally stored in [`src/steps/writing/creation`] under a path roughly corresponding to the file they describe.
258+
For example, the template for `tsup.config.ts` is stored in [`src/steps/writing/creation/createTsupConfig.ts`](../src/steps/writing/creation/createTsupConfig.ts).
259+
If the `createTsupConfig` function were to be modified without an equivalent change to `tsup.config.ts` -or vice-versa- then the migration test would report:
260+
261+
```plaintext
262+
Oh no! Running the migrate script unexpectedly modified:
263+
- tsup.config.ts
264+
```

Diff for: docs/Creation.md

+10-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,15 @@ You can run `npx create-typescript-app` in your terminal to interactively create
66
npx create-typescript-app
77
```
88

9-
Then, go through the following two steps to set up required repository tooling on GitHub:
9+
The creation script will by default:
10+
11+
1. Create a new directory with the given repository name
12+
2. Initialize that new directory as a local Git repository
13+
3. Copy the template's files to that directory
14+
4. Create a new repository on GitHub and set it as the local repository's upstream
15+
5. Configure relevant settings on the GitHub repository
16+
17+
You'll then need to manually go through the following two steps to set up tooling on GitHub:
1018

1119
1. Create two tokens in [repository secrets](https://docs.github.com/en/actions/security-guides/encrypted-secrets) _(unless you chose to opt out of releases)_:
1220
- `ACCESS_TOKEN`: A [GitHub PAT](https://github.com/settings/tokens/new) with _repo_ and _workflow_ permissions
@@ -23,7 +31,7 @@ Hooray! 🥳
2331
You can explicitly provide some or all of the options the script would prompt for as command-line flags.
2432
See [Options.md](./Options.md).
2533

26-
For example, running the creation script and skipping all GitHub APIs:
34+
For example, running the creation script and skipping all GitHub-related APIs:
2735

2836
```shell
2937
npx create-typescript-app --mode create --skip-all-contributors-api --skip-github-api

Diff for: docs/Initialization.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ It will then remove itself and uninstall dependencies only used for initializati
1818
pnpm run initialize
1919
```
2020

21-
Then, go through the following two steps to set up required repository tooling on GitHub:
21+
You'll then need to manually go through the following two steps to set up tooling on GitHub:
2222

2323
1. Create two tokens in [repository secrets](https://docs.github.com/en/actions/security-guides/encrypted-secrets) _(unless you chose to opt out of releases)_:
2424
- `ACCESS_TOKEN`: A [GitHub PAT](https://github.com/settings/tokens/new) with _repo_ and _workflow_ permissions
@@ -37,7 +37,7 @@ See [Options.md](./Options.md).
3737

3838
`pnpm run initialize` will set `--mode` to `initialize`.
3939

40-
For example, running the initialization script and skipping all GitHub APIs:
40+
For example, running the initialization script and skipping all GitHub-related APIs:
4141

4242
```shell
4343
pnpm run initialize --skip-all-contributors-api --skip-github-api

Diff for: docs/Migration.md

+36-2
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,54 @@ If you have an existing repository that you'd like to give the files from this r
66
npx create-typescript-app
77
```
88

9+
The migration script will:
10+
11+
- Uninstall any known old packages that conflict with this template's tooling
12+
- Delete configuration files used with those old packages
13+
- Install any packages needed for this template's tooling
14+
- Create or rewrite configuration files for the new tooling
15+
- Run ESLint and Prettier auto-fixers to align formatting and style to the new settings
16+
17+
For example, if the repository previously using Jest for testing:
18+
19+
- `eslint-plugin-jest`, `jest`, and other Jest-related packages will be uninstalled
20+
- Any Jest config file like `jest.config.js` will be deleted
21+
- `eslint-plugin-vitest`, `vitest`, and other Vitest-related packages will be installed
22+
- A `vitest.config.ts` file will be created
23+
24+
You'll then need to manually go through the following two steps to set up tooling on GitHub:
25+
26+
1. Create two tokens in [repository secrets](https://docs.github.com/en/actions/security-guides/encrypted-secrets) _(unless you chose to opt out of releases)_:
27+
- `ACCESS_TOKEN`: A [GitHub PAT](https://github.com/settings/tokens/new) with _repo_ and _workflow_ permissions
28+
- `NPM_TOKEN`: An [npm access token](https://docs.npmjs.com/creating-and-viewing-access-tokens/) with _Automation_ permissions
29+
2. Install two GitHub apps:
30+
- [Codecov](https://github.com/marketplace/codecov) _(unless you chose to opt out of tests)_
31+
- [Renovate](https://github.com/marketplace/renovate) _(unless you chose to opt out of renovate)_
32+
33+
Your repository will then have an approximate copy of this template's tooling ready for you to review!
34+
Hooray! 🥳
35+
936
> [!WARNING]
1037
> Migration will override many files in your repository.
1138
> You'll want to review each of the changes.
1239
> There will almost certainly be some incorrect changes you'll need to fix.
1340
1441
## Options
1542

43+
`create-typescript-app` will detect whether it's being run in an existing repository.
44+
It also allows specifying `--mode migrate` if that detection misinterprets the current directory:
45+
46+
```shell
47+
npx create-typescript-app --mode migrate
48+
```
49+
1650
You can explicitly provide some or all of the options the script would prompt for as command-line flags.
1751
See [Options.md](./Options.md).
1852

19-
For example, running the migration script and skipping all GitHub APIs:
53+
For example, running the migration script and skipping all GitHub-related APIs:
2054

2155
```shell
22-
npx create-typescript-app --mode migrate --skip-all-contributors-api --skip-github-api
56+
npx create-typescript-app --skip-all-contributors-api --skip-github-api
2357
```
2458

2559
See [Tooling.md](./Tooling.md) for details on the tooling pieces and which bases they're included in.

Diff for: docs/Options.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ The following required options will be prompted for interactively if not provide
1313
These required options determine how the creation script will set up and scaffold the repository:
1414

1515
- `--base`: Whether to scaffold the repository with:
16-
- `minimum`: Just the bare starter tooling most repositories should ideally include.
17-
- `common`: Important additions to the minimum starters such as releases and tests.
16+
- `minimum`: Just the bare starter tooling most repositories should ideally include
17+
- `common`: Important additions to the minimum starters such as releases and tests
1818
- `everything`: The most thorough tooling imaginable: sorting, spellchecking, and more!
1919
- `prompt`: Fine-grained control over which tooling pieces to use
2020
- `--mode`: Whether to:

Diff for: script/create-test-e2e.js

+3
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ const title = "Test Title";
1010

1111
await $`rm -rf ${repository}`;
1212

13+
// Fist we run with --mode create to create a new new local repository,
14+
// asserting that pnpm i passes in that repository's directory.
1315
await $({
1416
stdio: "inherit",
1517
})`c8 -o ./coverage-create -r html -r lcov --src src node ./bin/index.js --base everything --mode create --author ${author} --email ${email} --description ${description} --owner ${owner} --title ${title} --repository ${repository} --skip-all-contributors-api --skip-github-api`;
@@ -18,6 +20,7 @@ process.chdir(repository);
1820

1921
const failures = [];
2022

23+
// Then we run each of the CI commands to assert that they pass too.
2124
for (const command of [
2225
`pnpm i`,
2326
`pnpm run build`,

Diff for: script/initialize-test-e2e.js

+9-5
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,11 @@ const owner = "RNR1";
88
const title = "New Title Test";
99
const repository = "new-repository-test";
1010

11-
// First we run initialize to modifies the local repo, so we can test the changes
11+
// Fist we run with --mode initialize to modify the local repository files,
12+
// asserting that the created package.json keeps the general description.
1213
await $({
1314
stdio: "inherit",
14-
})`node ./bin/index.js --description ${description} --base everything --mode initialize --owner ${owner} --title ${title} --repository ${repository} --skip-all-contributors-api --skip-github-api --skip-restore`;
15+
})`pnpm run initialize --base everything --mode initialize --description ${description} --owner ${owner} --title ${title} --repository ${repository} --skip-all-contributors-api --skip-github-api --skip-restore`;
1516

1617
const newPackageJson = JSON.parse(
1718
(await fs.readFile("./package.json")).toString(),
@@ -21,6 +22,8 @@ console.log("New package JSON:", newPackageJson);
2122
assert.equal(newPackageJson.description, description);
2223
assert.equal(newPackageJson.name, repository);
2324

25+
// Assert that the initialize script used the provided values in files,
26+
// except for the 'This package was templated with ...' attribution notice.
2427
const files = await globby(["*.*", "**/*.*"], {
2528
gitignore: true,
2629
ignoreFiles: ["script/initialize-test-e2e.js"],
@@ -34,11 +37,12 @@ for (const search of [`/JoshuaKGoldberg/`, "create-typescript-app"]) {
3437
);
3538
}
3639

40+
// Use Knip to assert that none of the template-only dependencies remain.
41+
// They should have been removed as part of initialization.
3742
try {
3843
await $`pnpm run lint:knip`;
3944
} catch (error) {
40-
console.error("Error running lint:knip:", error);
41-
process.exitCode = 1;
45+
throw new Error("Error running lint:knip:", { cause: error });
4246
}
4347

4448
// Now that initialize has passed normal steps, we reset everything,
@@ -49,4 +53,4 @@ await $`pnpm i`;
4953
await $`pnpm run build`;
5054
await $({
5155
stdio: "inherit",
52-
})`c8 -o ./coverage -r html -r lcov --src src node ./bin/index.js --base everything --description ${description} --mode initialize --owner ${owner} --title ${title} --repository ${repository} --skip-all-contributors-api --skip-github-api --skip-removal --skip-restore`;
56+
})`c8 -o ./coverage -r html -r lcov --src src node ./bin/index.js --base everything --mode initialize --description ${description} --owner ${owner} --title ${title} --repository ${repository} --skip-all-contributors-api --skip-github-api --skip-removal --skip-restore`;

Diff for: script/migrate-test-e2e.js

+9-11
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,8 @@ describe("expected file changes", () => {
120120
`Looks like there were no changes to ${file} from migration?`,
121121
);
122122

123+
// If this fails, see .github/DEVELOPMENT.md > Setup Scripts for context.
124+
// Then see .github/DEVELOPMENT.md > Migration Snapshot Failures.
123125
expect(contentsAfterGitMarkers).toMatchSnapshot();
124126
});
125127
});
@@ -149,22 +151,18 @@ test("unexpected file changes", async () => {
149151
const gitDiffCommand = `git diff HEAD -- ${unstagedModifiedFiles.join(
150152
" ",
151153
)}`;
152-
console.log(
153-
`Stdout from running \`${gitDiffCommand}\`:\n${
154-
(await execaCommand(gitDiffCommand)).stdout
155-
}`,
156-
);
154+
const { stdout } = await execaCommand(gitDiffCommand);
155+
156+
console.log(`Stdout from running \`${gitDiffCommand}\`:\n${stdout}`);
157+
157158
throw new Error(
158159
[
159160
"",
160-
"Oh no! Running the migrate script modified some files:",
161+
"Oh no! Running the migrate script unexpectedly modified:",
161162
...unstagedModifiedFiles.map((filePath) => ` - ${filePath}`),
162163
"",
163-
"That likely indicates changes made to the repository without",
164-
"corresponding updates to templates in src/.",
165-
"",
166-
"Please search for those file(s)' name(s) under src/migrate for",
167-
"the corresponding template and update those as well.",
164+
"See .github/DEVELOPMENT.md > Setup Scripts for context.",
165+
"Then see .github/DEVELOPMENT.md > Unexpected File Modifications.",
168166
]
169167
.map((line) => chalk.red(line))
170168
.join("\n"),
+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { describe, expect, it } from "vitest";
2+
3+
import { createDotESLintignore } from "./createDotESLintignore.js";
4+
5+
describe("createDotESLintignore", () => {
6+
it("creates an ignore file with coverage when excludeTests is false", () => {
7+
const actual = createDotESLintignore({ excludeTests: false });
8+
9+
expect(actual).toMatchInlineSnapshot(`
10+
"!.*
11+
coverage
12+
lib
13+
node_modules
14+
pnpm-lock.yaml
15+
"
16+
`);
17+
});
18+
19+
it("creates an ignore file without coverage when excludeTests is true", () => {
20+
const actual = createDotESLintignore({ excludeTests: true });
21+
22+
expect(actual).toMatchInlineSnapshot(`
23+
"!.*
24+
lib
25+
node_modules
26+
pnpm-lock.yaml
27+
"
28+
`);
29+
});
30+
});

Diff for: src/steps/writing/creation/createDotESLintignore.ts

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { Options } from "../../../shared/types.js";
2+
import { formatIgnoreFile } from "./formatters/formatIgnoreFile.js";
3+
4+
export function createDotESLintignore(options: Pick<Options, "excludeTests">) {
5+
return formatIgnoreFile(
6+
[
7+
"!.*",
8+
...(options.excludeTests ? [] : ["coverage"]),
9+
"lib",
10+
"node_modules",
11+
"pnpm-lock.yaml",
12+
].filter(Boolean),
13+
);
14+
}
+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { describe, expect, it } from "vitest";
2+
3+
import { createDotGitignore } from "./createDotGitignore.js";
4+
5+
describe("createDotGitignore", () => {
6+
it("creates an ignore file with coverage when excludeTests is false", () => {
7+
const actual = createDotGitignore({ excludeTests: false });
8+
9+
expect(actual).toMatchInlineSnapshot(`
10+
"coverage/
11+
lib/
12+
node_modules/
13+
"
14+
`);
15+
});
16+
17+
it("creates an ignore file without coverage when excludeTests is true", () => {
18+
const actual = createDotGitignore({ excludeTests: true });
19+
20+
expect(actual).toMatchInlineSnapshot(`
21+
"lib/
22+
node_modules/
23+
"
24+
`);
25+
});
26+
});

Diff for: src/steps/writing/creation/createDotGitignore.ts

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { Options } from "../../../shared/types.js";
2+
import { formatIgnoreFile } from "./formatters/formatIgnoreFile.js";
3+
4+
export function createDotGitignore(options: Pick<Options, "excludeTests">) {
5+
return formatIgnoreFile([
6+
...(options.excludeTests ? [] : ["coverage/"]),
7+
"lib/",
8+
"node_modules/",
9+
]);
10+
}

0 commit comments

Comments
 (0)