UNPKG

testbeats

Version:

Publish test results to Microsoft Teams, Google Chat, Slack and InfluxDB

251 lines (232 loc) 7.56 kB
const trp = require('test-results-parser'); const prp = require('performance-results-parser'); const beats = require('../beats'); const target_manager = require('../targets'); const logger = require('../utils/logger'); const { processData } = require('../helpers/helper'); const { ExtensionsSetup } = require('../setups/extensions.setup'); const { sortExtensionsByOrder } = require('../helpers/extension.helper'); const { BaseCommand } = require('./base.command'); class PublishCommand extends BaseCommand { /** * @param {import('../index').CommandLineOptions} opts */ constructor(opts) { super(opts); this.errors = []; } async publish() { this.printBanner(); this.validateEnvDetails(); this.buildConfig(); this.#validateOptions(); this.#processConfig(); this.#validateConfig(); this.#processResults(); await this.#setupExtensions(); await this.#publishResults(); await this.#publishErrors(); } #validateOptions() { if (!this.opts) { throw new Error('Missing publish options'); } if (!this.opts.config) { throw new Error('Missing publish config'); } } #processConfig() { const processed_config = processData(this.opts.config); /**@type {import('../index').PublishConfig[]} */ this.configs = []; if (processed_config.reports) { for (const report of processed_config.reports) { this.configs.push(report); } } else { this.configs.push(processed_config); } } #validateConfig() { logger.info("🚓 Validating configuration...") for (const config of this.configs) { this.#validateResults(config); this.#validateTargets(config); } } /** * * @param {import('../index').PublishReport} config */ #validateResults(config) { logger.debug("Validating results...") if (!config.results) { throw new Error('Missing results properties in config'); } if (!Array.isArray(config.results)) { throw new Error(`'config.results' must be an array`); } if (!config.results.length) { throw new Error('At least one result must be defined'); } for (const result of config.results) { if (!result.type) { throw new Error('Missing result type'); } if (result.type === 'custom') { if (!result.result) { throw new Error(`custom 'config.results[*].result' is missing`); } } else { if (!result.files) { throw new Error('Missing result files'); } if (!Array.isArray(result.files)) { throw new Error('result files must be an array'); } if (!result.files.length) { throw new Error('At least one result file must be defined'); } } } logger.debug("Validating results - Successful!") } /** * * @param {import('../index').PublishReport} config */ #validateTargets(config) { logger.debug("Validating targets...") if (!config.targets) { logger.warn('⚠️ Targets are not defined in config'); return; } if (!Array.isArray(config.targets)) { throw new Error('targets must be an array'); } for (const target of config.targets) { if (target.enable === false || target.enable === 'false') { continue; } if (!target.name) { throw new Error(`'config.targets[*].name' is missing`); } if (target.name === 'slack' || target.name === 'teams' || target.name === 'chat') { if (!target.inputs) { throw new Error(`missing inputs in ${target.name} target`); } } if (target.inputs) { this.#validateURL(target); } } logger.debug("Validating targets - Successful!") } #validateURL(target) { const inputs = target.inputs; if (target.name === 'slack' || target.name === 'teams' || target.name === 'chat') { if (inputs.token) { if (!Array.isArray(inputs.channels)) { throw new Error(`channels in ${target.name} target inputs must be an array`); } if (!inputs.channels.length) { throw new Error(`at least one channel must be defined in ${target.name} target inputs`); } for (const channel of inputs.channels) { if (typeof channel !== 'string') { throw new Error(`channel in ${target.name} target inputs must be a string`); } } return; } if (!inputs.url) { throw new Error(`missing url in ${target.name} target inputs`); } if (typeof inputs.url !== 'string') { throw new Error(`url in ${target.name} target inputs must be a string`); } if (!inputs.url.startsWith('http')) { throw new Error(`url in ${target.name} target inputs must start with 'http' or 'https'`); } } } #processResults() { logger.info('🧙 Processing results...'); this.results = []; for (const config of this.configs) { for (const result_options of config.results) { if (result_options.type === 'custom') { this.results.push(result_options.result); } else if (result_options.type === 'jmeter') { this.results.push(prp.parse(result_options)); } else { const { result, errors } = trp.parseV2(result_options); if (result) { this.results.push(result); } if (errors) { this.errors = this.errors.concat(errors); } } } } } async #setupExtensions() { logger.info('⚙️ Setting up extensions...'); try { for (const config of this.configs) { const extensions = config.extensions || []; const setup = new ExtensionsSetup(extensions, this.results ? this.results[0] : null); await setup.run(); } } catch (error) { logger.error(`❌ Error setting up extensions: ${error.message}`); } } async #publishResults() { if (!this.results.length) { logger.warn('⚠️ No results to publish'); return; } for (const config of this.configs) { for (let i = 0; i < this.results.length; i++) { const result = this.results[i]; if (config.api_key) { result.name = config.run || result.name || 'demo-run'; } config.extensions = config.extensions || []; await beats.run(config, result); if (config.targets) { for (const target of config.targets) { if (target.enable === false || target.enable === 'false') { continue; } target.extensions = target.extensions || []; target.extensions = config.extensions.concat(target.extensions); target.extensions = sortExtensionsByOrder(target.extensions); await target_manager.run(target, result); } } else { logger.warn('⚠️ No targets defined, skipping sending results to targets'); } } } logger.info('✅ Results published successfully!'); } async #publishErrors() { if (!this.errors.length) { logger.debug('⚠️ No errors to publish'); return; } logger.info('🛑 Publishing errors...'); for (const config of this.configs) { if (config.targets) { for (const target of config.targets) { await target_manager.handleErrors({ target, errors: this.errors }); } } } throw new Error(this.errors.join('\n')); } } module.exports = { PublishCommand }