diff --git a/packages/owl-bot/src/bin/commands/validate.ts b/packages/owl-bot/src/bin/commands/validate.ts index 412e8b2494c..7366b8a5e32 100644 --- a/packages/owl-bot/src/bin/commands/validate.ts +++ b/packages/owl-bot/src/bin/commands/validate.ts @@ -17,31 +17,86 @@ import {owlBotYamlFromText} from '../../config-files'; import {promisify} from 'util'; import {readFile} from 'fs'; +import * as fs from 'fs'; import yargs = require('yargs'); +import {collectConfigs} from '../../configs-store'; const readFileAsync = promisify(readFile); interface Args { config: string; + 'ignore-regexp': string[]; } export const validate: yargs.CommandModule<{}, Args> = { - command: 'validate ', - describe: 'validate .OwlBot.yaml', + command: 'validate |', + describe: 'validates a config or all the configs in a directory', builder(yargs) { - return yargs.option('config', { - describe: 'path to .OwlBot.yaml', - type: 'string', - demand: true, - }); + return yargs + .option('config', { + describe: 'path to .OwlBot.yaml or directory', + type: 'string', + demand: true, + }) + .option('ignore-regexp', { + describe: + 'regular expression of paths to ignore while scanning the ' + + 'directory. Example: .*/templates/.*', + type: 'array', + demand: false, + default: [], + }); }, async handler(argv) { - try { - const yamlText = await readFileAsync(argv.config, 'utf8'); - owlBotYamlFromText(yamlText); - console.info(`${argv.config} is valid`); - } catch (e) { - console.info(e); + const stat = fs.statSync(argv.config); + if (stat.isFile()) { + // Validate one config. + try { + const yamlText = await readFileAsync(argv.config, 'utf8'); + owlBotYamlFromText(yamlText); + console.info(`${argv.config} is valid`); + } catch (e) { + console.error(e); + const error = e instanceof Error ? e : Error(String(e)); + yargs.exit(-1, error); + } + } else if (stat.isDirectory()) { + // Validate all the configs in the directory. + const configs = collectConfigs(argv.config); + + // Tell the user all the valid configs. + for (const config of configs.yamls) { + console.log(`${config.path} is valid`); + } + + // Ignore the bad configs the user asked us to ignore. + const ignores = argv['ignore-regexp'].map(pattern => new RegExp(pattern)); + const badConfigs = configs.badConfigs.filter( + config => + !ignores.some(regexp => { + const matched = regexp.exec(config.path); + if (matched) { + console.log('ignored error in', config.path); + } + return matched; + }) + ); + + // Report the bad configs. + for (const config of badConfigs) { + for (const error of config.errorMessages) { + console.error(`${config.path}: ${error}`); + } + } + if (badConfigs.length > 0) { + const errorMessage = `${badConfigs.length} invalid config(s).`; + console.error(errorMessage); + yargs.exit(-1, new Error(errorMessage)); + } + } else { + const errorMessage = `${argv.config} isn't a file or a directory.`; + console.error(errorMessage); + yargs.exit(-2, new Error(errorMessage)); } }, };