Skip to content

Commit

Permalink
Merge pull request OpenAPITools#335 from mcaden/features/custom-jar
Browse files Browse the repository at this point in the history
feat(custom generators): added '--custom-generator' parameter fixes OpenAPITools#237
  • Loading branch information
kay-schecker authored May 19, 2021
2 parents cd3aa24 + 8cb99ee commit 0645163
Show file tree
Hide file tree
Showing 7 changed files with 79 additions and 29 deletions.
4 changes: 4 additions & 0 deletions apps/generator-cli/src/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,10 @@ is automatically used to generate your code. 🎉
| relPath | file name and extension of file relative to the glob provided | docs/auth.yaml |
| ext | just file extension | yaml |

## Custom Generators

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

## Further Documentation

Please refer to the [official openapi-generator docs](https://github.com/OpenAPITools/openapi-generator#3---usage) for
Expand Down
12 changes: 6 additions & 6 deletions apps/generator-cli/src/app/app.module.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {AppModule} from './app.module';
import {Test} from '@nestjs/testing';
import {PassTroughService, VersionManagerService} from './services';
import {PassThroughService, VersionManagerService} from './services';
import {of} from 'rxjs';
import {COMMANDER_PROGRAM} from './constants';

Expand All @@ -12,7 +12,7 @@ describe('AppModule', () => {
parse: jest.fn(),
}

const passTroughServiceMock = {
const passThroughServiceMock = {
init: jest.fn(),
}

Expand All @@ -27,22 +27,22 @@ describe('AppModule', () => {

[
...Object.values(versionManagerServiceMock),
...Object.values(passTroughServiceMock),
...Object.values(passThroughServiceMock),
...Object.values(programMock),
].forEach(spy => spy.mockReset())

const moduleRef = await Test.createTestingModule({
providers: [
{provide: COMMANDER_PROGRAM, useValue: programMock},
{provide: VersionManagerService, useValue: versionManagerServiceMock},
{provide: PassTroughService, useValue: passTroughServiceMock},
{provide: PassThroughService, useValue: passThroughServiceMock},
]
}).compile();

fixture = new AppModule(
moduleRef.get(COMMANDER_PROGRAM),
moduleRef.get(VersionManagerService),
moduleRef.get(PassTroughService),
moduleRef.get(PassThroughService),
)
})

Expand All @@ -55,7 +55,7 @@ describe('AppModule', () => {
process.argv = ['foo', 'baz']

programMock.parse.mockImplementation(() => {
expect(passTroughServiceMock.init).toBeCalledTimes(1)
expect(passThroughServiceMock.init).toBeCalledTimes(1)
expect(versionManagerServiceMock.downloadIfNeeded).toBeCalledTimes(1)
})
})
Expand Down
8 changes: 4 additions & 4 deletions apps/generator-cli/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import * as url from 'url';

import { COMMANDER_PROGRAM, LOGGER } from './constants';
import { VersionManagerController } from './controllers/version-manager.controller';
import { ConfigService, GeneratorService, PassTroughService, UIService, VersionManagerService } from './services';
import { ConfigService, GeneratorService, PassThroughService, UIService, VersionManagerService } from './services';

let proxyConfig: AxiosProxyConfig;
const proxyUrl = process.env.HTTPS_PROXY || process.env.HTTP_PROXY;
Expand All @@ -31,7 +31,7 @@ if (proxyUrl) {
UIService,
ConfigService,
GeneratorService,
PassTroughService,
PassThroughService,
VersionManagerService,
{
provide: COMMANDER_PROGRAM,
Expand All @@ -45,7 +45,7 @@ export class AppModule implements OnApplicationBootstrap {
constructor(
@Inject(COMMANDER_PROGRAM) private readonly program: Command,
private readonly versionManager: VersionManagerService,
private readonly passTroughService: PassTroughService
private readonly passThroughService: PassThroughService
) {
}

Expand All @@ -60,7 +60,7 @@ export class AppModule implements OnApplicationBootstrap {
}

await this.versionManager.downloadIfNeeded(selectedVersion);
await this.passTroughService.init();
await this.passThroughService.init();
this.program.parse(process.argv);

};
Expand Down
17 changes: 17 additions & 0 deletions apps/generator-cli/src/app/mocks/passthrough-command.mock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
export class PassthroughCommandMock {
name = jest.fn().mockReturnValue(this._name);
options: Record<string, string> = {};

parseOptions = jest.fn().mockImplementation(() => {
const result = this.args.find(a => a.startsWith('--custom-generator'))?.split('=')[1];
this.options.customGenerator = result || undefined;
this.args = this.args.filter(a => !a.startsWith('--custom-generator'));
return this.opts();
});

helpInformation = jest.fn().mockReturnValue('has custom generator');

opts = jest.fn().mockImplementation(() => ({ ...this.options, unknown: this.args}));

constructor(private _name: string, public args: string[]) { }
}
2 changes: 1 addition & 1 deletion apps/generator-cli/src/app/services/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export * from './ui.service'
export * from './config.service'
export * from './generator.service'
export * from './pass-trough.service'
export * from './pass-through.service'
export * from './version-manager.service'
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import {Test} from '@nestjs/testing';
import {PassTroughService} from './pass-trough.service';
import {PassThroughService} from './pass-through.service';
import {mocked} from 'ts-jest/utils';
import {COMMANDER_PROGRAM, LOGGER} from '../constants';
import {VersionManagerService} from './version-manager.service';
import {noop} from 'rxjs';
import {CommandMock} from '../mocks/command.mock';
import {PassthroughCommandMock} from '../mocks/passthrough-command.mock';
import {GeneratorService} from './generator.service';

jest.mock('child_process');
// eslint-disable-next-line @typescript-eslint/no-var-requires
const childProcess = mocked(require('child_process'), true)

describe('PassTroughService', () => {
describe('PassThroughService', () => {

let fixture: PassTroughService;
let fixture: PassThroughService;
let commandMock: CommandMock;

const log = jest.fn()
Expand All @@ -26,15 +27,15 @@ describe('PassTroughService', () => {

const moduleRef = await Test.createTestingModule({
providers: [
PassTroughService,
PassThroughService,
{provide: VersionManagerService, useValue: {filePath, getSelectedVersion}},
{provide: GeneratorService, useValue: {generate, enabled: true}},
{provide: COMMANDER_PROGRAM, useValue: commandMock},
{provide: LOGGER, useValue: {log}},
],
}).compile();

fixture = moduleRef.get(PassTroughService);
fixture = moduleRef.get(PassThroughService);
});

describe('API', () => {
Expand Down Expand Up @@ -130,9 +131,10 @@ describe('PassTroughService', () => {
['completion', ''],
])('%s', (cmd, desc) => {

const cmdMock = {name: () => cmd, args: ['foo', 'baz']};
let cmdMock: PassthroughCommandMock;

beforeEach(() => {
cmdMock = new PassthroughCommandMock(cmd, ['foo', 'baz']);
const on = jest.fn();
childProcess.spawn.mockReset().mockReturnValue({on})
})
Expand Down Expand Up @@ -175,15 +177,34 @@ describe('PassTroughService', () => {
)
})

it('can delegate with custom jar', () => {
delete process.env['JAVA_OPTS'];
const args = [...cmdMock.args];
cmdMock.args.push('--custom-generator=../some/custom.jar');
commandMock.commands[cmd].action(cmdMock)
const cpDelimiter = process.platform === "win32" ? ';' : ':';
expect(childProcess.spawn).toHaveBeenNthCalledWith(
1,
`java -cp "${['/some/path/to/4.2.1.jar', '../some/custom.jar'].join(cpDelimiter)}" org.openapitools.codegen.OpenAPIGenerator`,
[cmd, ...args],
{
stdio: 'inherit',
shell: true
}
)
})

if (cmd === 'help') {
it('prints the help info and does not delegate, if args length = 0', () => {
childProcess.spawn.mockReset()
cmdMock.args = []
const logSpy = jest.spyOn(console, 'log').mockImplementationOnce(noop)
const logSpy = jest.spyOn(console, 'log').mockImplementation(noop)
commandMock.commands[cmd].action(cmdMock)
expect(childProcess.spawn).toBeCalledTimes(0)
expect(commandMock.helpInformation).toBeCalledTimes(1)
expect(logSpy).toHaveBeenNthCalledWith(1, 'some help text')
expect(logSpy).toHaveBeenCalledTimes(2);
expect(logSpy).toHaveBeenNthCalledWith(1, 'some help text');
expect(logSpy).toHaveBeenNthCalledWith(2, 'has custom generator');
})
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { exec, spawn } from 'child_process';
import { GeneratorService } from './generator.service';

@Injectable()
export class PassTroughService {
export class PassThroughService {

constructor(
@Inject(LOGGER) private readonly logger: LOGGER,
Expand All @@ -24,13 +24,15 @@ export class PassTroughService {
this.program
.command(command, { hidden: !desc })
.allowUnknownOption()
.option("--custom-generator <generator>", "Custom generator to use alongside 'generate'", "")
.description(desc)
.action(async (cmd: Command) => {

if (cmd.args.length === 0) {
const args = cmd.parseOptions(cmd.args).unknown;
if (args.length === 0) {
switch (cmd.name()) {
case 'help':
console.log(this.program.helpInformation());
console.log(cmd.helpInformation());
return;
case 'generate':
if (this.generatorService.enabled) {
Expand All @@ -43,16 +45,17 @@ export class PassTroughService {
}
}

this.passTrough([cmd.name(), ...cmd.args]);
this.passThrough([cmd.name(), ...args], cmd.opts().customGenerator);
});
});

}

public passTrough = (args: string[] = []) => spawn(this.cmd(), args, {
stdio: 'inherit',
shell: true
}).on('exit', process.exit);
public passThrough = (args: string[] = [], customGenerator: string) =>
spawn(this.cmd(customGenerator), args, {
stdio: 'inherit',
shell: true
}).on('exit', process.exit);

private getCommands = async (): Promise<[string, string | undefined][]> => {

Expand Down Expand Up @@ -85,8 +88,13 @@ export class PassTroughService {
});
});

private cmd() {
return ['java', process.env['JAVA_OPTS'], `-jar "${this.versionManager.filePath()}"`].filter(isString).join(' ');
private cmd(customJarPath = '') {
const cliPath = this.versionManager.filePath();
const cpDelimiter = process.platform === "win32" ? ';' : ':';
const subCmd = customJarPath
? `-cp "${[cliPath, customJarPath].join(cpDelimiter)}" org.openapitools.codegen.OpenAPIGenerator`
: `-jar "${cliPath}"`;
return ['java', process.env['JAVA_OPTS'], subCmd].filter(isString).join(' ');
}

}

0 comments on commit 0645163

Please sign in to comment.