diff --git a/.gitignore b/.gitignore index 890e9c97..5b912745 100644 --- a/.gitignore +++ b/.gitignore @@ -82,3 +82,5 @@ npm-audit.txt *.debug.js .vscode/ + +config-errors.txt diff --git a/backend/package.json b/backend/package.json index fbbe2ddc..b23dd8b6 100644 --- a/backend/package.json +++ b/backend/package.json @@ -24,6 +24,7 @@ "migrate-rollback": "npm run typeorm -- migration:revert -d dist/backend/src/data/dataSource.js", "migrate-rollback-prod": "cross-env NODE_ENV=production npm run migrate", "migrate-rollback-dev": "cross-env NODE_ENV=development npm run build && npm run migrate", + "validate-active-configs": "cross-env NODE_ENV=development node -r ./register-tsconfig-paths.js --unhandled-rejections=strict --enable-source-maps dist/backend/src/validateActiveConfigs.js > ../config-errors.txt", "test": "npm run build && npm run run-tests", "run-tests": "ava", "test-watch": "tsc-watch --onSuccess \"npx ava\"" diff --git a/backend/src/data/db.ts b/backend/src/data/db.ts index a4f9b88b..f8d8f3bf 100644 --- a/backend/src/data/db.ts +++ b/backend/src/data/db.ts @@ -15,3 +15,9 @@ export function connect() { return connectionPromise; } + +export function disconnect() { + if (connectionPromise) { + connectionPromise.then(() => dataSource.destroy()); + } +} diff --git a/backend/src/validateActiveConfigs.ts b/backend/src/validateActiveConfigs.ts new file mode 100644 index 00000000..c9e3414b --- /dev/null +++ b/backend/src/validateActiveConfigs.ts @@ -0,0 +1,46 @@ +import { YAMLException } from "js-yaml"; +import { validateGuildConfig } from "./configValidator"; +import { Configs } from "./data/Configs"; +import { connect, disconnect } from "./data/db"; +import { loadYamlSafely } from "./utils/loadYamlSafely"; +import { ObjectAliasError } from "./utils/validateNoObjectAliases"; + +function writeError(key: string, error: string) { + const indented = error.split("\n").map(s => " ".repeat(64) + s).join("\n"); + const prefix = `Invalid config ${key}:`; + const prefixed = prefix + indented.slice(prefix.length); + console.log(prefixed + "\n\n"); +} + +connect().then(async () => { + const configs = new Configs(); + const activeConfigs = await configs.getActive(); + for (const config of activeConfigs) { + if (config.key === "global") { + continue; + } + + let parsed: unknown; + try { + parsed = loadYamlSafely(config.config); + } catch (err) { + if (err instanceof ObjectAliasError) { + writeError(config.key, err.message); + continue; + } + if (err instanceof YAMLException) { + writeError(config.key, `invalid YAML: ${err.message}`); + continue; + } + throw err; + } + + const errors = await validateGuildConfig(parsed); + if (errors) { + writeError(config.key, errors); + } + } + + await disconnect(); + process.exit(0); +});