diff --git a/bin/index.js b/bin/index.js index 5eb0a45..775098f 100755 --- a/bin/index.js +++ b/bin/index.js @@ -39,6 +39,7 @@ program .description('Generates an Entando Bundle from an existing environment into the current or selected location') .option('--env ', 'The location for the env.json file containing the description of the environment to export', 'env.json') .option('--location ', 'The location for where to store the generated Bundle', './') + .option('--exclude-microservices', 'Whether to include microservices in the export') .requiredOption('--code ', 'The code for the Bundle') .requiredOption('--description ', 'The description of the Bundle') .action(generateFromEnv); diff --git a/lib/env-bundler.js b/lib/env-bundler.js index 09dc79d..079cb75 100644 --- a/lib/env-bundler.js +++ b/lib/env-bundler.js @@ -25,13 +25,12 @@ const ALL_TYPES = [ 'contentModel', 'asset', 'content', - 'plugin', 'category', 'label', 'language', ]; -var coreBaseApi, k8ssvcApi, clientId, clientSecret, apiUrlTable; +var coreBaseApi, componentManagerApi, clientId, clientSecret, apiUrlTable; const componentDetailExtractors = { page: (components) => @@ -480,6 +479,10 @@ const componentResponseProcessor = { const plugins = componentsToFetch; const schema = { + 'descriptorVersion': { + key: 'descriptorVersion', + default: () => { return 'v4' } + }, 'metadata.name': 'name', 'spec.image': 'image', 'spec.dbms': 'dbms', @@ -487,6 +490,7 @@ const componentResponseProcessor = { 'spec.ingressPath': 'ingressPath', 'spec.roles[].code': 'roles[]', 'spec.permissions': 'permissions', + 'spec.environmentVariables': 'environmentVariables', }; return plugins.map(p => objectMapper(p, schema)); @@ -695,6 +699,10 @@ const processContentAttribute = function(attribute) { return attribute; } +const shouldExportEnvironmentVariable=function(environmentVariable) { + return environmentVariable.name != "ENTANDO_TIMESTAMP"; +} + const defaultComponentDescriptorProcessor = function(type, location, code, components) { const typePlural = typeToPlural(type); const codeExtractor = componentCodeExtractors[type]; @@ -704,12 +712,33 @@ const defaultComponentDescriptorProcessor = function(type, location, code, compo console.log(`Processing ${type}: ${code}`); const descriptorName = `${typePlural}/${code}-descriptor.yaml`; + if (type == "plugin") { + if (component.environmentVariables) { + component.environmentVariables = component.environmentVariables.filter(e => shouldExportEnvironmentVariable(e)); + } + } fs.promises.writeFile(`${location}/${descriptorName}`, yaml.safeDump(component, { lineWidth: 1000000 })); return descriptorName; }); } +const pluginComponentDescriptorProcessor = function(type, location, code, components) { + const result = defaultComponentDescriptorProcessor(type, location, code, components); + + components.forEach(c => { + if (c.environmentVariables) { + c.environmentVariables.forEach(v => { + if ('valueFrom' in v) { + console.warn(`WARNING: Extracted plugin variable "${c.name}" references a k8s secret or configmap "${v.name}" that will not be extracted`); + } + }); + } + }); + + return result; +} + const assetComponentDescriptorProcessor = function(type, location, code, components) { const typePlural = typeToPlural(type); const codeExtractor = componentCodeExtractors[type]; @@ -788,7 +817,7 @@ const componentDescriptorProcessors = { return assetComponentDescriptorProcessor(type, location, code, components); }, plugin: (type, location, code, components) => { - return defaultComponentDescriptorProcessor(type, location, code, components); + return pluginComponentDescriptorProcessor(type, location, code, components); }, group: (type, location, code, components) => { return groupIntoSingleComponentDescriptorProcessor(type, location, code, components); @@ -849,13 +878,7 @@ async function getComponents (type, componentsToFetch) { headers: { Authorization: `Bearer ${token}` }, }); - if (type === 'plugin') { - componentsToFetch = response.data._embedded && - response.data._embedded.entandoPlugins || - []; - } else { - componentsToFetch = response.data.payload; - } + componentsToFetch = response.data.payload; } // Process response and extract any aditional details @@ -940,7 +963,8 @@ const collectQuestions = [ name: 'componentType', message: 'Which type of components do you want to add to the bundle?', choices: [ - { name: 'All components', value: 'all' }, + { name: 'All components', value: 'complete' }, + { name: 'All components no Microservices', value: 'all-no-plugin' }, { name: 'Pages', value: 'page' }, { name: 'Page templates', value: 'pageModel' }, { name: 'UX Fragments', value: 'fragment' }, @@ -956,7 +980,7 @@ const collectQuestions = [ ], }, { - when: (answers) => answers.componentType !== 'all', + when: (answers) => answers.componentType !== 'all-no-plugin' && answers.componentType !== 'complete', type: 'checkbox', name: 'components', message: 'Which components do you want to include in the bundle?', @@ -977,7 +1001,7 @@ const collectQuestions = [ name: 'addMoreComponents', message: 'Do you want to add more components to the Bundle?', default: true, - when: (answers) => answers.componentType !== 'all', + when: (answers) => answers.componentType !== 'all-no-plugin' && answers.componentType !== 'complete', }, ]; @@ -1122,11 +1146,20 @@ async function inquireComponents () { var answers; do { answers = await inquirer.prompt(collectQuestions); - const type = answers.componentType; + var type = answers.componentType; var components; - if (type === 'all') { + if (type === 'all-no-plugin' || type === 'complete') { console.log('Collecting all components from the provided environment...'); + if (type === 'complete') { + ALL_TYPES.push('plugin'); + type = 'plugin'; + } else { + const offset=ALL_TYPES.indexOf("plugin") + if (offset != -1) { + ALL_TYPES.splice(offset,1) + } + } components = await collectAllComponents(); for (const type of ALL_TYPES) { @@ -1136,7 +1169,7 @@ async function inquireComponents () { components = answers.components; allAnswers[type] = components; } - } while (answers.componentType !== 'all' && answers.addMoreComponents); + } while (answers.componentType !== 'all-no-plugin' && answers.componentType !== 'complete' && answers.addMoreComponents); } async function checkFileExists (file) { @@ -1153,9 +1186,14 @@ async function setupEnvironment (options) { const envContent = JSON.parse(fs.readFileSync(options.env)); + // plugins excluded only if specified + if (options.excludeMicroservices !== true) { + ALL_TYPES.push('plugin'); + } + // Setup env variables coreBaseApi = envContent.coreBaseApi; - k8ssvcApi = envContent.k8ssvcApi; + componentManagerApi = envContent.componentManagerApi || envContent.k8ssvcApi; clientId = envContent.clientId; clientSecret = envContent.clientSecret; @@ -1178,18 +1216,20 @@ async function setupEnvironment (options) { contentModel: `${coreBaseApi}/api/plugins/cms/contentmodels`, content: `${coreBaseApi}/api/plugins/cms/contents`, asset: `${coreBaseApi}/api/plugins/cms/assets`, - plugin: `${k8ssvcApi}/plugins`, + plugin: `${componentManagerApi}/plugins`, resource: `${coreBaseApi}/api/fileBrowser?protectedFolder=false¤tPath=`, resourceDetails: `${coreBaseApi}/api/fileBrowser/file?protectedFolder=false¤tPath={path}`, }; + + token = await getToken(); + + } async function interactiveSession () { const envAnswer = await inquirer.prompt(environmentQuestions); await setupEnvironment(envAnswer); - token = await getToken(); - let confirmation; do { await inquireComponents(); diff --git a/package.json b/package.json index a3a6a28..4bb2225 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@entando/entando-bundler", - "version": "6.3.2", + "version": "7.0.2", "license": "LGPL-3.0", "description": "Command line interface to generate Entando Bundles", "repository": {