Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: template pulling with npm config #1069

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/pr-testing-with-test-project.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
node: [ '12', '14', '16', '18' ]
node: [ '18', '20' ]
steps:
- name: Checkout repository
uses: actions/checkout@v3
Expand Down
4 changes: 2 additions & 2 deletions docs/installation-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ You can use the generator library to generate whatever you want in your event-dr

## Prerequisites
Before you install and use the AsyncAPI CLI and the generator library, ensure you meet the prerequisites below, then [install the CLI](#installation).
1. Node.js v12.16 and higher
2. Npm v6.13.7 and higher
1. Node.js v18.12.0 and higher
2. Npm v8.19.0 and higher

To verify the versions of Node and Npm you have, run the following command on your terminal:
```
Expand Down
20 changes: 16 additions & 4 deletions docs/using-private-template.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,26 @@
title: "Using private templates"
weight: 180
---
Generator allows fetching the template from private repositories like Verdaccio, Nexus, npm, etc.
Generator allows fetching the template from private repositories like Verdaccio, Nexus, npm, etc.
By default, the generator fetches the template from the public npm registry configured in the npm configuration.
To fetch the template from a private registry, you need to provide the registry URL and authentication details in the .npmrc. For more information [read the docs](https://docs.npmjs.com/cli/v9/configuring-npm/npmrc).
However, you can override the default behavior by providing the registry URL and authentication details as arguments of the commandline.


## Private registry options:
## Private registry using .npmrc:
```bash
npm config set registry http://verdaccio:4873
npm config set //verdaccio:4873/:_auth=$(echo -n 'username:password' | base64)
```
* **npm config set registry** : Provide the registry URL that points to the registry URL.
* **npm config set _auth** : Provide the base64 encoded value that represents the username and password for basic auth.
* **npm config set _authToken** : Provide the access token generated by the registry.

## Private registry overriding arguments:

* **registry.url**: The URL of the registry where the private template is located. Defaults to `registry.npmjs.org`.
* **registry.auth**: An optional parameter to pass the npm registry username and password encoded with base64, formatted as `username:password`. For example, if the username and password are `admin` and `nimda`, you need to encode them with the base64 value like `admin:nimda` which results in `YWRtaW46bmltZGE=`.
**registry.token**: An optional parameter to pass to the npm registry authentication token. To get the token, you can first authenticate with the registry using `npm login` and then grab the generated token from the `.npmrc` file.
* **registry.token**: An optional parameter to pass to the npm registry authentication token. To get the token, you can first authenticate with the registry using `npm login` and then grab the generated token from the `.npmrc` file.

## Pulling private template using library:

Expand All @@ -26,4 +38,4 @@ const generator = new Generator('@asyncapi/html-template', 'output',
}
});
```
Assuming you host `@asyncapi/html-template` in a private package registry like Verdaccio. To pull this template, you need to provide `registry.url` option that points to the registry URL and `registry.auth` as a base64 encoded value that represents the username and password. Instead of username and password, you can also pass `registry.token`.
Assuming you host `@asyncapi/html-template` in a private package registry like Verdaccio. To pull this template, you need to provide `registry.url` option that points to the registry URL and `registry.auth` as a base64 encoded value that represents the username and password. Instead of username and password, you can also pass `registry.token`.
47 changes: 30 additions & 17 deletions lib/generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ const filenamify = require('filenamify');
const git = require('simple-git');
const log = require('loglevel');
const Arborist = require('@npmcli/arborist');
const Config = require('@npmcli/config');
const requireg = require('requireg');
const npmPath = requireg.resolve('npm').replace('index.js','');

const { isAsyncAPIDocument } = require('@asyncapi/parser/cjs/document');

const { configureReact, renderReact, saveRenderedReactContent } = require('./renderer/react');
Expand All @@ -31,6 +35,7 @@ const {
const { parse, usesNewAPI, getProperApiDocument } = require('./parser');
const { registerFilters } = require('./filtersRegistry');
const { registerHooks } = require('./hooksRegistry');
const { definitions, flatten, shorthands } = require('@npmcli/config/lib/definitions');

const FILTERS_DIRNAME = 'filters';
const HOOKS_DIRNAME = 'hooks';
Expand Down Expand Up @@ -532,7 +537,7 @@ class Generator {
arbOptions.registry = providedRegistry;
registryUrl = providedRegistry;
}

const domainName = registryUrl.replace(/^https?:\/\//, '');
//doing basic if/else so basically only one auth type is used and token as more secure is primary
if (this.registry.token) {
Expand All @@ -541,11 +546,12 @@ class Generator {
} else if (this.registry.auth) {
authorizationName = `//${domainName}:_auth`;
arbOptions[authorizationName] = this.registry.auth;
}
}

//not sharing in logs neither token nor auth for security reasons
log.debug(`Using npm registry ${registryUrl} and authorization type ${authorizationName} to handle template installation.`);
}

/**
* Downloads and installs a template and its dependencies
*
Expand All @@ -556,14 +562,14 @@ class Generator {
let pkgPath;
let installedPkg;
let packageVersion;

try {
installedPkg = getTemplateDetails(this.templateName, PACKAGE_JSON_FILENAME);
pkgPath = installedPkg && installedPkg.pkgPath;
packageVersion = installedPkg && installedPkg.version;
log.debug(logMessage.templateSource(pkgPath));
if (packageVersion) log.debug(logMessage.templateVersion(packageVersion));

return {
name: installedPkg.name,
path: pkgPath
Expand All @@ -573,38 +579,45 @@ class Generator {
// We did our best. Proceed with installation...
}
}

const debugMessage = force ? logMessage.TEMPLATE_INSTALL_FLAG_MSG : logMessage.TEMPLATE_INSTALL_DISK_MSG;
log.debug(logMessage.installationDebugMessage(debugMessage));

if (isFileSystemPath(this.templateName)) log.debug(logMessage.NPM_INSTALL_TRIGGER);

const arbOptions = {
path: ROOT_DIR,
};
if (this.registry) {

const config = new Config({
definitions,
flatten,
shorthands,
npmPath
});

await config.load();

const arbOptions = {...{path: ROOT_DIR}, ...config.flat};

if (Object.keys(this.registry).length !== 0) {
derberg marked this conversation as resolved.
Show resolved Hide resolved
this.initialiseArbOptions(arbOptions);
}

const arb = new Arborist(arbOptions);

try {
const installResult = await arb.reify({
add: [this.templateName],
saveType: 'prod',
save: false
});

const addResult = arb[Symbol.for('resolvedAdd')];
if (!addResult) throw new Error('Unable to resolve the name of the added package. It was most probably not added to node_modules successfully');

const packageName = addResult[0].name;
const packageVersion = installResult.children.get(packageName).version;
const packagePath = installResult.children.get(packageName).path;

if (!isFileSystemPath(this.templateName)) log.debug(logMessage.templateSuccessfullyInstalled(packageName, packagePath));
if (packageVersion) log.debug(logMessage.templateVersion(packageVersion));

return {
name: packageName,
path: packagePath,
Expand Down
Loading
Loading