From 9ec451336fe790d5bf2c74acb9035398f0805354 Mon Sep 17 00:00:00 2001 From: atarasevich Date: Fri, 2 Dec 2022 18:56:02 -0500 Subject: [PATCH 1/4] Add support for private repository --- lib/generator.js | 35 ++++++++++++++++++++++++++++++----- test/generator.test.js | 12 +++++++++++- 2 files changed, 41 insertions(+), 6 deletions(-) diff --git a/lib/generator.js b/lib/generator.js index c6912e986..a441b9679 100644 --- a/lib/generator.js +++ b/lib/generator.js @@ -46,7 +46,7 @@ const DEFAULT_TEMPLATES_DIR = path.resolve(ROOT_DIR, 'node_modules'); const TRANSPILED_TEMPLATE_LOCATION = '__transpiled'; const TEMPLATE_CONTENT_DIRNAME = 'template'; -const GENERATOR_OPTIONS = ['debug', 'disabledHooks', 'entrypoint', 'forceWrite', 'install', 'noOverwriteGlobs', 'output', 'templateParams', 'mapBaseUrlToFolder']; +const GENERATOR_OPTIONS = ['debug', 'disabledHooks', 'entrypoint', 'forceWrite', 'install', 'noOverwriteGlobs', 'output', 'templateParams', 'mapBaseUrlToFolder','registry','registryUsername','registryPassword','registryToken']; const logMessage = require('./logMessages'); @@ -91,8 +91,12 @@ class Generator { * @param {Boolean} [options.install=false] Install the template and its dependencies, even when the template has already been installed. * @param {Boolean} [options.debug=false] Enable more specific errors in the console. At the moment it only shows specific errors about filters. Keep in mind that as a result errors about template are less descriptive. * @param {Object} [options.mapBaseUrlToFolder] Optional parameter to map schema references from a base url to a local base folder e.g. url=https://schema.example.com/crm/ folder=./test/docs/ . + * @param {String} [options.registry] Optional parameter to pass npm registry url + * @param {String} [options.registryUsername] Optional parameter to pass npm registry username + * @param {String} [options.registryPassword] Optional parameter to pass npm registry base64 encoded password + * @param {String} [options.registryToken] Optional parameter to pass npm registry auth token */ - constructor(templateName, targetDir, { templateParams = {}, entrypoint, noOverwriteGlobs, disabledHooks, output = 'fs', forceWrite = false, install = false, debug = false, mapBaseUrlToFolder = {} } = {}) { + constructor(templateName, targetDir, { templateParams = {}, entrypoint, noOverwriteGlobs, disabledHooks, output = 'fs', forceWrite = false, install = false, debug = false, mapBaseUrlToFolder = {}, registry, registryUsername, registryPassword, registryToken } = {}) { const invalidOptions = getInvalidOptions(GENERATOR_OPTIONS, arguments[arguments.length - 1] || []); if (invalidOptions.length) throw new Error(`These options are not supported by the generator: ${invalidOptions.join(', ')}`); if (!templateName) throw new Error('No template name has been specified.'); @@ -123,6 +127,14 @@ class Generator { this.hooks = {}; /** @type {Object} Maps schema URL to folder. */ this.mapBaseUrlToFolder = mapBaseUrlToFolder; + /** @type {String} Npm registry url. */ + this.registry = registry; + /** @type {String} Npm registry username. */ + this.registryUsername = registryUsername; + /** @type {String} Npm registry base64 encoded password. */ + this.registryPassword = registryPassword; + /** @type {String} Npm registry token. */ + this.registryToken = registryToken; // Load template configuration /** @type {Object} The template parameters. The structure for this object is based on each individual template. */ @@ -385,9 +397,22 @@ class Generator { if (isFileSystemPath(this.templateName)) log.debug(logMessage.NPM_INSTALL_TRIGGER); - const arb = new Arborist({ - path: ROOT_DIR - }); + const arbOptions = { + path: ROOT_DIR, + }; + if (this.registry) { + arbOptions.registry = this.registry; + } + if (this.registryUsername) { + arbOptions.username = this.registryUsername; + } + if (this.registryPassword) { + arbOptions.password = this.registryPassword; + } + if (this.registryToken) { + arbOptions.token = this.registryToken; + } + const arb = new Arborist(arbOptions); try { const installResult = await arb.reify({ diff --git a/test/generator.test.js b/test/generator.test.js index 3ec4a81c7..a69611f20 100644 --- a/test/generator.test.js +++ b/test/generator.test.js @@ -322,7 +322,7 @@ describe('Generator', () => { const utils = require('../lib/utils'); const asyncapiURL = 'http://example.com/fake-asyncapi.yml'; utils.__contentOfFetchedFile = 'fake text'; - + const generateFromStringMock = jest.fn().mockResolvedValue(); const gen = new Generator('testTemplate', __dirname); gen.generateFromString = generateFromStringMock; @@ -410,6 +410,16 @@ describe('Generator', () => { }, 0); }); + it('works with a path to registry', async () => { + log.debug = jest.fn(); + utils.__getTemplateDetails = undefined; + const gen = new Generator('nameOfTestTemplate', __dirname, {debug: true, registry: 'some.registry.com', registryUsername: 'user', registryPassword: 'password', registryToken: 'token'}); + await gen.installTemplate(); + setTimeout(() => { // This puts the call at the end of the Node.js event loop queue. + expect(arboristMock.reify).toHaveBeenCalledTimes(1); + }, 0); + }); + it('works with a url and force = true', async () => { const gen = new Generator('https://my-test-template.com', __dirname); await gen.installTemplate(true); From d6e08bc3b529bb273a2f5e7dd6b58fdcc18f3685 Mon Sep 17 00:00:00 2001 From: atarasevich Date: Mon, 12 Dec 2022 14:33:44 -0500 Subject: [PATCH 2/4] few tweaks --- docs/template.md | 2 +- lib/generator.js | 41 +++++++++++++++++++---------------------- test/generator.test.js | 2 +- 3 files changed, 21 insertions(+), 24 deletions(-) diff --git a/docs/template.md b/docs/template.md index a08688e78..b2a4fd2f6 100644 --- a/docs/template.md +++ b/docs/template.md @@ -16,7 +16,7 @@ Examples outputs: A template is an independent Node.js project unrelated to the `generator` repository. AsyncAPI templates are managed, released, and published separately. You can also create templates and manage templates on your own. -The generator uses the official [Arborist](https://www.npmjs.com/package/@npmcli/arborist) NPM library. (This means templates do not have to be published to package managers to use them.) Arborist helps the generator fetch the template's source code and use it for the generation process. +The generator uses the official [Arborist](https://www.npmjs.com/package/@npmcli/arborist) NPM library. (This means templates do not have to be published to package managers to use them.) Arborist helps the generator fetch the template's source code and use it for the generation process. By default, this library pulls data from public NPM repository, but you can pass URL and credentials for private repo in **params.registry** object. You can store template projects on a local drive or as a `git` repository during the development process. diff --git a/lib/generator.js b/lib/generator.js index 671acf782..7e7248595 100644 --- a/lib/generator.js +++ b/lib/generator.js @@ -91,12 +91,13 @@ class Generator { * @param {Boolean} [options.install=false] Install the template and its dependencies, even when the template has already been installed. * @param {Boolean} [options.debug=false] Enable more specific errors in the console. At the moment it only shows specific errors about filters. Keep in mind that as a result errors about template are less descriptive. * @param {Object} [options.mapBaseUrlToFolder] Optional parameter to map schema references from a base url to a local base folder e.g. url=https://schema.example.com/crm/ folder=./test/docs/ . - * @param {String} [options.registry] Optional parameter to pass npm registry url - * @param {String} [options.registryUsername] Optional parameter to pass npm registry username - * @param {String} [options.registryPassword] Optional parameter to pass npm registry base64 encoded password - * @param {String} [options.registryToken] Optional parameter to pass npm registry auth token + * @param {Object} [options.registry] Optional parameter with private registry configuration + * @param {String} [options.registry.url] Parameter to pass npm registry url + * @param {String} [options.registry.username] Optional parameter to pass npm registry username + * @param {String} [options.registry.password] Optional parameter to pass npm registry base64 encoded password + * @param {String} [options.registry.token] Optional parameter to pass npm registry auth token */ - constructor(templateName, targetDir, { templateParams = {}, entrypoint, noOverwriteGlobs, disabledHooks, output = 'fs', forceWrite = false, install = false, debug = false, mapBaseUrlToFolder = {}, registry, registryUsername, registryPassword, registryToken } = {}) { + constructor(templateName, targetDir, { templateParams = {}, entrypoint, noOverwriteGlobs, disabledHooks, output = 'fs', forceWrite = false, install = false, debug = false, mapBaseUrlToFolder = {}, registry = {url: '', username: '', password: '', token: '' }} = {}) { const invalidOptions = getInvalidOptions(GENERATOR_OPTIONS, arguments[arguments.length - 1] || []); if (invalidOptions.length) throw new Error(`These options are not supported by the generator: ${invalidOptions.join(', ')}`); if (!templateName) throw new Error('No template name has been specified.'); @@ -127,14 +128,8 @@ class Generator { this.hooks = {}; /** @type {Object} Maps schema URL to folder. */ this.mapBaseUrlToFolder = mapBaseUrlToFolder; - /** @type {String} Npm registry url. */ + /** @type {Object} Npm registry information. */ this.registry = registry; - /** @type {String} Npm registry username. */ - this.registryUsername = registryUsername; - /** @type {String} Npm registry base64 encoded password. */ - this.registryPassword = registryPassword; - /** @type {String} Npm registry token. */ - this.registryToken = registryToken; // Load template configuration /** @type {Object} The template parameters. The structure for this object is based on each individual template. */ @@ -401,16 +396,18 @@ class Generator { path: ROOT_DIR, }; if (this.registry) { - arbOptions.registry = this.registry; - } - if (this.registryUsername) { - arbOptions.username = this.registryUsername; - } - if (this.registryPassword) { - arbOptions.password = this.registryPassword; - } - if (this.registryToken) { - arbOptions.token = this.registryToken; + if (this.registry.url) { + arbOptions.registry = this.registry.url; + } + if (this.registry.username) { + arbOptions.username = this.registry.username; + } + if (this.registry.password) { + arbOptions.password = this.registry.password; + } + if (this.registry.token) { + arbOptions.token = this.registry.token; + } } const arb = new Arborist(arbOptions); diff --git a/test/generator.test.js b/test/generator.test.js index a69611f20..2258b2f6e 100644 --- a/test/generator.test.js +++ b/test/generator.test.js @@ -413,7 +413,7 @@ describe('Generator', () => { it('works with a path to registry', async () => { log.debug = jest.fn(); utils.__getTemplateDetails = undefined; - const gen = new Generator('nameOfTestTemplate', __dirname, {debug: true, registry: 'some.registry.com', registryUsername: 'user', registryPassword: 'password', registryToken: 'token'}); + const gen = new Generator('nameOfTestTemplate', __dirname, {debug: true, registry: {url: 'some.registry.com', username: 'user', password: 'password', token: 'token'}}); await gen.installTemplate(); setTimeout(() => { // This puts the call at the end of the Node.js event loop queue. expect(arboristMock.reify).toHaveBeenCalledTimes(1); From 1378b538d9730adaf9da148bc0728dd262638d16 Mon Sep 17 00:00:00 2001 From: atarasevich Date: Wed, 14 Dec 2022 21:27:01 -0500 Subject: [PATCH 3/4] Fix registry parameter validation and adjusted docs --- docs/template.md | 2 +- lib/generator.js | 10 ++++++++-- test/generator.test.js | 10 ++++++++++ 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/docs/template.md b/docs/template.md index b2a4fd2f6..d36357b56 100644 --- a/docs/template.md +++ b/docs/template.md @@ -16,7 +16,7 @@ Examples outputs: A template is an independent Node.js project unrelated to the `generator` repository. AsyncAPI templates are managed, released, and published separately. You can also create templates and manage templates on your own. -The generator uses the official [Arborist](https://www.npmjs.com/package/@npmcli/arborist) NPM library. (This means templates do not have to be published to package managers to use them.) Arborist helps the generator fetch the template's source code and use it for the generation process. By default, this library pulls data from public NPM repository, but you can pass URL and credentials for private repo in **params.registry** object. +The generator uses the official [Arborist](https://www.npmjs.com/package/@npmcli/arborist) NPM library. (This means templates do not have to be published to package managers to use them.) Arborist helps the generator fetch the template's source code and use it for the generation process. By default, this library pulls data from the default NPM registry, which is https://registry.npmjs.org. You can also configure the generator to fetch templates that are private or hosted in different NPM registries. You can store template projects on a local drive or as a `git` repository during the development process. diff --git a/lib/generator.js b/lib/generator.js index 7e7248595..5906c9f5b 100644 --- a/lib/generator.js +++ b/lib/generator.js @@ -46,7 +46,8 @@ const DEFAULT_TEMPLATES_DIR = path.resolve(ROOT_DIR, 'node_modules'); const TRANSPILED_TEMPLATE_LOCATION = '__transpiled'; const TEMPLATE_CONTENT_DIRNAME = 'template'; -const GENERATOR_OPTIONS = ['debug', 'disabledHooks', 'entrypoint', 'forceWrite', 'install', 'noOverwriteGlobs', 'output', 'templateParams', 'mapBaseUrlToFolder','registry','registryUsername','registryPassword','registryToken']; +const GENERATOR_OPTIONS = ['debug', 'disabledHooks', 'entrypoint', 'forceWrite', 'install', 'noOverwriteGlobs', 'output', 'templateParams', 'mapBaseUrlToFolder','registry']; +const REGISTRY_OPTIONS = ['url', 'username', 'password', 'token']; const logMessage = require('./logMessages'); @@ -98,8 +99,13 @@ class Generator { * @param {String} [options.registry.token] Optional parameter to pass npm registry auth token */ constructor(templateName, targetDir, { templateParams = {}, entrypoint, noOverwriteGlobs, disabledHooks, output = 'fs', forceWrite = false, install = false, debug = false, mapBaseUrlToFolder = {}, registry = {url: '', username: '', password: '', token: '' }} = {}) { - const invalidOptions = getInvalidOptions(GENERATOR_OPTIONS, arguments[arguments.length - 1] || []); + const options = arguments[arguments.length - 1]; + const invalidOptions = getInvalidOptions(GENERATOR_OPTIONS, options || []); if (invalidOptions.length) throw new Error(`These options are not supported by the generator: ${invalidOptions.join(', ')}`); + if (options && options.registry) { + const invalidRegOptions = getInvalidOptions(REGISTRY_OPTIONS, options.registry || []); + if (invalidRegOptions.length) throw new Error(`There invalid parameters were specified to configure private registry: ${invalidRegOptions.join(', ')}`); + } if (!templateName) throw new Error('No template name has been specified.'); if (!entrypoint && !targetDir) throw new Error('No target directory has been specified.'); if (!['fs', 'string'].includes(output)) throw new Error(`Invalid output type ${output}. Valid values are 'fs' and 'string'.`); diff --git a/test/generator.test.js b/test/generator.test.js index 2258b2f6e..c95f233e0 100644 --- a/test/generator.test.js +++ b/test/generator.test.js @@ -420,6 +420,16 @@ describe('Generator', () => { }, 0); }); + it('throws an error indicating an unexpected param was given for registry configuration', () => { + const t = () => new Generator('testTemplate', __dirname, { + registry: { + url: 'some.url.com', + privateKey: 'some.key' + } + }); + expect(t).toThrow('There invalid parameters were specified to configure private registry: privateKey'); + }); + it('works with a url and force = true', async () => { const gen = new Generator('https://my-test-template.com', __dirname); await gen.installTemplate(true); From 6f4a17a0f8d86578625b0cd640d478b2853a41bd Mon Sep 17 00:00:00 2001 From: atarasevich Date: Wed, 14 Dec 2022 21:29:38 -0500 Subject: [PATCH 4/4] Adjust styling --- lib/generator.js | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/lib/generator.js b/lib/generator.js index 5906c9f5b..dc13e60e0 100644 --- a/lib/generator.js +++ b/lib/generator.js @@ -402,18 +402,10 @@ class Generator { path: ROOT_DIR, }; if (this.registry) { - if (this.registry.url) { - arbOptions.registry = this.registry.url; - } - if (this.registry.username) { - arbOptions.username = this.registry.username; - } - if (this.registry.password) { - arbOptions.password = this.registry.password; - } - if (this.registry.token) { - arbOptions.token = this.registry.token; - } + if (this.registry.url) arbOptions.registry = this.registry.url; + if (this.registry.username) arbOptions.username = this.registry.username; + if (this.registry.password) arbOptions.password = this.registry.password; + if (this.registry.token) arbOptions.token = this.registry.token; } const arb = new Arborist(arbOptions);