Skip to content

Commit c91375e

Browse files
authored
feat(plugin-coverage): add setup wizard binding (#1273)
1 parent daa6ccb commit c91375e

File tree

15 files changed

+786
-25
lines changed

15 files changed

+786
-25
lines changed

package-lock.json

Lines changed: 13 additions & 17 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
"glob": "^11.0.1",
3333
"lighthouse": "^12.0.0",
3434
"lighthouse-logger": "2.0.1",
35+
"magicast": "^0.3.5",
3536
"nx": "22.3.3",
3637
"ora": "^9.0.0",
3738
"parse-lcov": "^1.0.4",

packages/create-cli/README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,18 @@ Each plugin exposes its own configuration keys that can be passed as CLI argumen
3737
| **`--eslint.patterns`** | `string` | `src` or `.` | File patterns to lint |
3838
| **`--eslint.categories`** | `boolean` | `true` | Add recommended categories |
3939

40+
#### Coverage
41+
42+
| Option | Type | Default | Description |
43+
| ------------------------------- | ------------------------------------------ | -------------------- | ------------------------------ |
44+
| **`--coverage.framework`** | `'jest'` \| `'vitest'` \| `'other'` | auto-detected | Test framework |
45+
| **`--coverage.configFile`** | `string` | auto-detected | Path to test config file |
46+
| **`--coverage.reportPath`** | `string` | `coverage/lcov.info` | Path to LCOV report file |
47+
| **`--coverage.testCommand`** | `string` | auto-detected | Command to run tests |
48+
| **`--coverage.types`** | `('function'` \| `'branch'` \| `'line')[]` | all | Coverage types to measure |
49+
| **`--coverage.continueOnFail`** | `boolean` | `true` | Continue if test command fails |
50+
| **`--coverage.categories`** | `boolean` | `true` | Add code coverage category |
51+
4052
### Examples
4153

4254
Run interactively (default):

packages/create-cli/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
},
2727
"type": "module",
2828
"dependencies": {
29+
"@code-pushup/coverage-plugin": "0.120.1",
2930
"@code-pushup/eslint-plugin": "0.120.1",
3031
"@code-pushup/models": "0.120.1",
3132
"@code-pushup/utils": "0.120.1",

packages/create-cli/src/index.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#! /usr/bin/env node
22
import yargs from 'yargs';
33
import { hideBin } from 'yargs/helpers';
4+
import { coverageSetupBinding } from '@code-pushup/coverage-plugin';
45
import { eslintSetupBinding } from '@code-pushup/eslint-plugin';
56
import { parsePluginSlugs, validatePluginSlugs } from './lib/setup/plugins.js';
67
import {
@@ -11,8 +12,11 @@ import {
1112
} from './lib/setup/types.js';
1213
import { runSetupWizard } from './lib/setup/wizard.js';
1314

14-
// TODO: create, import and pass remaining plugin bindings (coverage, lighthouse, typescript, js-packages, jsdocs, axe)
15-
const bindings: PluginSetupBinding[] = [eslintSetupBinding];
15+
// TODO: create, import and pass remaining plugin bindings (lighthouse, typescript, js-packages, jsdocs, axe)
16+
const bindings: PluginSetupBinding[] = [
17+
eslintSetupBinding,
18+
coverageSetupBinding,
19+
];
1620

1721
const argv = await yargs(hideBin(process.argv))
1822
.option('dry-run', {

packages/create-cli/src/lib/setup/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export type {
77
PluginCodegenResult,
88
PluginPromptDescriptor,
99
PluginSetupBinding,
10+
PluginSetupTree,
1011
} from '@code-pushup/models';
1112

1213
export const CI_PROVIDERS = ['github', 'gitlab', 'none'] as const;

packages/create-cli/src/lib/setup/wizard.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import type {
3232
PluginCodegenResult,
3333
PluginSetupBinding,
3434
ScopedPluginResult,
35+
Tree,
3536
WriteContext,
3637
} from './types.js';
3738
import { createTree } from './virtual-fs.js';
@@ -57,19 +58,19 @@ export async function runSetupWizard(
5758
const format = await promptConfigFormat(targetDir, cliArgs);
5859
const ciProvider = await promptCiProvider(cliArgs);
5960

61+
const tree = createTree(await getGitRoot());
62+
6063
const resolved: ScopedPluginResult[] = await asyncSequential(
6164
selectedBindings,
6265
async binding => ({
6366
scope: binding.scope ?? 'project',
64-
result: await resolveBinding(binding, cliArgs, targetDir),
67+
result: await resolveBinding(binding, cliArgs, targetDir, tree),
6568
}),
6669
);
6770

6871
const packageJson = await readPackageJson(targetDir);
6972
const isEsm = packageJson.type === 'module';
7073
const configFilename = resolveFilename('code-pushup.config', format, isEsm);
71-
72-
const tree = createTree(await getGitRoot());
7374
const writeContext: WriteContext = { tree, format, configFilename, isEsm };
7475

7576
await (context.mode === 'monorepo' && context.tool != null
@@ -103,13 +104,14 @@ async function resolveBinding(
103104
binding: PluginSetupBinding,
104105
cliArgs: CliArgs,
105106
targetDir: string,
107+
tree: Pick<Tree, 'read' | 'write'>,
106108
): Promise<PluginCodegenResult> {
107109
const descriptors = binding.prompts ? await binding.prompts(targetDir) : [];
108110
const answers =
109111
descriptors.length > 0
110112
? await promptPluginOptions(descriptors, cliArgs)
111113
: {};
112-
return binding.generateConfig(answers);
114+
return binding.generateConfig(answers, tree);
113115
}
114116

115117
async function writeStandaloneConfig(

packages/models/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ export type {
118118
PluginCodegenResult,
119119
PluginPromptDescriptor,
120120
PluginSetupBinding,
121+
PluginSetupTree,
121122
} from './lib/plugin-setup.js';
122123
export {
123124
auditReportSchema,

packages/models/src/lib/plugin-setup.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,19 @@ export type ImportDeclarationStructure = {
4747
/** A single value in the answers record produced by plugin prompts. */
4848
export type PluginAnswer = string | string[] | boolean;
4949

50-
/** Import declarations and plugin initialization code produced by `generateConfig`. */
50+
/** Code a plugin binding contributes to the generated config. */
5151
export type PluginCodegenResult = {
5252
imports: ImportDeclarationStructure[];
5353
pluginInit: string;
5454
categories?: CategoryConfig[];
5555
};
5656

57+
/** Minimal file system abstraction passed to plugin bindings. */
58+
export type PluginSetupTree = {
59+
read: (path: string) => Promise<string | null>;
60+
write: (path: string, content: string) => Promise<void>;
61+
};
62+
5763
/**
5864
* Defines how a plugin integrates with the setup wizard.
5965
*
@@ -71,5 +77,6 @@ export type PluginSetupBinding = {
7177
isRecommended?: (targetDir: string) => Promise<boolean>;
7278
generateConfig: (
7379
answers: Record<string, PluginAnswer>,
74-
) => PluginCodegenResult;
80+
tree: PluginSetupTree,
81+
) => PluginCodegenResult | Promise<PluginCodegenResult>;
7582
};

packages/plugin-coverage/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
"dependencies": {
3737
"@code-pushup/models": "0.120.1",
3838
"@code-pushup/utils": "0.120.1",
39+
"magicast": "^0.3.5",
3940
"parse-lcov": "^1.0.4",
4041
"zod": "^4.2.1"
4142
},

0 commit comments

Comments
 (0)