Skip to content
Open
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
48 changes: 3 additions & 45 deletions packages/create-cli/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#! /usr/bin/env node
import yargs from 'yargs';
import { hideBin } from 'yargs/helpers';
import { axeSetupBinding } from '@code-pushup/axe-plugin';
import { coverageSetupBinding } from '@code-pushup/coverage-plugin';
Expand All @@ -8,13 +7,8 @@ import { jsPackagesSetupBinding } from '@code-pushup/js-packages-plugin';
import { jsDocsSetupBinding } from '@code-pushup/jsdocs-plugin';
import { lighthouseSetupBinding } from '@code-pushup/lighthouse-plugin';
import { typescriptSetupBinding } from '@code-pushup/typescript-plugin';
import { parsePluginSlugs, validatePluginSlugs } from './lib/setup/plugins.js';
import {
CI_PROVIDERS,
CONFIG_FILE_FORMATS,
type PluginSetupBinding,
SETUP_MODES,
} from './lib/setup/types.js';
import { yargsCli } from './lib/setup/cli-args.js';
import type { PluginSetupBinding } from './lib/setup/types.js';
import { runSetupWizard } from './lib/setup/wizard.js';

const bindings: PluginSetupBinding[] = [
Expand All @@ -27,42 +21,6 @@ const bindings: PluginSetupBinding[] = [
jsDocsSetupBinding,
];

const argv = await yargs(hideBin(process.argv))
.option('dry-run', {
type: 'boolean',
default: false,
describe: 'Preview changes without writing files',
})
.option('yes', {
alias: 'y',
type: 'boolean',
default: false,
describe: 'Skip prompts and use defaults',
})
.option('config-format', {
type: 'string',
choices: CONFIG_FILE_FORMATS,
describe: 'Config file format (default: auto-detected from project)',
})
.option('plugins', {
type: 'string',
describe: 'Comma-separated plugin slugs to include (e.g. eslint,coverage)',
coerce: parsePluginSlugs,
})
.option('mode', {
type: 'string',
choices: SETUP_MODES,
describe: 'Setup mode (default: auto-detected from project)',
})
.option('ci', {
type: 'string',
choices: CI_PROVIDERS,
describe: 'CI/CD integration (github, gitlab, or none)',
})
.check(parsed => {
validatePluginSlugs(bindings, parsed.plugins);
return true;
})
.parse();
const argv = await yargsCli(bindings).parse(hideBin(process.argv));

await runSetupWizard(bindings, argv);
2 changes: 1 addition & 1 deletion packages/create-cli/src/lib/setup/ci.unit.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { select } from '@inquirer/prompts';
import { vol } from 'memfs';
import { MEMFS_VOLUME } from '@code-pushup/test-utils';
import { createTree } from '@code-pushup/utils';
import { promptCiProvider, resolveCi } from './ci.js';
import type { ConfigContext } from './types.js';
import { createTree } from './virtual-fs.js';

vi.mock('@inquirer/prompts', () => ({
select: vi.fn(),
Expand Down
53 changes: 53 additions & 0 deletions packages/create-cli/src/lib/setup/cli-args.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import yargs, { type Argv } from 'yargs';
import { parsePluginSlugs, validatePluginSlugs } from './plugins.js';
import {
CI_PROVIDERS,
CONFIG_FILE_FORMATS,
type PluginSetupBinding,
SETUP_MODES,
} from './types.js';

export function yargsCli(bindings: PluginSetupBinding[]): Argv {
return yargs()
.scriptName('create-cli')
.usage('$0 [options]')
.parserConfiguration({ 'dot-notation': false })
.option('dry-run', {
type: 'boolean',
default: false,
describe: 'Preview changes without writing files',
})
.option('yes', {
alias: 'y',
type: 'boolean',
default: false,
describe: 'Skip prompts and use defaults',
})
.option('config-format', {
type: 'string',
choices: CONFIG_FILE_FORMATS,
describe: 'Config file format (default: auto-detected from project)',
})
.option('plugins', {
type: 'string',
describe:
'Comma-separated plugin slugs to include (e.g. eslint,coverage)',
coerce: parsePluginSlugs,
})
.option('mode', {
type: 'string',
choices: SETUP_MODES,
describe: 'Setup mode (default: auto-detected from project)',
})
.option('ci', {
type: 'string',
choices: CI_PROVIDERS,
describe: 'CI/CD integration (github, gitlab, or none)',
})
.check(parsed => {
validatePluginSlugs(bindings, parsed.plugins);
return true;
})
.help()
.version();
}
34 changes: 34 additions & 0 deletions packages/create-cli/src/lib/setup/cli-args.unit.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { yargsCli } from './cli-args.js';
import type { PluginSetupBinding } from './types.js';

const bareBindings: PluginSetupBinding[] = [
{
slug: 'eslint',
title: 'ESLint',
packageName: '@code-pushup/eslint-plugin',
generateConfig: () => ({ imports: [], pluginInit: [] }),
},
];

describe('yargsCli', () => {
it('should expose --eslint.patterns as a flat key', async () => {
const argv = await yargsCli(bareBindings).parse([
'--eslint.patterns',
'src',
]);

expect(argv['eslint.patterns']).toBe('src');
});

it('should expose --no-eslint.categories as a flat false', async () => {
const argv = await yargsCli(bareBindings).parse(['--no-eslint.categories']);

expect(argv['eslint.categories']).toBeFalse();
});

it('should expose --eslint.categories without a value as a flat true', async () => {
const argv = await yargsCli(bareBindings).parse(['--eslint.categories']);

expect(argv['eslint.categories']).toBeTrue();
});
});
2 changes: 1 addition & 1 deletion packages/create-cli/src/lib/setup/gitignore.unit.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { vol } from 'memfs';
import { readFile } from 'node:fs/promises';
import { MEMFS_VOLUME } from '@code-pushup/test-utils';
import { createTree } from '@code-pushup/utils';
import { resolveGitignore } from './gitignore.js';
import { createTree } from './virtual-fs.js';

describe('resolveGitignore', () => {
it('should create .gitignore with comment when it does not exist', async () => {
Expand Down
3 changes: 1 addition & 2 deletions packages/create-cli/src/lib/setup/monorepo.unit.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { select } from '@inquirer/prompts';
import { vol } from 'memfs';
import { MEMFS_VOLUME } from '@code-pushup/test-utils';
import { logger } from '@code-pushup/utils';
import { createTree, logger } from '@code-pushup/utils';
import { addCodePushUpCommand, promptSetupMode } from './monorepo.js';
import type { WizardProject } from './types.js';
import { createTree } from './virtual-fs.js';

vi.mock('@inquirer/prompts', () => ({
select: vi.fn(),
Expand Down
33 changes: 4 additions & 29 deletions packages/create-cli/src/lib/setup/types.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
import type { PluginCodegenResult } from '@code-pushup/models';
import type { MonorepoTool } from '@code-pushup/utils';
import type { MonorepoTool, Tree } from '@code-pushup/utils';

export type {
CategoryCodegenConfig,
ImportDeclarationStructure,
PluginAnswer,
PluginCodegenInput,
PluginCodegenResult,
PluginPromptDescriptor,
PluginSetupBinding,
PluginSetupTree,
} from '@code-pushup/models';

export type { FileChange, FileSystemAdapter, Tree } from '@code-pushup/utils';

export const CI_PROVIDERS = ['github', 'gitlab', 'none'] as const;
export type CiProvider = (typeof CI_PROVIDERS)[number];

Expand Down Expand Up @@ -58,31 +61,3 @@ export type WriteContext = {
configFilename: string;
isEsm: boolean;
};

/** A single file operation recorded by the virtual tree. */
export type FileChange = {
path: string;
type: 'CREATE' | 'UPDATE';
content: string;
};

/** Virtual file system that buffers writes in memory until flushed to disk. */
export type Tree = {
root: string;
exists: (filePath: string) => Promise<boolean>;
read: (filePath: string) => Promise<string | null>;
write: (filePath: string, content: string) => Promise<void>;
listChanges: () => FileChange[];
flush: () => Promise<void>;
};

/** Abstraction over `node:fs` used by the virtual tree for disk I/O. */
export type FileSystemAdapter = {
readFile: (path: string, encoding: 'utf8') => Promise<string>;
writeFile: (path: string, content: string) => Promise<void>;
exists: (path: string) => Promise<boolean>;
mkdir: (
path: string,
options: { recursive: true },
) => Promise<string | undefined>;
};
67 changes: 0 additions & 67 deletions packages/create-cli/src/lib/setup/virtual-fs.ts

This file was deleted.

Loading
Loading