Skip to content

Commit 1b9b447

Browse files
committed
feat(336): add support for --generator-key
1 parent 4dd568c commit 1b9b447

8 files changed

Lines changed: 238 additions & 152 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
/dist
55
/tmp
66
/out-tsc
7+
/output
78

89
# dependencies
910
/node_modules

apps/generator-cli/src/README.md

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ Further it is also possible to configure generators, for example:
133133
"version": "4.3.1",
134134
"storageDir": "~/my/custom/storage/dir", // optional
135135
"generators": { // optional
136-
"v2.0": { // any name you like (just printed to the console log)
136+
"v2.0": { // any name you like (just printed to the console log or reference it using --generator-key)
137137
"generatorName": "typescript-angular",
138138
"output": "#{cwd}/output/v2.0/#{ext}/#{name}",
139139
"glob": "examples/v2.0/{json,yaml}/*.{json,yaml}",
@@ -145,7 +145,7 @@ Further it is also possible to configure generators, for example:
145145
"withInterfaces": true
146146
}
147147
},
148-
"v3.0": { // any name you like (just printed to the console log)
148+
"v3.0": { // any name you like (just printed to the console log or reference it using --generator-key)
149149
"generatorName": "typescript-fetch",
150150
"output": "#{cwd}/output/v3.0/#{ext}/#{name}",
151151
"glob": "examples/v3.0/petstore.{json,yaml}"
@@ -173,6 +173,14 @@ is automatically used to generate your code. 🎉
173173
| relPath | file name and extension of file relative to the glob provided | docs/auth.yaml |
174174
| ext | just file extension | yaml |
175175

176+
## Run specific generators
177+
178+
| cmd | v3.0 runs | v2.0 runs |
179+
|----------------------------------------------------------|-----------|-----------|
180+
| openapi-generator-cli generate --generator-key v3.0 | yes | no |
181+
| openapi-generator-cli generate --generator-key v3.0 v2.0 | yes | yes |
182+
| openapi-generator-cli generate --generator-key foo | no | no |
183+
176184
## Custom Generators
177185

178186
Custom generators can be used by passing the `--custom-generator=/my/custom-generator.jar` argument.

apps/generator-cli/src/app/mocks/passthrough-command.mock.ts

Lines changed: 0 additions & 17 deletions
This file was deleted.

apps/generator-cli/src/app/services/generator.service.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,21 @@ export class GeneratorService {
2929
) {
3030
}
3131

32-
public async generate() {
32+
public async generate(...keys: string[]) {
3333

3434
const cwd = this.configService.cwd
3535
const generators = Object.entries(this.configService.get<{ [name: string]: GeneratorConfig }>(this.configPath, {}))
36-
const enabledGenerators = generators.filter(([, {disabled}]) => disabled !== true)
36+
const enabledGenerators = generators
37+
.filter(([key, {disabled}]) => {
38+
if (!disabled) return true;
39+
this.logger.log(chalk.grey(`[info] Skip ${chalk.yellow(key)}, because this generator is disabled`));
40+
return false;
41+
})
42+
.filter(([key]) => {
43+
if (!keys.length || keys.includes(key)) return true;
44+
this.logger.log(chalk.grey(`[info] Skip ${chalk.yellow(key)}, because only ${keys.map((k) => chalk.yellow(k)).join(', ')} shall run`));
45+
return false;
46+
})
3747

3848
const globsWithNoMatches = []
3949

apps/generator-cli/src/app/services/pass-through.service.spec.ts

Lines changed: 133 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,47 @@
1-
import {Test} from '@nestjs/testing';
2-
import {PassThroughService} from './pass-through.service';
3-
import {mocked} from 'ts-jest/utils';
4-
import {COMMANDER_PROGRAM, LOGGER} from '../constants';
5-
import {VersionManagerService} from './version-manager.service';
6-
import {noop} from 'rxjs';
7-
import {CommandMock} from '../mocks/command.mock';
8-
import {PassthroughCommandMock} from '../mocks/passthrough-command.mock';
9-
import {GeneratorService} from './generator.service';
10-
11-
jest.mock('child_process');
1+
import { Test } from '@nestjs/testing'
2+
import * as chalk from 'chalk'
3+
import { Command, createCommand } from 'commander'
4+
import { mocked } from 'ts-jest/utils'
5+
import { COMMANDER_PROGRAM, LOGGER } from '../constants'
6+
import { GeneratorService } from './generator.service'
7+
import { PassThroughService } from './pass-through.service'
8+
import { VersionManagerService } from './version-manager.service'
9+
10+
jest.mock('child_process')
1211
// eslint-disable-next-line @typescript-eslint/no-var-requires
1312
const childProcess = mocked(require('child_process'), true)
1413

1514
describe('PassThroughService', () => {
1615

17-
let fixture: PassThroughService;
18-
let commandMock: CommandMock;
16+
let fixture: PassThroughService
17+
let program: Command
1918

2019
const log = jest.fn()
2120
const generate = jest.fn().mockResolvedValue(true)
22-
const getSelectedVersion = jest.fn().mockReturnValue('4.2.1');
23-
const filePath = jest.fn().mockReturnValue(`/some/path/to/4.2.1.jar`);
21+
const getSelectedVersion = jest.fn().mockReturnValue('4.2.1')
22+
const filePath = jest.fn().mockReturnValue(`/some/path/to/4.2.1.jar`)
23+
24+
const getCommand = (name: string) => program.commands.find(c => c.name() === name);
2425

2526
beforeEach(async () => {
26-
commandMock = new CommandMock()
27+
program = createCommand()
28+
jest.spyOn(program, 'helpInformation')
2729

2830
const moduleRef = await Test.createTestingModule({
2931
providers: [
3032
PassThroughService,
31-
{provide: VersionManagerService, useValue: {filePath, getSelectedVersion}},
32-
{provide: GeneratorService, useValue: {generate, enabled: true}},
33-
{provide: COMMANDER_PROGRAM, useValue: commandMock},
34-
{provide: LOGGER, useValue: {log}},
33+
{ provide: VersionManagerService, useValue: { filePath, getSelectedVersion } },
34+
{ provide: GeneratorService, useValue: { generate, enabled: true } },
35+
{ provide: COMMANDER_PROGRAM, useValue: program },
36+
{ provide: LOGGER, useValue: { log } },
3537
],
36-
}).compile();
38+
}).compile()
39+
40+
fixture = moduleRef.get(PassThroughService)
3741

38-
fixture = moduleRef.get(PassThroughService);
39-
});
42+
childProcess.spawn.mockReset().mockReturnValue({ on: jest.fn() })
43+
44+
})
4045

4146
describe('API', () => {
4247

@@ -51,20 +56,18 @@ describe('PassThroughService', () => {
5156
try {
5257
await fixture.init()
5358
} catch (e) {
54-
error = e;
59+
error = e
5560
}
5661
})
5762

58-
it('throw the error', () => {
63+
it('throws the error', () => {
5964
expect(error.message).toEqual('Some error')
6065
})
6166

6267
it('adds no commands', () => {
63-
expect(commandMock.action).toBeCalledTimes(0)
64-
expect(commandMock.command).toBeCalledTimes(0)
65-
expect(commandMock.description).toBeCalledTimes(0)
68+
expect(program.commands).toHaveLength(0)
6669
})
67-
});
70+
})
6871

6972
describe('the help command works', () => {
7073

@@ -101,21 +104,19 @@ describe('PassThroughService', () => {
101104

102105
beforeEach(async () => {
103106
childProcess.exec.mockImplementation((cmd: string, cb) => {
104-
if(cmd.endsWith('"/some/path/to/4.2.1.jar" help')) {
107+
if (cmd.endsWith('"/some/path/to/4.2.1.jar" help')) {
105108
cb(undefined, helpText)
106109
}
107110

108-
if(cmd.endsWith('"/some/path/to/4.2.1.jar" completion')) {
111+
if (cmd.endsWith('"/some/path/to/4.2.1.jar" completion')) {
109112
cb(undefined, completionText)
110113
}
111114
})
112115
await fixture.init()
113116
})
114117

115-
it('adds 19 commands', () => {
116-
expect(commandMock.action).toBeCalledTimes(10)
117-
expect(commandMock.command).toBeCalledTimes(10)
118-
expect(commandMock.description).toBeCalledTimes(10)
118+
it('adds 10 commands', () => {
119+
expect(program.commands).toHaveLength(10)
119120
})
120121

121122
describe.each([
@@ -129,94 +130,144 @@ describe('PassThroughService', () => {
129130
['version', 'Show version information used in tooling'],
130131
['batch', ''],
131132
['completion', ''],
132-
])('%s', (cmd, desc) => {
133+
])('%s', (name, desc) => {
133134

134-
let cmdMock: PassthroughCommandMock;
135+
let cmd: Command
136+
const argv = ['foo', 'baz']
135137

136138
beforeEach(() => {
137-
cmdMock = new PassthroughCommandMock(cmd, ['foo', 'baz']);
138-
const on = jest.fn();
139-
childProcess.spawn.mockReset().mockReturnValue({on})
139+
cmd = getCommand(name);
140+
delete process.env['JAVA_OPTS']
140141
})
141142

142143
it('adds the correct description', () => {
143-
expect(commandMock.commands[cmd].description).toEqual(desc)
144+
expect(cmd.description()).toEqual(desc)
144145
})
145146

146147
it('allows unknown options', () => {
147-
expect(commandMock.commands[cmd].allowUnknownOption).toBeTruthy()
148+
expect(cmd['_allowUnknownOption']).toBeTruthy()
148149
})
149150

150-
it('can delegate with JAVA_OPTS', () => {
151-
process.env['JAVA_OPTS'] = 'java-opt-1=1'
152-
commandMock.commands[cmd].action(cmdMock)
153-
151+
it('can delegate', async () => {
152+
await program.parseAsync([name, ...argv], { from: 'user' })
154153
expect(childProcess.spawn).toHaveBeenNthCalledWith(
155154
1,
156-
'java java-opt-1=1 -jar "/some/path/to/4.2.1.jar"',
157-
[cmd, ...cmdMock.args],
155+
'java -jar "/some/path/to/4.2.1.jar"',
156+
[name, ...argv],
158157
{
159158
stdio: 'inherit',
160159
shell: true
161160
}
162161
)
163162
})
164163

165-
it('can delegate without JAVA_OPTS', () => {
166-
delete process.env['JAVA_OPTS']
167-
commandMock.commands[cmd].action(cmdMock)
168-
164+
it('can delegate with JAVA_OPTS', async () => {
165+
process.env['JAVA_OPTS'] = 'java-opt-1=1'
166+
await program.parseAsync([name, ...argv], { from: 'user' })
169167
expect(childProcess.spawn).toHaveBeenNthCalledWith(
170168
1,
171-
'java -jar "/some/path/to/4.2.1.jar"',
172-
[cmd, ...cmdMock.args],
169+
'java java-opt-1=1 -jar "/some/path/to/4.2.1.jar"',
170+
[name, ...argv],
173171
{
174172
stdio: 'inherit',
175173
shell: true
176174
}
177175
)
178176
})
179177

180-
it('can delegate with custom jar', () => {
181-
delete process.env['JAVA_OPTS'];
182-
const args = [...cmdMock.args];
183-
cmdMock.args.push('--custom-generator=../some/custom.jar');
184-
commandMock.commands[cmd].action(cmdMock)
185-
const cpDelimiter = process.platform === "win32" ? ';' : ':';
178+
it('can delegate with custom jar', async () => {
179+
await program.parseAsync([name, ...argv, '--custom-generator=../some/custom.jar'], { from: 'user' })
180+
const cpDelimiter = process.platform === 'win32' ? ';' : ':'
181+
186182
expect(childProcess.spawn).toHaveBeenNthCalledWith(
187183
1,
188184
`java -cp "${['/some/path/to/4.2.1.jar', '../some/custom.jar'].join(cpDelimiter)}" org.openapitools.codegen.OpenAPIGenerator`,
189-
[cmd, ...args],
185+
[name, ...argv],
190186
{
191187
stdio: 'inherit',
192188
shell: true
193189
}
194190
)
195191
})
196192

197-
if (cmd === 'help') {
198-
it('prints the help info and does not delegate, if args length = 0', () => {
199-
childProcess.spawn.mockReset()
200-
cmdMock.args = []
201-
const logSpy = jest.spyOn(console, 'log').mockImplementation(noop)
202-
commandMock.commands[cmd].action(cmdMock)
203-
expect(childProcess.spawn).toBeCalledTimes(0)
204-
expect(commandMock.helpInformation).toBeCalledTimes(1)
205-
expect(logSpy).toHaveBeenCalledTimes(2);
206-
expect(logSpy).toHaveBeenNthCalledWith(1, 'some help text');
207-
expect(logSpy).toHaveBeenNthCalledWith(2, 'has custom generator');
208-
})
209-
}
193+
// if (name === 'help') {
194+
// it('prints the help info and does not delegate, if args length = 0', async () => {
195+
// childProcess.spawn.mockReset()
196+
// cmd.args = []
197+
// const logSpy = jest.spyOn(console, 'log').mockImplementation(noop)
198+
// await program.parseAsync([name], { from: 'user' })
199+
// expect(childProcess.spawn).toBeCalledTimes(0)
200+
// expect(program.helpInformation).toBeCalledTimes(1)
201+
// // expect(logSpy).toHaveBeenCalledTimes(2)
202+
// expect(logSpy).toHaveBeenNthCalledWith(1, 'some help text')
203+
// expect(logSpy).toHaveBeenNthCalledWith(2, 'has custom generator')
204+
// })
205+
// }
206+
//
207+
// if (name === 'generate') {
208+
// it('generates by using the generator config', async () => {
209+
// childProcess.spawn.mockReset()
210+
// await program.parseAsync([name], { from: 'user' })
211+
// expect(childProcess.spawn).toBeCalledTimes(0)
212+
// expect(generate).toHaveBeenNthCalledWith(1)
213+
// })
214+
// }
215+
216+
})
217+
218+
describe('command behavior', () => {
219+
220+
describe('help', () => {
221+
222+
const programHelp = () => chalk.cyanBright(program.helpInformation());
223+
const commandHelp = (name: string) => () => chalk.cyanBright(getCommand(name).helpInformation());
224+
225+
describe.each`
226+
cmd | helpText | spawn
227+
${'help'} | ${programHelp} | ${undefined}
228+
${'help generate'} | ${commandHelp('generate')} | ${'a'}
229+
${'help author'} | ${commandHelp('author')} | ${'b'}
230+
${'help hidden'} | ${undefined} | ${'c'}
231+
`('$cmd', ({ cmd, helpText, spawn }) => {
232+
233+
let spy: jest.SpyInstance;
234+
235+
beforeEach(async () => {
236+
spy = jest.spyOn(console, 'log').mockClear().mockImplementation();
237+
await program.parseAsync(cmd.split(' '), { from: 'user' })
238+
})
239+
240+
describe('help text', () => {
241+
it(`logs ${helpText ? 1 : 0} times`, () => {
242+
expect(spy).toHaveBeenCalledTimes(helpText ? 1 : 0);
243+
})
244+
245+
helpText && it('prints the correct help text', () => {
246+
expect(spy).toHaveBeenCalledWith(helpText())
247+
})
248+
})
249+
250+
describe('process spawn', () => {
251+
it(`spawns ${spawn ? 1 : 0} times`, () => {
252+
expect(childProcess.spawn).toHaveBeenCalledTimes(spawn ? 1 : 0);
253+
})
254+
255+
spawn && it('spawns the correct process', () => {
256+
257+
expect(childProcess.spawn).toHaveBeenNthCalledWith(
258+
1,
259+
'java -jar "/some/path/to/4.2.1.jar"',
260+
cmd.split(' '),
261+
{stdio: 'inherit', shell: true}
262+
);
263+
264+
})
265+
266+
})
210267

211-
if (cmd === 'generate') {
212-
it('generates by using the generator config', () => {
213-
childProcess.spawn.mockReset()
214-
cmdMock.args = []
215-
commandMock.commands[cmd].action(cmdMock)
216-
expect(childProcess.spawn).toBeCalledTimes(0)
217-
expect(generate).toHaveBeenNthCalledWith(1)
218268
})
219-
}
269+
270+
})
220271

221272
})
222273

0 commit comments

Comments
 (0)