Skip to content

Commit 418086e

Browse files
committed
Merge remote-tracking branch 'origin/main' into feature/ci-workflow
2 parents ec975f0 + bf78197 commit 418086e

File tree

4 files changed

+29
-88
lines changed

4 files changed

+29
-88
lines changed

bin/index.js

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -30,28 +30,22 @@ program
3030
.option('--frontend-generator', 'Use create-next-app to scaffold the frontend instead of the bundled template')
3131
.option('--with-actions', 'Generate a GitHub Actions CI workflow (ci.yml)')
3232
.option('--yes', 'Skip confirmation (assume yes) for non-interactive use')
33-
.action(async (projectNameArg, options) => {
33+
.action(async (...args) => {
34+
const projectNameArg = args[0];
35+
const command = args[args.length - 1];
36+
const options = command.opts();
37+
3438
await scaffoldMonorepo(projectNameArg, options);
3539
});
3640

3741
// Backward compatibility: calling the root command directly still scaffolds (deprecated path).
42+
// Simplified to avoid option conflicts with subcommands
3843
program
3944
.argument('[project-name]', '(Deprecated: call `create-polyglot init <name>` instead) Project name')
40-
.option('-s, --services <services>', '(Deprecated) Services list')
41-
.option('--preset <preset>', '(Deprecated) Preset turborepo|nx')
42-
.option('--no-install', '(Deprecated) Skip install')
43-
.option('--git', '(Deprecated) Init git')
44-
.option('--force', '(Deprecated) Overwrite directory')
45-
.option('--package-manager <pm>', '(Deprecated) Package manager')
46-
.option('--frontend-generator', '(Deprecated) Use create-next-app for frontend')
47-
.option('--with-actions', '(Deprecated) Generate GitHub Actions workflow')
48-
.option('--yes', '(Deprecated) Assume yes for prompts')
49-
.action(async (projectNameArg, options) => {
50-
if (!options._deprecatedNoticeShown) {
51-
console.log(chalk.yellow('⚠️ Direct invocation is deprecated. Use `create-polyglot init` going forward.'));
52-
options._deprecatedNoticeShown = true;
53-
}
54-
await scaffoldMonorepo(projectNameArg, options);
45+
.action(async (projectNameArg) => {
46+
console.log(chalk.yellow('⚠️ Direct invocation is deprecated. Use `create-polyglot init` going forward.'));
47+
console.log(chalk.yellow(' Example: create-polyglot init ' + (projectNameArg || 'my-project')));
48+
process.exit(1);
5549
});
5650

5751
// Additional commands must be registered before final parse.

bin/lib/admin.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ async function checkServiceStatus(service) {
1111
resolve({ status: 'down', error: 'Timeout' });
1212
}, 3000);
1313

14-
const req = http.get(`http://localhost:${service.port}`, (res) => {
14+
const req = http.get(`http://localhost:${service.port}/health`, (res) => {
1515
clearTimeout(timeout);
1616
resolve({
1717
status: res.statusCode < 400 ? 'up' : 'error',

bin/lib/scaffold.js

Lines changed: 17 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -23,22 +23,7 @@ export async function scaffoldMonorepo(projectNameArg, options) {
2323
validate: v => v && /^[a-zA-Z0-9._-]+$/.test(v) ? true : 'Use alphanumerics, dash, underscore, dot'
2424
});
2525
}
26-
if (!options.services) {
27-
interactiveQuestions.push({
28-
type: 'multiselect',
29-
name: 'services',
30-
message: 'Select services to include:',
31-
choices: [
32-
{ title: 'Node.js (Express)', value: 'node' },
33-
{ title: 'Python (FastAPI)', value: 'python' },
34-
{ title: 'Go (Fiber-like)', value: 'go' },
35-
{ title: 'Java (Spring Boot)', value: 'java' },
36-
{ title: 'Frontend (Next.js)', value: 'frontend' }
37-
],
38-
instructions: false,
39-
min: 1
40-
});
41-
}
26+
4227
if (!options.preset) {
4328
interactiveQuestions.push({
4429
type: 'select',
@@ -97,9 +82,6 @@ export async function scaffoldMonorepo(projectNameArg, options) {
9782
case 'projectName':
9883
answers.projectName = projectNameArg || 'app';
9984
break;
100-
case 'services':
101-
answers.services = ['node'];
102-
break;
10385
case 'preset':
10486
answers.preset = '';
10587
break;
@@ -131,11 +113,7 @@ export async function scaffoldMonorepo(projectNameArg, options) {
131113
console.error(chalk.red('Project name is required.'));
132114
process.exit(1);
133115
}
134-
options.services = options.services || (answers.services ? answers.services.join(',') : undefined);
135-
if (!options.services) {
136-
console.error(chalk.red('At least one service must be selected.'));
137-
process.exit(1);
138-
}
116+
// Note: options.services will be handled in the dynamic flow below if not provided via CLI
139117
options.preset = options.preset || answers.preset || '';
140118
options.packageManager = options.packageManager || answers.packageManager || 'npm';
141119
if (options.git === undefined) options.git = answers.git;
@@ -187,17 +165,21 @@ export async function scaffoldMonorepo(projectNameArg, options) {
187165
services.push({ type, name, port });
188166
}
189167
} else {
190-
// New dynamic interactive flow: ask how many services, then collect each.
191-
const countAns = await prompts({
192-
type: 'number',
193-
name: 'svcCount',
194-
message: 'How many services do you want to create?',
195-
initial: 1,
196-
min: 1,
197-
validate: v => Number.isInteger(v) && v > 0 && v <= 50 ? true : 'Enter a positive integer (max 50)'
198-
});
199-
const svcCount = countAns.svcCount || 1;
200-
for (let i = 0; i < svcCount; i++) {
168+
// Dynamic interactive flow: ask how many services, then collect each.
169+
// In non-interactive mode, default to a single node service
170+
if (nonInteractive) {
171+
services.push({ type: 'node', name: 'node', port: defaultPorts.node });
172+
} else {
173+
const countAns = await prompts({
174+
type: 'number',
175+
name: 'svcCount',
176+
message: 'How many services do you want to create?',
177+
initial: 1,
178+
min: 1,
179+
validate: v => Number.isInteger(v) && v > 0 && v <= 50 ? true : 'Enter a positive integer (max 50)'
180+
});
181+
const svcCount = countAns.svcCount || 1;
182+
for (let i = 0; i < svcCount; i++) {
201183
const typeAns = await prompts({
202184
type: 'select',
203185
name: 'svcType',
@@ -238,41 +220,6 @@ export async function scaffoldMonorepo(projectNameArg, options) {
238220
}
239221
}
240222
services.push({ type: svcType, name: svcName, port: svcPort });
241-
}
242-
}
243-
244-
// Always allow customization of name & port in interactive mode (not nonInteractive)
245-
if (!nonInteractive) {
246-
for (let i = 0; i < services.length; i++) {
247-
const svc = services[i];
248-
const rename = await prompts({
249-
type: 'text',
250-
name: 'newName',
251-
message: `Name for ${svc.type} service (leave blank to keep '${svc.name}'):`,
252-
validate: v => !v || (/^[a-zA-Z0-9._-]+$/.test(v) ? true : 'Use alphanumerics, dash, underscore, dot')
253-
});
254-
if (rename.newName && rename.newName !== svc.name) {
255-
if (reservedNames.has(rename.newName)) {
256-
console.log(chalk.red(`Name '${rename.newName}' is reserved. Keeping '${svc.name}'.`));
257-
} else if (services.find(s => s !== svc && s.name === rename.newName)) {
258-
console.log(chalk.red(`Name '${rename.newName}' already used. Keeping '${svc.name}'.`));
259-
} else {
260-
svc.name = rename.newName;
261-
}
262-
}
263-
const portResp = await prompts({
264-
type: 'text',
265-
name: 'newPort',
266-
message: `Port for ${svc.name} (${svc.type}) (default ${svc.port}):`,
267-
validate: v => !v || (/^\d+$/.test(v) && +v > 0 && +v <= 65535) ? true : 'Enter a valid port 1-65535'
268-
});
269-
if (portResp.newPort) {
270-
const newPort = Number(portResp.newPort);
271-
if (services.find(s => s !== svc && s.port === newPort)) {
272-
console.log(chalk.red(`Port ${newPort} already used; keeping ${svc.port}.`));
273-
} else {
274-
svc.port = newPort;
275-
}
276223
}
277224
}
278225
}

tests/smoke.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ describe('create-polyglot CLI smoke', () => {
2020
it('scaffolds a project with a node service', async () => {
2121
const repoRoot = process.cwd();
2222
const cliPath = path.join(repoRoot, 'bin/index.js');
23-
await execa('node', [cliPath, projName, '--services', 'node', '--no-install', '--yes'], { cwd: tmpDir });
23+
await execa('node', [cliPath, 'init', projName, '--services', 'node', '--no-install', '--yes'], { cwd: tmpDir });
2424
const projectPath = path.join(tmpDir, projName);
2525
expect(fs.existsSync(path.join(projectPath, 'services/node'))).toBe(true);
2626
expect(fs.existsSync(path.join(projectPath, 'package.json'))).toBe(true);

0 commit comments

Comments
 (0)