UNPKG

msbot

Version:

MSBot command line tool for manipulating Microsoft Bot Framework .bot files

283 lines 12.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); /** * Copyright(c) Microsoft Corporation.All rights reserved. * Licensed under the MIT License. */ // tslint:disable:no-console // tslint:disable:no-object-literal-type-assertion const botframework_config_1 = require("botframework-config"); const chalk = require("chalk"); const program = require("commander"); const fsx = require("fs-extra"); const process = require("process"); const processUtils_1 = require("./processUtils"); const utils_1 = require("./utils"); program.Command.prototype.unknownOption = (flag) => { console.error(chalk.default.redBright(`Unknown arguments: ${flag}`)); program.help(); }; program .name('msbot export services') .description('export all of the connected services to local folder with .bot.recipe file to support cloning') .option('-f, --folder <folder>', 'path to folder to place exported resources') .option('--verbose', 'show verbose export information') .option('-q, --quiet', 'disable output') .option('-b, --bot <path>', 'path to bot file. If omitted, local folder will look for a .bot file') .option('--secret <secret>', 'bot file secret password for encrypting service secrets') .option('--prefix', 'Append [msbot] prefix to all messages') .action((cmd, actions) => undefined); const command = program.parse(process.argv); const args = {}; Object.assign(args, command); args.verbose = process.env.VERBOSE === 'verbose'; if (!args.bot) { botframework_config_1.BotConfiguration.loadBotFromFolder(process.cwd(), args.secret) .then(processConfiguration) .catch((reason) => { console.error(chalk.default.redBright(reason.toString().split('\n')[0])); showErrorHelp(); }); } else { botframework_config_1.BotConfiguration.load(args.bot, args.secret) .then(processConfiguration) .catch((reason) => { console.error(chalk.default.redBright(reason.toString().split('\n')[0])); showErrorHelp(); }); } async function processConfiguration(config) { if (!args.folder) { throw new Error('missing --folder argument'); } try { const recipe = await exportBot(config, args.folder, { progress: (service, newCommand, index, total) => { if (!args.quiet) { const output = `exporting ${chalk.default.bold(service.name)} [${service.type}] (${index}/${total})`; if (args.verbose) { console.warn(chalk.default.bold(output)); console.log(chalk.default.italic(`${newCommand}\n`)); } else { console.warn(output); } } } }); } catch (error) { const lines = error.message.split('\n'); for (const line of lines) { // trim to copywrite symbol, help from inner process command line args is inappropriate if (line.indexOf('©') > 0) { process.exit(1); } console.error(chalk.default.redBright(line)); } } } // export the services from the bot file as resource files and recipe file async function exportBot(config, folder, exportOptions) { let options = Object.assign({ download: true }, exportOptions); let recipe = new botframework_config_1.BotRecipe(); await fsx.ensureDir(folder); let index = 0; for (let service of config.services) { index++; switch (service.type) { case botframework_config_1.ServiceTypes.Dispatch: { await exportLuisService(service); let dispatchResource = { type: service.type, id: service.id, name: service.name, serviceIds: service.serviceIds }; recipe.resources.push(dispatchResource); } break; case botframework_config_1.ServiceTypes.Luis: { await exportLuisService(service); let resource = { type: service.type, id: service.id, name: service.name }; recipe.resources.push(resource); } break; case botframework_config_1.ServiceTypes.QnA: { let qnaService = service; if (options.download) { let command = `qnamaker export kb --kbId ${qnaService.kbId} --environment prod --subscriptionKey ${qnaService.subscriptionKey} --hostname ${qnaService.hostname} --endpointKey ${qnaService.endpointKey}`; if (options.progress) { options.progress(service, command, index, config.services.length); } let json = ''; await processUtils_1.spawnAsync(command, (stdout) => json += stdout, (stderr) => console.error(stderr)); // make sure it's json JSON.parse(json); await fsx.writeFile(folder + `/${qnaService.id}.qna`, json, { encoding: 'utf8' }); } else { if (options.progress) { options.progress(service, '', index, config.services.length); } } let resource = { type: service.type, id: service.id, name: service.name }; recipe.resources.push(resource); } break; case botframework_config_1.ServiceTypes.Endpoint: { if (options.progress) { options.progress(service, '', index, config.services.length); } let endpointResource = { type: botframework_config_1.ServiceTypes.Endpoint, id: service.id, name: service.name, url: service.endpoint }; recipe.resources.push(endpointResource); } break; case botframework_config_1.ServiceTypes.BlobStorage: { if (options.progress) { options.progress(service, '', index, config.services.length); } let blobResource = { type: botframework_config_1.ServiceTypes.BlobStorage, id: service.id, name: service.name, container: service.container || '' }; recipe.resources.push(blobResource); } break; case botframework_config_1.ServiceTypes.CosmosDB: { if (options.progress) { options.progress(service, '', index, config.services.length); } let cosmosDBResource = { type: botframework_config_1.ServiceTypes.CosmosDB, id: service.id, name: service.name, database: service.database, collection: service.collection, }; recipe.resources.push(cosmosDBResource); } break; case botframework_config_1.ServiceTypes.File: { if (options.progress) { options.progress(service, '', index, config.services.length); } let fileResource = { type: botframework_config_1.ServiceTypes.File, id: service.id, name: service.name, path: service.path, }; recipe.resources.push(fileResource); } break; case botframework_config_1.ServiceTypes.Generic: { if (options.progress) { options.progress(service, '', index, config.services.length); } console.warn(`WARNING: Generic services cannot be cloned and all configuration data will be passed unchanged and unencrypted `); let genericService = service; let genericResource = { type: botframework_config_1.ServiceTypes.Generic, id: service.id, name: service.name, url: genericService.url, configuration: genericService.configuration, }; recipe.resources.push(genericResource); } break; case botframework_config_1.ServiceTypes.Bot: { if (options.progress) { options.progress(service, '', index, config.services.length); } let resource = { type: service.type, id: service.id, name: service.name }; recipe.resources.push(resource); } break; case botframework_config_1.ServiceTypes.AppInsights: { if (options.progress) { options.progress(service, '', index, config.services.length); } let resource = { type: service.type, id: service.id, name: service.name }; recipe.resources.push(resource); } break; default: if (options.progress) { options.progress(service, '', index, config.services.length); } console.warn(`WARNING: Unknown service type [${service.type}]. This service will not be exported.`); break; } } await fsx.writeFile(folder + `/bot.recipe`, JSON.stringify(recipe, null, 2), { encoding: 'utf8' }); return recipe; async function exportLuisService(service) { let luisService = service; if (options.download) { const luisAuthoringRegion = utils_1.regionToLuisAuthoringRegionMap[luisService.region]; let command = `luis export version --region ${luisAuthoringRegion} --appId ${luisService.appId} --authoringKey ${luisService.authoringKey} --versionId "${luisService.version}"`; if (options.progress) { options.progress(service, command, index, config.services.length); } let json = ''; await processUtils_1.spawnAsync(command, (stdout) => json += stdout, (stderr) => console.error(stderr)); // make sure it's json try { JSON.parse(json); } catch (err) { throw new Error(`${err.message || err}\n${json}`); } await fsx.writeFile(folder + `/${luisService.id}.luis`, json, { encoding: 'utf8' }); } else { if (options.progress) { options.progress(service, '', index, config.services.length); } } } } function showErrorHelp() { program.outputHelp((str) => { console.error(str); return ''; }); process.exit(1); } //# sourceMappingURL=msbot-export-services.js.map