Skip to content

Commit d3727b4

Browse files
committed
refactor(create-gen-app): move CLI to create-gen-app-test package
Remove CLI entry point from create-gen-app package to make it a pure library API. The CLI implementation and tests are now housed in the create-gen-app-test package for integration testing purposes. Changes: - Remove src/cli.ts and __tests__/cli.test.ts from create-gen-app - Remove bin field and minimist dependencies from create-gen-app/package.json - Update README.md to clarify that the published package is API-only - Port CLI code to create-gen-app-test/src/cli.ts - Add CLI tests to create-gen-app-test/src/__tests__/cli.test.ts - Add minimist and inquirerer dependencies to create-gen-app-test - Update CLI imports to use create-gen-app library APIs This separation ensures create-gen-app remains focused on its core template generation functionality while maintaining CLI testing capabilities in the dedicated test harness package.
1 parent ffce313 commit d3727b4

File tree

5 files changed

+51
-62
lines changed

5 files changed

+51
-62
lines changed

packages/create-gen-app-test/package.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,13 @@
3030
},
3131
"dependencies": {
3232
"appstash": "workspace:*",
33-
"create-gen-app": "workspace:*"
33+
"create-gen-app": "workspace:*",
34+
"inquirerer": "workspace:*",
35+
"minimist": "^1.2.8"
3436
},
3537
"devDependencies": {
38+
"@types/minimist": "^1.2.5",
3639
"makage": "0.1.5"
3740
},
3841
"keywords": []
39-
}
42+
}

packages/create-gen-app/__tests__/cli.test.ts renamed to packages/create-gen-app-test/src/__tests__/cli.test.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
import * as fs from "fs";
22
import * as path from "path";
33

4-
import { runCli } from "../src/cli";
4+
import { runCli } from "../cli";
55
import {
66
TEST_BRANCH,
77
TEST_REPO,
88
TEST_TEMPLATE,
99
buildAnswers,
1010
cleanupWorkspace,
1111
createTempWorkspace,
12-
} from "../test-utils/integration-helpers";
12+
} from "../../../create-gen-app/test-utils/integration-helpers";
1313

1414
jest.setTimeout(180_000);
1515

