Skip to content

Commit 2275102

Browse files
authored
feat(cli): allow to include/exclude plugins when generate (#1676)
1 parent 0b466bf commit 2275102

File tree

4 files changed

+69
-27
lines changed

4 files changed

+69
-27
lines changed

packages/schema/src/cli/actions/generate.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { PluginError } from '@zenstackhq/sdk';
2+
import { isPlugin } from '@zenstackhq/sdk/ast';
23
import colors from 'colors';
34
import path from 'path';
45
import { CliError } from '../cli-error';
@@ -18,6 +19,8 @@ type Options = {
1819
dependencyCheck: boolean;
1920
versionCheck: boolean;
2021
compile: boolean;
22+
withPlugins?: string[];
23+
withoutPlugins?: string[];
2124
defaultPlugins: boolean;
2225
};
2326

@@ -57,9 +60,19 @@ async function runPlugins(options: Options) {
5760

5861
const model = await loadDocument(schema);
5962

63+
for (const name of [...(options.withPlugins ?? []), ...(options.withoutPlugins ?? [])]) {
64+
const pluginDecl = model.declarations.find((d) => isPlugin(d) && d.name === name);
65+
if (!pluginDecl) {
66+
console.error(colors.red(`Plugin "${name}" not found in schema.`));
67+
throw new CliError(`Plugin "${name}" not found in schema.`);
68+
}
69+
}
70+
6071
const runnerOpts: PluginRunnerOptions = {
6172
schema: model,
6273
schemaPath: path.resolve(schema),
74+
withPlugins: options.withPlugins,
75+
withoutPlugins: options.withoutPlugins,
6376
defaultPlugins: options.defaultPlugins,
6477
output: options.output,
6578
compile: options.compile,

packages/schema/src/cli/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,8 @@ export function createProgram() {
120120
.description('Run code generation.')
121121
.addOption(schemaOption)
122122
.addOption(new Option('-o, --output <path>', 'default output directory for core plugins'))
123+
.addOption(new Option('--with-plugins <plugins...>', 'only run specific plugins'))
124+
.addOption(new Option('--without-plugins <plugins...>', 'exclude specific plugins'))
123125
.addOption(new Option('--no-default-plugins', 'do not run default plugins'))
124126
.addOption(new Option('--no-compile', 'do not compile the output of core plugins'))
125127
.addOption(noVersionCheckOption)

packages/schema/src/cli/plugin-runner.ts

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ export type PluginRunnerOptions = {
4040
schema: Model;
4141
schemaPath: string;
4242
output?: string;
43+
withPlugins?: string[];
44+
withoutPlugins?: string[];
4345
defaultPlugins: boolean;
4446
compile: boolean;
4547
};
@@ -137,7 +139,17 @@ export class PluginRunner {
137139
const project = createProject();
138140
for (const { name, description, run, options: pluginOptions } of corePlugins) {
139141
const options = { ...pluginOptions, prismaClientPath };
140-
const r = await this.runPlugin(name, description, run, runnerOptions, options, dmmf, shortNameMap, project);
142+
const r = await this.runPlugin(
143+
name,
144+
description,
145+
run,
146+
runnerOptions,
147+
options,
148+
dmmf,
149+
shortNameMap,
150+
project,
151+
true
152+
);
141153
warnings.push(...(r?.warnings ?? [])); // the null-check is for backward compatibility
142154

143155
if (r.dmmf) {
@@ -162,7 +174,17 @@ export class PluginRunner {
162174
// run user plugins
163175
for (const { name, description, run, options: pluginOptions } of userPlugins) {
164176
const options = { ...pluginOptions, prismaClientPath };
165-
const r = await this.runPlugin(name, description, run, runnerOptions, options, dmmf, shortNameMap, project);
177+
const r = await this.runPlugin(
178+
name,
179+
description,
180+
run,
181+
runnerOptions,
182+
options,
183+
dmmf,
184+
shortNameMap,
185+
project,
186+
false
187+
);
166188
warnings.push(...(r?.warnings ?? [])); // the null-check is for backward compatibility
167189
}
168190

@@ -180,8 +202,7 @@ export class PluginRunner {
180202
if (existingPrisma) {
181203
corePlugins.push(existingPrisma);
182204
plugins.splice(plugins.indexOf(existingPrisma), 1);
183-
} else if (options.defaultPlugins || plugins.some((p) => p.provider !== CorePlugins.Prisma)) {
184-
// "@core/prisma" is enabled as default or if any other plugin is configured
205+
} else if (options.defaultPlugins) {
185206
corePlugins.push(this.makeCorePlugin(CorePlugins.Prisma, options.schemaPath, {}));
186207
}
187208

@@ -215,7 +236,8 @@ export class PluginRunner {
215236

216237
if (
217238
!corePlugins.some((p) => p.provider === CorePlugins.Zod) &&
218-
(options.defaultPlugins || corePlugins.some((p) => p.provider === CorePlugins.Enhancer)) &&
239+
options.defaultPlugins &&
240+
corePlugins.some((p) => p.provider === CorePlugins.Enhancer) &&
219241
hasValidation
220242
) {
221243
// ensure "@core/zod" is enabled if "@core/enhancer" is enabled and there're validation rules
@@ -319,10 +341,17 @@ export class PluginRunner {
319341
options: PluginDeclaredOptions,
320342
dmmf: DMMF.Document | undefined,
321343
shortNameMap: Map<string, string> | undefined,
322-
project: Project
344+
project: Project,
345+
isCorePlugin: boolean
323346
) {
347+
if (!isCorePlugin && !this.isPluginEnabled(name, runnerOptions)) {
348+
ora(`Plugin "${name}" is skipped`).start().warn();
349+
return { warnings: [] };
350+
}
351+
324352
const title = description ?? `Running plugin ${colors.cyan(name)}`;
325353
const spinner = ora(title).start();
354+
326355
try {
327356
const r = await telemetry.trackSpan<PluginResult | void>(
328357
'cli:plugin:start',
@@ -358,6 +387,18 @@ export class PluginRunner {
358387
}
359388
}
360389

390+
private isPluginEnabled(name: string, runnerOptions: PluginRunnerOptions) {
391+
if (runnerOptions.withPlugins && !runnerOptions.withPlugins.includes(name)) {
392+
return false;
393+
}
394+
395+
if (runnerOptions.withoutPlugins && runnerOptions.withoutPlugins.includes(name)) {
396+
return false;
397+
}
398+
399+
return true;
400+
}
401+
361402
private getPluginModulePath(provider: string, schemaPath: string) {
362403
if (process.env.ZENSTACK_TEST === '1' && provider.startsWith('@zenstackhq/')) {
363404
// test code runs with its own sandbox of node_modules, make sure we don't

tests/integration/tests/cli/generate.test.ts

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -112,42 +112,28 @@ model Post {
112112
expect(fs.existsSync('./prisma/schema.prisma')).toBeTruthy();
113113
});
114114

115-
it('generate no default plugins with access-policy with zod', async () => {
115+
it('generate no default plugins with enhancer and zod', async () => {
116116
fs.appendFileSync(
117117
'schema.zmodel',
118118
`
119-
plugin enhancer {
120-
provider = '@core/enhancer'
119+
plugin prisma {
120+
provider = '@core/prisma'
121+
}
122+
123+
plugin zod {
124+
provider = '@core/zod'
121125
}
122-
`
123-
);
124-
const program = createProgram();
125-
await program.parseAsync(['generate', '--no-dependency-check', '--no-default-plugins'], { from: 'user' });
126-
expect(fs.existsSync('./node_modules/.zenstack/policy.js')).toBeTruthy();
127-
expect(fs.existsSync('./node_modules/.zenstack/model-meta.js')).toBeTruthy();
128-
expect(fs.existsSync('./prisma/schema.prisma')).toBeTruthy();
129-
});
130126
131-
it('generate no default plugins with access-policy without zod', async () => {
132-
fs.appendFileSync(
133-
'schema.zmodel',
134-
`
135127
plugin enhancer {
136128
provider = '@core/enhancer'
137129
}
138130
`
139131
);
140-
let content = fs.readFileSync('schema.zmodel', 'utf-8');
141-
content = content.replace('@email', '');
142-
fs.writeFileSync('schema.zmodel', content, 'utf-8');
143-
144132
const program = createProgram();
145133
await program.parseAsync(['generate', '--no-dependency-check', '--no-default-plugins'], { from: 'user' });
146134
expect(fs.existsSync('./node_modules/.zenstack/policy.js')).toBeTruthy();
147135
expect(fs.existsSync('./node_modules/.zenstack/model-meta.js')).toBeTruthy();
148136
expect(fs.existsSync('./prisma/schema.prisma')).toBeTruthy();
149-
const z = require(path.join(process.cwd(), './node_modules/.zenstack/zod/models'));
150-
expect(z).toEqual({});
151137
});
152138

153139
it('generate no compile', async () => {

0 commit comments

Comments
 (0)