UNPKG

@unito/integration-cli

Version:

Integration CLI

228 lines (225 loc) 11.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const tslib_1 = require("tslib"); const core_1 = require("@oclif/core"); const chalk_1 = tslib_1.__importDefault(require("chalk")); const child_process_1 = tslib_1.__importDefault(require("child_process")); const crawlerDriver_1 = require("@unito/integration-debugger/dist/src/services/crawlerDriver"); const baseCommand_1 = require("../baseCommand"); const errors_1 = require("../errors"); const GlobalConfiguration = tslib_1.__importStar(require("../resources/globalConfiguration")); const integrations_1 = require("../resources/integrations"); const configuration_1 = require("../resources/configuration"); const decryption_1 = require("../resources/decryption"); const credentials_1 = require("../resources/credentials"); class Test extends baseCommand_1.BaseCommand { static description = 'Test your integration'; static examples = ['<%= config.bin %> <%= command.id %>']; static flags = { environment: core_1.Flags.custom({ description: 'the environment of the platform', options: Object.values(GlobalConfiguration.Environment), default: GlobalConfiguration.Environment.Production, })(), verbose: core_1.Flags.boolean({ description: 'output more (debug) information', default: false, }), 'starting-path': core_1.Flags.string({ description: 'starting path of the crawler', default: '/', }), 'starting-operation': core_1.Flags.custom({ description: 'starting operation of the crawler', options: Object.values(crawlerDriver_1.Operation), default: crawlerDriver_1.Operation.GetItem, })(), 'output-path': core_1.Flags.string({ description: 'output report in JSON format at the specified path', }), 'credential-payload': core_1.Flags.string({ description: '(advanced) credential payload to use.', exclusive: ['credential-id'], }), 'credential-id': core_1.Flags.string({ description: '(advanced) credential to use.', exclusive: ['credential-payload'], }), 'test-account': core_1.Flags.string({ description: 'test account to use.', options: Object.values(configuration_1.CredentialScope), default: configuration_1.CredentialScope.DEVELOPMENT, }), 'read-only': core_1.Flags.boolean({ description: 'whether or not to only perform read operations', allowNo: true, }), timeout: core_1.Flags.integer({ description: `timeout in seconds passed as 'X-Unito-Operation-Deadline' header to the integration. Set to 0 for no timeout.`, default: 20, // Test mode has a default timeout of 20 seconds. }), crawlMode: core_1.Flags.string({ description: 'mode to use while crawling the integration graph', options: Object.values(configuration_1.CrawlMode), default: configuration_1.CrawlMode.FULL, }), checks: core_1.Flags.string({ description: 'checks to perform while crawling the integration graph', multiple: true, default: [], }), debug: core_1.Flags.boolean({ description: 'log launch command to console before running it - including decrypted values - for debugging only', hidden: true, default: false, }), 'config-path': core_1.Flags.string({ summary: 'relative path to a custom ".unito.json" file', description: `use a custom configuration file instead of the default '.unito.json' or other environment specific ones. If you want to force the CLI to use a specific configuration file, you can use this flag to specify the relative path from your integration's root folder (with a leading '/'). Usage: <%= config.bin %> <%= command.id %> --config-path=/myCustomConfig.json`, }), 'skip-install': core_1.Flags.boolean({ description: 'whether or not to run npm install before starting the integration. Useful when npx linking modules to the integration.', allowNo: true, default: false, }), }; async catch(error) { /* istanbul ignore if */ if ((0, errors_1.handleError)(this, error)) { this.exit(-1); } throw error; } async run() { (0, integrations_1.validateIsIntegrationDirectory)(); const { flags } = await this.parse(Test); if (!flags['skip-install']) { // Install NPM dependencies. core_1.ux.action.start('Installing NPM dependencies', undefined, { stdout: true }); child_process_1.default.execSync('npm install', { env: { ...process.env, NODE_ENV: 'development' }, stdio: ['ignore', 'ignore', 'inherit'], }); core_1.ux.action.stop(); } // Resolve the configuration. const environment = flags.environment ?? GlobalConfiguration.Environment.Production; const configuration = await (0, configuration_1.getConfiguration)(environment, flags['config-path']); let credentialPayload = '{}'; let readOnly = flags['read-only'] ?? false; if (flags['credential-id']) { const credential = await (0, credentials_1.fetchCredential)(environment, this.config.configDir, flags['credential-id']); credentialPayload = JSON.stringify({ ...credential.payload, unitoCredentialId: credential.id, unitoUserId: credential.unitoUserId, }); // When "credential-id" is provided, the default value of "read-only" is false. readOnly = flags['read-only'] ?? true; } else if (flags['credential-payload']) { credentialPayload = flags['credential-payload']; } else { const credentials = configuration.testAccounts?.[flags['test-account']]; if (credentials) { const decryptedEntries = await (0, decryption_1.decryptEntries)(configuration.name, environment, this.config.configDir, credentials); if (decryptedEntries.failed.length) { throw new errors_1.EntryDecryptionError(decryptedEntries.failed.at(0), environment); } credentialPayload = JSON.stringify({ ...decryptedEntries.successful, unitoCredentialId: flags['test-account'], unitoUserId: flags['test-account'], }); } } // Load secrets. const { successful: secrets, failed: failedSecrets } = await (0, decryption_1.decryptEntries)(configuration.name, environment, this.config.configDir, configuration.secrets ?? {}); if (failedSecrets.length) { throw new errors_1.EntryDecryptionError(failedSecrets.at(0), environment); } // Load environment variables. const { successful: environmentVariables, failed: failedEnvironmentVariables } = await (0, decryption_1.decryptEntries)(configuration.name, environment, this.config.configDir, configuration.environmentVariables ?? {}); for (const environmentVariable of failedEnvironmentVariables) { if (!process.env[environmentVariable]) { core_1.ux.log(); core_1.ux.log(`Could not decrypt the environment variable ${chalk_1.default.yellowBright(environmentVariable)}.`); core_1.ux.log('It may be a normal behavior locally as some environment variables are sensitive secrets.'); core_1.ux.log(`You can still pass ${chalk_1.default.yellowBright(`${environmentVariable}=<value>`)} to the CLI command to provide a value for this environment variable.`); core_1.ux.log(`Example: ${chalk_1.default.yellowBright(`${environmentVariable}=foo ${this.config.bin} ${this.id}`)}`); } } // Launch the tests. const commandArguments = [ `${process.env.NODE_MODULES_FOLDER}/@unito/integration-debugger/dist/src/index.js`, '--integration-url=http://localhost:9200', '--spawn-process=npm run dev', `--credential-payload=${credentialPayload}`, `--secrets-payload=${JSON.stringify(secrets)}`, '--non-interactive', `--starting-path=${flags['starting-path']}`, `--starting-operation=${flags['starting-operation']}`, ]; if (readOnly) { commandArguments.push('--read-only'); } if (flags.timeout) { commandArguments.push(`--timeout=${flags.timeout}`); } if (configuration.graphRelativeUrl) { commandArguments.push(`--graph-relative-url=${configuration.graphRelativeUrl}`); } if (configuration.credentialAccountRelativeUrl) { commandArguments.push(`--credential-account-relative-url=${configuration.credentialAccountRelativeUrl}`); } if (configuration.webhookParsingRelativeUrl) { commandArguments.push(`--webhook-parsing-relative-url=${configuration.webhookParsingRelativeUrl}`); } if (configuration.webhookSubscriptionsRelativeUrl) { commandArguments.push(`--webhook-subscriptions-relative-url=${configuration.webhookSubscriptionsRelativeUrl}`); } if (configuration.webhookAcknowledgeRelativeUrl) { commandArguments.push(`--webhook-acknowledge-relative-url=${configuration.webhookAcknowledgeRelativeUrl}`); } if (flags.checks?.length) { commandArguments.push(`--checks=${flags.checks.join(',')}`); } if (flags.verbose) { commandArguments.push('--verbose'); } if (flags['output-path']) { commandArguments.push(`--output-path=${flags['output-path']}`); } if (flags['crawlMode'] === configuration_1.CrawlMode.SAMPLE) { commandArguments.push('--operation-collection-items-per-page=5'); commandArguments.push('--operation-collection-follow-next-pages=false'); } if (flags['crawlMode'] === configuration_1.CrawlMode.SINGLE) { commandArguments.push('--operation-collection-items-per-page=1'); commandArguments.push('--operation-collection-follow-next-pages=false'); } if (flags.debug) { core_1.ux.log(`Launching... node ${commandArguments.join(' ')}`); } const child = child_process_1.default.spawn('node', commandArguments, { detached: true, stdio: 'inherit', env: { ...process.env, ...environmentVariables, NODE_ENV: 'development', PORT: '9200' }, }); // istanbul ignore next child.on('exit', (code) => { process.exit(code); }); // Window change (ex: resize) signal. // istanbul ignore next process.on('SIGWINCH', () => { child.kill('SIGWINCH'); }); } } exports.default = Test;