import {DotenvParseOutput, parse} from 'dotenv'; import * as fs from 'fs'; import {readAppYaml} from './AppContext'; import {getEnv} from './Config'; import {die} from './die'; export function gatherAppEnv(shard: string) { return buildAppEnv(gatherEnvFiles(shard)); } export function validateAppEnvs(shards: string[]) { const manifest = readAppYaml(); const expected = (manifest && manifest.environment) || []; if (getEnv() === 'production') { validateEnvFiles(shards, manifest); } validateEnvContents(shards, expected); } function validateEnvFiles(shards: string[], manifest: any) { const errors: string[] = []; if (manifest.meta.availability && manifest.meta.availability.includes('all')) { if (shards.map((s) => `.env.${s}`).some((f) => fs.existsSync(f))) { errors.push("Shard specific .env files are not allowed for 'all' availability"); } } if (errors.length) { die(errors.map((s) => `* ${s}`).join('\n')); } } function validateEnvContents(shards: string[], expected: string[]) { const errors: string[] = []; for (const shard of shards) { const files = gatherEnvFiles(shard); errors.push(...validateAppEnv(buildAppEnv(files), expected, files)); } if (errors.length) { die(errors.map((s) => `* ${s}`).join('\n')); } } function validateAppEnv(appEnv: DotenvParseOutput, expected: string[], envFiles: string[]) { const errors: string[] = []; Object.keys(appEnv).forEach((name) => { if (!expected.includes(name)) { errors.push(`${envFiles}: One of the env files contains a variable not listed in the app.yml: ${name}`); } }); expected.forEach((name) => { if (!appEnv[name]) { errors.push(`${envFiles}: None of the env files provide a value for the required variable: ${name}`); } }); return errors; } function gatherEnvFiles(shard: string) { const files = ['.env', `.env.${getEnv()}`]; if (getEnv() === 'production') { files.push(`.env.${shard}`); } return files; } function buildAppEnv(files: string[]) { const appEnv: DotenvParseOutput = {}; files.filter((f) => fs.existsSync(f)).forEach((f) => { Object.assign(appEnv, parse(fs.readFileSync(f))); }); return appEnv; }