diff --git a/apps/generator-cli/src/README.md b/apps/generator-cli/src/README.md index ceab9a9f0..77b268ba0 100644 --- a/apps/generator-cli/src/README.md +++ b/apps/generator-cli/src/README.md @@ -175,6 +175,7 @@ is automatically used to generate your code. 🎉 | relDir | directory name of file relative to the glob provided | docs | | relPath | file name and extension of file relative to the glob provided | docs/auth.yaml | | ext | just file extension | yaml | +| env. | environment variable (use ${env.name} syntax) | | ### Using custom / private maven registry @@ -196,6 +197,18 @@ If you're using a private maven registry you can configure the `downloadUrl` and If the `version` property param is set it is not necessary to configure the `queryUrl`. +`queryUrl` and `downloadUrl` can use the following placeholders: + +| placeholder | description | +|-------------|----------------------------------------------------| +| groupId | maven groupId where '.' has been replace with / | +| artifactId | maven artifactId where '.' has been replace with / | +| versionName | maven version (only for downloadUrl) | +| group.id | maven groupId | +| artifact.id | maven artifactId | +| env. | environment variable name | + + ### Use locally built JAR In order to use a locally built jar of the generator CLI, you can copy the jar from your local build (i.e. if you were to `build` the [OpenAPITools/openapi-generator](https://github.com/OpenAPITools/openapi-generator) repository it would be in `~/openapi-generator/modules/openapi-generator-cli/target/openapi-generator-cli.jar`) into `./node_modules/@openapitools/openapi-generator-cli/versions/` and change the `version` in the `openapitools.json` file to the base name of the jar file. E.g.: diff --git a/apps/generator-cli/src/app/services/config.service.spec.ts b/apps/generator-cli/src/app/services/config.service.spec.ts index 92c81446c..d6bb69828 100644 --- a/apps/generator-cli/src/app/services/config.service.spec.ts +++ b/apps/generator-cli/src/app/services/config.service.spec.ts @@ -90,6 +90,41 @@ describe('ConfigService', () => { ); }); }); + + describe('the config has values having placeholders', () => { + beforeEach(() => { + fs.readJSONSync.mockReturnValue({ + $schema: 'foo.json', + spaces: 4, + 'generator-cli': { + version: '1.2.3', + repository: { + queryUrl: 'https://${env.__unit_test_username}:${env.__unit_test_password}@server/api', + downloadUrl: 'https://${env.__unit_test_non_matching}@server/api' + } + }, + }); + process.env['__unit_test_username'] = 'myusername'; + process.env['__unit_test_password'] = 'mypassword'; + }); + + afterEach(() => { + delete process.env['__unit_test_username']; + delete process.env['__unit_test_password']; + }) + + it('verify placeholder replaced with env vars', () => { + const value = fixture.get('generator-cli.repository.queryUrl'); + + expect(value).toEqual('https://myusername:mypassword@server/api'); + }); + + it('verify placeholders not matching env vars are not replaced', () => { + const value = fixture.get('generator-cli.repository.downloadUrl'); + + expect(value).toEqual('https://${env.__unit_test_non_matching}@server/api'); + }); + }); }); describe('has()', () => { diff --git a/apps/generator-cli/src/app/services/config.service.ts b/apps/generator-cli/src/app/services/config.service.ts index f968eadd0..28945ca48 100644 --- a/apps/generator-cli/src/app/services/config.service.ts +++ b/apps/generator-cli/src/app/services/config.service.ts @@ -60,14 +60,43 @@ export class ConfigService { private read() { fs.ensureFileSync(this.configFile) - return merge( + const config = merge( this.defaultConfig, fs.readJSONSync(this.configFile, {throws: false, encoding: 'utf8'}), ) + + return this.replacePlaceholders(config) } private write(config) { fs.writeJSONSync(this.configFile, config, {encoding: 'utf8', spaces: config.spaces || 2}) } + private replacePlaceholders(config: any): any { + const envVariables = Object.fromEntries( + Object.entries(process.env).map(([key, value]) => [`env.${key}`, value]) + ); + const placeholders = { + ...envVariables + }; + const replacePlaceholderInString = (str: string): string => { + return str.replace(/\${(.*?)}/g, (match, p1) => { + const key = p1.trim(); + return placeholders[key] !== undefined ? placeholders[key] : match; + }); + }; + const traverseAndReplace = (obj: any): any => { + if (typeof obj === 'string') { + return replacePlaceholderInString(obj); + } else if (Array.isArray(obj)) { + return obj.map(item => traverseAndReplace(item)); + } else if (obj !== null && typeof obj === 'object') { + return Object.fromEntries( + Object.entries(obj).map(([key, value]) => [key, traverseAndReplace(value)]) + ); + } + return obj; // Return the value as is if it's not a string, array, or object + }; + return traverseAndReplace(config); + } }