16-
describe("CLI integration (GitHub templates)", () => {
16+
describe("CLI integration via create-gen-app-test harness", () => {
1717
it("generates a project using the real repo", async () => {
1818
const workspace = createTempWorkspace("cli");
1919
const answers = buildAnswers("cli");
@@ -65,12 +65,15 @@ describe("CLI integration (GitHub templates)", () => {
6565
});
6666

6767
it("prints version and exits when --version is provided", async () => {
68-
const logSpy = jest.spyOn(console, "log").mockImplementation(() => undefined);
68+
const logSpy = jest
69+
.spyOn(console, "log")
70+
.mockImplementation(() => undefined);
6971

7072
await runCli(["--version"]);
7173

72-
expect(logSpy).toHaveBeenCalledWith(expect.stringMatching(/create-gen-app v/));
74+
expect(logSpy).toHaveBeenCalledWith(
75+
expect.stringMatching(/create-gen-app v/)
76+
);
7377
logSpy.mockRestore();
7478
});
7579
});
76-
Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,15 @@ import * as path from "path";
66
import { Inquirerer, ListQuestion } from "inquirerer";
77
import minimist, { ParsedArgs } from "minimist";
88

9-
import { cloneRepo } from "./clone";
10-
import { createGen } from "./index";
11-
import packageJson from "../package.json";
9+
import { cloneRepo, createGen } from "create-gen-app";
10+
import createGenPackageJson from "create-gen-app/package.json";
1211

1312
const DEFAULT_REPO = "https://github.com/launchql/pgpm-boilerplates.git";
1413
const DEFAULT_PATH = ".";
1514
const DEFAULT_OUTPUT_FALLBACK = "create-gen-app-output";
1615

17-
const PACKAGE_VERSION = packageJson.version ?? "0.0.0";
16+
const PACKAGE_VERSION =
17+
(createGenPackageJson as { version?: string }).version ?? "0.0.0";
1818

1919
const RESERVED_ARG_KEYS = new Set([
2020
"_",
@@ -43,7 +43,9 @@ export interface CliResult {
4343
template: string;
4444
}
4545

46-
export async function runCli(rawArgv: string[] = process.argv.slice(2)): Promise<CliResult | void> {
46+
export async function runCli(
47+
rawArgv: string[] = process.argv.slice(2)
48+
): Promise<CliResult | void> {
4749
const args = minimist(rawArgv, {
4850
alias: {
4951
r: "repo",
@@ -87,8 +89,13 @@ export async function runCli(rawArgv: string[] = process.argv.slice(2)): Promise
8789
tempDir = await cloneRepo(args.repo, { branch: args.branch });
8890

8991
const selectionRoot = path.join(tempDir, args.path);
90-
if (!fs.existsSync(selectionRoot) || !fs.statSync(selectionRoot).isDirectory()) {
91-
throw new Error(`Template path "${args.path}" does not exist in ${args.repo}`);
92+
if (
93+
!fs.existsSync(selectionRoot) ||
94+
!fs.statSync(selectionRoot).isDirectory()
95+
) {
96+
throw new Error(
97+
`Template path "${args.path}" does not exist in ${args.repo}`
98+
);
9299
}
93100

94101
const templates = fs
@@ -134,7 +141,9 @@ export async function runCli(rawArgv: string[] = process.argv.slice(2)): Promise
134141
ensureOutputDir(outputDir, Boolean(args.force));
135142

136143
const answerOverrides = extractAnswerOverrides(args);
137-
const noTty = Boolean(args["no-tty"] ?? (args as Record<string, unknown>).noTty);
144+
const noTty = Boolean(
145+
args["no-tty"] ?? (args as Record<string, unknown>).noTty
146+
);
138147

139148
await createGen({
140149
templateUrl: args.repo,
@@ -156,11 +165,10 @@ export async function runCli(rawArgv: string[] = process.argv.slice(2)): Promise
156165

157166
function printHelp(): void {
158167
console.log(`
159-
create-gen-app CLI
168+
create-gen-app CLI (test harness)
160169
161170
Usage:
162-
create-gen-app [options] [outputDir]
163-
cga [options] [outputDir]
171+
node cli [options] [outputDir]
164172
165173
Options:
166174
-r, --repo <url> Git repository to clone (default: ${DEFAULT_REPO})
@@ -174,7 +182,7 @@ Options:
174182
-h, --help Show this help message
175183
176184
You can also pass variable overrides, e.g.:
177-
create-gen-app --template module --PROJECT_NAME my-app
185+
node cli --template module --PROJECT_NAME my-app
178186
`);
179187
}
180188

@@ -193,7 +201,9 @@ async function promptForTemplate(templates: string[]): Promise<string> {
193201
};
194202

195203
try {
196-
const answers = (await prompter.prompt({}, [question])) as { template: string };
204+
const answers = (await prompter.prompt({}, [question])) as {
205+
template: string;
206+
};
197207
return answers.template;
198208
} finally {
199209
if (typeof (prompter as any).close === "function") {
@@ -202,8 +212,13 @@ async function promptForTemplate(templates: string[]): Promise<string> {
202212
}
203213
}
204214

205-
function resolveOutputDir(outputArg: string | undefined, template?: string): string {
206-
const base = outputArg ?? (template ? path.join(process.cwd(), template) : DEFAULT_OUTPUT_FALLBACK);
215+
function resolveOutputDir(
216+
outputArg: string | undefined,
217+
template?: string
218+
): string {
219+
const base =
220+
outputArg ??
221+
(template ? path.join(process.cwd(), template) : DEFAULT_OUTPUT_FALLBACK);
207222
return path.resolve(base);
208223
}
209224

@@ -238,4 +253,3 @@ if (require.main === module) {
238253
process.exitCode = 1;
239254
});
240255
}
241-

packages/create-gen-app/README.md

Lines changed: 5 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -16,48 +16,23 @@
1616
<a href="https://www.npmjs.com/package/create-gen-app"><img height="20" src="https://img.shields.io/github/package-json/v/hyperweb-io/dev-utils?filename=packages%2Fcreate-gen-app%2Fpackage.json"></a>
1717
</p>
1818

19-
A TypeScript-first CLI/library for cloning template repositories, asking the user for variables, and generating a new project with sensible defaults.
19+
A TypeScript-first library for cloning template repositories, asking the user for variables, and generating a new project with sensible defaults.
2020

2121
## Features
2222

2323
- Clone any Git repo (or GitHub `org/repo` shorthand) and optionally select a branch + subdirectory
2424
- Extract template variables from filenames and file contents using the safer `____variable____` convention
2525
- Merge auto-discovered variables with `.questions.{json,js}` (questions win, including `ignore` patterns)
26-
- Interactive prompts powered by `inquirerer`, with CLI flag overrides (`--VAR value`) and non-TTY mode for CI
27-
- Built-in CLI (`create-gen-app` / `cga`) that discovers templates, prompts once, and writes output safely
26+
- Interactive prompts powered by `inquirerer`, with flexible override mapping (`argv` support) and non-TTY mode for CI
2827
- License scaffolding: choose from MIT, Apache-2.0, ISC, GPL-3.0, BSD-3-Clause, Unlicense, or MPL-2.0 and generate a populated `LICENSE`
2928

3029
## Installation
3130

3231
```bash
3332
npm install create-gen-app
34-
# or for CLI only
35-
npm install -g create-gen-app
3633
```
3734

38-
## CLI Usage
39-
40-
```bash
41-
# interactively pick a template from launchql/pgpm-boilerplates
42-
create-gen-app --output ./workspace
43-
44-
# short alias
45-
cga --template module --branch main --output ./module \
46-
--USERFULLNAME "Jane Dev" --USEREMAIL [email protected]
47-
48-
# point to a different repo/branch/path
49-
cga --repo github:my-org/my-templates --branch release \
50-
--path ./templates --template api --output ./api
51-
```
52-
53-
Key flags:
54-
55-
- `--repo`, `--branch`, `--path` – choose the Git repo, branch/tag, and subdirectory that contains templates
56-
- `--template` – folder inside `--path` (auto-prompted if omitted)
57-
- `--output` – destination directory (defaults to `./<template>`); use `--force` to overwrite
58-
- `--no-tty` – disable interactive prompts (ideal for CI)
59-
- `--version`, `--help` – standard metadata
60-
- Any extra `--VAR value` pairs become variable overrides
35+
> **Note:** The published package is API-only. An internal CLI harness used for integration testing now lives in `packages/create-gen-app-test/`.
6136
6237
## Library Usage
6338

@@ -126,14 +101,14 @@ Or `.questions.js` for dynamic logic. Question names can use `____var____` or pl
126101

127102
- `{{YEAR}}`, `{{AUTHOR}}`, `{{EMAIL_LINE}}`
128103

129-
No code changes are needed; the CLI discovers templates at runtime and will warn if a `.questions` option doesn’t have a matching template.
104+
No code changes are needed; the generator discovers templates at runtime and will warn if a `.questions` option doesn’t have a matching template.
130105

131106
## API Overview
132107

133108
- `createGen(options)` – full pipeline (clone → extract → prompt → replace)
134109
- `cloneRepo(url, { branch })` – clone to a temp dir
135110
- `extractVariables(dir)` – parse file/folder names + content for variables, load `.questions`
136-
- `promptUser(extracted, argv, noTty)` – run interactive questions with CLI overrides and alias deduping
111+
- `promptUser(extracted, argv, noTty)` – run interactive questions with override alias deduping
137112
- `replaceVariables(templateDir, outputDir, extracted, answers)` – copy files, rename paths, render licenses
138113

139114
See `dev/README.md` for the local development helper script (`pnpm dev`).

packages/create-gen-app/package.json

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,6 @@
33
"version": "0.1.7",
44
"author": "Dan Lynch <[email protected]>",
55
"description": "Clone and customize template repositories with variable replacement",
6-
"bin": {
7-
"create-gen-app": "./cli.js",
8-
"cga": "./cli.js"
9-
},
106
"main": "index.js",
117
"module": "esm/index.js",
128
"types": "index.d.ts",
@@ -33,13 +29,11 @@
3329
"test:watch": "jest --watch"
3430
},
3531
"dependencies": {
36-
"inquirerer": "workspace:*",
37-
"minimist": "^1.2.8"
32+
"inquirerer": "workspace:*"
3833
},
3934
"devDependencies": {
40-
"@types/minimist": "^1.2.5",
4135
"copyfiles": "^2.4.1",
4236
"makage": "0.1.5"
4337
},
4438
"keywords": []
45-
}
39+
}

0 commit comments

Comments
 (0)