@axway/axway-central-cli
Version:
Manage APIs, services and publish to the Amplify Marketplace
272 lines (262 loc) • 11.6 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.get = void 0;
var _chalk = _interopRequireDefault(require("chalk"));
var _snooplogg = _interopRequireDefault(require("snooplogg"));
var _ApiServerClient = require("../../common/ApiServerClient");
var _DefinitionsManager = require("../../common/DefinitionsManager");
var _Renderer = _interopRequireDefault(require("../../common/Renderer"));
var _resultsRenderers = require("../../common/resultsRenderers");
var _types = require("../../common/types");
var _utils = require("../../common/utils");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
const {
log
} = (0, _snooplogg.default)('engage: get');
const getListOrByName = async (resourceDef, client, scopeName, resourceName, scopeDef, query, progressListener, expand, langDef, fieldSet) => {
return resourceName ? await client.getResourceByName({
resourceDef,
resourceName,
scopeDef,
scopeName,
expand,
langDef,
fieldSet
}) : await client.getResourcesList({
resourceDef,
scopeDef,
scopeName,
query,
progressListener,
expand,
langDef,
fieldSet
});
};
const get = exports.get = {
action: async function ({
argv,
console
}) {
if (!argv.team && argv.owner === false) {
// no --team set and --no-owner was set, so we set the team to `null` which will know
// to get teams that do not have an owner
argv.team = null;
}
const {
args,
attribute,
baseUrl,
cache,
account,
region,
tag,
team,
title
} = argv;
// will be set to true and exit 1 if any get result contains an error or args invalid
let isCmdError = true;
// name can be provided or not (args[0] is the resource type)
const resourceName = args[1];
// verify output argument
if (!!argv.output && !(argv.output in _types.OutputTypes)) throw Error(`invalid "output" (-o,--output) value provided, allowed: ${_types.OutputTypes.yaml} | ${_types.OutputTypes.json}`);
const renderer = new _Renderer.default(console, argv.output);
const getResults = [];
try {
// get specs and allowed words
const client = new _ApiServerClient.ApiServerClient({
baseUrl,
account,
region,
team,
useCache: cache
});
const defsManager = await new _DefinitionsManager.DefinitionsManager(client).init();
const scope = (0, _utils.parseScopeParam)(argv.scope);
let languageExpand = argv.language;
const languageDefinition = argv.languageDefinition;
const formattedFilter = (0, _utils.transformSimpleFilters)(title, attribute, tag);
const query = argv.query ? argv.query : formattedFilter;
// verify either "--language" or "--languageDefinition" argument is passed and error when both are passed
if (languageExpand && languageDefinition) {
throw Error('You must specify either of the "--language" or "--languageDefinition" argument and not both.');
}
if (languageDefinition && !argv.output) {
throw Error('The "--languageDefinition" argument can only be used with output(-o,--output) argument');
}
if (languageExpand) {
// when "*" is provided, expand all supported languages
let lang = "";
let i = 0;
if (languageExpand.trim() === "*") {
lang = "languages-*";
} else {
let langCodeArr = languageExpand.split(',');
langCodeArr.forEach(v => {
if (i < langCodeArr.length - 1) {
lang = lang + "languages-" + v.trim() + ",";
} else {
lang = lang + "languages-" + v.trim();
}
i++;
});
}
languageExpand = 'languages,' + lang;
}
if (argv.query && formattedFilter) {
console.log(`${_chalk.default.yellow('Both simple queries and advanced query parameters have been provided. Only the advanced query parameter will be applied.')}`);
}
// verify passed args
if (!args.length) {
renderer.error('Error: You must specify the type of resource to get.');
console.log(`\nUSAGE:
Get a list of the resources:
${_chalk.default.cyan(`axway engage get <Resource>`)}\n
Get a list of multiple resources:
${_chalk.default.cyan(`axway engage get <Resource1>,<Resource2>,...,<ResourceN>`)}\n
Get a list of resources in a specific scope:
${_chalk.default.cyan(`axway engage get <Resource> -s/--scope <Scope Kind>/<Scope Name>`)}\n
Get a list of resources matching a specific RSQL query:
${_chalk.default.cyan(`axway engage get <Resource> -q/--query "<RSQL query>"`)}\n
Get a specific resource by name in all scopes with a specific name:
${_chalk.default.cyan(`axway engage get <Resource> <Name> -s/--scope <Scope Name>`)}\n
Get a specific resource by name in a specific scope:
${_chalk.default.cyan(`axway engage get <Resource> <Name> -s/--scope <Scope Kind>/<Scope Name>`)}\n
The server supports the following resources:
${defsManager.getDefsTableForHelpMsg()}`);
process.exit(1);
}
// Start showing download progress.
const downloadMessage = 'Retrieving resource(s)';
renderer.startSpin(downloadMessage);
const progressListener = percent => {
renderer.updateSpinText(`${downloadMessage} - ${percent}%`);
};
// parse passed resources types (if passed comma-separated)
for (const typedResource of args[0].split(',')) {
const defs = defsManager.findDefsByWord(typedResource);
// is typed resource known?
if (!defs) throw Error(`the server doesn't have a resource type "${typedResource}"`);
// check if a user is trying to get a scoped-only resource by name without providing a scope name
if (defs.every(defs => !!defs.scope) && resourceName && !scope) throw Error(`scope name param (-s/--scope) is required for the scoped "${defs[0].resource.spec.kind}" resource.`);
// verify passed scope param kind
(0, _utils.verifyScopeParam)(defsManager.getAllKindsList(), defs, scope);
/**
1) If "scope" param provided: execute getByName or getList calls for every definition that match this scope name/kind.
2) If "scope" param is not provided: execute list (get all) api calls for scoped resources without providing the scope in
the path so api-server returns the entire list in all scopes. For example, using "Document" kind and calling
https://apicentral.axway.com/apis/catalog/v1alpha1/documents returns a list of documents in Asset and AssetRelease
scopes in a single api call. So getting unique list of groups and finding first matching definitions to do a call
Note: this logic might have some edge cases if same kind can be used for "scoped" and "scope" resources and api-server is
not handling this case correctly anymore.
*/
if (scope) {
const results = await Promise.all(defs.filter(defs => !scope.kind || !defs.scope || defs.scope.spec.kind === scope.kind).map(async defs => ({
response: await getListOrByName(defs.resource, client, scope.name, resourceName, defs.scope, query, progressListener, languageExpand, languageDefinition, argv.output ? undefined : getFieldSetFromDefinitionColumns(defs)),
cli: defs.cli
})));
results.forEach(({
response,
cli
}) => {
getResults.push({
columns: cli.spec.columns,
response
});
});
} else {
const defsMatchingGroup = {};
defs.forEach(def => {
if (!defsMatchingGroup[def.resource.metadata.scope.name]) {
defsMatchingGroup[def.resource.metadata.scope.name] = def;
}
});
const results = await Promise.all(Object.values(defsMatchingGroup).map(async defs => ({
response: await getListOrByName(defs.resource, client, undefined, resourceName, undefined, query, progressListener, languageExpand, languageDefinition, argv.output ? undefined : getFieldSetFromDefinitionColumns(defs)),
cli: defs.cli
})));
results.forEach(({
response,
cli
}) => {
getResults.push({
columns: cli.spec.columns,
response
});
});
}
}
// resolve team guids
for (const obj of getResults) {
await (0, _resultsRenderers.resolveTeamNames)(obj);
}
// considering the command successful if at least 1 response found
isCmdError = !getResults.filter(res => res.response.data !== null).length;
renderer.renderGetResults(getResults, 'Resource(s) successfully retrieved', languageDefinition);
} catch (e) {
log('command error', e);
isCmdError = true;
renderer.anyError(e);
} finally {
log('command complete');
renderer.stopSpin();
if (isCmdError) process.exit(1);
}
},
desc: 'List one or more resources',
args: [{
name: 'args',
desc: 'Command arguments, run "axway engage get" to see the examples',
multiple: true,
required: false
}],
options: {
..._types.commonCmdArgsDescription,
'-o, --output [value]': {
desc: `Additional output formats. One of: ${_types.OutputTypes.yaml} | ${_types.OutputTypes.json}`
},
'-s, --scope [name|kind/name]': {
desc: 'Scope name or kind/name for scoped resources'
},
'-q, --query [RSQL query]': {
desc: 'RSQL-formatted query to search for filters that match specific parameters'
},
'--title [title]': {
desc: 'Title of resource(s) to fetch'
},
'--attribute [key=value]': {
desc: 'Attribute in key=value pair format to filter by'
},
'--tag [tag]': {
desc: 'Tag of resource(s) to fetch'
},
'--team [guid|name]': 'The team name or guid to use',
'--no-owner': 'Returns resources which do not have an owner',
'--language=[langCode]': {
desc: `Show the language detail of the retruned object. One of: * | Comma Separated values of ${_types.LanguageTypes.French} | ${_types.LanguageTypes.US} | ${_types.LanguageTypes.German} | ${_types.LanguageTypes.Portugese}`
},
'--languageDefinition=[langCode]': {
desc: `Show the language definition constraint of the returned object. One of: Comma Separated values of ${_types.LanguageTypes.French} | ${_types.LanguageTypes.US} | ${_types.LanguageTypes.German} | ${_types.LanguageTypes.Portugese}`
}
}
};
/**
* Gets the resource field names to be shown when outputting the resource as a table.
* These names are to be assigned to the api-server HTTP GET request's "fields" query param.
* @param def The resource definition providing the columns to be shown in the outputed table.
* @returns Returns a set set of field names.
*/
function getFieldSetFromDefinitionColumns(def) {
var _def$cli, _def$cli$spec, _def$cli$spec$columns;
const fieldSet = new Set();
(_def$cli = def.cli) === null || _def$cli === void 0 ? void 0 : (_def$cli$spec = _def$cli.spec) === null || _def$cli$spec === void 0 ? void 0 : (_def$cli$spec$columns = _def$cli$spec.columns) === null || _def$cli$spec$columns === void 0 ? void 0 : _def$cli$spec$columns.forEach(column => {
let fieldName = column.jsonPath;
if (fieldName.startsWith('.')) {
fieldName = fieldName.substring(1);
}
fieldSet.add(fieldName);
});
return fieldSet;
}