diff --git a/apps/generator-cli/src/README.md b/apps/generator-cli/src/README.md index 595434dcf..7e9304cbd 100644 --- a/apps/generator-cli/src/README.md +++ b/apps/generator-cli/src/README.md @@ -175,7 +175,22 @@ is automatically used to generate your code. 🎉 ## Custom Generators -Custom generators can be used by passing the `--custom-generator=/my/custom-generator.jar` argument. +Custom generators can be used by passing the `--custom-generator=my/custom-generator.jar` argument. Alternatively, use a `customJarPath` property in *openapitools.json* as shown here. + +```json5 +{ + ... + "generators": { + ... + "myCustom": { + "generatorName": "my-custom-generator", + "customJarPath": "my/custom-generator.jar", + ... + } + } + ... +} +``` ## Further Documentation diff --git a/apps/generator-cli/src/app/services/generator.service.spec.ts b/apps/generator-cli/src/app/services/generator.service.spec.ts index 470d7ab2b..94c31d1bf 100644 --- a/apps/generator-cli/src/app/services/generator.service.spec.ts +++ b/apps/generator-cli/src/app/services/generator.service.spec.ts @@ -85,6 +85,13 @@ describe('GeneratorService', () => { someBool: false, }, }, + ['bar-custom-generator.json']: { + bar: { + glob: 'bar/abc/**/*.yaml', + output: 'bar/#{name}', + customJarPath: 'path/to/custom-generators.jar', + }, + }, ['no-glob.json']: { noGlob: { inputSpec: 'http://example.local/openapi.json', @@ -123,10 +130,17 @@ describe('GeneratorService', () => { }) }) - const cmd = (name, appendix: string[]) => ({ - name, - command: `java -jar "/path/to/4.2.1.jar" generate ${appendix.join(' ')}`, - }); + const cmd = (name, appendix: string[], customJarPath?: string) => { + const cliPath = '/path/to/4.2.1.jar' + const cpDelimiter = process.platform === "win32" ? ';' : ':'; + const subCmd = customJarPath + ? `-cp "${[cliPath, customJarPath].join(cpDelimiter)}" org.openapitools.codegen.OpenAPIGenerator` + : `-jar "${cliPath}"` + return { + name, + command: `java ${subCmd} generate ${appendix.join(' ')}`, + } + }; describe.each([ ['foo.json', [ @@ -183,6 +197,16 @@ describe('GeneratorService', () => { '--some-bool', ]), ]], + ['bar-custom-generator.json', [ + cmd('[bar] api/cat.yaml', [ + `--input-spec="${cwd}/api/cat.yaml"`, + `--output="bar/cat"`, + ], 'path/to/custom-generators.jar'), + cmd('[bar] api/bird.json', [ + `--input-spec="${cwd}/api/bird.json"`, + `--output="bar/bird"`, + ], 'path/to/custom-generators.jar'), + ]], ['none.json', []], ['also-none.json', []], ['no-glob.json', [ diff --git a/apps/generator-cli/src/app/services/generator.service.ts b/apps/generator-cli/src/app/services/generator.service.ts index 3b8744861..623ce468f 100644 --- a/apps/generator-cli/src/app/services/generator.service.ts +++ b/apps/generator-cli/src/app/services/generator.service.ts @@ -29,7 +29,7 @@ export class GeneratorService { ) { } - public async generate() { + public async generate(customJarPath?: string) { const cwd = this.configService.cwd const generators = Object.entries(this.configService.get<{ [name: string]: GeneratorConfig }>(this.configPath, {})) @@ -85,7 +85,7 @@ export class GeneratorService { }).join('\n')) } - private buildCommand(cwd: string, params: Record, specFile?: string) { + private buildCommand(cwd: string, params: Record, specFile?: string, customJarPath?: string) { const absoluteSpecPath = specFile ? path.resolve(cwd, specFile) : String(params.inputSpec) const command = Object.entries({ @@ -94,6 +94,12 @@ export class GeneratorService { }).map(([k, v]) => { const key = kebabCase(k) + + if (key === 'custom-jar-path') { + customJarPath = v + return '' + } + const value = (() => { switch (typeof v) { case 'object': @@ -109,7 +115,7 @@ export class GeneratorService { })() return value === undefined ? `--${key}` : `--${key}=${value}` - }).join(' ') + }).filter(arg => arg).join(' ') const ext = path.extname(absoluteSpecPath) const name = path.basename(absoluteSpecPath, ext) @@ -133,15 +139,23 @@ export class GeneratorService { .filter(([, replacement]) => !!replacement) .reduce((cmd, [search, replacement]) => { return cmd.split(`#{${search}}`).join(replacement) - }, command)) + }, command), customJarPath) } - private cmd = (appendix: string) => [ - 'java', - process.env['JAVA_OPTS'], - `-jar "${this.versionManager.filePath()}"`, - 'generate', - appendix, - ].filter(isString).join(' '); + private cmd = (appendix: string, customJarPath?: string) => { + 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, + 'generate', + appendix, + ].filter(isString).join(' '); + } } diff --git a/apps/generator-cli/src/app/services/pass-through.service.spec.ts b/apps/generator-cli/src/app/services/pass-through.service.spec.ts index db39e81fb..c0cc00b06 100644 --- a/apps/generator-cli/src/app/services/pass-through.service.spec.ts +++ b/apps/generator-cli/src/app/services/pass-through.service.spec.ts @@ -214,7 +214,7 @@ describe('PassThroughService', () => { cmdMock.args = [] commandMock.commands[cmd].action(cmdMock) expect(childProcess.spawn).toBeCalledTimes(0) - expect(generate).toHaveBeenNthCalledWith(1) + expect(generate).toBeCalledTimes(1); }) } diff --git a/apps/generator-cli/src/app/services/pass-through.service.ts b/apps/generator-cli/src/app/services/pass-through.service.ts index 6d4868bbd..f71b7dede 100644 --- a/apps/generator-cli/src/app/services/pass-through.service.ts +++ b/apps/generator-cli/src/app/services/pass-through.service.ts @@ -36,7 +36,7 @@ export class PassThroughService { return; case 'generate': if (this.generatorService.enabled) { - if (!await this.generatorService.generate()) { + if (!await this.generatorService.generate(cmd.opts().customGenerator)) { this.logger.log(chalk.red('Code generation failed')); process.exit(1); } diff --git a/apps/generator-cli/src/app/services/version-manager.service.spec.ts b/apps/generator-cli/src/app/services/version-manager.service.spec.ts index 989d92d1f..6e6993f8e 100644 --- a/apps/generator-cli/src/app/services/version-manager.service.spec.ts +++ b/apps/generator-cli/src/app/services/version-manager.service.spec.ts @@ -6,7 +6,7 @@ import { mocked } from 'ts-jest/utils'; import { LOGGER } from '../constants'; import * as chalk from 'chalk'; import { ConfigService } from './config.service'; -import { resolve } from 'path'; +import { resolve, join } from 'path'; import * as os from 'os'; import { TestingModule } from '@nestjs/testing/testing-module'; @@ -442,7 +442,7 @@ describe('VersionManagerService', () => { it('creates a temporary directory', () => { - expect(fs.mkdtempSync).toHaveBeenNthCalledWith(1, '/tmp/generator-cli-'); + expect(fs.mkdtempSync).toHaveBeenNthCalledWith(1, join(os.tmpdir(), 'generator-cli-')); }); it('creates the correct write stream', () => { diff --git a/apps/generator-cli/src/config.schema.json b/apps/generator-cli/src/config.schema.json index a193f2650..47b73eb38 100644 --- a/apps/generator-cli/src/config.schema.json +++ b/apps/generator-cli/src/config.schema.json @@ -78,6 +78,9 @@ "type": "boolean", "default": false }, + "customJarPath": { + "type": "string" + }, "generatorName": { "description": "generator to use (see list command for list)", "anyOf": [